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 #ifdef HAVE_CHARSET
 429     path_element->dir.converter = (path_element->encoding != NULL)
 430         ? str_crt_conv_from (path_element->encoding)
 431         : str_cnv_from_term;
 432     if (path_element->dir.converter == INVALID_CONV)
 433         path_element->dir.converter = str_cnv_from_term;
 434 #endif
 435 
 436     handle = vfs_new_handle (path_element->class, vfs_path_element_clone (path_element));
 437 
 438     handlep = g_new (int, 1);
 439     *handlep = handle;
 440     return (DIR *) handlep;
 441 }
 442 
 443 /* --------------------------------------------------------------------------------------------- */
 444 
 445 struct vfs_dirent *
 446 mc_readdir (DIR *dirp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 447 {
 448     int handle;
 449     struct vfs_class *vfs;
 450     void *fsinfo = NULL;
 451     struct vfs_dirent *entry = NULL;
 452     vfs_path_element_t *vfs_path_element;
 453 
 454     if (dirp == NULL)
 455     {
 456         errno = EFAULT;
 457         return NULL;
 458     }
 459 
 460     handle = *(int *) dirp;
 461 
 462     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 463     if (vfs == NULL || fsinfo == NULL)
 464         return NULL;
 465 
 466     vfs_path_element = (vfs_path_element_t *) fsinfo;
 467     if (vfs->readdir != NULL)
 468     {
 469         entry = vfs->readdir (vfs_path_element->dir.info);
 470         if (entry == NULL)
 471             return NULL;
 472 
 473         g_string_set_size (vfs_str_buffer, 0);
 474 #ifdef HAVE_CHARSET
 475         str_vfs_convert_from (vfs_path_element->dir.converter, entry->d_name, vfs_str_buffer);
 476 #else
 477         g_string_append_len (vfs_str_buffer, entry->d_name, entry->d_len);
 478 #endif
 479         vfs_dirent_assign (mc_readdir_result, vfs_str_buffer->str, entry->d_ino);
 480         vfs_dirent_free (entry);
 481     }
 482     if (entry == NULL)
 483         errno = vfs->readdir ? vfs_ferrno (vfs) : ENOTSUP;
 484     return (entry != NULL) ? mc_readdir_result : NULL;
 485 }
 486 
 487 /* --------------------------------------------------------------------------------------------- */
 488 
 489 int
 490 mc_closedir (DIR *dirp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 491 {
 492     int handle;
 493     struct vfs_class *vfs;
 494     void *fsinfo = NULL;
 495     int result = -1;
 496 
 497     if (dirp == NULL)
 498         return result;
 499 
 500     handle = *(int *) dirp;
 501 
 502     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 503     if (vfs != NULL && fsinfo != NULL)
 504     {
 505         vfs_path_element_t *vfs_path_element = (vfs_path_element_t *) fsinfo;
 506 
 507 #ifdef HAVE_CHARSET
 508         if (vfs_path_element->dir.converter != str_cnv_from_term)
 509         {
 510             str_close_conv (vfs_path_element->dir.converter);
 511             vfs_path_element->dir.converter = INVALID_CONV;
 512         }
 513 #endif
 514 
 515         result = vfs->closedir ? (*vfs->closedir) (vfs_path_element->dir.info) : -1;
 516         vfs_free_handle (handle);
 517         vfs_path_element_free (vfs_path_element);
 518     }
 519     g_free (dirp);
 520     return result;
 521 }
 522 
 523 /* --------------------------------------------------------------------------------------------- */
 524 
 525 #define MC_STATOP(name)                                                                            \
 526     int mc_##name (const vfs_path_t *vpath, struct stat *buf)                                      \
 527     {                                                                                              \
 528         int result = -1;                                                                           \
 529         struct vfs_class *me;                                                                      \
 530                                                                                                    \
 531         if (vpath == NULL)                                                                         \
 532             return (-1);                                                                           \
 533                                                                                                    \
 534         me = VFS_CLASS (vfs_path_get_last_path_vfs (vpath));                                       \
 535         if (me != NULL)                                                                            \
 536         {                                                                                          \
 537             result = me->name ? me->name (vpath, buf) : -1;                                        \
 538             if (result == -1)                                                                      \
 539                 errno = me->name ? vfs_ferrno (me) : ENOTSUP;                                      \
 540         }                                                                                          \
 541                                                                                                    \
 542         return result;                                                                             \
 543     }
 544 
 545 MC_STATOP (stat)
     /* [previous][next][first][last][top][bottom][index][help]  */
 546 MC_STATOP (lstat)
 547 
 548 /* --------------------------------------------------------------------------------------------- */
 549 
 550 vfs_path_t *
 551 mc_getlocalcopy (const vfs_path_t *pathname_vpath)
 552 {
 553     vfs_path_t *result = NULL;
 554     struct vfs_class *me;
 555 
 556     if (pathname_vpath == NULL)
 557         return NULL;
 558 
 559     me = VFS_CLASS (vfs_path_get_last_path_vfs (pathname_vpath));
 560     if (me != NULL)
 561     {
 562         result = me->getlocalcopy != NULL ? me->getlocalcopy (pathname_vpath)
 563                                           : mc_def_getlocalcopy (pathname_vpath);
 564         if (result == NULL)
 565             errno = vfs_ferrno (me);
 566     }
 567     return result;
 568 }
 569 
 570 /* --------------------------------------------------------------------------------------------- */
 571 
 572 int
 573 mc_ungetlocalcopy (const vfs_path_t *pathname_vpath, const vfs_path_t *local_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 574                    gboolean has_changed)
 575 {
 576     int result = -1;
 577     const struct vfs_class *me;
 578 
 579     if (pathname_vpath == NULL)
 580         return (-1);
 581 
 582     me = vfs_path_get_last_path_vfs (pathname_vpath);
 583     if (me != NULL)
 584         result = me->ungetlocalcopy != NULL
 585             ? me->ungetlocalcopy (pathname_vpath, local_vpath, has_changed)
 586             : mc_def_ungetlocalcopy (pathname_vpath, local_vpath, has_changed);
 587 
 588     return result;
 589 }
 590 
 591 /* --------------------------------------------------------------------------------------------- */
 592 /**
 593  * VFS chdir.
 594  *
 595  * @param vpath VFS path.
 596  *              May be NULL. In this case NULL is returned and errno set to 0.
 597  *
 598  * @return 0 on success, -1 on failure.
 599  */
 600 
 601 int
 602 mc_chdir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 603 {
 604     struct vfs_class *old_vfs;
 605     vfsid old_vfsid;
 606     int result;
 607     struct vfs_class *me;
 608     const vfs_path_element_t *path_element;
 609     vfs_path_t *cd_vpath;
 610 
 611     if (vpath == NULL)
 612     {
 613         errno = 0;
 614         return (-1);
 615     }
 616 
 617     if (vpath->relative)
 618         cd_vpath = vfs_path_to_absolute (vpath);
 619     else
 620         cd_vpath = vfs_path_clone (vpath);
 621 
 622     me = VFS_CLASS (vfs_path_get_last_path_vfs (cd_vpath));
 623     if (me == NULL)
 624     {
 625         errno = EINVAL;
 626         goto error_end;
 627     }
 628 
 629     if (me->chdir == NULL)
 630     {
 631         errno = ENOTSUP;
 632         goto error_end;
 633     }
 634 
 635     result = me->chdir (cd_vpath);
 636     if (result == -1)
 637     {
 638         errno = vfs_ferrno (me);
 639         goto error_end;
 640     }
 641 
 642     old_vfsid = vfs_getid (vfs_get_raw_current_dir ());
 643     old_vfs = current_vfs;
 644 
 645     // Actually change directory
 646     vfs_set_raw_current_dir (cd_vpath);
 647     current_vfs = me;
 648 
 649     // This function uses the new current_dir implicitly
 650     vfs_stamp_create (old_vfs, old_vfsid);
 651 
 652     // Sometimes we assume no trailing slash on cwd
 653     path_element = vfs_path_get_by_index (vfs_get_raw_current_dir (), -1);
 654     if (vfs_path_element_valid (path_element))
 655     {
 656         if (*path_element->path != '\0')
 657         {
 658             char *p;
 659 
 660             p = strchr (path_element->path, 0) - 1;
 661             if (IS_PATH_SEP (*p) && p > path_element->path)
 662                 *p = '\0';
 663         }
 664 
 665 #ifdef ENABLE_VFS_NET
 666         {
 667             struct vfs_s_super *super;
 668 
 669             super = vfs_get_super_by_vpath (vpath);
 670             if (super != NULL && super->path_element != NULL)
 671             {
 672                 g_free (super->path_element->path);
 673                 super->path_element->path = g_strdup (path_element->path);
 674             }
 675         }
 676 #endif
 677     }
 678 
 679     return 0;
 680 
 681 error_end:
 682     vfs_path_free (cd_vpath, TRUE);
 683     return (-1);
 684 }
 685 
 686 /* --------------------------------------------------------------------------------------------- */
 687 
 688 off_t
 689 mc_lseek (int fd, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
 690 {
 691     struct vfs_class *vfs;
 692     void *fsinfo = NULL;
 693     off_t result;
 694 
 695     if (fd == -1)
 696         return (-1);
 697 
 698     vfs = vfs_class_find_by_handle (fd, &fsinfo);
 699     if (vfs == NULL)
 700         return (-1);
 701 
 702     result = vfs->lseek ? vfs->lseek (fsinfo, offset, whence) : -1;
 703     if (result == -1)
 704         errno = vfs->lseek ? vfs_ferrno (vfs) : ENOTSUP;
 705     return result;
 706 }
 707 
 708 /* --------------------------------------------------------------------------------------------- */
 709 /* Following code heavily borrows from libiberty, mkstemps.c */
 710 /*
 711  * Arguments:
 712  * pname (output) - pointer to the name of the temp file (needs g_free).
 713  *                  NULL if the function fails.
 714  * prefix - part of the filename before the random part.
 715  *          Prepend $TMPDIR or /tmp if there are no path separators.
 716  * suffix - if not NULL, part of the filename after the random part.
 717  *
 718  * Result:
 719  * handle of the open file or -1 if couldn't open any.
 720  */
 721 
 722 int
 723 mc_mkstemps (vfs_path_t **pname_vpath, const char *prefix, const char *suffix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 724 {
 725     char *p1, *p2;
 726     int fd;
 727 
 728     if (strchr (prefix, PATH_SEP) != NULL)
 729         p1 = g_strdup (prefix);
 730     else
 731     {
 732         // Add prefix first to find the position of XXXXXX
 733         p1 = g_build_filename (mc_tmpdir (), prefix, (char *) NULL);
 734     }
 735 
 736     p2 = g_strconcat (p1, "XXXXXX", suffix, (char *) NULL);
 737     g_free (p1);
 738 
 739     fd = g_mkstemp (p2);
 740     if (fd >= 0)
 741         *pname_vpath = vfs_path_from_str (p2);
 742     else
 743     {
 744         *pname_vpath = NULL;
 745         fd = -1;
 746     }
 747 
 748     g_free (p2);
 749 
 750     return fd;
 751 }
 752 
 753 /* --------------------------------------------------------------------------------------------- */
 754 /**
 755  * Return the directory where mc should keep its temporary files.
 756  * This directory is (in Bourne shell terms) "${TMPDIR=/tmp}/mc-XXXXXX"
 757  * When called the first time, the directory is created if needed.
 758  * The first call should be done early, since we are using fprintf()
 759  * and not message() to report possible problems.
 760  */
 761 
 762 const char *
 763 mc_tmpdir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 764 {
 765     static char buffer[PATH_MAX];
 766     static const char *tmpdir = NULL;
 767     const char *sys_tmp;
 768     gchar *template;
 769 
 770     // Check if already correctly initialized
 771     if (tmpdir != NULL)
 772     {
 773         struct stat st;
 774 
 775         if (lstat (tmpdir, &st) == 0 && S_ISDIR (st.st_mode) && st.st_uid == getuid ()
 776             && (st.st_mode & 0777) == 0700)
 777             return tmpdir;
 778     }
 779 
 780     sys_tmp = getenv ("MC_TMPDIR");
 781     if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
 782     {
 783         sys_tmp = getenv ("TMPDIR");
 784         if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
 785             sys_tmp = TMPDIR_DEFAULT;
 786     }
 787 
 788     template = g_build_filename (sys_tmp, "mc-XXXXXX", (char *) NULL);
 789     g_strlcpy (buffer, template, sizeof (buffer));
 790     g_free (template);
 791 
 792     tmpdir = g_mkdtemp (buffer);
 793     if (tmpdir != NULL)
 794         g_setenv ("MC_TMPDIR", tmpdir, TRUE);
 795     else
 796     {
 797         fprintf (stderr,
 798                  _ ("Cannot create temporary directory %s: %s.\n"
 799                     "Temporary files will not be created\n"),
 800                  buffer, unix_error_string (errno));
 801         g_snprintf (buffer, sizeof (buffer), "%s", "/dev/null/");
 802         fprintf (stderr, "%s\n", _ ("Press any key to continue..."));
 803         getc (stdin);
 804     }
 805 
 806     return tmpdir;
 807 }
 808 
 809 /* --------------------------------------------------------------------------------------------- */

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