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 struct vfs_dirent *mc_readdir_result = NULL;
  81 GPtrArray *vfs__classes_list = NULL;
  82 GString *vfs_str_buffer = NULL;
  83 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         return NULL;
 206 
 207     g_assert (h->handle == handle);
 208 
 209     return h;
 210 }
 211 
 212 /* --------------------------------------------------------------------------------------------- */
 213 
 214 static gboolean
 215 vfs_test_current_dir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 216 {
 217     struct stat my_stat, my_stat2;
 218 
 219     return (mc_global.vfs.cd_symlinks && mc_stat (vpath, &my_stat) == 0
 220             && mc_stat (vfs_get_raw_current_dir (), &my_stat2) == 0
 221             && my_stat.st_ino == my_stat2.st_ino && my_stat.st_dev == my_stat2.st_dev);
 222 }
 223 
 224 
 225 /* --------------------------------------------------------------------------------------------- */
 226 /*** public functions ****************************************************************************/
 227 /* --------------------------------------------------------------------------------------------- */
 228 /** Free open file data for given file handle */
 229 
 230 void
 231 vfs_free_handle (int handle)
     /* [previous][next][first][last][top][bottom][index][help]  */
 232 {
 233     const int idx = handle - VFS_FIRST_HANDLE;
 234 
 235     if (handle >= VFS_FIRST_HANDLE && (guint) idx < vfs_openfiles->len)
 236     {
 237         struct vfs_openfile *h;
 238 
 239         h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, idx);
 240         g_free (h);
 241         g_ptr_array_index (vfs_openfiles, idx) = (void *) vfs_free_handle_list;
 242         vfs_free_handle_list = idx;
 243     }
 244 }
 245 
 246 
 247 /* --------------------------------------------------------------------------------------------- */
 248 /** Find VFS class by file handle */
 249 
 250 struct vfs_class *
 251 vfs_class_find_by_handle (int handle, void **fsinfo)
     /* [previous][next][first][last][top][bottom][index][help]  */
 252 {
 253     struct vfs_openfile *h;
 254 
 255     h = vfs_get_openfile (handle);
 256 
 257     if (h == NULL)
 258         return NULL;
 259 
 260     if (fsinfo != NULL)
 261         *fsinfo = h->fsinfo;
 262 
 263     return h->vclass;
 264 }
 265 
 266 /* --------------------------------------------------------------------------------------------- */
 267 
 268 /**
 269  * Create new VFS handle and put it to the list
 270  */
 271 
 272 int
 273 vfs_new_handle (struct vfs_class *vclass, void *fsinfo)
     /* [previous][next][first][last][top][bottom][index][help]  */
 274 {
 275     struct vfs_openfile *h;
 276 
 277     h = g_new (struct vfs_openfile, 1);
 278     h->fsinfo = fsinfo;
 279     h->vclass = vclass;
 280 
 281     /* Allocate the first free handle */
 282     h->handle = vfs_free_handle_list;
 283     if (h->handle == -1)
 284     {
 285         /* No free allocated handles, allocate one */
 286         h->handle = vfs_openfiles->len;
 287         g_ptr_array_add (vfs_openfiles, h);
 288     }
 289     else
 290     {
 291         vfs_free_handle_list = (long) g_ptr_array_index (vfs_openfiles, vfs_free_handle_list);
 292         g_ptr_array_index (vfs_openfiles, h->handle) = h;
 293     }
 294 
 295     h->handle += VFS_FIRST_HANDLE;
 296     return h->handle;
 297 }
 298 
 299 /* --------------------------------------------------------------------------------------------- */
 300 
 301 int
 302 vfs_ferrno (struct vfs_class *vfs)
     /* [previous][next][first][last][top][bottom][index][help]  */
 303 {
 304     return vfs->ferrno ? (*vfs->ferrno) (vfs) : E_UNKNOWN;
 305     /* Hope that error message is obscure enough ;-) */
 306 }
 307 
 308 /* --------------------------------------------------------------------------------------------- */
 309 
 310 gboolean
 311 vfs_register_class (struct vfs_class * vfs)
     /* [previous][next][first][last][top][bottom][index][help]  */
 312 {
 313     if (vfs->init != NULL)      /* vfs has own initialization function */
 314         if (!vfs->init (vfs))   /* but it failed */
 315             return FALSE;
 316 
 317     g_ptr_array_add (vfs__classes_list, vfs);
 318 
 319     return TRUE;
 320 }
 321 
 322 /* --------------------------------------------------------------------------------------------- */
 323 
 324 void
 325 vfs_unregister_class (struct vfs_class *vfs)
     /* [previous][next][first][last][top][bottom][index][help]  */
 326 {
 327     if (vfs->done != NULL)
 328         vfs->done (vfs);
 329 
 330     g_ptr_array_remove (vfs__classes_list, vfs);
 331 }
 332 
 333 /* --------------------------------------------------------------------------------------------- */
 334 /** Strip known vfs suffixes from a filename (possible improvement: strip
 335  *  suffix from last path component).
 336  *  \return a malloced string which has to be freed.
 337  */
 338 
 339 char *
 340 vfs_strip_suffix_from_filename (const char *filename)
     /* [previous][next][first][last][top][bottom][index][help]  */
 341 {
 342     char *semi, *p;
 343 
 344     if (filename == NULL)
 345         vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
 346 
 347     p = g_strdup (filename);
 348     semi = g_strrstr (p, VFS_PATH_URL_DELIMITER);
 349     if (semi != NULL)
 350     {
 351         char *vfs_prefix;
 352 
 353         *semi = '\0';
 354         vfs_prefix = strrchr (p, PATH_SEP);
 355         if (vfs_prefix == NULL)
 356             *semi = *VFS_PATH_URL_DELIMITER;
 357         else
 358             *vfs_prefix = '\0';
 359     }
 360 
 361     return p;
 362 }
 363 
 364 /* --------------------------------------------------------------------------------------------- */
 365 
 366 const char *
 367 vfs_translate_path (const char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
 368 {
 369     estr_t state;
 370 
 371     g_string_set_size (vfs_str_buffer, 0);
 372     state = _vfs_translate_path (path, -1, str_cnv_from_term, vfs_str_buffer);
 373     return (state != ESTR_FAILURE) ? vfs_str_buffer->str : NULL;
 374 }
 375 
 376 /* --------------------------------------------------------------------------------------------- */
 377 
 378 char *
 379 vfs_translate_path_n (const char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
 380 {
 381     const char *result;
 382 
 383     result = vfs_translate_path (path);
 384     return g_strdup (result);
 385 }
 386 
 387 /* --------------------------------------------------------------------------------------------- */
 388 /**
 389  * Get current directory without any OS calls.
 390  *
 391  * @return string contains current path
 392  */
 393 
 394 const char *
 395 vfs_get_current_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 396 {
 397     return current_path->str;
 398 }
 399 
 400 /* --------------------------------------------------------------------------------------------- */
 401 /**
 402  * Get current directory without any OS calls.
 403  *
 404  * @return newly allocated string contains current path
 405  */
 406 
 407 char *
 408 vfs_get_current_dir_n (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 409 {
 410     return g_strdup (current_path->str);
 411 }
 412 
 413 /* --------------------------------------------------------------------------------------------- */
 414 /**
 415  * Get raw current directory object without any OS calls.
 416  *
 417  * @return object contain current path
 418  */
 419 
 420 const vfs_path_t *
 421 vfs_get_raw_current_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 422 {
 423     return current_path;
 424 }
 425 
 426 /* --------------------------------------------------------------------------------------------- */
 427 /**
 428  * Set current directory object.
 429  *
 430  * @param vpath new path
 431  */
 432 void
 433 vfs_set_raw_current_dir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 434 {
 435     vfs_path_free (current_path, TRUE);
 436     current_path = (vfs_path_t *) vpath;
 437 }
 438 
 439 /* --------------------------------------------------------------------------------------------- */
 440 /* Return TRUE is the current VFS class is local */
 441 
 442 gboolean
 443 vfs_current_is_local (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 444 {
 445     return (current_vfs->flags & VFSF_LOCAL) != 0;
 446 }
 447 
 448 /* --------------------------------------------------------------------------------------------- */
 449 /* Return flags of the VFS class of the given filename */
 450 
 451 vfs_flags_t
 452 vfs_file_class_flags (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 453 {
 454     const vfs_path_element_t *path_element;
 455 
 456     path_element = vfs_path_get_by_index (vpath, -1);
 457     if (!vfs_path_element_valid (path_element))
 458         return VFSF_UNKNOWN;
 459 
 460     return path_element->class->flags;
 461 }
 462 
 463 /* --------------------------------------------------------------------------------------------- */
 464 
 465 void
 466 vfs_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 467 {
 468     /* create the VFS handle arrays */
 469     vfs__classes_list = g_ptr_array_new ();
 470 
 471     /* create the VFS handle array */
 472     vfs_openfiles = g_ptr_array_new ();
 473 
 474     vfs_str_buffer = g_string_new ("");
 475 
 476     mc_readdir_result = vfs_dirent_init (NULL, "", -1);
 477 }
 478 
 479 /* --------------------------------------------------------------------------------------------- */
 480 
 481 void
 482 vfs_setup_work_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 483 {
 484     vfs_setup_cwd ();
 485 
 486     /* FIXME: is we really need for this check? */
 487     /*
 488        if (strlen (current_dir) > MC_MAXPATHLEN - 2)
 489        vfs_die ("Current dir too long.\n");
 490      */
 491 
 492     current_vfs = VFS_CLASS (vfs_path_get_last_path_vfs (current_path));
 493 }
 494 
 495 /* --------------------------------------------------------------------------------------------- */
 496 
 497 void
 498 vfs_shut (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 499 {
 500     guint i;
 501 
 502     vfs_gc_done ();
 503 
 504     vfs_set_raw_current_dir (NULL);
 505 
 506     for (i = 0; i < vfs__classes_list->len; i++)
 507     {
 508         struct vfs_class *vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
 509 
 510         if (vfs->done != NULL)
 511             vfs->done (vfs);
 512     }
 513 
 514     /* NULL-ize pointers to make unit tests happy */
 515     g_ptr_array_free (vfs_openfiles, TRUE);
 516     vfs_openfiles = NULL;
 517     g_ptr_array_free (vfs__classes_list, TRUE);
 518     vfs__classes_list = NULL;
 519     g_string_free (vfs_str_buffer, TRUE);
 520     vfs_str_buffer = NULL;
 521     current_vfs = NULL;
 522     vfs_free_handle_list = -1;
 523     vfs_dirent_free (mc_readdir_result);
 524     mc_readdir_result = NULL;
 525 }
 526 
 527 /* --------------------------------------------------------------------------------------------- */
 528 /**
 529   * Init or create vfs_dirent structure
 530   *
 531   * @d vfs_dirent structure to init. If NULL, new structure is created.
 532   * @fname file name
 533   * @ino file inode number
 534   *
 535   * @return pointer to d if d isn't NULL, or pointer to newly created structure.
 536   */
 537 
 538 struct vfs_dirent *
 539 vfs_dirent_init (struct vfs_dirent *d, const char *fname, ino_t ino)
     /* [previous][next][first][last][top][bottom][index][help]  */
 540 {
 541     struct vfs_dirent *ret = d;
 542 
 543     if (ret == NULL)
 544         ret = g_new0 (struct vfs_dirent, 1);
 545 
 546     if (ret->d_name_str == NULL)
 547         ret->d_name_str = g_string_sized_new (MC_MAXFILENAMELEN);
 548 
 549     vfs_dirent_assign (ret, fname, ino);
 550 
 551     return ret;
 552 }
 553 
 554 /* --------------------------------------------------------------------------------------------- */
 555 /**
 556   * Assign members of vfs_dirent structure
 557   *
 558   * @d vfs_dirent structure for assignment
 559   * @fname file name
 560   * @ino file inode number
 561   */
 562 
 563 void
 564 vfs_dirent_assign (struct vfs_dirent *d, const char *fname, ino_t ino)
     /* [previous][next][first][last][top][bottom][index][help]  */
 565 {
 566     g_string_assign (d->d_name_str, fname);
 567     d->d_name = d->d_name_str->str;
 568     d->d_ino = ino;
 569 }
 570 
 571 /* --------------------------------------------------------------------------------------------- */
 572 /**
 573   * Destroy vfs_dirent structure
 574   *
 575   * @d vfs_dirent structure to destroy.
 576   */
 577 
 578 void
 579 vfs_dirent_free (struct vfs_dirent *d)
     /* [previous][next][first][last][top][bottom][index][help]  */
 580 {
 581     g_string_free (d->d_name_str, TRUE);
 582     g_free (d);
 583 }
 584 
 585 /* --------------------------------------------------------------------------------------------- */
 586 
 587 /**
 588  * These ones grab information from the VFS
 589  *  and handles them to an upper layer
 590  */
 591 
 592 void
 593 vfs_fill_names (fill_names_f func)
     /* [previous][next][first][last][top][bottom][index][help]  */
 594 {
 595     guint i;
 596 
 597     for (i = 0; i < vfs__classes_list->len; i++)
 598     {
 599         struct vfs_class *vfs = VFS_CLASS (g_ptr_array_index (vfs__classes_list, i));
 600 
 601         if (vfs->fill_names != NULL)
 602             vfs->fill_names (vfs, func);
 603     }
 604 }
 605 
 606 /* --------------------------------------------------------------------------------------------- */
 607 
 608 gboolean
 609 vfs_file_is_local (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 610 {
 611     return (vfs_file_class_flags (vpath) & VFSF_LOCAL) != 0;
 612 }
 613 
 614 /* --------------------------------------------------------------------------------------------- */
 615 
 616 void
 617 vfs_print_message (const char *msg, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 618 {
 619     ev_vfs_print_message_t event_data;
 620     va_list ap;
 621 
 622     va_start (ap, msg);
 623     event_data.msg = g_strdup_vprintf (msg, ap);
 624     va_end (ap);
 625 
 626     mc_event_raise (MCEVENT_GROUP_CORE, "vfs_print_message", (gpointer) & event_data);
 627 }
 628 
 629 /* --------------------------------------------------------------------------------------------- */
 630 /**
 631  * If it's local, reread the current directory
 632  * from the OS.
 633  */
 634 
 635 void
 636 vfs_setup_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 637 {
 638     char *current_dir;
 639     vfs_path_t *tmp_vpath;
 640     const struct vfs_class *me;
 641 
 642     if (vfs_get_raw_current_dir () == NULL)
 643     {
 644         current_dir = g_get_current_dir ();
 645         vfs_set_raw_current_dir (vfs_path_from_str (current_dir));
 646         g_free (current_dir);
 647 
 648         current_dir = getenv ("PWD");
 649         tmp_vpath = vfs_path_from_str (current_dir);
 650 
 651         if (tmp_vpath != NULL)
 652         {
 653             if (vfs_test_current_dir (tmp_vpath))
 654                 vfs_set_raw_current_dir (tmp_vpath);
 655             else
 656                 vfs_path_free (tmp_vpath, TRUE);
 657         }
 658     }
 659 
 660     me = vfs_path_get_last_path_vfs (vfs_get_raw_current_dir ());
 661     if ((me->flags & VFSF_LOCAL) != 0)
 662     {
 663         current_dir = g_get_current_dir ();
 664         tmp_vpath = vfs_path_from_str (current_dir);
 665         g_free (current_dir);
 666 
 667         if (tmp_vpath != NULL)
 668         {
 669             /* One of directories in the path is not readable */
 670 
 671             /* Check if it is O.K. to use the current_dir */
 672             if (!vfs_test_current_dir (tmp_vpath))
 673                 vfs_set_raw_current_dir (tmp_vpath);
 674             else
 675                 vfs_path_free (tmp_vpath, TRUE);
 676         }
 677     }
 678 }
 679 
 680 /* --------------------------------------------------------------------------------------------- */
 681 /**
 682  * Return current directory.  If it's local, reread the current directory
 683  * from the OS.
 684  */
 685 
 686 char *
 687 vfs_get_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 688 {
 689     vfs_setup_cwd ();
 690     return vfs_get_current_dir_n ();
 691 }
 692 
 693 /* --------------------------------------------------------------------------------------------- */
 694 /**
 695  * Preallocate space for file in new place for ensure that file
 696  * will be fully copied with less fragmentation.
 697  *
 698  * @param dest_vfs_fd mc VFS file handler
 699  * @param src_fsize source file size
 700  * @param dest_fsize destination file size (if destination exists, otherwise should be 0)
 701  *
 702  * @return 0 if success and non-zero otherwise.
 703  * Note: function doesn't touch errno global variable.
 704  */
 705 
 706 int
 707 vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize)
     /* [previous][next][first][last][top][bottom][index][help]  */
 708 {
 709 #ifndef HAVE_POSIX_FALLOCATE
 710     (void) dest_vfs_fd;
 711     (void) src_fsize;
 712     (void) dest_fsize;
 713     return 0;
 714 
 715 #else /* HAVE_POSIX_FALLOCATE */
 716     void *dest_fd = NULL;
 717     struct vfs_class *dest_class;
 718 
 719     if (src_fsize == 0)
 720         return 0;
 721 
 722     dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd);
 723     if ((dest_class->flags & VFSF_LOCAL) == 0 || dest_fd == NULL)
 724         return 0;
 725 
 726     return posix_fallocate (*(int *) dest_fd, dest_fsize, src_fsize - dest_fsize);
 727 
 728 #endif /* HAVE_POSIX_FALLOCATE */
 729 }
 730 
 731  /* --------------------------------------------------------------------------------------------- */
 732 
 733 int
 734 vfs_clone_file (int dest_vfs_fd, int src_vfs_fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 735 {
 736 #ifdef FICLONE
 737     void *dest_fd = NULL;
 738     void *src_fd = NULL;
 739     struct vfs_class *dest_class;
 740     struct vfs_class *src_class;
 741 
 742     dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd);
 743     if ((dest_class->flags & VFSF_LOCAL) == 0)
 744     {
 745         errno = ENOTSUP;
 746         return (-1);
 747     }
 748     if (dest_fd == NULL)
 749     {
 750         errno = EBADF;
 751         return (-1);
 752     }
 753 
 754     src_class = vfs_class_find_by_handle (src_vfs_fd, &src_fd);
 755     if ((src_class->flags & VFSF_LOCAL) == 0)
 756     {
 757         errno = ENOTSUP;
 758         return (-1);
 759     }
 760     if (src_fd == NULL)
 761     {
 762         errno = EBADF;
 763         return (-1);
 764     }
 765 
 766     return ioctl (*(int *) dest_fd, FICLONE, *(int *) src_fd);
 767 #else
 768     (void) dest_vfs_fd;
 769     (void) src_vfs_fd;
 770     errno = ENOTSUP;
 771     return (-1);
 772 #endif
 773 }
 774 
 775 /* --------------------------------------------------------------------------------------------- */

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