Manual pages: mcmcdiffmceditmcview

root/lib/vfs/interface.c

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

DEFINITIONS

This source file includes following definitions.
  1. mc_def_getlocalcopy
  2. mc_def_ungetlocalcopy
  3. mc_open
  4. MC_NAMEOP
  5. MC_RENAMEOP
  6. mc_setctl
  7. mc_close
  8. mc_opendir
  9. mc_readdir
  10. mc_closedir
  11. MC_STATOP
  12. mc_ungetlocalcopy
  13. mc_chdir
  14. mc_lseek
  15. mc_mkstemps
  16. mc_tmpdir

   1 /*
   2    Virtual File System: interface functions
   3 
   4    Copyright (C) 2011-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Slava Zanko <slavazanko@gmail.com>, 2011, 2013
   9    Andrew Borodin <aborodin@vmail.ru>, 2011-2022
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  25  */
  26 
  27 /**
  28  * \file
  29  * \brief Source: Virtual File System: path handlers
  30  * \author Slava Zanko
  31  * \date 2011
  32  */
  33 
  34 #include <config.h>
  35 
  36 #include <stdio.h>
  37 #include <stdlib.h>  // For atol()
  38 #include <stdarg.h>
  39 #include <string.h>
  40 #include <errno.h>
  41 #include <sys/types.h>
  42 #include <signal.h>
  43 #include <ctype.h>  // is_digit()
  44 #include <sys/stat.h>
  45 #include <unistd.h>
  46 #include <dirent.h>
  47 #include <pwd.h>
  48 #include <grp.h>
  49 
  50 #include "lib/global.h"
  51 
  52 #include "lib/widget.h"   // message()
  53 #include "lib/strutil.h"  // str_crt_conv_from()
  54 #include "lib/util.h"
  55 
  56 #include "vfs.h"
  57 #include "utilvfs.h"
  58 #include "path.h"
  59 #include "gc.h"
  60 #include "xdirentry.h"
  61 
  62 /* TODO: move it to separate private .h */
  63 extern GString *vfs_str_buffer;
  64 extern vfs_class *current_vfs;
  65 extern struct vfs_dirent *mc_readdir_result;
  66 
  67 /*** global variables ****************************************************************************/
  68 
  69 /*** file scope macro definitions ****************************************************************/
  70 
  71 /*** file scope type declarations ****************************************************************/
  72 
  73 /*** forward declarations (file scope functions) *************************************************/
  74 
  75 /*** file scope variables ************************************************************************/
  76 
  77 /* --------------------------------------------------------------------------------------------- */
  78 /*** file scope functions ************************************************************************/
  79 /* --------------------------------------------------------------------------------------------- */
  80 
  81 static vfs_path_t *
  82 mc_def_getlocalcopy (const vfs_path_t *filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
  83 {
  84     vfs_path_t *tmp_vpath = NULL;
  85     int fdin, fdout = -1;
  86     ssize_t i;
  87     char buffer[BUF_1K * 8];
  88     struct stat mystat;
  89 
  90     fdin = mc_open (filename_vpath, O_RDONLY | O_LINEAR);
  91     if (fdin == -1)
  92         goto fail;
  93 
  94     fdout = vfs_mkstemps (&tmp_vpath, "vfs", vfs_path_get_last_path_str (filename_vpath));
  95     if (fdout == -1)
  96         goto fail;
  97 
  98     while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0)
  99     {
 100         if (write (fdout, buffer, i) != i)
 101             goto fail;
 102     }
 103     if (i == -1)
 104         goto fail;
 105     i = mc_close (fdin);
 106     fdin = -1;
 107     if (i == -1)
 108         goto fail;
 109 
 110     i = close (fdout);
 111     fdout = -1;
 112     if (i == -1)
 113         goto fail;
 114 
 115     if (mc_stat (filename_vpath, &mystat) != -1)
 116         mc_chmod (tmp_vpath, mystat.st_mode);
 117 
 118     return tmp_vpath;
 119 
 120 fail:
 121     vfs_path_free (tmp_vpath, TRUE);
 122     if (fdout != -1)
 123         close (fdout);
 124     if (fdin != -1)
 125         mc_close (fdin);
 126     return NULL;
 127 }
 128 
 129 /* --------------------------------------------------------------------------------------------- */
 130 
 131 static int
 132 mc_def_ungetlocalcopy (const vfs_path_t *filename_vpath, const vfs_path_t *local_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 133                        gboolean has_changed)
 134 {
 135     int fdin = -1, fdout = -1;
 136     const char *local;
 137 
 138     local = vfs_path_get_last_path_str (local_vpath);
 139 
 140     if (has_changed)
 141     {
 142         char buffer[BUF_1K * 8];
 143         ssize_t i;
 144 
 145         if (vfs_path_get_last_path_vfs (filename_vpath)->write == NULL)
 146             goto failed;
 147 
 148         fdin = open (local, O_RDONLY);
 149         if (fdin == -1)
 150             goto failed;
 151         fdout = mc_open (filename_vpath, O_WRONLY | O_TRUNC);
 152         if (fdout == -1)
 153             goto failed;
 154         while ((i = read (fdin, buffer, sizeof (buffer))) > 0)
 155             if (mc_write (fdout, buffer, (size_t) i) != i)
 156                 goto failed;
 157         if (i == -1)
 158             goto failed;
 159 
 160         if (close (fdin) == -1)
 161         {
 162             fdin = -1;
 163             goto failed;
 164         }
 165         fdin = -1;
 166         if (mc_close (fdout) == -1)
 167         {
 168             fdout = -1;
 169             goto failed;
 170         }
 171     }
 172     unlink (local);
 173     return 0;
 174 
 175 failed:
 176     message (D_ERROR, _ ("Changes to file lost"), "%s",
 177              vfs_path_get_last_path_str (filename_vpath));
 178     if (fdout != -1)
 179         mc_close (fdout);
 180     if (fdin != -1)
 181         close (fdin);
 182     unlink (local);
 183     return (-1);
 184 }
 185 
 186 /* --------------------------------------------------------------------------------------------- */
 187 /*** public functions ****************************************************************************/
 188 /* --------------------------------------------------------------------------------------------- */
 189 
 190 int
 191 mc_open (const vfs_path_t *vpath, int flags, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 192 {
 193     int result = -1;
 194     mode_t mode = 0;
 195     struct vfs_class *me;
 196 
 197     if (vpath == NULL)
 198         return (-1);
 199 
 200     // Get the mode flag
 201     if ((flags & O_CREAT) != 0)
 202     {
 203         va_list ap;
 204 
 205         va_start (ap, flags);
 206         /* We have to use PROMOTED_MODE_T instead of mode_t. Doing 'va_arg (ap, mode_t)'
 207          * fails on systems where 'mode_t' is smaller than 'int' because of C's "default
 208          * argument promotions". */
 209         mode = va_arg (ap, PROMOTED_MODE_T);
 210         va_end (ap);
 211     }
 212 
 213     me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
 214     if (me != NULL && me->open != NULL)
 215     {
 216         void *info;
 217 
 218         // open must be supported
 219         info = me->open (vpath, flags, mode);
 220         if (info == NULL)
 221             errno = vfs_ferrno (me);
 222         else
 223             result = vfs_new_handle (me, info);
 224     }
 225     else
 226         errno = ENOTSUP;
 227 
 228     return result;
 229 }
 230 
 231 /* --------------------------------------------------------------------------------------------- */
 232 
 233 #define MC_NAMEOP(name, inarg, callarg)                                                            \
 234     int mc_##name inarg                                                                            \
 235     {                                                                                              \
 236         int result;                                                                                \
 237         struct vfs_class *me;                                                                      \
 238                                                                                                    \
 239         if (vpath == NULL)                                                                         \
 240             return (-1);                                                                           \
 241                                                                                                    \
 242         me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));                                       \
 243         if (me == NULL)                                                                            \
 244             return (-1);                                                                           \
 245                                                                                                    \
 246         result = me->name != NULL ? me->name callarg : -1;                                         \
 247         if (result == -1)                                                                          \
 248             errno = me->name != NULL ? vfs_ferrno (me) : ENOTSUP;                                  \
 249         return result;                                                                             \
 250     }
 251 
 252 MC_NAMEOP (chmod, (const vfs_path_t *vpath, mode_t mode), (vpath, mode))
     /* [previous][next][first][last][top][bottom][index][help]  */
 253 MC_NAMEOP (chown, (const vfs_path_t *vpath, uid_t owner, gid_t group), (vpath, owner, group))
 254 MC_NAMEOP (fgetflags, (const vfs_path_t *vpath, unsigned long *flags), (vpath, flags))
 255 MC_NAMEOP (fsetflags, (const vfs_path_t *vpath, unsigned long flags), (vpath, flags))
 256 MC_NAMEOP (utime, (const vfs_path_t *vpath, mc_timesbuf_t *times), (vpath, times))
 257 MC_NAMEOP (readlink, (const vfs_path_t *vpath, char *buf, size_t bufsiz), (vpath, buf, bufsiz))
 258 MC_NAMEOP (unlink, (const vfs_path_t *vpath), (vpath))
 259 MC_NAMEOP (mkdir, (const vfs_path_t *vpath, mode_t mode), (vpath, mode))
 260 MC_NAMEOP (rmdir, (const vfs_path_t *vpath), (vpath))
 261 MC_NAMEOP (mknod, (const vfs_path_t *vpath, mode_t mode, dev_t dev), (vpath, mode, dev))
 262 
 263 /* --------------------------------------------------------------------------------------------- */
 264 
 265 int
 266 mc_symlink (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
 267 {
 268     int result = -1;
 269 
 270     if (vpath1 != NULL && vpath2 != NULL)
 271     {
 272         struct vfs_class *me;
 273 
 274         me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath2));
 275         if (me != NULL)
 276         {
 277             result = me->symlink != NULL ? me->symlink (vpath1, vpath2) : -1;
 278             if (result == -1)
 279                 errno = me->symlink != NULL ? vfs_ferrno (me) : ENOTSUP;
 280         }
 281     }
 282     return result;
 283 }
 284 
 285 /* --------------------------------------------------------------------------------------------- */
 286 
 287 #define MC_HANDLEOP(rettype, name, inarg, callarg)                                                 \
 288     rettype mc_##name inarg                                                                        \
 289     {                                                                                              \
 290         struct vfs_class *vfs;                                                                     \
 291         void *fsinfo = NULL;                                                                       \
 292         rettype result;                                                                            \
 293                                                                                                    \
 294         if (handle == -1)                                                                          \
 295             return (-1);                                                                           \
 296                                                                                                    \
 297         vfs = vfs_class_find_by_handle (handle, &fsinfo);                                          \
 298         if (vfs == NULL)                                                                           \
 299             return (-1);                                                                           \
 300                                                                                                    \
 301         result = vfs->name != NULL ? vfs->name callarg : -1;                                       \
 302         if (result == -1)                                                                          \
 303             errno = vfs->name != NULL ? vfs_ferrno (vfs) : ENOTSUP;                                \
 304         return result;                                                                             \
 305     }
 306 
 307 MC_HANDLEOP (ssize_t, read, (int handle, void *buf, size_t count), (fsinfo, buf, count))
 308 MC_HANDLEOP (ssize_t, write, (int handle, const void *buf, size_t count), (fsinfo, buf, count))
 309 MC_HANDLEOP (int, fstat, (int handle, struct stat *buf), (fsinfo, buf))
 310 
 311 /* --------------------------------------------------------------------------------------------- */
 312 
 313 #define MC_RENAMEOP(name)                                                                          \
 314     int mc_##name (const vfs_path_t *vpath1, const vfs_path_t *vpath2)                             \
 315     {                                                                                              \
 316         int result;                                                                                \
 317         struct vfs_class *me1, *me2;                                                               \
 318                                                                                                    \
 319         if (vpath1 == NULL || vpath2 == NULL)                                                      \
 320             return (-1);                                                                           \
 321                                                                                                    \
 322         me1 = VFS_CLASS (vfs_path_get_last_path_vfs (vpath1));                                     \
 323         me2 = VFS_CLASS (vfs_path_get_last_path_vfs (vpath2));                                     \
 324                                                                                                    \
 325         if (me1 == NULL || me2 == NULL || me1 != me2)                                              \
 326         {                                                                                          \
 327             errno = EXDEV;                                                                         \
 328             return (-1);                                                                           \
 329         }                                                                                          \
 330                                                                                                    \
 331         result = me1->name != NULL ? me1->name (vpath1, vpath2) : -1;                              \
 332         if (result == -1)                                                                          \
 333             errno = me1->name != NULL ? vfs_ferrno (me1) : ENOTSUP;                                \
 334         return result;                                                                             \
 335     }
 336 
 337 MC_RENAMEOP (link)
     /* [previous][next][first][last][top][bottom][index][help]  */
 338 MC_RENAMEOP (rename)
 339 
 340 /* --------------------------------------------------------------------------------------------- */
 341 
 342 int
 343 mc_ctl (int handle, int ctlop, void *arg)
 344 {
 345     struct vfs_class *vfs;
 346     void *fsinfo = NULL;
 347 
 348     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 349 
 350     return (vfs == NULL || vfs->ctl == NULL) ? 0 : vfs->ctl (fsinfo, ctlop, arg);
 351 }
 352 
 353 /* --------------------------------------------------------------------------------------------- */
 354 
 355 int
 356 mc_setctl (const vfs_path_t *vpath, int ctlop, void *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 357 {
 358     int result = -1;
 359     struct vfs_class *me;
 360 
 361     if (vpath == NULL)
 362         vfs_die ("You don't want to pass NULL to mc_setctl.");
 363 
 364     me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));
 365     if (me != NULL)
 366         result = me->setctl != NULL ? me->setctl (vpath, ctlop, arg) : 0;
 367 
 368     return result;
 369 }
 370 
 371 /* --------------------------------------------------------------------------------------------- */
 372 
 373 int
 374 mc_close (int handle)
     /* [previous][next][first][last][top][bottom][index][help]  */
 375 {
 376     struct vfs_class *vfs;
 377     void *fsinfo = NULL;
 378     int result;
 379 
 380     if (handle == -1)
 381         return (-1);
 382 
 383     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 384     if (vfs == NULL || fsinfo == NULL)
 385         return (-1);
 386 
 387     if (handle < 3)
 388         return close (handle);
 389 
 390     if (vfs->close == NULL)
 391         vfs_die ("VFS must support close.\n");
 392     result = vfs->close (fsinfo);
 393     vfs_free_handle (handle);
 394     if (result == -1)
 395         errno = vfs_ferrno (vfs);
 396 
 397     return result;
 398 }
 399 
 400 /* --------------------------------------------------------------------------------------------- */
 401 
 402 DIR *
 403 mc_opendir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 404 {
 405     int handle, *handlep;
 406     void *info;
 407     vfs_path_element_t *path_element;
 408 
 409     if (vpath == NULL)
 410         return NULL;
 411 
 412     path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, -1);
 413     if (!vfs_path_element_valid (path_element))
 414     {
 415         errno = ENOTSUP;
 416         return NULL;
 417     }
 418 
 419     info = path_element->class->opendir ? path_element->class->opendir (vpath) : NULL;
 420     if (info == NULL)
 421     {
 422         errno = path_element->class->opendir ? vfs_ferrno (path_element->class) : ENOTSUP;
 423         return NULL;
 424     }
 425 
 426     path_element->dir.info = info;
 427 
 428     path_element->dir.converter = (path_element->encoding != NULL)
 429         ? str_crt_conv_from (path_element->encoding)
 430         : str_cnv_from_term;
 431     if (path_element->dir.converter == INVALID_CONV)
 432         path_element->dir.converter = str_cnv_from_term;
 433 
 434     handle = vfs_new_handle (path_element->class, vfs_path_element_clone (path_element));
 435 
 436     handlep = g_new (int, 1);
 437     *handlep = handle;
 438     return (DIR *) handlep;
 439 }
 440 
 441 /* --------------------------------------------------------------------------------------------- */
 442 
 443 struct vfs_dirent *
 444 mc_readdir (DIR *dirp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 445 {
 446     int handle;
 447     struct vfs_class *vfs;
 448     void *fsinfo = NULL;
 449     struct vfs_dirent *entry = NULL;
 450     vfs_path_element_t *vfs_path_element;
 451 
 452     if (dirp == NULL)
 453     {
 454         errno = EFAULT;
 455         return NULL;
 456     }
 457 
 458     handle = *(int *) dirp;
 459 
 460     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 461     if (vfs == NULL || fsinfo == NULL)
 462         return NULL;
 463 
 464     vfs_path_element = (vfs_path_element_t *) fsinfo;
 465     if (vfs->readdir != NULL)
 466     {
 467         entry = vfs->readdir (vfs_path_element->dir.info);
 468         if (entry == NULL)
 469             return NULL;
 470 
 471         g_string_set_size (vfs_str_buffer, 0);
 472         str_vfs_convert_from (vfs_path_element->dir.converter, entry->d_name, vfs_str_buffer);
 473         vfs_dirent_assign (mc_readdir_result, vfs_str_buffer->str, entry->d_ino);
 474         vfs_dirent_free (entry);
 475     }
 476     if (entry == NULL)
 477         errno = vfs->readdir ? vfs_ferrno (vfs) : ENOTSUP;
 478     return (entry != NULL) ? mc_readdir_result : NULL;
 479 }
 480 
 481 /* --------------------------------------------------------------------------------------------- */
 482 
 483 int
 484 mc_closedir (DIR *dirp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 485 {
 486     int handle;
 487     struct vfs_class *vfs;
 488     void *fsinfo = NULL;
 489     int result = -1;
 490 
 491     if (dirp == NULL)
 492         return result;
 493 
 494     handle = *(int *) dirp;
 495 
 496     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 497     if (vfs != NULL && fsinfo != NULL)
 498     {
 499         vfs_path_element_t *vfs_path_element = (vfs_path_element_t *) fsinfo;
 500 
 501         if (vfs_path_element->dir.converter != str_cnv_from_term)
 502         {
 503             str_close_conv (vfs_path_element->dir.converter);
 504             vfs_path_element->dir.converter = INVALID_CONV;
 505         }
 506 
 507         result = vfs->closedir ? (*vfs->closedir) (vfs_path_element->dir.info) : -1;
 508         vfs_free_handle (handle);
 509         vfs_path_element_free (vfs_path_element);
 510     }
 511     g_free (dirp);
 512     return result;
 513 }
 514 
 515 /* --------------------------------------------------------------------------------------------- */
 516 
 517 #define MC_STATOP(name)                                                                            \
 518     int mc_##name (const vfs_path_t *vpath, struct stat *buf)                                      \
 519     {                                                                                              \
 520         int result = -1;                                                                           \
 521         struct vfs_class *me;                                                                      \
 522                                                                                                    \
 523         if (vpath == NULL)                                                                         \
 524             return (-1);                                                                           \
 525                                                                                                    \
 526         me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));                                       \
 527         if (me != NULL)                                                                            \
 528         {                                                                                          \
 529             result = me->name ? me->name (vpath, buf) : -1;                                        \
 530             if (result == -1)                                                                      \
 531                 errno = me->name ? vfs_ferrno (me) : ENOTSUP;                                      \
 532         }                                                                                          \
 533                                                                                                    \
 534         return result;                                                                             \
 535     }
 536 
 537 MC_STATOP (stat)
     /* [previous][next][first][last][top][bottom][index][help]  */
 538 MC_STATOP (lstat)
 539 
 540 /* --------------------------------------------------------------------------------------------- */
 541 
 542 vfs_path_t *
 543 mc_getlocalcopy (const vfs_path_t *pathname_vpath)
 544 {
 545     vfs_path_t *result = NULL;
 546     struct vfs_class *me;
 547 
 548     if (pathname_vpath == NULL)
 549         return NULL;
 550 
 551     me = VFS_CLASS (vfs_path_get_last_path_vfs (pathname_vpath));
 552     if (me != NULL)
 553     {
 554         result = me->getlocalcopy != NULL ? me->getlocalcopy (pathname_vpath)
 555                                           : mc_def_getlocalcopy (pathname_vpath);
 556         if (result == NULL)
 557             errno = vfs_ferrno (me);
 558     }
 559     return result;
 560 }
 561 
 562 /* --------------------------------------------------------------------------------------------- */
 563 
 564 int
 565 mc_ungetlocalcopy (const vfs_path_t *pathname_vpath, const vfs_path_t *local_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 566                    gboolean has_changed)
 567 {
 568     int result = -1;
 569     const struct vfs_class *me;
 570 
 571     if (pathname_vpath == NULL)
 572         return (-1);
 573 
 574     me = vfs_path_get_last_path_vfs (pathname_vpath);
 575     if (me != NULL)
 576         result = me->ungetlocalcopy != NULL
 577             ? me->ungetlocalcopy (pathname_vpath, local_vpath, has_changed)
 578             : mc_def_ungetlocalcopy (pathname_vpath, local_vpath, has_changed);
 579 
 580     return result;
 581 }
 582 
 583 /* --------------------------------------------------------------------------------------------- */
 584 /**
 585  * VFS chdir.
 586  *
 587  * @param vpath VFS path.
 588  *              May be NULL. In this case NULL is returned and errno set to 0.
 589  *
 590  * @return 0 on success, -1 on failure.
 591  */
 592 
 593 int
 594 mc_chdir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 595 {
 596     struct vfs_class *old_vfs;
 597     vfsid old_vfsid;
 598     int result;
 599     struct vfs_class *me;
 600     const vfs_path_element_t *path_element;
 601     vfs_path_t *cd_vpath;
 602 
 603     if (vpath == NULL)
 604     {
 605         errno = 0;
 606         return (-1);
 607     }
 608 
 609     if (vpath->relative)
 610         cd_vpath = vfs_path_to_absolute (vpath);
 611     else
 612         cd_vpath = vfs_path_clone (vpath);
 613 
 614     me = VFS_CLASS (vfs_path_get_last_path_vfs (cd_vpath));
 615     if (me == NULL)
 616     {
 617         errno = EINVAL;
 618         goto error_end;
 619     }
 620 
 621     if (me->chdir == NULL)
 622     {
 623         errno = ENOTSUP;
 624         goto error_end;
 625     }
 626 
 627     result = me->chdir (cd_vpath);
 628     if (result == -1)
 629     {
 630         errno = vfs_ferrno (me);
 631         goto error_end;
 632     }
 633 
 634     old_vfsid = vfs_getid (vfs_get_raw_current_dir ());
 635     old_vfs = current_vfs;
 636 
 637     // Actually change directory
 638     vfs_set_raw_current_dir (cd_vpath);
 639     current_vfs = me;
 640 
 641     // This function uses the new current_dir implicitly
 642     vfs_stamp_create (old_vfs, old_vfsid);
 643 
 644     // Sometimes we assume no trailing slash on cwd
 645     path_element = vfs_path_get_by_index (vfs_get_raw_current_dir (), -1);
 646     if (vfs_path_element_valid (path_element))
 647     {
 648         if (*path_element->path != '\0')
 649         {
 650             char *p;
 651 
 652             p = strchr (path_element->path, 0) - 1;
 653             if (IS_PATH_SEP (*p) && p > path_element->path)
 654                 *p = '\0';
 655         }
 656 
 657 #ifdef ENABLE_VFS_NET
 658         {
 659             struct vfs_s_super *super;
 660 
 661             super = vfs_get_super_by_vpath (vpath);
 662             if (super != NULL && super->path_element != NULL)
 663             {
 664                 g_free (super->path_element->path);
 665                 super->path_element->path = g_strdup (path_element->path);
 666             }
 667         }
 668 #endif
 669     }
 670 
 671     return 0;
 672 
 673 error_end:
 674     vfs_path_free (cd_vpath, TRUE);
 675     return (-1);
 676 }
 677 
 678 /* --------------------------------------------------------------------------------------------- */
 679 
 680 off_t
 681 mc_lseek (int fd, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
 682 {
 683     struct vfs_class *vfs;
 684     void *fsinfo = NULL;
 685     off_t result;
 686 
 687     if (fd == -1)
 688         return (-1);
 689 
 690     vfs = vfs_class_find_by_handle (fd, &fsinfo);
 691     if (vfs == NULL)
 692         return (-1);
 693 
 694     result = vfs->lseek ? vfs->lseek (fsinfo, offset, whence) : -1;
 695     if (result == -1)
 696         errno = vfs->lseek ? vfs_ferrno (vfs) : ENOTSUP;
 697     return result;
 698 }
 699 
 700 /* --------------------------------------------------------------------------------------------- */
 701 /* Following code heavily borrows from libiberty, mkstemps.c */
 702 /*
 703  * Arguments:
 704  * pname (output) - pointer to the name of the temp file (needs g_free).
 705  *                  NULL if the function fails.
 706  * prefix - part of the filename before the random part.
 707  *          Prepend $TMPDIR or /tmp if there are no path separators.
 708  * suffix - if not NULL, part of the filename after the random part.
 709  *
 710  * Result:
 711  * handle of the open file or -1 if couldn't open any.
 712  */
 713 
 714 int
 715 mc_mkstemps (vfs_path_t **pname_vpath, const char *prefix, const char *suffix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 716 {
 717     char *p1, *p2;
 718     int fd;
 719 
 720     if (strchr (prefix, PATH_SEP) != NULL)
 721         p1 = g_strdup (prefix);
 722     else
 723     {
 724         // Add prefix first to find the position of XXXXXX
 725         p1 = g_build_filename (mc_tmpdir (), prefix, (char *) NULL);
 726     }
 727 
 728     p2 = g_strconcat (p1, "XXXXXX", suffix, (char *) NULL);
 729     g_free (p1);
 730 
 731     fd = g_mkstemp (p2);
 732     if (fd >= 0)
 733         *pname_vpath = vfs_path_from_str (p2);
 734     else
 735     {
 736         *pname_vpath = NULL;
 737         fd = -1;
 738     }
 739 
 740     g_free (p2);
 741 
 742     return fd;
 743 }
 744 
 745 /* --------------------------------------------------------------------------------------------- */
 746 /**
 747  * Return the directory where mc should keep its temporary files.
 748  * This directory is (in Bourne shell terms) "${TMPDIR=/tmp}/mc-XXXXXX"
 749  * When called the first time, the directory is created if needed.
 750  * The first call should be done early, since we are using fprintf()
 751  * and not message() to report possible problems.
 752  */
 753 
 754 const char *
 755 mc_tmpdir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 756 {
 757     static char buffer[PATH_MAX];
 758     static const char *tmpdir = NULL;
 759     const char *sys_tmp;
 760     gchar *template;
 761 
 762     // Check if already correctly initialized
 763     if (tmpdir != NULL)
 764     {
 765         struct stat st;
 766 
 767         if (lstat (tmpdir, &st) == 0 && S_ISDIR (st.st_mode) && st.st_uid == getuid ()
 768             && (st.st_mode & 0777) == 0700)
 769             return tmpdir;
 770     }
 771 
 772     sys_tmp = getenv ("MC_TMPDIR");
 773     if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
 774     {
 775         sys_tmp = getenv ("TMPDIR");
 776         if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
 777             sys_tmp = TMPDIR_DEFAULT;
 778     }
 779 
 780     template = g_build_filename (sys_tmp, "mc-XXXXXX", (char *) NULL);
 781     g_strlcpy (buffer, template, sizeof (buffer));
 782     g_free (template);
 783 
 784     tmpdir = g_mkdtemp (buffer);
 785     if (tmpdir != NULL)
 786         g_setenv ("MC_TMPDIR", tmpdir, TRUE);
 787     else
 788     {
 789         fprintf (stderr,
 790                  _ ("Cannot create temporary directory %s: %s.\n"
 791                     "Temporary files will not be created\n"),
 792                  buffer, unix_error_string (errno));
 793         g_snprintf (buffer, sizeof (buffer), "%s", "/dev/null/");
 794         fprintf (stderr, "%s\n", _ ("Press any key to continue..."));
 795         getc (stdin);
 796     }
 797 
 798     return tmpdir;
 799 }
 800 
 801 /* --------------------------------------------------------------------------------------------- */

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