vfs.c 20 KB

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