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_dirent_init
  23. vfs_dirent_assign
  24. vfs_dirent_free
  25. vfs_fill_names
  26. vfs_file_is_local
  27. vfs_print_message
  28. vfs_setup_cwd
  29. vfs_get_cwd
  30. vfs_preallocate
  31. vfs_clone_file

   1 /*
   2    Virtual File System switch code
   3 
   4    Copyright (C) 1995-2024
   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>, 2011-2013
  11    Andrew Borodin <aborodin@vmail.ru>, 2011-2022
  12 
  13    This file is part of the Midnight Commander.
  14 
  15    The Midnight Commander is free software: you can redistribute it
  16    and/or modify it under the terms of the GNU General Public License as
  17    published by the Free Software Foundation, either version 3 of the License,
  18    or (at your option) any later version.
  19 
  20    The Midnight Commander is distributed in the hope that it will be useful,
  21    but WITHOUT ANY WARRANTY; without even the implied warranty of
  22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23    GNU General Public License for more details.
  24 
  25    You should have received a copy of the GNU General Public License
  26    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  27  */
  28 
  29 /**
  30  * \file
  31  * \brief Source: Virtual File System switch code
  32  * \author Miguel de Icaza
  33  * \author Jakub Jelinek
  34  * \author Pavel Machek
  35  * \date 1995, 1998
  36  * \warning functions like extfs_lstat() have right to destroy any
  37  * strings you pass to them. This is actually ok as you g_strdup what
  38  * you are passing to them, anyway; still, beware.
  39  *
  40  * Namespace: exports *many* functions with vfs_ prefix; exports
  41  * parse_ls_lga and friends which do not have that prefix.
  42  */
  43 
  44 #include <config.h>
  45 
  46 #include <errno.h>
  47 #include <stdlib.h>
  48 
  49 #ifdef __linux__
  50 #ifdef HAVE_LINUX_FS_H
  51 #include <linux/fs.h>
  52 #endif /* HAVE_LINUX_FS_H */
  53 #ifdef HAVE_SYS_IOCTL_H
  54 #include <sys/ioctl.h>
  55 #endif /* HAVE_SYS_IOCTL_H */
  56 #endif /* __linux__ */
  57 
  58 #include "lib/global.h"
  59 #include "lib/strutil.h"
  60 #include "lib/util.h"
  61 #include "lib/widget.h"         /* message() */
  62 #include "lib/event.h"
  63 
  64 #ifdef HAVE_CHARSET
  65 #include "lib/charsets.h"
  66 #endif
  67 
  68 #include "vfs.h"
  69 #include "utilvfs.h"
  70 #include "gc.h"
  71 
  72 /* TODO: move it to the separate .h */
  73 extern struct vfs_dirent *mc_readdir_result;
  74 extern GPtrArray *vfs__classes_list;
  75 extern GString *vfs_str_buffer;
  76 extern vfs_class *current_vfs;
  77 
  78 /*** global variables ****************************************************************************/
  79 
  80 MC_MOCKABLE struct vfs_dirent *mc_readdir_result = NULL;
  81 MC_MOCKABLE GPtrArray *vfs__classes_list = NULL;
  82 MC_MOCKABLE GString *vfs_str_buffer = NULL;
  83 MC_MOCKABLE vfs_class *current_vfs = NULL;
  84 
  85 /*** file scope macro definitions ****************************************************************/
  86 
  87 #define VFS_FIRST_HANDLE 100
  88 
  89 /*** file scope type declarations ****************************************************************/
  90 
  91 struct vfs_openfile
  92 {
  93     int handle;
  94     vfs_class *vclass;
  95     void *fsinfo;
  96 };
  97 
  98 /*** forward declarations (file scope functions) *************************************************/
  99 
 100 /*** file scope variables ************************************************************************/
 101 
 102 /** They keep track of the current directory */
 103 static vfs_path_t *current_path = NULL;
 104 
 105 static GPtrArray *vfs_openfiles = NULL;
 106 static long vfs_free_handle_list = -1;
 107 
 108 /* --------------------------------------------------------------------------------------------- */
 109 /*** file scope functions ************************************************************************/
 110 /* --------------------------------------------------------------------------------------------- */
 111 /* now used only by vfs_translate_path, but could be used in other vfs 
 112  * plugin to automatic detect encoding
 113  * path - path to translate
 114  * size - how many bytes from path translate
 115  * defcnv - converter, that is used as default, when path does not contain any
 116  *          #enc: substring
 117  * buffer - used to store result of translation
 118  */
 119 
 120 static estr_t
 121 _vfs_translate_path (const char *path, int size, GIConv defcnv, GString *buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 122 {
 123     estr_t state = ESTR_SUCCESS;
 124 #ifdef HAVE_CHARSET
 125     const char *semi;
 126 
 127     if (size == 0)
 128         return ESTR_SUCCESS;
 129 
 130     size = (size > 0) ? size : (signed int) strlen (path);
 131 
 132     /* try found /#enc: */
 133     semi = g_strrstr_len (path, size, VFS_ENCODING_PREFIX);
 134     if (semi != NULL && (semi == path || IS_PATH_SEP (semi[-1])))
 135     {
 136         char encoding[16];
 137         const char *slash;
 138         GIConv coder = INVALID_CONV;
 139         int ms;
 140 
 141         /* first must be translated part before #enc: */
 142         ms = semi - path;
 143 
 144         state = _vfs_translate_path (path, ms, defcnv, buffer);
 145 
 146         if (state != ESTR_SUCCESS)
 147             return state;
 148 
 149         /* now can be translated part after #enc: */
 150         semi += strlen (VFS_ENCODING_PREFIX);   /* skip "#enc:" */
 151         slash = strchr (semi, PATH_SEP);
 152         /* ignore slashes after size; */
 153         if (slash - path >= size)
 154             slash = NULL;
 155 
 156         ms = (slash != NULL) ? slash - semi : (int) strlen (semi);
 157         ms = MIN ((unsigned int) ms, sizeof (encoding) - 1);
 158         /* limit encoding size (ms) to path size (size) */
 159         if (semi + ms > path + size)
 160             ms = path + size - semi;
 161         memcpy (encoding, semi, ms);
 162         encoding[ms] = '\0';
 163 
 164         if (is_supported_encoding (encoding))
 165             coder = str_crt_conv_to (encoding);
 166 
 167         if (coder != INVALID_CONV)
 168         {
 169             if (slash != NULL)
 170                 state = str_vfs_convert_to (coder, slash + 1, path + size - slash - 1, buffer);
 171             str_close_conv (coder);
 172             return state;
 173         }
 174 
 175         errno = EINVAL;
 176         state = ESTR_FAILURE;
 177     }
 178     else
 179     {
 180         /* path can be translated whole at once */
 181         state = str_vfs_convert_to (defcnv, path, size, buffer);
 182     }
 183 #else
 184     (void) size;
 185     (void) defcnv;
 186 
 187     g_string_assign (buffer, path);
 188 #endif /* HAVE_CHARSET */
 189 
 190     return state;
 191 }
 192 
 193 /* --------------------------------------------------------------------------------------------- */
 194 
 195 static struct vfs_openfile *
 196 vfs_get_openfile (int handle)
     /* [previous][next][first][last][top][bottom][index][help]  */
 197 {
 198     struct vfs_openfile *h;
 199 
 200     if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len)
 201         return NULL;
 202 
 203     h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE);
 204     if (h != NULL)
 205         g_assert (h->handle == handle);
 206 
 207     return h;
 208 }
 209 
 210 /* --------------------------------------------------------------------------------------------- */
 211 
 212 static gboolean
 213 vfs_test_current_dir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 214 {
 215     struct stat my_stat, my_stat2;
 216 
 217     return (mc_global.vfs.cd_symlinks && mc_stat (vpath, &my_stat) == 0
 218             && mc_stat (vfs_get_raw_current_dir (), &my_stat2) == 0
 219             && my_stat.st_ino == my_stat2.st_ino && my_stat.st_dev == my_stat2.st_dev);
 220 }
 221 
 222 /* --------------------------------------------------------------------------------------------- */
 223 /*** public functions ****************************************************************************/
 224 /* --------------------------------------------------------------------------------------------- */
 225 /** Free open file data for given file handle */
 226 
 227 void
 228 vfs_free_handle (int handle)
     /* [previous][next][first][last][top][bottom][index][help]  */
 229 {
 230     const int idx = handle - VFS_FIRST_HANDLE;
 231 
 232     if (handle >= VFS_FIRST_HANDLE && (guint) idx < vfs_openfiles->len)
 233     {
 234         struct vfs_openfile *h;
 235 
 236         h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, idx);
 237         g_free (h);
 238         g_ptr_array_index (vfs_openfiles, idx) = (void *) vfs_free_handle_list;
 239         vfs_free_handle_list = idx;
 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 != NULL ? 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) == 0)       /* 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, TRUE);
 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 & VFSF_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 VFSF_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     mc_readdir_result = vfs_dirent_init (NULL, "", -1);
 473 }
 474 
 475 /* --------------------------------------------------------------------------------------------- */
 476 
 477 void
 478 vfs_setup_work_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 479 {
 480     vfs_setup_cwd ();
 481 
 482     /* FIXME: is we really need for this check? */
 483     /*
 484        if (strlen (current_dir) > MC_MAXPATHLEN - 2)
 485        vfs_die ("Current dir too long.\n");
 486      */
 487 
 488     current_vfs = VFS_CLASS (vfs_path_get_last_path_vfs (current_path));
 489 }
 490 
 491 /* --------------------------------------------------------------------------------------------- */
 492 
 493 void
 494 vfs_shut (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 495 {
 496     guint i;
 497 
 498     vfs_gc_done ();
 499 
 500     vfs_set_raw_current_dir (NULL);
 501 
 502     for (i = 0; i < vfs__classes_list->len; i++)
 503     {
 504         struct vfs_class *vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
 505 
 506         if (vfs->done != NULL)
 507             vfs->done (vfs);
 508     }
 509 
 510     /* NULL-ize pointers to make unit tests happy */
 511     g_ptr_array_free (vfs_openfiles, TRUE);
 512     vfs_openfiles = NULL;
 513     g_ptr_array_free (vfs__classes_list, TRUE);
 514     vfs__classes_list = NULL;
 515     g_string_free (vfs_str_buffer, TRUE);
 516     vfs_str_buffer = NULL;
 517     current_vfs = NULL;
 518     vfs_free_handle_list = -1;
 519     vfs_dirent_free (mc_readdir_result);
 520     mc_readdir_result = NULL;
 521 }
 522 
 523 /* --------------------------------------------------------------------------------------------- */
 524 /**
 525   * Init or create vfs_dirent structure
 526   *
 527   * @d vfs_dirent structure to init. If NULL, new structure is created.
 528   * @fname file name
 529   * @ino file inode number
 530   *
 531   * @return pointer to d if d isn't NULL, or pointer to newly created structure.
 532   */
 533 
 534 struct vfs_dirent *
 535 vfs_dirent_init (struct vfs_dirent *d, const char *fname, ino_t ino)
     /* [previous][next][first][last][top][bottom][index][help]  */
 536 {
 537     struct vfs_dirent *ret = d;
 538 
 539     if (ret == NULL)
 540         ret = g_new0 (struct vfs_dirent, 1);
 541 
 542     if (ret->d_name_str == NULL)
 543         ret->d_name_str = g_string_sized_new (MC_MAXFILENAMELEN);
 544 
 545     vfs_dirent_assign (ret, fname, ino);
 546 
 547     return ret;
 548 }
 549 
 550 /* --------------------------------------------------------------------------------------------- */
 551 /**
 552   * Assign members of vfs_dirent structure
 553   *
 554   * @d vfs_dirent structure for assignment
 555   * @fname file name
 556   * @ino file inode number
 557   */
 558 
 559 void
 560 vfs_dirent_assign (struct vfs_dirent *d, const char *fname, ino_t ino)
     /* [previous][next][first][last][top][bottom][index][help]  */
 561 {
 562     g_string_assign (d->d_name_str, fname);
 563     d->d_name = d->d_name_str->str;
 564     d->d_len = d->d_name_str->len;
 565     d->d_ino = ino;
 566 }
 567 
 568 /* --------------------------------------------------------------------------------------------- */
 569 /**
 570   * Destroy vfs_dirent structure
 571   *
 572   * @d vfs_dirent structure to destroy.
 573   */
 574 
 575 void
 576 vfs_dirent_free (struct vfs_dirent *d)
     /* [previous][next][first][last][top][bottom][index][help]  */
 577 {
 578     g_string_free (d->d_name_str, TRUE);
 579     g_free (d);
 580 }
 581 
 582 /* --------------------------------------------------------------------------------------------- */
 583 
 584 /**
 585  * These ones grab information from the VFS
 586  *  and handles them to an upper layer
 587  */
 588 
 589 void
 590 vfs_fill_names (fill_names_f func)
     /* [previous][next][first][last][top][bottom][index][help]  */
 591 {
 592     guint i;
 593 
 594     for (i = 0; i < vfs__classes_list->len; i++)
 595     {
 596         struct vfs_class *vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
 597 
 598         if (vfs->fill_names != NULL)
 599             vfs->fill_names (vfs, func);
 600     }
 601 }
 602 
 603 /* --------------------------------------------------------------------------------------------- */
 604 
 605 gboolean
 606 vfs_file_is_local (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 607 {
 608     return (vfs_file_class_flags (vpath) & VFSF_LOCAL) != 0;
 609 }
 610 
 611 /* --------------------------------------------------------------------------------------------- */
 612 
 613 void
 614 vfs_print_message (const char *msg, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 615 {
 616     ev_vfs_print_message_t event_data;
 617     va_list ap;
 618 
 619     va_start (ap, msg);
 620     event_data.msg = g_strdup_vprintf (msg, ap);
 621     va_end (ap);
 622 
 623     mc_event_raise (MCEVENT_GROUP_CORE, "vfs_print_message", (gpointer) & event_data);
 624 }
 625 
 626 /* --------------------------------------------------------------------------------------------- */
 627 /**
 628  * If it's local, reread the current directory
 629  * from the OS.
 630  */
 631 
 632 void
 633 vfs_setup_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 634 {
 635     char *current_dir;
 636     vfs_path_t *tmp_vpath;
 637     const struct vfs_class *me;
 638 
 639     if (vfs_get_raw_current_dir () == NULL)
 640     {
 641         current_dir = my_get_current_dir ();
 642         vfs_set_raw_current_dir (vfs_path_from_str (current_dir));
 643         g_free (current_dir);
 644 
 645         current_dir = getenv ("PWD");
 646         tmp_vpath = vfs_path_from_str (current_dir);
 647 
 648         if (tmp_vpath != NULL)
 649         {
 650             if (vfs_test_current_dir (tmp_vpath))
 651                 vfs_set_raw_current_dir (tmp_vpath);
 652             else
 653                 vfs_path_free (tmp_vpath, TRUE);
 654         }
 655     }
 656 
 657     me = vfs_path_get_last_path_vfs (vfs_get_raw_current_dir ());
 658     if ((me->flags & VFSF_LOCAL) != 0)
 659     {
 660         current_dir = my_get_current_dir ();
 661         tmp_vpath = vfs_path_from_str (current_dir);
 662         g_free (current_dir);
 663 
 664         if (tmp_vpath != NULL)
 665         {
 666             /* One of directories in the path is not readable */
 667 
 668             /* Check if it is O.K. to use the current_dir */
 669             if (!vfs_test_current_dir (tmp_vpath))
 670                 vfs_set_raw_current_dir (tmp_vpath);
 671             else
 672                 vfs_path_free (tmp_vpath, TRUE);
 673         }
 674     }
 675 }
 676 
 677 /* --------------------------------------------------------------------------------------------- */
 678 /**
 679  * Return current directory.  If it's local, reread the current directory
 680  * from the OS.
 681  */
 682 
 683 char *
 684 vfs_get_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 685 {
 686     vfs_setup_cwd ();
 687     return vfs_get_current_dir_n ();
 688 }
 689 
 690 /* --------------------------------------------------------------------------------------------- */
 691 /**
 692  * Preallocate space for file in new place for ensure that file
 693  * will be fully copied with less fragmentation.
 694  *
 695  * @param dest_vfs_fd mc VFS file handler
 696  * @param src_fsize source file size
 697  * @param dest_fsize destination file size (if destination exists, otherwise should be 0)
 698  *
 699  * @return 0 if success and non-zero otherwise.
 700  * Note: function doesn't touch errno global variable.
 701  */
 702 
 703 int
 704 vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize)
     /* [previous][next][first][last][top][bottom][index][help]  */
 705 {
 706 #ifndef HAVE_POSIX_FALLOCATE
 707     (void) dest_vfs_fd;
 708     (void) src_fsize;
 709     (void) dest_fsize;
 710     return 0;
 711 
 712 #else /* HAVE_POSIX_FALLOCATE */
 713     void *dest_fd = NULL;
 714     struct vfs_class *dest_class;
 715 
 716     if (src_fsize == 0)
 717         return 0;
 718 
 719     dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd);
 720     if ((dest_class->flags & VFSF_LOCAL) == 0 || dest_fd == NULL)
 721         return 0;
 722 
 723     return posix_fallocate (*(int *) dest_fd, dest_fsize, src_fsize - dest_fsize);
 724 
 725 #endif /* HAVE_POSIX_FALLOCATE */
 726 }
 727 
 728  /* --------------------------------------------------------------------------------------------- */
 729 
 730 int
 731 vfs_clone_file (int dest_vfs_fd, int src_vfs_fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 732 {
 733 #ifdef FICLONE
 734     void *dest_fd = NULL;
 735     void *src_fd = NULL;
 736     struct vfs_class *dest_class;
 737     struct vfs_class *src_class;
 738 
 739     dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd);
 740     if ((dest_class->flags & VFSF_LOCAL) == 0)
 741     {
 742         errno = ENOTSUP;
 743         return (-1);
 744     }
 745     if (dest_fd == NULL)
 746     {
 747         errno = EBADF;
 748         return (-1);
 749     }
 750 
 751     src_class = vfs_class_find_by_handle (src_vfs_fd, &src_fd);
 752     if ((src_class->flags & VFSF_LOCAL) == 0)
 753     {
 754         errno = ENOTSUP;
 755         return (-1);
 756     }
 757     if (src_fd == NULL)
 758     {
 759         errno = EBADF;
 760         return (-1);
 761     }
 762 
 763     return ioctl (*(int *) dest_fd, FICLONE, *(int *) src_fd);
 764 #else
 765     (void) dest_vfs_fd;
 766     (void) src_vfs_fd;
 767     errno = ENOTSUP;
 768     return (-1);
 769 #endif
 770 }
 771 
 772 /* --------------------------------------------------------------------------------------------- */

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