vfs.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /*
  2. Virtual File System switch code
  3. Copyright (C) 1995-2021
  4. Free Software Foundation, Inc.
  5. Written by: 1995 Miguel de Icaza
  6. Jakub Jelinek, 1995
  7. Pavel Machek, 1998
  8. Slava Zanko <slavazanko@gmail.com>, 2013
  9. This file is part of the Midnight Commander.
  10. The Midnight Commander is free software: you can redistribute it
  11. and/or modify it under the terms of the GNU General Public License as
  12. published by the Free Software Foundation, either version 3 of the License,
  13. or (at your option) any later version.
  14. The Midnight Commander is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. /**
  22. * \file
  23. * \brief Source: Virtual File System switch code
  24. * \author Miguel de Icaza
  25. * \author Jakub Jelinek
  26. * \author Pavel Machek
  27. * \date 1995, 1998
  28. * \warning functions like extfs_lstat() have right to destroy any
  29. * strings you pass to them. This is acutally ok as you g_strdup what
  30. * you are passing to them, anyway; still, beware.
  31. *
  32. * Namespace: exports *many* functions with vfs_ prefix; exports
  33. * parse_ls_lga and friends which do not have that prefix.
  34. */
  35. #include <config.h>
  36. #include <errno.h>
  37. #include <stdlib.h>
  38. #ifdef __linux__
  39. #ifdef HAVE_LINUX_FS_H
  40. #include <linux/fs.h>
  41. #endif /* HAVE_LINUX_FS_H */
  42. #ifdef HAVE_SYS_IOCTL_H
  43. #include <sys/ioctl.h>
  44. #endif /* HAVE_SYS_IOCTL_H */
  45. #endif /* __linux__ */
  46. #include "lib/global.h"
  47. #include "lib/strutil.h"
  48. #include "lib/util.h"
  49. #include "lib/widget.h" /* message() */
  50. #include "lib/event.h"
  51. #ifdef HAVE_CHARSET
  52. #include "lib/charsets.h"
  53. #endif
  54. #include "vfs.h"
  55. #include "utilvfs.h"
  56. #include "gc.h"
  57. /* TODO: move it to the separate .h */
  58. extern struct vfs_dirent *mc_readdir_result;
  59. extern GPtrArray *vfs__classes_list;
  60. extern GString *vfs_str_buffer;
  61. extern vfs_class *current_vfs;
  62. /*** global variables ****************************************************************************/
  63. struct vfs_dirent *mc_readdir_result = NULL;
  64. GPtrArray *vfs__classes_list = NULL;
  65. GString *vfs_str_buffer = NULL;
  66. vfs_class *current_vfs = NULL;
  67. /*** file scope macro definitions ****************************************************************/
  68. #define VFS_FIRST_HANDLE 100
  69. /*** file scope type declarations ****************************************************************/
  70. struct vfs_openfile
  71. {
  72. int handle;
  73. vfs_class *vclass;
  74. void *fsinfo;
  75. };
  76. /*** file scope variables ************************************************************************/
  77. /** They keep track of the current directory */
  78. static vfs_path_t *current_path = NULL;
  79. static GPtrArray *vfs_openfiles = NULL;
  80. static long vfs_free_handle_list = -1;
  81. /* --------------------------------------------------------------------------------------------- */
  82. /*** file scope functions ************************************************************************/
  83. /* --------------------------------------------------------------------------------------------- */
  84. /* now used only by vfs_translate_path, but could be used in other vfs
  85. * plugin to automatic detect encoding
  86. * path - path to translate
  87. * size - how many bytes from path translate
  88. * defcnv - convertor, that is used as default, when path does not contain any
  89. * #enc: subtring
  90. * buffer - used to store result of translation
  91. */
  92. static estr_t
  93. _vfs_translate_path (const char *path, int size, GIConv defcnv, GString * buffer)
  94. {
  95. estr_t state = ESTR_SUCCESS;
  96. #ifdef HAVE_CHARSET
  97. const char *semi;
  98. if (size == 0)
  99. return ESTR_SUCCESS;
  100. size = (size > 0) ? size : (signed int) strlen (path);
  101. /* try found /#enc: */
  102. semi = g_strrstr_len (path, size, VFS_ENCODING_PREFIX);
  103. if (semi != NULL && (semi == path || IS_PATH_SEP (semi[-1])))
  104. {
  105. char encoding[16];
  106. const char *slash;
  107. GIConv coder = INVALID_CONV;
  108. int ms;
  109. /* first must be translated part before #enc: */
  110. ms = semi - path;
  111. state = _vfs_translate_path (path, ms, defcnv, buffer);
  112. if (state != ESTR_SUCCESS)
  113. return state;
  114. /* now can be translated part after #enc: */
  115. semi += strlen (VFS_ENCODING_PREFIX); /* skip "#enc:" */
  116. slash = strchr (semi, PATH_SEP);
  117. /* ignore slashes after size; */
  118. if (slash - path >= size)
  119. slash = NULL;
  120. ms = (slash != NULL) ? slash - semi : (int) strlen (semi);
  121. ms = MIN ((unsigned int) ms, sizeof (encoding) - 1);
  122. /* limit encoding size (ms) to path size (size) */
  123. if (semi + ms > path + size)
  124. ms = path + size - semi;
  125. memcpy (encoding, semi, ms);
  126. encoding[ms] = '\0';
  127. if (is_supported_encoding (encoding))
  128. coder = str_crt_conv_to (encoding);
  129. if (coder != INVALID_CONV)
  130. {
  131. if (slash != NULL)
  132. state = str_vfs_convert_to (coder, slash + 1, path + size - slash - 1, buffer);
  133. str_close_conv (coder);
  134. return state;
  135. }
  136. errno = EINVAL;
  137. state = ESTR_FAILURE;
  138. }
  139. else
  140. {
  141. /* path can be translated whole at once */
  142. state = str_vfs_convert_to (defcnv, path, size, buffer);
  143. }
  144. #else
  145. (void) size;
  146. (void) defcnv;
  147. g_string_assign (buffer, path);
  148. #endif /* HAVE_CHARSET */
  149. return state;
  150. }
  151. /* --------------------------------------------------------------------------------------------- */
  152. static struct vfs_openfile *
  153. vfs_get_openfile (int handle)
  154. {
  155. struct vfs_openfile *h;
  156. if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len)
  157. return NULL;
  158. h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE);
  159. if (h == NULL)
  160. return NULL;
  161. g_assert (h->handle == handle);
  162. return h;
  163. }
  164. /* --------------------------------------------------------------------------------------------- */
  165. static gboolean
  166. vfs_test_current_dir (const vfs_path_t * vpath)
  167. {
  168. struct stat my_stat, my_stat2;
  169. return (mc_global.vfs.cd_symlinks && mc_stat (vpath, &my_stat) == 0
  170. && mc_stat (vfs_get_raw_current_dir (), &my_stat2) == 0
  171. && my_stat.st_ino == my_stat2.st_ino && my_stat.st_dev == my_stat2.st_dev);
  172. }
  173. /* --------------------------------------------------------------------------------------------- */
  174. /*** public functions ****************************************************************************/
  175. /* --------------------------------------------------------------------------------------------- */
  176. /** Free open file data for given file handle */
  177. void
  178. vfs_free_handle (int handle)
  179. {
  180. const int idx = handle - VFS_FIRST_HANDLE;
  181. if (handle >= VFS_FIRST_HANDLE && (guint) idx < vfs_openfiles->len)
  182. {
  183. struct vfs_openfile *h;
  184. h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, idx);
  185. g_free (h);
  186. g_ptr_array_index (vfs_openfiles, idx) = (void *) vfs_free_handle_list;
  187. vfs_free_handle_list = idx;
  188. }
  189. }
  190. /* --------------------------------------------------------------------------------------------- */
  191. /** Find VFS class by file handle */
  192. struct vfs_class *
  193. vfs_class_find_by_handle (int handle, void **fsinfo)
  194. {
  195. struct vfs_openfile *h;
  196. h = vfs_get_openfile (handle);
  197. if (h == NULL)
  198. return NULL;
  199. if (fsinfo != NULL)
  200. *fsinfo = h->fsinfo;
  201. return h->vclass;
  202. }
  203. /* --------------------------------------------------------------------------------------------- */
  204. /**
  205. * Create new VFS handle and put it to the list
  206. */
  207. int
  208. vfs_new_handle (struct vfs_class *vclass, void *fsinfo)
  209. {
  210. struct vfs_openfile *h;
  211. h = g_new (struct vfs_openfile, 1);
  212. h->fsinfo = fsinfo;
  213. h->vclass = vclass;
  214. /* Allocate the first free handle */
  215. h->handle = vfs_free_handle_list;
  216. if (h->handle == -1)
  217. {
  218. /* No free allocated handles, allocate one */
  219. h->handle = vfs_openfiles->len;
  220. g_ptr_array_add (vfs_openfiles, h);
  221. }
  222. else
  223. {
  224. vfs_free_handle_list = (long) g_ptr_array_index (vfs_openfiles, vfs_free_handle_list);
  225. g_ptr_array_index (vfs_openfiles, h->handle) = h;
  226. }
  227. h->handle += VFS_FIRST_HANDLE;
  228. return h->handle;
  229. }
  230. /* --------------------------------------------------------------------------------------------- */
  231. int
  232. vfs_ferrno (struct vfs_class *vfs)
  233. {
  234. return vfs->ferrno ? (*vfs->ferrno) (vfs) : E_UNKNOWN;
  235. /* Hope that error message is obscure enough ;-) */
  236. }
  237. /* --------------------------------------------------------------------------------------------- */
  238. gboolean
  239. vfs_register_class (struct vfs_class * vfs)
  240. {
  241. if (vfs->init != NULL) /* vfs has own initialization function */
  242. if (!vfs->init (vfs)) /* but it failed */
  243. return FALSE;
  244. g_ptr_array_add (vfs__classes_list, vfs);
  245. return TRUE;
  246. }
  247. /* --------------------------------------------------------------------------------------------- */
  248. void
  249. vfs_unregister_class (struct vfs_class *vfs)
  250. {
  251. if (vfs->done != NULL)
  252. vfs->done (vfs);
  253. g_ptr_array_remove (vfs__classes_list, vfs);
  254. }
  255. /* --------------------------------------------------------------------------------------------- */
  256. /** Strip known vfs suffixes from a filename (possible improvement: strip
  257. * suffix from last path component).
  258. * \return a malloced string which has to be freed.
  259. */
  260. char *
  261. vfs_strip_suffix_from_filename (const char *filename)
  262. {
  263. char *semi, *p;
  264. if (filename == NULL)
  265. vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
  266. p = g_strdup (filename);
  267. semi = g_strrstr (p, VFS_PATH_URL_DELIMITER);
  268. if (semi != NULL)
  269. {
  270. char *vfs_prefix;
  271. *semi = '\0';
  272. vfs_prefix = strrchr (p, PATH_SEP);
  273. if (vfs_prefix == NULL)
  274. *semi = *VFS_PATH_URL_DELIMITER;
  275. else
  276. *vfs_prefix = '\0';
  277. }
  278. return p;
  279. }
  280. /* --------------------------------------------------------------------------------------------- */
  281. const char *
  282. vfs_translate_path (const char *path)
  283. {
  284. estr_t state;
  285. g_string_set_size (vfs_str_buffer, 0);
  286. state = _vfs_translate_path (path, -1, str_cnv_from_term, vfs_str_buffer);
  287. return (state != ESTR_FAILURE) ? vfs_str_buffer->str : NULL;
  288. }
  289. /* --------------------------------------------------------------------------------------------- */
  290. char *
  291. vfs_translate_path_n (const char *path)
  292. {
  293. const char *result;
  294. result = vfs_translate_path (path);
  295. return g_strdup (result);
  296. }
  297. /* --------------------------------------------------------------------------------------------- */
  298. /**
  299. * Get current directory without any OS calls.
  300. *
  301. * @return string contains current path
  302. */
  303. const char *
  304. vfs_get_current_dir (void)
  305. {
  306. return current_path->str;
  307. }
  308. /* --------------------------------------------------------------------------------------------- */
  309. /**
  310. * Get current directory without any OS calls.
  311. *
  312. * @return newly allocated string contains current path
  313. */
  314. char *
  315. vfs_get_current_dir_n (void)
  316. {
  317. return g_strdup (current_path->str);
  318. }
  319. /* --------------------------------------------------------------------------------------------- */
  320. /**
  321. * Get raw current directory object without any OS calls.
  322. *
  323. * @return object contain current path
  324. */
  325. const vfs_path_t *
  326. vfs_get_raw_current_dir (void)
  327. {
  328. return current_path;
  329. }
  330. /* --------------------------------------------------------------------------------------------- */
  331. /**
  332. * Set current directory object.
  333. *
  334. * @param vpath new path
  335. */
  336. void
  337. vfs_set_raw_current_dir (const vfs_path_t * vpath)
  338. {
  339. vfs_path_free (current_path, TRUE);
  340. current_path = (vfs_path_t *) vpath;
  341. }
  342. /* --------------------------------------------------------------------------------------------- */
  343. /* Return TRUE is the current VFS class is local */
  344. gboolean
  345. vfs_current_is_local (void)
  346. {
  347. return (current_vfs->flags & VFSF_LOCAL) != 0;
  348. }
  349. /* --------------------------------------------------------------------------------------------- */
  350. /* Return flags of the VFS class of the given filename */
  351. vfs_flags_t
  352. vfs_file_class_flags (const vfs_path_t * vpath)
  353. {
  354. const vfs_path_element_t *path_element;
  355. path_element = vfs_path_get_by_index (vpath, -1);
  356. if (!vfs_path_element_valid (path_element))
  357. return VFSF_UNKNOWN;
  358. return path_element->class->flags;
  359. }
  360. /* --------------------------------------------------------------------------------------------- */
  361. void
  362. vfs_init (void)
  363. {
  364. /* create the VFS handle arrays */
  365. vfs__classes_list = g_ptr_array_new ();
  366. /* create the VFS handle array */
  367. vfs_openfiles = g_ptr_array_new ();
  368. vfs_str_buffer = g_string_new ("");
  369. mc_readdir_result = vfs_dirent_init (NULL, "", -1);
  370. }
  371. /* --------------------------------------------------------------------------------------------- */
  372. void
  373. vfs_setup_work_dir (void)
  374. {
  375. const vfs_path_element_t *path_element;
  376. vfs_setup_cwd ();
  377. /* FIXME: is we really need for this check? */
  378. /*
  379. if (strlen (current_dir) > MC_MAXPATHLEN - 2)
  380. vfs_die ("Current dir too long.\n");
  381. */
  382. path_element = vfs_path_get_by_index (current_path, -1);
  383. current_vfs = path_element->class;
  384. }
  385. /* --------------------------------------------------------------------------------------------- */
  386. void
  387. vfs_shut (void)
  388. {
  389. guint i;
  390. vfs_gc_done ();
  391. vfs_set_raw_current_dir (NULL);
  392. for (i = 0; i < vfs__classes_list->len; i++)
  393. {
  394. struct vfs_class *vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
  395. if (vfs->done != NULL)
  396. vfs->done (vfs);
  397. }
  398. /* NULL-ize pointers to make unit tests happy */
  399. g_ptr_array_free (vfs_openfiles, TRUE);
  400. vfs_openfiles = NULL;
  401. g_ptr_array_free (vfs__classes_list, TRUE);
  402. vfs__classes_list = NULL;
  403. g_string_free (vfs_str_buffer, TRUE);
  404. vfs_str_buffer = NULL;
  405. current_vfs = NULL;
  406. vfs_free_handle_list = -1;
  407. vfs_dirent_free (mc_readdir_result);
  408. mc_readdir_result = NULL;
  409. }
  410. /* --------------------------------------------------------------------------------------------- */
  411. /**
  412. * Init or create vfs_dirent structure
  413. *
  414. * @d vfs_dirent structure to init. If NULL, new structure is created.
  415. * @fname file name
  416. * @ino file inode number
  417. *
  418. * @return pointer to d if d isn't NULL, or pointer to newly created structure.
  419. */
  420. struct vfs_dirent *
  421. vfs_dirent_init (struct vfs_dirent *d, const char *fname, ino_t ino)
  422. {
  423. struct vfs_dirent *ret = d;
  424. if (ret == NULL)
  425. ret = g_new0 (struct vfs_dirent, 1);
  426. if (ret->d_name_str == NULL)
  427. ret->d_name_str = g_string_sized_new (MC_MAXFILENAMELEN);
  428. vfs_dirent_assign (ret, fname, ino);
  429. return ret;
  430. }
  431. /* --------------------------------------------------------------------------------------------- */
  432. /**
  433. * Assign members of vfs_dirent structure
  434. *
  435. * @d vfs_dirent structure for assignment
  436. * @fname file name
  437. * @ino file inode number
  438. */
  439. void
  440. vfs_dirent_assign (struct vfs_dirent *d, const char *fname, ino_t ino)
  441. {
  442. g_string_assign (d->d_name_str, fname);
  443. d->d_name = d->d_name_str->str;
  444. d->d_ino = ino;
  445. }
  446. /* --------------------------------------------------------------------------------------------- */
  447. /**
  448. * Destroy vfs_dirent structure
  449. *
  450. * @d vfs_dirent structure to destroy.
  451. */
  452. void
  453. vfs_dirent_free (struct vfs_dirent *d)
  454. {
  455. g_string_free (d->d_name_str, TRUE);
  456. g_free (d);
  457. }
  458. /* --------------------------------------------------------------------------------------------- */
  459. /**
  460. * These ones grab information from the VFS
  461. * and handles them to an upper layer
  462. */
  463. void
  464. vfs_fill_names (fill_names_f func)
  465. {
  466. guint i;
  467. for (i = 0; i < vfs__classes_list->len; i++)
  468. {
  469. struct vfs_class *vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
  470. if (vfs->fill_names != NULL)
  471. vfs->fill_names (vfs, func);
  472. }
  473. }
  474. /* --------------------------------------------------------------------------------------------- */
  475. gboolean
  476. vfs_file_is_local (const vfs_path_t * vpath)
  477. {
  478. return (vfs_file_class_flags (vpath) & VFSF_LOCAL) != 0;
  479. }
  480. /* --------------------------------------------------------------------------------------------- */
  481. void
  482. vfs_print_message (const char *msg, ...)
  483. {
  484. ev_vfs_print_message_t event_data;
  485. va_list ap;
  486. va_start (ap, msg);
  487. event_data.msg = g_strdup_vprintf (msg, ap);
  488. va_end (ap);
  489. mc_event_raise (MCEVENT_GROUP_CORE, "vfs_print_message", (gpointer) & event_data);
  490. }
  491. /* --------------------------------------------------------------------------------------------- */
  492. /**
  493. * If it's local, reread the current directory
  494. * from the OS.
  495. */
  496. void
  497. vfs_setup_cwd (void)
  498. {
  499. char *current_dir;
  500. vfs_path_t *tmp_vpath;
  501. const vfs_path_element_t *path_element;
  502. if (vfs_get_raw_current_dir () == NULL)
  503. {
  504. current_dir = g_get_current_dir ();
  505. vfs_set_raw_current_dir (vfs_path_from_str (current_dir));
  506. g_free (current_dir);
  507. current_dir = getenv ("PWD");
  508. tmp_vpath = vfs_path_from_str (current_dir);
  509. if (tmp_vpath != NULL)
  510. {
  511. if (vfs_test_current_dir (tmp_vpath))
  512. vfs_set_raw_current_dir (tmp_vpath);
  513. else
  514. vfs_path_free (tmp_vpath, TRUE);
  515. }
  516. }
  517. path_element = vfs_path_get_by_index (vfs_get_raw_current_dir (), -1);
  518. if ((path_element->class->flags & VFSF_LOCAL) != 0)
  519. {
  520. current_dir = g_get_current_dir ();
  521. tmp_vpath = vfs_path_from_str (current_dir);
  522. g_free (current_dir);
  523. if (tmp_vpath != NULL)
  524. {
  525. /* One of directories in the path is not readable */
  526. /* Check if it is O.K. to use the current_dir */
  527. if (!vfs_test_current_dir (tmp_vpath))
  528. vfs_set_raw_current_dir (tmp_vpath);
  529. else
  530. vfs_path_free (tmp_vpath, TRUE);
  531. }
  532. }
  533. }
  534. /* --------------------------------------------------------------------------------------------- */
  535. /**
  536. * Return current directory. If it's local, reread the current directory
  537. * from the OS.
  538. */
  539. char *
  540. _vfs_get_cwd (void)
  541. {
  542. const vfs_path_t *current_dir_vpath;
  543. vfs_setup_cwd ();
  544. current_dir_vpath = vfs_get_raw_current_dir ();
  545. return g_strdup (vfs_path_as_str (current_dir_vpath));
  546. }
  547. /* --------------------------------------------------------------------------------------------- */
  548. /**
  549. * Preallocate space for file in new place for ensure that file
  550. * will be fully copied with less fragmentation.
  551. *
  552. * @param dest_vfs_fd mc VFS file handler
  553. * @param src_fsize source file size
  554. * @param dest_fsize destination file size (if destination exists, otherwise should be 0)
  555. *
  556. * @return 0 if success and non-zero otherwise.
  557. * Note: function doesn't touch errno global variable.
  558. */
  559. int
  560. vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize)
  561. {
  562. #ifndef HAVE_POSIX_FALLOCATE
  563. (void) dest_vfs_fd;
  564. (void) src_fsize;
  565. (void) dest_fsize;
  566. return 0;
  567. #else /* HAVE_POSIX_FALLOCATE */
  568. void *dest_fd = NULL;
  569. struct vfs_class *dest_class;
  570. if (src_fsize == 0)
  571. return 0;
  572. dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd);
  573. if ((dest_class->flags & VFSF_LOCAL) == 0 || dest_fd == NULL)
  574. return 0;
  575. return posix_fallocate (*(int *) dest_fd, dest_fsize, src_fsize - dest_fsize);
  576. #endif /* HAVE_POSIX_FALLOCATE */
  577. }
  578. /* --------------------------------------------------------------------------------------------- */
  579. int
  580. vfs_clone_file (int dest_vfs_fd, int src_vfs_fd)
  581. {
  582. #ifdef FICLONE
  583. void *dest_fd = NULL;
  584. void *src_fd = NULL;
  585. struct vfs_class *dest_class;
  586. struct vfs_class *src_class;
  587. dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd);
  588. if ((dest_class->flags & VFSF_LOCAL) == 0)
  589. {
  590. errno = EOPNOTSUPP;
  591. return (-1);
  592. }
  593. if (dest_fd == NULL)
  594. {
  595. errno = EBADF;
  596. return (-1);
  597. }
  598. src_class = vfs_class_find_by_handle (src_vfs_fd, &src_fd);
  599. if ((src_class->flags & VFSF_LOCAL) == 0)
  600. {
  601. errno = EOPNOTSUPP;
  602. return (-1);
  603. }
  604. if (src_fd == NULL)
  605. {
  606. errno = EBADF;
  607. return (-1);
  608. }
  609. return ioctl (*(int *) dest_fd, FICLONE, *(int *) src_fd);
  610. #else
  611. (void) dest_vfs_fd;
  612. (void) src_vfs_fd;
  613. errno = EOPNOTSUPP;
  614. return (-1);
  615. #endif
  616. }
  617. /* --------------------------------------------------------------------------------------------- */