root/lib/vfs/vfs.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. _vfs_translate_path
  2. vfs_get_openfile
  3. vfs_test_current_dir
  4. vfs_free_handle
  5. vfs_class_find_by_handle
  6. vfs_new_handle
  7. vfs_ferrno
  8. vfs_register_class
  9. vfs_unregister_class
  10. vfs_strip_suffix_from_filename
  11. vfs_translate_path
  12. vfs_translate_path_n
  13. vfs_get_current_dir
  14. vfs_get_current_dir_n
  15. vfs_get_raw_current_dir
  16. vfs_set_raw_current_dir
  17. vfs_current_is_local
  18. vfs_file_class_flags
  19. vfs_init
  20. vfs_setup_work_dir
  21. vfs_shut
  22. vfs_fill_names
  23. vfs_file_is_local
  24. vfs_print_message
  25. vfs_setup_cwd
  26. _vfs_get_cwd
  27. vfs_preallocate
  28. vfs_clone_file

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

/* [previous][next][first][last][top][bottom][index][help]  */