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-2021
   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 vfs_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 struct vfs_dirent *mc_readdir_result = NULL;
  80 GPtrArray *vfs__classes_list = NULL;
  81 GString *vfs_str_buffer = NULL;
  82 vfs_class *current_vfs = NULL;
  83 
  84 /*** file scope macro definitions ****************************************************************/
  85 
  86 #define VFS_FIRST_HANDLE 100
  87 
  88 /*** file scope type declarations ****************************************************************/
  89 
  90 struct vfs_openfile
  91 {
  92     int handle;
  93     vfs_class *vclass;
  94     void *fsinfo;
  95 };
  96 
  97 /*** file scope variables ************************************************************************/
  98 
  99 /** They keep track of the current directory */
 100 static vfs_path_t *current_path = NULL;
 101 
 102 static GPtrArray *vfs_openfiles = NULL;
 103 static long vfs_free_handle_list = -1;
 104 
 105 /* --------------------------------------------------------------------------------------------- */
 106 /*** file scope functions ************************************************************************/
 107 /* --------------------------------------------------------------------------------------------- */
 108 /* now used only by vfs_translate_path, but could be used in other vfs 
 109  * plugin to automatic detect encoding
 110  * path - path to translate
 111  * size - how many bytes from path translate
 112  * defcnv - convertor, that is used as default, when path does not contain any
 113  *          #enc: subtring
 114  * buffer - used to store result of translation
 115  */
 116 
 117 static estr_t
 118 _vfs_translate_path (const char *path, int size, GIConv defcnv, GString * buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 119 {
 120     estr_t state = ESTR_SUCCESS;
 121 #ifdef HAVE_CHARSET
 122     const char *semi;
 123 
 124     if (size == 0)
 125         return ESTR_SUCCESS;
 126 
 127     size = (size > 0) ? size : (signed int) strlen (path);
 128 
 129     /* try found /#enc: */
 130     semi = g_strrstr_len (path, size, VFS_ENCODING_PREFIX);
 131     if (semi != NULL && (semi == path || IS_PATH_SEP (semi[-1])))
 132     {
 133         char encoding[16];
 134         const char *slash;
 135         GIConv coder = INVALID_CONV;
 136         int ms;
 137 
 138         /* first must be translated part before #enc: */
 139         ms = semi - path;
 140 
 141         state = _vfs_translate_path (path, ms, defcnv, buffer);
 142 
 143         if (state != ESTR_SUCCESS)
 144             return state;
 145 
 146         /* now can be translated part after #enc: */
 147         semi += strlen (VFS_ENCODING_PREFIX);   /* skip "#enc:" */
 148         slash = strchr (semi, PATH_SEP);
 149         /* ignore slashes after size; */
 150         if (slash - path >= size)
 151             slash = NULL;
 152 
 153         ms = (slash != NULL) ? slash - semi : (int) strlen (semi);
 154         ms = MIN ((unsigned int) ms, sizeof (encoding) - 1);
 155         /* limit encoding size (ms) to path size (size) */
 156         if (semi + ms > path + size)
 157             ms = path + size - semi;
 158         memcpy (encoding, semi, ms);
 159         encoding[ms] = '\0';
 160 
 161         if (is_supported_encoding (encoding))
 162             coder = str_crt_conv_to (encoding);
 163 
 164         if (coder != INVALID_CONV)
 165         {
 166             if (slash != NULL)
 167                 state = str_vfs_convert_to (coder, slash + 1, path + size - slash - 1, buffer);
 168             str_close_conv (coder);
 169             return state;
 170         }
 171 
 172         errno = EINVAL;
 173         state = ESTR_FAILURE;
 174     }
 175     else
 176     {
 177         /* path can be translated whole at once */
 178         state = str_vfs_convert_to (defcnv, path, size, buffer);
 179     }
 180 #else
 181     (void) size;
 182     (void) defcnv;
 183 
 184     g_string_assign (buffer, path);
 185 #endif /* HAVE_CHARSET */
 186 
 187     return state;
 188 }
 189 
 190 /* --------------------------------------------------------------------------------------------- */
 191 
 192 static struct vfs_openfile *
 193 vfs_get_openfile (int handle)
     /* [previous][next][first][last][top][bottom][index][help]  */
 194 {
 195     struct vfs_openfile *h;
 196 
 197     if (handle < VFS_FIRST_HANDLE || (guint) (handle - VFS_FIRST_HANDLE) >= vfs_openfiles->len)
 198         return NULL;
 199 
 200     h = (struct vfs_openfile *) g_ptr_array_index (vfs_openfiles, handle - VFS_FIRST_HANDLE);
 201     if (h == NULL)
 202         return NULL;
 203 
 204     g_assert (h->handle == handle);
 205 
 206     return h;
 207 }
 208 
 209 /* --------------------------------------------------------------------------------------------- */
 210 
 211 static gboolean
 212 vfs_test_current_dir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 213 {
 214     struct stat my_stat, my_stat2;
 215 
 216     return (mc_global.vfs.cd_symlinks && mc_stat (vpath, &my_stat) == 0
 217             && mc_stat (vfs_get_raw_current_dir (), &my_stat2) == 0
 218             && my_stat.st_ino == my_stat2.st_ino && my_stat.st_dev == my_stat2.st_dev);
 219 }
 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 /* --------------------------------------------------------------------------------------------- */
 245 /** Find VFS class by file handle */
 246 
 247 struct vfs_class *
 248 vfs_class_find_by_handle (int handle, void **fsinfo)
     /* [previous][next][first][last][top][bottom][index][help]  */
 249 {
 250     struct vfs_openfile *h;
 251 
 252     h = vfs_get_openfile (handle);
 253 
 254     if (h == NULL)
 255         return NULL;
 256 
 257     if (fsinfo != NULL)
 258         *fsinfo = h->fsinfo;
 259 
 260     return h->vclass;
 261 }
 262 
 263 /* --------------------------------------------------------------------------------------------- */
 264 
 265 /**
 266  * Create new VFS handle and put it to the list
 267  */
 268 
 269 int
 270 vfs_new_handle (struct vfs_class *vclass, void *fsinfo)
     /* [previous][next][first][last][top][bottom][index][help]  */
 271 {
 272     struct vfs_openfile *h;
 273 
 274     h = g_new (struct vfs_openfile, 1);
 275     h->fsinfo = fsinfo;
 276     h->vclass = vclass;
 277 
 278     /* Allocate the first free handle */
 279     h->handle = vfs_free_handle_list;
 280     if (h->handle == -1)
 281     {
 282         /* No free allocated handles, allocate one */
 283         h->handle = vfs_openfiles->len;
 284         g_ptr_array_add (vfs_openfiles, h);
 285     }
 286     else
 287     {
 288         vfs_free_handle_list = (long) g_ptr_array_index (vfs_openfiles, vfs_free_handle_list);
 289         g_ptr_array_index (vfs_openfiles, h->handle) = h;
 290     }
 291 
 292     h->handle += VFS_FIRST_HANDLE;
 293     return h->handle;
 294 }
 295 
 296 /* --------------------------------------------------------------------------------------------- */
 297 
 298 int
 299 vfs_ferrno (struct vfs_class *vfs)
     /* [previous][next][first][last][top][bottom][index][help]  */
 300 {
 301     return vfs->ferrno ? (*vfs->ferrno) (vfs) : E_UNKNOWN;
 302     /* Hope that error message is obscure enough ;-) */
 303 }
 304 
 305 /* --------------------------------------------------------------------------------------------- */
 306 
 307 gboolean
 308 vfs_register_class (struct vfs_class * vfs)
     /* [previous][next][first][last][top][bottom][index][help]  */
 309 {
 310     if (vfs->init != NULL)      /* vfs has own initialization function */
 311         if (!vfs->init (vfs))   /* but it failed */
 312             return FALSE;
 313 
 314     g_ptr_array_add (vfs__classes_list, vfs);
 315 
 316     return TRUE;
 317 }
 318 
 319 /* --------------------------------------------------------------------------------------------- */
 320 
 321 void
 322 vfs_unregister_class (struct vfs_class *vfs)
     /* [previous][next][first][last][top][bottom][index][help]  */
 323 {
 324     if (vfs->done != NULL)
 325         vfs->done (vfs);
 326 
 327     g_ptr_array_remove (vfs__classes_list, vfs);
 328 }
 329 
 330 /* --------------------------------------------------------------------------------------------- */
 331 /** Strip known vfs suffixes from a filename (possible improvement: strip
 332  *  suffix from last path component).
 333  *  \return a malloced string which has to be freed.
 334  */
 335 
 336 char *
 337 vfs_strip_suffix_from_filename (const char *filename)
     /* [previous][next][first][last][top][bottom][index][help]  */
 338 {
 339     char *semi, *p;
 340 
 341     if (filename == NULL)
 342         vfs_die ("vfs_strip_suffix_from_path got NULL: impossible");
 343 
 344     p = g_strdup (filename);
 345     semi = g_strrstr (p, VFS_PATH_URL_DELIMITER);
 346     if (semi != NULL)
 347     {
 348         char *vfs_prefix;
 349 
 350         *semi = '\0';
 351         vfs_prefix = strrchr (p, PATH_SEP);
 352         if (vfs_prefix == NULL)
 353             *semi = *VFS_PATH_URL_DELIMITER;
 354         else
 355             *vfs_prefix = '\0';
 356     }
 357 
 358     return p;
 359 }
 360 
 361 /* --------------------------------------------------------------------------------------------- */
 362 
 363 const char *
 364 vfs_translate_path (const char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
 365 {
 366     estr_t state;
 367 
 368     g_string_set_size (vfs_str_buffer, 0);
 369     state = _vfs_translate_path (path, -1, str_cnv_from_term, vfs_str_buffer);
 370     return (state != ESTR_FAILURE) ? vfs_str_buffer->str : NULL;
 371 }
 372 
 373 /* --------------------------------------------------------------------------------------------- */
 374 
 375 char *
 376 vfs_translate_path_n (const char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
 377 {
 378     const char *result;
 379 
 380     result = vfs_translate_path (path);
 381     return g_strdup (result);
 382 }
 383 
 384 /* --------------------------------------------------------------------------------------------- */
 385 /**
 386  * Get current directory without any OS calls.
 387  *
 388  * @return string contains current path
 389  */
 390 
 391 const char *
 392 vfs_get_current_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 393 {
 394     return current_path->str;
 395 }
 396 
 397 /* --------------------------------------------------------------------------------------------- */
 398 /**
 399  * Get current directory without any OS calls.
 400  *
 401  * @return newly allocated string contains current path
 402  */
 403 
 404 char *
 405 vfs_get_current_dir_n (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 406 {
 407     return g_strdup (current_path->str);
 408 }
 409 
 410 /* --------------------------------------------------------------------------------------------- */
 411 /**
 412  * Get raw current directory object without any OS calls.
 413  *
 414  * @return object contain current path
 415  */
 416 
 417 const vfs_path_t *
 418 vfs_get_raw_current_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 419 {
 420     return current_path;
 421 }
 422 
 423 /* --------------------------------------------------------------------------------------------- */
 424 /**
 425  * Set current directory object.
 426  *
 427  * @param vpath new path
 428  */
 429 void
 430 vfs_set_raw_current_dir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 431 {
 432     vfs_path_free (current_path, TRUE);
 433     current_path = (vfs_path_t *) vpath;
 434 }
 435 
 436 /* --------------------------------------------------------------------------------------------- */
 437 /* Return TRUE is the current VFS class is local */
 438 
 439 gboolean
 440 vfs_current_is_local (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 441 {
 442     return (current_vfs->flags & VFSF_LOCAL) != 0;
 443 }
 444 
 445 /* --------------------------------------------------------------------------------------------- */
 446 /* Return flags of the VFS class of the given filename */
 447 
 448 vfs_flags_t
 449 vfs_file_class_flags (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 450 {
 451     const vfs_path_element_t *path_element;
 452 
 453     path_element = vfs_path_get_by_index (vpath, -1);
 454     if (!vfs_path_element_valid (path_element))
 455         return VFSF_UNKNOWN;
 456 
 457     return path_element->class->flags;
 458 }
 459 
 460 /* --------------------------------------------------------------------------------------------- */
 461 
 462 void
 463 vfs_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 464 {
 465     /* create the VFS handle arrays */
 466     vfs__classes_list = g_ptr_array_new ();
 467 
 468     /* create the VFS handle array */
 469     vfs_openfiles = g_ptr_array_new ();
 470 
 471     vfs_str_buffer = g_string_new ("");
 472 
 473     mc_readdir_result = vfs_dirent_init (NULL, "", -1);
 474 }
 475 
 476 /* --------------------------------------------------------------------------------------------- */
 477 
 478 void
 479 vfs_setup_work_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 480 {
 481     const vfs_path_element_t *path_element;
 482 
 483     vfs_setup_cwd ();
 484 
 485     /* FIXME: is we really need for this check? */
 486     /*
 487        if (strlen (current_dir) > MC_MAXPATHLEN - 2)
 488        vfs_die ("Current dir too long.\n");
 489      */
 490 
 491     path_element = vfs_path_get_by_index (current_path, -1);
 492     current_vfs = path_element->class;
 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 vfs_path_element_t *path_element;
 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     path_element = vfs_path_get_by_index (vfs_get_raw_current_dir (), -1);
 661 
 662     if ((path_element->class->flags & VFSF_LOCAL) != 0)
 663     {
 664         current_dir = g_get_current_dir ();
 665         tmp_vpath = vfs_path_from_str (current_dir);
 666         g_free (current_dir);
 667 
 668         if (tmp_vpath != NULL)
 669         {
 670             /* One of directories in the path is not readable */
 671 
 672             /* Check if it is O.K. to use the current_dir */
 673             if (!vfs_test_current_dir (tmp_vpath))
 674                 vfs_set_raw_current_dir (tmp_vpath);
 675             else
 676                 vfs_path_free (tmp_vpath, TRUE);
 677         }
 678     }
 679 }
 680 
 681 /* --------------------------------------------------------------------------------------------- */
 682 /**
 683  * Return current directory.  If it's local, reread the current directory
 684  * from the OS.
 685  */
 686 
 687 char *
 688 _vfs_get_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 689 {
 690     const vfs_path_t *current_dir_vpath;
 691 
 692     vfs_setup_cwd ();
 693     current_dir_vpath = vfs_get_raw_current_dir ();
 694     return g_strdup (vfs_path_as_str (current_dir_vpath));
 695 }
 696 
 697 /* --------------------------------------------------------------------------------------------- */
 698 /**
 699  * Preallocate space for file in new place for ensure that file
 700  * will be fully copied with less fragmentation.
 701  *
 702  * @param dest_vfs_fd mc VFS file handler
 703  * @param src_fsize source file size
 704  * @param dest_fsize destination file size (if destination exists, otherwise should be 0)
 705  *
 706  * @return 0 if success and non-zero otherwise.
 707  * Note: function doesn't touch errno global variable.
 708  */
 709 
 710 int
 711 vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize)
     /* [previous][next][first][last][top][bottom][index][help]  */
 712 {
 713 #ifndef HAVE_POSIX_FALLOCATE
 714     (void) dest_vfs_fd;
 715     (void) src_fsize;
 716     (void) dest_fsize;
 717     return 0;
 718 
 719 #else /* HAVE_POSIX_FALLOCATE */
 720     void *dest_fd = NULL;
 721     struct vfs_class *dest_class;
 722 
 723     if (src_fsize == 0)
 724         return 0;
 725 
 726     dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd);
 727     if ((dest_class->flags & VFSF_LOCAL) == 0 || dest_fd == NULL)
 728         return 0;
 729 
 730     return posix_fallocate (*(int *) dest_fd, dest_fsize, src_fsize - dest_fsize);
 731 
 732 #endif /* HAVE_POSIX_FALLOCATE */
 733 }
 734 
 735  /* --------------------------------------------------------------------------------------------- */
 736 
 737 int
 738 vfs_clone_file (int dest_vfs_fd, int src_vfs_fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 739 {
 740 #ifdef FICLONE
 741     void *dest_fd = NULL;
 742     void *src_fd = NULL;
 743     struct vfs_class *dest_class;
 744     struct vfs_class *src_class;
 745 
 746     dest_class = vfs_class_find_by_handle (dest_vfs_fd, &dest_fd);
 747     if ((dest_class->flags & VFSF_LOCAL) == 0)
 748     {
 749         errno = EOPNOTSUPP;
 750         return (-1);
 751     }
 752     if (dest_fd == NULL)
 753     {
 754         errno = EBADF;
 755         return (-1);
 756     }
 757 
 758     src_class = vfs_class_find_by_handle (src_vfs_fd, &src_fd);
 759     if ((src_class->flags & VFSF_LOCAL) == 0)
 760     {
 761         errno = EOPNOTSUPP;
 762         return (-1);
 763     }
 764     if (src_fd == NULL)
 765     {
 766         errno = EBADF;
 767         return (-1);
 768     }
 769 
 770     return ioctl (*(int *) dest_fd, FICLONE, *(int *) src_fd);
 771 #else
 772     (void) dest_vfs_fd;
 773     (void) src_vfs_fd;
 774     errno = EOPNOTSUPP;
 775     return (-1);
 776 #endif
 777 }
 778 
 779 /* --------------------------------------------------------------------------------------------- */

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