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_stat
  12. mc_lstat
  13. mc_fstat
  14. mc_getlocalcopy
  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-2019
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Slava Zanko <slavazanko@gmail.com>, 2011, 2013
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24  */
  25 
  26 /**
  27  * \file
  28  * \brief Source: Virtual File System: path handlers
  29  * \author Slava Zanko
  30  * \date 2011
  31  */
  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 dirent *mc_readdir_result;
  66 
  67 /*** global variables ****************************************************************************/
  68 
  69 struct dirent *mc_readdir_result = NULL;
  70 
  71 /*** file scope macro definitions ****************************************************************/
  72 
  73 /*** file scope type declarations ****************************************************************/
  74 
  75 /*** file scope variables ************************************************************************/
  76 
  77 /*** file scope functions ************************************************************************/
  78 /* --------------------------------------------------------------------------------------------- */
  79 
  80 static vfs_path_t *
  81 mc_def_getlocalcopy (const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
  82 {
  83     vfs_path_t *tmp_vpath = NULL;
  84     int fdin, fdout = -1;
  85     ssize_t i;
  86     char buffer[BUF_1K * 8];
  87     struct stat mystat;
  88 
  89     fdin = mc_open (filename_vpath, O_RDONLY | O_LINEAR);
  90     if (fdin == -1)
  91         goto fail;
  92 
  93     fdout = vfs_mkstemps (&tmp_vpath, "vfs", vfs_path_get_last_path_str (filename_vpath));
  94     if (fdout == -1)
  95         goto fail;
  96 
  97     while ((i = mc_read (fdin, buffer, sizeof (buffer))) > 0)
  98     {
  99         if (write (fdout, buffer, i) != i)
 100             goto fail;
 101     }
 102     if (i == -1)
 103         goto fail;
 104     i = mc_close (fdin);
 105     fdin = -1;
 106     if (i == -1)
 107         goto fail;
 108 
 109     i = close (fdout);
 110     fdout = -1;
 111     if (i == -1)
 112         goto fail;
 113 
 114     if (mc_stat (filename_vpath, &mystat) != -1)
 115         mc_chmod (tmp_vpath, mystat.st_mode);
 116 
 117     return tmp_vpath;
 118 
 119   fail:
 120     vfs_path_free (tmp_vpath);
 121     if (fdout != -1)
 122         close (fdout);
 123     if (fdin != -1)
 124         mc_close (fdin);
 125     return NULL;
 126 }
 127 
 128 /* --------------------------------------------------------------------------------------------- */
 129 
 130 static int
 131 mc_def_ungetlocalcopy (const vfs_path_t * filename_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 132                        const vfs_path_t * local_vpath, gboolean has_changed)
 133 {
 134     int fdin = -1, fdout = -1;
 135     const char *local;
 136 
 137     local = vfs_path_get_last_path_str (local_vpath);
 138 
 139     if (has_changed)
 140     {
 141         char buffer[BUF_1K * 8];
 142         ssize_t i;
 143 
 144         if (vfs_path_get_last_path_vfs (filename_vpath)->write == NULL)
 145             goto failed;
 146 
 147         fdin = open (local, O_RDONLY);
 148         if (fdin == -1)
 149             goto failed;
 150         fdout = mc_open (filename_vpath, O_WRONLY | O_TRUNC);
 151         if (fdout == -1)
 152             goto failed;
 153         while ((i = read (fdin, buffer, sizeof (buffer))) > 0)
 154             if (mc_write (fdout, buffer, (size_t) i) != i)
 155                 goto failed;
 156         if (i == -1)
 157             goto failed;
 158 
 159         if (close (fdin) == -1)
 160         {
 161             fdin = -1;
 162             goto failed;
 163         }
 164         fdin = -1;
 165         if (mc_close (fdout) == -1)
 166         {
 167             fdout = -1;
 168             goto failed;
 169         }
 170     }
 171     unlink (local);
 172     return 0;
 173 
 174   failed:
 175     message (D_ERROR, _("Changes to file lost"), "%s", vfs_path_get_last_path_str (filename_vpath));
 176     if (fdout != -1)
 177         mc_close (fdout);
 178     if (fdin != -1)
 179         close (fdin);
 180     unlink (local);
 181     return (-1);
 182 }
 183 
 184 /* --------------------------------------------------------------------------------------------- */
 185 /*** public functions ****************************************************************************/
 186 /* --------------------------------------------------------------------------------------------- */
 187 
 188 int
 189 mc_open (const vfs_path_t * vpath, int flags, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 190 {
 191     int result = -1;
 192     mode_t mode = 0;
 193     const vfs_path_element_t *path_element;
 194 
 195     if (vpath == NULL)
 196         return (-1);
 197 
 198     /* Get the mode flag */
 199     if ((flags & O_CREAT) != 0)
 200     {
 201         va_list ap;
 202 
 203         va_start (ap, flags);
 204         /* We have to use PROMOTED_MODE_T instead of mode_t. Doing 'va_arg (ap, mode_t)'
 205          * fails on systems where 'mode_t' is smaller than 'int' because of C's "default
 206          * argument promotions". */
 207         mode = va_arg (ap, PROMOTED_MODE_T);
 208         va_end (ap);
 209     }
 210 
 211     path_element = vfs_path_get_by_index (vpath, -1);
 212     if (vfs_path_element_valid (path_element) && path_element->class->open != NULL)
 213     {
 214         void *info;
 215 
 216         /* open must be supported */
 217         info = path_element->class->open (vpath, flags, mode);
 218         if (info == NULL)
 219             errno = vfs_ferrno (path_element->class);
 220         else
 221             result = vfs_new_handle (path_element->class, info);
 222     }
 223     else
 224         errno = -EOPNOTSUPP;
 225 
 226     return result;
 227 }
 228 
 229 /* --------------------------------------------------------------------------------------------- */
 230 
 231 /* *INDENT-OFF* */
 232 
 233 #define MC_NAMEOP(name, inarg, callarg) \
 234 int mc_##name inarg \
 235 { \
 236     int result; \
 237     const vfs_path_element_t *path_element; \
 238 \
 239     if (vpath == NULL) \
 240         return (-1); \
 241 \
 242     path_element = vfs_path_get_by_index (vpath, -1); \
 243     if (!vfs_path_element_valid (path_element)) \
 244         return (-1); \
 245 \
 246     result = path_element->class->name != NULL ? path_element->class->name callarg : -1; \
 247     if (result == -1) \
 248         errno = path_element->class->name != NULL ? vfs_ferrno (path_element->class) : E_NOTSUPP; \
 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 (utime, (const vfs_path_t *vpath, mc_timesbuf_t * times), (vpath, times))
 255 MC_NAMEOP (readlink, (const vfs_path_t *vpath, char *buf, size_t bufsiz), (vpath, buf, bufsiz))
 256 MC_NAMEOP (unlink, (const vfs_path_t *vpath), (vpath))
 257 MC_NAMEOP (mkdir, (const vfs_path_t *vpath, mode_t mode), (vpath, mode))
 258 MC_NAMEOP (rmdir, (const vfs_path_t *vpath), (vpath))
 259 MC_NAMEOP (mknod, (const vfs_path_t *vpath, mode_t mode, dev_t dev), (vpath, mode, dev))
 260 
 261 /* *INDENT-ON* */
 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         const vfs_path_element_t *path_element;
 273 
 274         path_element = vfs_path_get_by_index (vpath2, -1);
 275         if (vfs_path_element_valid (path_element))
 276         {
 277             result =
 278                 path_element->class->symlink != NULL ?
 279                 path_element->class->symlink (vpath1, vpath2) : -1;
 280 
 281             if (result == -1)
 282                 errno =
 283                     path_element->class->symlink != NULL ?
 284                     vfs_ferrno (path_element->class) : E_NOTSUPP;
 285         }
 286     }
 287     return result;
 288 }
 289 
 290 /* --------------------------------------------------------------------------------------------- */
 291 
 292 /* *INDENT-OFF* */
 293 
 294 #define MC_HANDLEOP(name) \
 295 ssize_t mc_##name (int handle, C void *buf, size_t count) \
 296 { \
 297     struct vfs_class *vfs; \
 298     void *fsinfo = NULL; \
 299     int result; \
 300 \
 301     if (handle == -1) \
 302         return (-1); \
 303 \
 304     vfs = vfs_class_find_by_handle (handle, &fsinfo); \
 305     if (vfs == NULL) \
 306         return (-1); \
 307 \
 308     result = vfs->name != NULL ? vfs->name (fsinfo, buf, count) : -1; \
 309     if (result == -1) \
 310         errno = vfs->name != NULL ? vfs_ferrno (vfs) : E_NOTSUPP; \
 311     return result; \
 312 }
 313 
 314 #define C
 315 MC_HANDLEOP (read)
 316 #undef C
 317 #define C const
 318 MC_HANDLEOP (write)
 319 #undef C
 320 
 321 /* --------------------------------------------------------------------------------------------- */
 322 
 323 #define MC_RENAMEOP(name) \
 324 int mc_##name (const vfs_path_t *vpath1, const vfs_path_t *vpath2) \
 325 { \
 326     int result; \
 327     const vfs_path_element_t *path_element1; \
 328     const vfs_path_element_t *path_element2; \
 329 \
 330     if (vpath1 == NULL || vpath2 == NULL) \
 331         return (-1); \
 332 \
 333     path_element1 = vfs_path_get_by_index (vpath1, (-1)); \
 334     path_element2 = vfs_path_get_by_index (vpath2, (-1)); \
 335 \
 336     if (!vfs_path_element_valid (path_element1) || !vfs_path_element_valid (path_element2) || \
 337         path_element1->class != path_element2->class) \
 338     { \
 339         errno = EXDEV; \
 340         return (-1); \
 341     } \
 342 \
 343     result = path_element1->class->name != NULL \
 344         ? path_element1->class->name (vpath1, vpath2) : -1; \
 345     if (result == -1) \
 346         errno = path_element1->class->name != NULL ? vfs_ferrno (path_element1->class) : E_NOTSUPP; \
 347     return result; \
 348 }
 349 
 350 MC_RENAMEOP (link)
     /* [previous][next][first][last][top][bottom][index][help]  */
 351 MC_RENAMEOP (rename)
 352 
 353 /* *INDENT-ON* */
 354 
 355 /* --------------------------------------------------------------------------------------------- */
 356 
 357 int
 358 mc_ctl (int handle, int ctlop, void *arg)
 359 {
 360     struct vfs_class *vfs;
 361     void *fsinfo = NULL;
 362 
 363     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 364 
 365     return (vfs == NULL || vfs->ctl == NULL) ? 0 : vfs->ctl (fsinfo, ctlop, arg);
 366 }
 367 
 368 /* --------------------------------------------------------------------------------------------- */
 369 
 370 int
 371 mc_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 372 {
 373     int result = -1;
 374     const vfs_path_element_t *path_element;
 375 
 376     if (vpath == NULL)
 377         vfs_die ("You don't want to pass NULL to mc_setctl.");
 378 
 379     path_element = vfs_path_get_by_index (vpath, -1);
 380     if (vfs_path_element_valid (path_element))
 381         result =
 382             path_element->class->setctl != NULL ? path_element->class->setctl (vpath,
 383                                                                                ctlop, arg) : 0;
 384 
 385     return result;
 386 }
 387 
 388 /* --------------------------------------------------------------------------------------------- */
 389 
 390 int
 391 mc_close (int handle)
     /* [previous][next][first][last][top][bottom][index][help]  */
 392 {
 393     struct vfs_class *vfs;
 394     void *fsinfo = NULL;
 395     int result;
 396 
 397     if (handle == -1)
 398         return (-1);
 399 
 400     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 401     if (vfs == NULL || fsinfo == NULL)
 402         return (-1);
 403 
 404     if (handle < 3)
 405         return close (handle);
 406 
 407     if (vfs->close == NULL)
 408         vfs_die ("VFS must support close.\n");
 409     result = vfs->close (fsinfo);
 410     vfs_free_handle (handle);
 411     if (result == -1)
 412         errno = vfs_ferrno (vfs);
 413 
 414     return result;
 415 }
 416 
 417 /* --------------------------------------------------------------------------------------------- */
 418 
 419 DIR *
 420 mc_opendir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 421 {
 422     int handle, *handlep;
 423     void *info;
 424     vfs_path_element_t *path_element;
 425 
 426     if (vpath == NULL)
 427         return NULL;
 428 
 429     path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, -1);
 430     if (!vfs_path_element_valid (path_element))
 431     {
 432         errno = E_NOTSUPP;
 433         return NULL;
 434     }
 435 
 436     info = path_element->class->opendir ? path_element->class->opendir (vpath) : NULL;
 437     if (info == NULL)
 438     {
 439         errno = path_element->class->opendir ? vfs_ferrno (path_element->class) : E_NOTSUPP;
 440         return NULL;
 441     }
 442 
 443     path_element->dir.info = info;
 444 
 445 #ifdef HAVE_CHARSET
 446     path_element->dir.converter = (path_element->encoding != NULL) ?
 447         str_crt_conv_from (path_element->encoding) : str_cnv_from_term;
 448     if (path_element->dir.converter == INVALID_CONV)
 449         path_element->dir.converter = str_cnv_from_term;
 450 #endif
 451 
 452     handle = vfs_new_handle (path_element->class, vfs_path_element_clone (path_element));
 453 
 454     handlep = g_new (int, 1);
 455     *handlep = handle;
 456     return (DIR *) handlep;
 457 }
 458 
 459 /* --------------------------------------------------------------------------------------------- */
 460 
 461 struct dirent *
 462 mc_readdir (DIR * dirp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 463 {
 464     int handle;
 465     struct vfs_class *vfs;
 466     void *fsinfo = NULL;
 467     struct dirent *entry = NULL;
 468     vfs_path_element_t *vfs_path_element;
 469 
 470     if (mc_readdir_result == NULL)
 471     {
 472         /* We can't just allocate struct dirent as (see man dirent.h)
 473          * struct dirent has VERY nonnaive semantics of allocating
 474          * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
 475          * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
 476          * heap corrupter. So, allocate longliving dirent with at least
 477          * (MAXNAMLEN + 1) for d_name in it.
 478          * Strictly saying resulting dirent is unusable as we don't adjust internal
 479          * structures, holding dirent size. But we don't use it in libc infrastructure.
 480          * TODO: to make simpler homemade dirent-alike structure.
 481          */
 482         mc_readdir_result = (struct dirent *) g_malloc (sizeof (struct dirent) + MAXNAMLEN + 1);
 483     }
 484 
 485     if (dirp == NULL)
 486     {
 487         errno = EFAULT;
 488         return NULL;
 489     }
 490 
 491     handle = *(int *) dirp;
 492 
 493     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 494     if (vfs == NULL || fsinfo == NULL)
 495         return NULL;
 496 
 497     vfs_path_element = (vfs_path_element_t *) fsinfo;
 498     if (vfs->readdir != NULL)
 499     {
 500         entry = vfs->readdir (vfs_path_element->dir.info);
 501         if (entry == NULL)
 502             return NULL;
 503 
 504         g_string_set_size (vfs_str_buffer, 0);
 505 #ifdef HAVE_CHARSET
 506         str_vfs_convert_from (vfs_path_element->dir.converter, entry->d_name, vfs_str_buffer);
 507 #else
 508         g_string_assign (vfs_str_buffer, entry->d_name);
 509 #endif
 510         mc_readdir_result->d_ino = entry->d_ino;
 511         g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, MAXNAMLEN + 1);
 512     }
 513     if (entry == NULL)
 514         errno = vfs->readdir ? vfs_ferrno (vfs) : E_NOTSUPP;
 515     return (entry != NULL) ? mc_readdir_result : NULL;
 516 }
 517 
 518 /* --------------------------------------------------------------------------------------------- */
 519 
 520 int
 521 mc_closedir (DIR * dirp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 522 {
 523     int handle;
 524     struct vfs_class *vfs;
 525     void *fsinfo = NULL;
 526     int result = -1;
 527 
 528     if (dirp == NULL)
 529         return result;
 530 
 531     handle = *(int *) dirp;
 532 
 533     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 534     if (vfs != NULL && fsinfo != NULL)
 535     {
 536         vfs_path_element_t *vfs_path_element = (vfs_path_element_t *) fsinfo;
 537 
 538 #ifdef HAVE_CHARSET
 539         if (vfs_path_element->dir.converter != str_cnv_from_term)
 540         {
 541             str_close_conv (vfs_path_element->dir.converter);
 542             vfs_path_element->dir.converter = INVALID_CONV;
 543         }
 544 #endif
 545 
 546         result = vfs->closedir ? (*vfs->closedir) (vfs_path_element->dir.info) : -1;
 547         vfs_free_handle (handle);
 548         vfs_path_element_free (vfs_path_element);
 549     }
 550     g_free (dirp);
 551     return result;
 552 }
 553 
 554 /* --------------------------------------------------------------------------------------------- */
 555 
 556 int
 557 mc_stat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 558 {
 559     int result = -1;
 560     const vfs_path_element_t *path_element;
 561 
 562     if (vpath == NULL)
 563         return (-1);
 564 
 565     path_element = vfs_path_get_by_index (vpath, -1);
 566     if (vfs_path_element_valid (path_element))
 567     {
 568         result = path_element->class->stat ? path_element->class->stat (vpath, buf) : -1;
 569         if (result == -1)
 570             errno = path_element->class->name ? vfs_ferrno (path_element->class) : E_NOTSUPP;
 571     }
 572 
 573     return result;
 574 }
 575 
 576 /* --------------------------------------------------------------------------------------------- */
 577 
 578 int
 579 mc_lstat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 580 {
 581     int result = -1;
 582     const vfs_path_element_t *path_element;
 583 
 584     if (vpath == NULL)
 585         return (-1);
 586 
 587     path_element = vfs_path_get_by_index (vpath, -1);
 588     if (vfs_path_element_valid (path_element))
 589     {
 590         result = path_element->class->lstat ? path_element->class->lstat (vpath, buf) : -1;
 591         if (result == -1)
 592             errno = path_element->class->name ? vfs_ferrno (path_element->class) : E_NOTSUPP;
 593     }
 594 
 595     return result;
 596 }
 597 
 598 /* --------------------------------------------------------------------------------------------- */
 599 
 600 int
 601 mc_fstat (int handle, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 602 {
 603     struct vfs_class *vfs;
 604     void *fsinfo = NULL;
 605     int result;
 606 
 607     if (handle == -1)
 608         return (-1);
 609 
 610     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 611     if (vfs == NULL)
 612         return (-1);
 613 
 614     result = vfs->fstat ? vfs->fstat (fsinfo, buf) : -1;
 615     if (result == -1)
 616         errno = vfs->fstat ? vfs_ferrno (vfs) : E_NOTSUPP;
 617     return result;
 618 }
 619 
 620 /* --------------------------------------------------------------------------------------------- */
 621 
 622 vfs_path_t *
 623 mc_getlocalcopy (const vfs_path_t * pathname_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 624 {
 625     vfs_path_t *result = NULL;
 626     const vfs_path_element_t *path_element;
 627 
 628     if (pathname_vpath == NULL)
 629         return NULL;
 630 
 631     path_element = vfs_path_get_by_index (pathname_vpath, -1);
 632     if (vfs_path_element_valid (path_element))
 633     {
 634         result = path_element->class->getlocalcopy != NULL ?
 635             path_element->class->getlocalcopy (pathname_vpath) :
 636             mc_def_getlocalcopy (pathname_vpath);
 637         if (result == NULL)
 638             errno = vfs_ferrno (path_element->class);
 639     }
 640     return result;
 641 }
 642 
 643 /* --------------------------------------------------------------------------------------------- */
 644 
 645 int
 646 mc_ungetlocalcopy (const vfs_path_t * pathname_vpath, const vfs_path_t * local_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 647                    gboolean has_changed)
 648 {
 649     int result = -1;
 650     const vfs_path_element_t *path_element;
 651 
 652     if (pathname_vpath == NULL)
 653         return (-1);
 654 
 655     path_element = vfs_path_get_by_index (pathname_vpath, -1);
 656     if (vfs_path_element_valid (path_element))
 657         result = path_element->class->ungetlocalcopy != NULL ?
 658             path_element->class->ungetlocalcopy (pathname_vpath, local_vpath, has_changed) :
 659             mc_def_ungetlocalcopy (pathname_vpath, local_vpath, has_changed);
 660 
 661     return result;
 662 }
 663 
 664 /* --------------------------------------------------------------------------------------------- */
 665 /**
 666  * VFS chdir.
 667  *
 668  * @param vpath VFS-path
 669  *
 670  * @return 0 on success, -1 on failure.
 671  */
 672 
 673 int
 674 mc_chdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 675 {
 676     struct vfs_class *old_vfs;
 677     vfsid old_vfsid;
 678     int result;
 679     const vfs_path_element_t *path_element;
 680     vfs_path_t *cd_vpath;
 681 
 682     if (vpath == NULL)
 683         return (-1);
 684 
 685     if (vpath->relative)
 686         cd_vpath = vfs_path_to_absolute (vpath);
 687     else
 688         cd_vpath = vfs_path_clone (vpath);
 689 
 690     path_element = vfs_path_get_by_index (cd_vpath, -1);
 691     if (!vfs_path_element_valid (path_element) || path_element->class->chdir == NULL)
 692         goto error_end;
 693 
 694 
 695     result = path_element->class->chdir (cd_vpath);
 696     if (result == -1)
 697     {
 698         errno = vfs_ferrno (path_element->class);
 699         goto error_end;
 700     }
 701 
 702     old_vfsid = vfs_getid (vfs_get_raw_current_dir ());
 703     old_vfs = current_vfs;
 704 
 705     /* Actually change directory */
 706     vfs_set_raw_current_dir (cd_vpath);
 707 
 708     current_vfs = path_element->class;
 709 
 710     /* This function uses the new current_dir implicitly */
 711     vfs_stamp_create (old_vfs, old_vfsid);
 712 
 713     /* Sometimes we assume no trailing slash on cwd */
 714     path_element = vfs_path_get_by_index (vfs_get_raw_current_dir (), -1);
 715     if (vfs_path_element_valid (path_element))
 716     {
 717         if (*path_element->path != '\0')
 718         {
 719             char *p;
 720 
 721             p = strchr (path_element->path, 0) - 1;
 722             if (IS_PATH_SEP (*p) && p > path_element->path)
 723                 *p = '\0';
 724         }
 725 
 726 #ifdef ENABLE_VFS_NET
 727         {
 728             struct vfs_s_super *super;
 729 
 730             super = vfs_get_super_by_vpath (vpath);
 731             if (super != NULL && super->path_element != NULL)
 732             {
 733                 g_free (super->path_element->path);
 734                 super->path_element->path = g_strdup (path_element->path);
 735             }
 736         }
 737 #endif /* ENABLE_VFS_NET */
 738     }
 739 
 740     return 0;
 741 
 742   error_end:
 743     vfs_path_free (cd_vpath);
 744     return (-1);
 745 }
 746 
 747 /* --------------------------------------------------------------------------------------------- */
 748 
 749 off_t
 750 mc_lseek (int fd, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
 751 {
 752     struct vfs_class *vfs;
 753     void *fsinfo = NULL;
 754     off_t result;
 755 
 756     if (fd == -1)
 757         return (-1);
 758 
 759     vfs = vfs_class_find_by_handle (fd, &fsinfo);
 760     if (vfs == NULL)
 761         return (-1);
 762 
 763     result = vfs->lseek ? vfs->lseek (fsinfo, offset, whence) : -1;
 764     if (result == -1)
 765         errno = vfs->lseek ? vfs_ferrno (vfs) : E_NOTSUPP;
 766     return result;
 767 }
 768 
 769 /* --------------------------------------------------------------------------------------------- */
 770 /* Following code heavily borrows from libiberty, mkstemps.c */
 771 /*
 772  * Arguments:
 773  * pname (output) - pointer to the name of the temp file (needs g_free).
 774  *                  NULL if the function fails.
 775  * prefix - part of the filename before the random part.
 776  *          Prepend $TMPDIR or /tmp if there are no path separators.
 777  * suffix - if not NULL, part of the filename after the random part.
 778  *
 779  * Result:
 780  * handle of the open file or -1 if couldn't open any.
 781  */
 782 
 783 int
 784 mc_mkstemps (vfs_path_t ** pname_vpath, const char *prefix, const char *suffix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 785 {
 786     char *p1, *p2;
 787     int fd;
 788 
 789     if (strchr (prefix, PATH_SEP) != NULL)
 790         p1 = g_strdup (prefix);
 791     else
 792     {
 793         /* Add prefix first to find the position of XXXXXX */
 794         p1 = g_build_filename (mc_tmpdir (), prefix, (char *) NULL);
 795     }
 796 
 797     p2 = g_strconcat (p1, "XXXXXX", suffix, (char *) NULL);
 798     g_free (p1);
 799 
 800     fd = g_mkstemp (p2);
 801     if (fd >= 0)
 802         *pname_vpath = vfs_path_from_str (p2);
 803     else
 804     {
 805         *pname_vpath = NULL;
 806         fd = -1;
 807     }
 808 
 809     g_free (p2);
 810 
 811     return fd;
 812 }
 813 
 814 /* --------------------------------------------------------------------------------------------- */
 815 /**
 816  * Return the directory where mc should keep its temporary files.
 817  * This directory is (in Bourne shell terms) "${TMPDIR=/tmp}/mc-$USER"
 818  * When called the first time, the directory is created if needed.
 819  * The first call should be done early, since we are using fprintf()
 820  * and not message() to report possible problems.
 821  */
 822 
 823 const char *
 824 mc_tmpdir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 825 {
 826     static char buffer[PATH_MAX];
 827     static const char *tmpdir = NULL;
 828     const char *sys_tmp;
 829     struct passwd *pwd;
 830     struct stat st;
 831     const char *error = NULL;
 832 
 833     /* Check if already correctly initialized */
 834     if (tmpdir != NULL && lstat (tmpdir, &st) == 0 && S_ISDIR (st.st_mode) &&
 835         st.st_uid == getuid () && (st.st_mode & 0777) == 0700)
 836         return tmpdir;
 837 
 838     sys_tmp = getenv ("TMPDIR");
 839     if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
 840         sys_tmp = TMPDIR_DEFAULT;
 841 
 842     pwd = getpwuid (getuid ());
 843     if (pwd != NULL)
 844         g_snprintf (buffer, sizeof (buffer), "%s/mc-%s", sys_tmp, pwd->pw_name);
 845     else
 846         g_snprintf (buffer, sizeof (buffer), "%s/mc-%lu", sys_tmp, (unsigned long) getuid ());
 847 
 848     canonicalize_pathname (buffer);
 849 
 850     /* Try to create directory */
 851     if (mkdir (buffer, S_IRWXU) != 0)
 852     {
 853         if (errno == EEXIST && lstat (buffer, &st) == 0)
 854         {
 855             /* Sanity check for existing directory */
 856             if (!S_ISDIR (st.st_mode))
 857                 error = _("%s is not a directory\n");
 858             else if (st.st_uid != getuid ())
 859                 error = _("Directory %s is not owned by you\n");
 860             else if (((st.st_mode & 0777) != 0700) && (chmod (buffer, 0700) != 0))
 861                 error = _("Cannot set correct permissions for directory %s\n");
 862         }
 863         else
 864         {
 865             fprintf (stderr,
 866                      _("Cannot create temporary directory %s: %s\n"),
 867                      buffer, unix_error_string (errno));
 868             error = "";
 869         }
 870     }
 871 
 872     if (error != NULL)
 873     {
 874         int test_fd;
 875         char *fallback_prefix;
 876         gboolean fallback_ok = FALSE;
 877         vfs_path_t *test_vpath;
 878 
 879         if (*error != '\0')
 880             fprintf (stderr, error, buffer);
 881 
 882         /* Test if sys_tmp is suitable for temporary files */
 883         fallback_prefix = g_strdup_printf ("%s/mctest", sys_tmp);
 884         test_fd = mc_mkstemps (&test_vpath, fallback_prefix, NULL);
 885         g_free (fallback_prefix);
 886         if (test_fd != -1)
 887         {
 888             close (test_fd);
 889             test_fd = open (vfs_path_as_str (test_vpath), O_RDONLY);
 890             if (test_fd != -1)
 891             {
 892                 close (test_fd);
 893                 unlink (vfs_path_as_str (test_vpath));
 894                 fallback_ok = TRUE;
 895             }
 896         }
 897 
 898         if (fallback_ok)
 899         {
 900             fprintf (stderr, _("Temporary files will be created in %s\n"), sys_tmp);
 901             g_snprintf (buffer, sizeof (buffer), "%s", sys_tmp);
 902             error = NULL;
 903         }
 904         else
 905         {
 906             fprintf (stderr, _("Temporary files will not be created\n"));
 907             g_snprintf (buffer, sizeof (buffer), "%s", "/dev/null/");
 908         }
 909 
 910         vfs_path_free (test_vpath);
 911         fprintf (stderr, "%s\n", _("Press any key to continue..."));
 912         getc (stdin);
 913     }
 914 
 915     tmpdir = buffer;
 916 
 917     if (error == NULL)
 918         g_setenv ("MC_TMPDIR", tmpdir, TRUE);
 919 
 920     return tmpdir;
 921 }
 922 
 923 /* --------------------------------------------------------------------------------------------- */

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