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_mkdir_internal
  2. mc_mkdir_recursive
  3. mc_def_getlocalcopy
  4. mc_def_ungetlocalcopy
  5. mc_open
  6. MC_NAMEOP
  7. mc_symlink
  8. MC_RENAMEOP
  9. mc_setctl
  10. mc_close
  11. mc_opendir
  12. mc_readdir
  13. mc_closedir
  14. MC_STATOP
  15. mc_ungetlocalcopy
  16. mc_chdir
  17. mc_lseek
  18. mc_mkstemps
  19. mc_tmpdir

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

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