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)
 200     {
 201         va_list ap;
 202         va_start (ap, flags);
 203         /* We have to use PROMOTED_MODE_T instead of mode_t. Doing 'va_arg (ap, mode_t)'
 204          * fails on systems where 'mode_t' is smaller than 'int' because of C's "default
 205          * argument promotions". */
 206         mode = va_arg (ap, PROMOTED_MODE_T);
 207         va_end (ap);
 208     }
 209 
 210     path_element = vfs_path_get_by_index (vpath, -1);
 211     if (vfs_path_element_valid (path_element) && path_element->class->open != NULL)
 212     {
 213         void *info;
 214         /* open must be supported */
 215         info = path_element->class->open (vpath, flags, mode);
 216         if (info == NULL)
 217             errno = vfs_ferrno (path_element->class);
 218         else
 219             result = vfs_new_handle (path_element->class, info);
 220     }
 221     else
 222         errno = -EOPNOTSUPP;
 223 
 224     return result;
 225 }
 226 
 227 /* --------------------------------------------------------------------------------------------- */
 228 
 229 /* *INDENT-OFF* */
 230 
 231 #define MC_NAMEOP(name, inarg, callarg) \
 232 int mc_##name inarg \
 233 { \
 234     int result; \
 235     const vfs_path_element_t *path_element; \
 236 \
 237     if (vpath == NULL) \
 238         return -1; \
 239 \
 240     path_element = vfs_path_get_by_index (vpath, -1); \
 241     if (!vfs_path_element_valid (path_element)) \
 242     { \
 243         return -1; \
 244     } \
 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)
 271         return -1;
 272 
 273     if (vpath1 != NULL)
 274     {
 275         const vfs_path_element_t *path_element;
 276 
 277         path_element = vfs_path_get_by_index (vpath2, -1);
 278         if (vfs_path_element_valid (path_element))
 279         {
 280             result =
 281                 path_element->class->symlink != NULL ?
 282                 path_element->class->symlink (vpath1, vpath2) : -1;
 283 
 284             if (result == -1)
 285                 errno =
 286                     path_element->class->symlink != NULL ?
 287                     vfs_ferrno (path_element->class) : E_NOTSUPP;
 288         }
 289     }
 290     return result;
 291 }
 292 
 293 /* --------------------------------------------------------------------------------------------- */
 294 
 295 /* *INDENT-OFF* */
 296 
 297 #define MC_HANDLEOP(name) \
 298 ssize_t mc_##name (int handle, C void *buf, size_t count) \
 299 { \
 300     struct vfs_class *vfs; \
 301     void *fsinfo = NULL; \
 302     int result; \
 303     if (handle == -1) \
 304         return -1; \
 305     vfs = vfs_class_find_by_handle (handle, &fsinfo); \
 306     if (vfs == NULL) \
 307         return -1; \
 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) \
 345         : -1; \
 346     if (result == -1) \
 347         errno = path_element1->class->name != NULL ? vfs_ferrno (path_element1->class) : E_NOTSUPP; \
 348     return result; \
 349 }
 350 
 351 MC_RENAMEOP (link)
     /* [previous][next][first][last][top][bottom][index][help]  */
 352 MC_RENAMEOP (rename)
 353 
 354 /* *INDENT-ON* */
 355 
 356 /* --------------------------------------------------------------------------------------------- */
 357 
 358 int
 359 mc_ctl (int handle, int ctlop, void *arg)
 360 {
 361     struct vfs_class *vfs;
 362     void *fsinfo = NULL;
 363 
 364     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 365 
 366     return (vfs == NULL || vfs->ctl == NULL) ? 0 : vfs->ctl (fsinfo, ctlop, arg);
 367 }
 368 
 369 /* --------------------------------------------------------------------------------------------- */
 370 
 371 int
 372 mc_setctl (const vfs_path_t * vpath, int ctlop, void *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 373 {
 374     int result = -1;
 375     const vfs_path_element_t *path_element;
 376 
 377     if (vpath == NULL)
 378         vfs_die ("You don't want to pass NULL to mc_setctl.");
 379 
 380     path_element = vfs_path_get_by_index (vpath, -1);
 381     if (vfs_path_element_valid (path_element))
 382         result =
 383             path_element->class->setctl != NULL ? path_element->class->setctl (vpath,
 384                                                                                ctlop, arg) : 0;
 385 
 386     return result;
 387 }
 388 
 389 /* --------------------------------------------------------------------------------------------- */
 390 
 391 int
 392 mc_close (int handle)
     /* [previous][next][first][last][top][bottom][index][help]  */
 393 {
 394     struct vfs_class *vfs;
 395     void *fsinfo = NULL;
 396     int result;
 397 
 398     if (handle == -1)
 399         return -1;
 400 
 401     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 402     if (vfs == NULL || fsinfo == NULL)
 403         return -1;
 404 
 405     if (handle < 3)
 406         return close (handle);
 407 
 408     if (!vfs->close)
 409         vfs_die ("VFS must support close.\n");
 410     result = (*vfs->close) (fsinfo);
 411     vfs_free_handle (handle);
 412     if (result == -1)
 413         errno = vfs_ferrno (vfs);
 414 
 415     return result;
 416 }
 417 
 418 /* --------------------------------------------------------------------------------------------- */
 419 
 420 DIR *
 421 mc_opendir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 422 {
 423     int handle, *handlep;
 424     void *info;
 425     vfs_path_element_t *path_element;
 426 
 427     if (vpath == NULL)
 428         return NULL;
 429 
 430     path_element = (vfs_path_element_t *) vfs_path_get_by_index (vpath, -1);
 431 
 432     if (!vfs_path_element_valid (path_element))
 433     {
 434         errno = E_NOTSUPP;
 435         return NULL;
 436     }
 437 
 438     info = path_element->class->opendir ? (*path_element->class->opendir) (vpath) : NULL;
 439 
 440     if (info == NULL)
 441     {
 442         errno = path_element->class->opendir ? vfs_ferrno (path_element->class) : E_NOTSUPP;
 443         return NULL;
 444     }
 445 
 446     path_element->dir.info = info;
 447 
 448 #ifdef HAVE_CHARSET
 449     path_element->dir.converter = (path_element->encoding != NULL) ?
 450         str_crt_conv_from (path_element->encoding) : str_cnv_from_term;
 451     if (path_element->dir.converter == INVALID_CONV)
 452         path_element->dir.converter = str_cnv_from_term;
 453 #endif
 454 
 455     handle = vfs_new_handle (path_element->class, vfs_path_element_clone (path_element));
 456 
 457     handlep = g_new (int, 1);
 458     *handlep = handle;
 459     return (DIR *) handlep;
 460 }
 461 
 462 /* --------------------------------------------------------------------------------------------- */
 463 
 464 struct dirent *
 465 mc_readdir (DIR * dirp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 466 {
 467     int handle;
 468     struct vfs_class *vfs;
 469     void *fsinfo = NULL;
 470     struct dirent *entry = NULL;
 471     vfs_path_element_t *vfs_path_element;
 472 
 473     if (!mc_readdir_result)
 474     {
 475         /* We can't just allocate struct dirent as (see man dirent.h)
 476          * struct dirent has VERY nonnaive semantics of allocating
 477          * d_name in it. Moreover, linux's glibc-2.9 allocates dirents _less_,
 478          * than 'sizeof (struct dirent)' making full bitwise (sizeof dirent) copy
 479          * heap corrupter. So, allocate longliving dirent with at least
 480          * (MAXNAMLEN + 1) for d_name in it.
 481          * Strictly saying resulting dirent is unusable as we don't adjust internal
 482          * structures, holding dirent size. But we don't use it in libc infrastructure.
 483          * TODO: to make simpler homemade dirent-alike structure.
 484          */
 485         mc_readdir_result = (struct dirent *) g_malloc (sizeof (struct dirent) + MAXNAMLEN + 1);
 486     }
 487 
 488     if (!dirp)
 489     {
 490         errno = EFAULT;
 491         return NULL;
 492     }
 493     handle = *(int *) dirp;
 494 
 495     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 496     if (vfs == NULL || fsinfo == NULL)
 497         return NULL;
 498 
 499     vfs_path_element = (vfs_path_element_t *) fsinfo;
 500     if (vfs->readdir)
 501     {
 502         entry = (*vfs->readdir) (vfs_path_element->dir.info);
 503         if (entry == NULL)
 504             return NULL;
 505 
 506         g_string_set_size (vfs_str_buffer, 0);
 507 #ifdef HAVE_CHARSET
 508         str_vfs_convert_from (vfs_path_element->dir.converter, entry->d_name, vfs_str_buffer);
 509 #else
 510         g_string_assign (vfs_str_buffer, entry->d_name);
 511 #endif
 512         mc_readdir_result->d_ino = entry->d_ino;
 513         g_strlcpy (mc_readdir_result->d_name, vfs_str_buffer->str, MAXNAMLEN + 1);
 514     }
 515     if (entry == NULL)
 516         errno = vfs->readdir ? vfs_ferrno (vfs) : E_NOTSUPP;
 517     return (entry != NULL) ? mc_readdir_result : NULL;
 518 }
 519 
 520 /* --------------------------------------------------------------------------------------------- */
 521 
 522 int
 523 mc_closedir (DIR * dirp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 524 {
 525     int handle;
 526     struct vfs_class *vfs;
 527     void *fsinfo = NULL;
 528     int result = -1;
 529 
 530     if (dirp == NULL)
 531         return result;
 532 
 533     handle = *(int *) dirp;
 534 
 535     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 536     if (vfs != NULL && fsinfo != NULL)
 537     {
 538         vfs_path_element_t *vfs_path_element = (vfs_path_element_t *) fsinfo;
 539 
 540 #ifdef HAVE_CHARSET
 541         if (vfs_path_element->dir.converter != str_cnv_from_term)
 542         {
 543             str_close_conv (vfs_path_element->dir.converter);
 544             vfs_path_element->dir.converter = INVALID_CONV;
 545         }
 546 #endif
 547 
 548         result = vfs->closedir ? (*vfs->closedir) (vfs_path_element->dir.info) : -1;
 549         vfs_free_handle (handle);
 550         vfs_path_element_free (vfs_path_element);
 551     }
 552     g_free (dirp);
 553     return result;
 554 }
 555 
 556 /* --------------------------------------------------------------------------------------------- */
 557 
 558 int
 559 mc_stat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 560 {
 561     int result = -1;
 562     const vfs_path_element_t *path_element;
 563 
 564     if (vpath == NULL)
 565         return -1;
 566 
 567     path_element = vfs_path_get_by_index (vpath, -1);
 568 
 569     if (vfs_path_element_valid (path_element))
 570     {
 571         result = path_element->class->stat ? (*path_element->class->stat) (vpath, buf) : -1;
 572         if (result == -1)
 573             errno = path_element->class->name ? vfs_ferrno (path_element->class) : E_NOTSUPP;
 574     }
 575 
 576     return result;
 577 }
 578 
 579 /* --------------------------------------------------------------------------------------------- */
 580 
 581 int
 582 mc_lstat (const vfs_path_t * vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 583 {
 584     int result = -1;
 585     const vfs_path_element_t *path_element;
 586 
 587     if (vpath == NULL)
 588         return -1;
 589 
 590     path_element = vfs_path_get_by_index (vpath, -1);
 591 
 592     if (vfs_path_element_valid (path_element))
 593     {
 594         result = path_element->class->lstat ? (*path_element->class->lstat) (vpath, buf) : -1;
 595         if (result == -1)
 596             errno = path_element->class->name ? vfs_ferrno (path_element->class) : E_NOTSUPP;
 597     }
 598 
 599     return result;
 600 }
 601 
 602 /* --------------------------------------------------------------------------------------------- */
 603 
 604 int
 605 mc_fstat (int handle, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 606 {
 607     struct vfs_class *vfs;
 608     void *fsinfo = NULL;
 609     int result;
 610 
 611     if (handle == -1)
 612         return -1;
 613 
 614     vfs = vfs_class_find_by_handle (handle, &fsinfo);
 615     if (vfs == NULL)
 616         return -1;
 617 
 618     result = vfs->fstat ? (*vfs->fstat) (fsinfo, buf) : -1;
 619     if (result == -1)
 620         errno = vfs->fstat ? vfs_ferrno (vfs) : E_NOTSUPP;
 621     return result;
 622 }
 623 
 624 /* --------------------------------------------------------------------------------------------- */
 625 
 626 vfs_path_t *
 627 mc_getlocalcopy (const vfs_path_t * pathname_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 628 {
 629     vfs_path_t *result = NULL;
 630     const vfs_path_element_t *path_element;
 631 
 632     if (pathname_vpath == NULL)
 633         return NULL;
 634 
 635     path_element = vfs_path_get_by_index (pathname_vpath, -1);
 636 
 637     if (vfs_path_element_valid (path_element))
 638     {
 639         result = path_element->class->getlocalcopy != NULL ?
 640             path_element->class->getlocalcopy (pathname_vpath) :
 641             mc_def_getlocalcopy (pathname_vpath);
 642         if (result == NULL)
 643             errno = vfs_ferrno (path_element->class);
 644     }
 645     return result;
 646 }
 647 
 648 /* --------------------------------------------------------------------------------------------- */
 649 
 650 int
 651 mc_ungetlocalcopy (const vfs_path_t * pathname_vpath, const vfs_path_t * local_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 652                    gboolean has_changed)
 653 {
 654     int return_value = -1;
 655     const vfs_path_element_t *path_element;
 656 
 657     if (pathname_vpath == NULL)
 658         return -1;
 659 
 660     path_element = vfs_path_get_by_index (pathname_vpath, -1);
 661 
 662     if (vfs_path_element_valid (path_element))
 663         return_value = path_element->class->ungetlocalcopy != NULL ?
 664             path_element->class->ungetlocalcopy (pathname_vpath, local_vpath, has_changed) :
 665             mc_def_ungetlocalcopy (pathname_vpath, local_vpath, has_changed);
 666 
 667     return return_value;
 668 }
 669 
 670 /* --------------------------------------------------------------------------------------------- */
 671 /**
 672  * VFS chdir.
 673  *
 674  * @param vpath VFS-path
 675  *
 676  * @return 0 on success, -1 on failure.
 677  */
 678 
 679 int
 680 mc_chdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 681 {
 682     struct vfs_class *old_vfs;
 683     vfsid old_vfsid;
 684     int result;
 685     const vfs_path_element_t *path_element;
 686     vfs_path_t *cd_vpath;
 687 
 688     if (vpath == NULL)
 689         return -1;
 690 
 691     if (vpath->relative)
 692         cd_vpath = vfs_path_to_absolute (vpath);
 693     else
 694         cd_vpath = vfs_path_clone (vpath);
 695 
 696     path_element = vfs_path_get_by_index (cd_vpath, -1);
 697 
 698     if (!vfs_path_element_valid (path_element) || path_element->class->chdir == NULL)
 699     {
 700         goto error_end;
 701     }
 702 
 703     result = (*path_element->class->chdir) (cd_vpath);
 704 
 705     if (result == -1)
 706     {
 707         errno = vfs_ferrno (path_element->class);
 708         goto error_end;
 709     }
 710 
 711     old_vfsid = vfs_getid (vfs_get_raw_current_dir ());
 712     old_vfs = current_vfs;
 713 
 714     /* Actually change directory */
 715     vfs_set_raw_current_dir (cd_vpath);
 716 
 717     current_vfs = path_element->class;
 718 
 719     /* This function uses the new current_dir implicitly */
 720     vfs_stamp_create (old_vfs, old_vfsid);
 721 
 722     /* Sometimes we assume no trailing slash on cwd */
 723     path_element = vfs_path_get_by_index (vfs_get_raw_current_dir (), -1);
 724     if (vfs_path_element_valid (path_element))
 725     {
 726         if (*path_element->path != '\0')
 727         {
 728             char *p;
 729 
 730             p = strchr (path_element->path, 0) - 1;
 731             if (IS_PATH_SEP (*p) && p > path_element->path)
 732                 *p = '\0';
 733         }
 734 
 735 #ifdef ENABLE_VFS_NET
 736         {
 737             struct vfs_s_super *super;
 738 
 739             super = vfs_get_super_by_vpath (vpath);
 740             if (super != NULL && super->path_element != NULL)
 741             {
 742                 g_free (super->path_element->path);
 743                 super->path_element->path = g_strdup (path_element->path);
 744             }
 745         }
 746 #endif /* ENABLE_VFS_NET */
 747     }
 748 
 749     return 0;
 750 
 751   error_end:
 752     vfs_path_free (cd_vpath);
 753     return -1;
 754 }
 755 
 756 /* --------------------------------------------------------------------------------------------- */
 757 
 758 off_t
 759 mc_lseek (int fd, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
 760 {
 761     struct vfs_class *vfs;
 762     void *fsinfo = NULL;
 763     off_t result;
 764 
 765     if (fd == -1)
 766         return -1;
 767 
 768     vfs = vfs_class_find_by_handle (fd, &fsinfo);
 769     if (vfs == NULL)
 770         return -1;
 771 
 772     result = vfs->lseek ? (*vfs->lseek) (fsinfo, offset, whence) : -1;
 773     if (result == -1)
 774         errno = vfs->lseek ? vfs_ferrno (vfs) : E_NOTSUPP;
 775     return result;
 776 }
 777 
 778 /* --------------------------------------------------------------------------------------------- */
 779 /* Following code heavily borrows from libiberty, mkstemps.c */
 780 /*
 781  * Arguments:
 782  * pname (output) - pointer to the name of the temp file (needs g_free).
 783  *                  NULL if the function fails.
 784  * prefix - part of the filename before the random part.
 785  *          Prepend $TMPDIR or /tmp if there are no path separators.
 786  * suffix - if not NULL, part of the filename after the random part.
 787  *
 788  * Result:
 789  * handle of the open file or -1 if couldn't open any.
 790  */
 791 
 792 int
 793 mc_mkstemps (vfs_path_t ** pname_vpath, const char *prefix, const char *suffix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 794 {
 795     char *p1, *p2;
 796     int fd;
 797 
 798     if (strchr (prefix, PATH_SEP) != NULL)
 799         p1 = g_strdup (prefix);
 800     else
 801     {
 802         /* Add prefix first to find the position of XXXXXX */
 803         p1 = g_build_filename (mc_tmpdir (), prefix, (char *) NULL);
 804     }
 805 
 806     p2 = g_strconcat (p1, "XXXXXX", suffix, (char *) NULL);
 807     g_free (p1);
 808 
 809     fd = g_mkstemp (p2);
 810     if (fd >= 0)
 811         *pname_vpath = vfs_path_from_str (p2);
 812     else
 813     {
 814         *pname_vpath = NULL;
 815         fd = -1;
 816     }
 817 
 818     g_free (p2);
 819 
 820     return fd;
 821 }
 822 
 823 /* --------------------------------------------------------------------------------------------- */
 824 /**
 825  * Return the directory where mc should keep its temporary files.
 826  * This directory is (in Bourne shell terms) "${TMPDIR=/tmp}/mc-$USER"
 827  * When called the first time, the directory is created if needed.
 828  * The first call should be done early, since we are using fprintf()
 829  * and not message() to report possible problems.
 830  */
 831 
 832 const char *
 833 mc_tmpdir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 834 {
 835     static char buffer[PATH_MAX];
 836     static const char *tmpdir = NULL;
 837     const char *sys_tmp;
 838     struct passwd *pwd;
 839     struct stat st;
 840     const char *error = NULL;
 841 
 842     /* Check if already correctly initialized */
 843     if (tmpdir && lstat (tmpdir, &st) == 0 && S_ISDIR (st.st_mode) &&
 844         st.st_uid == getuid () && (st.st_mode & 0777) == 0700)
 845         return tmpdir;
 846 
 847     sys_tmp = getenv ("TMPDIR");
 848     if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
 849         sys_tmp = TMPDIR_DEFAULT;
 850 
 851     pwd = getpwuid (getuid ());
 852 
 853     if (pwd)
 854         g_snprintf (buffer, sizeof (buffer), "%s/mc-%s", sys_tmp, pwd->pw_name);
 855     else
 856         g_snprintf (buffer, sizeof (buffer), "%s/mc-%lu", sys_tmp, (unsigned long) getuid ());
 857 
 858     canonicalize_pathname (buffer);
 859 
 860     /* Try to create directory */
 861     if (mkdir (buffer, S_IRWXU) != 0)
 862     {
 863         if (errno == EEXIST && lstat (buffer, &st) == 0)
 864         {
 865             /* Sanity check for existing directory */
 866             if (!S_ISDIR (st.st_mode))
 867                 error = _("%s is not a directory\n");
 868             else if (st.st_uid != getuid ())
 869                 error = _("Directory %s is not owned by you\n");
 870             else if (((st.st_mode & 0777) != 0700) && (chmod (buffer, 0700) != 0))
 871                 error = _("Cannot set correct permissions for directory %s\n");
 872         }
 873         else
 874         {
 875             fprintf (stderr,
 876                      _("Cannot create temporary directory %s: %s\n"),
 877                      buffer, unix_error_string (errno));
 878             error = "";
 879         }
 880     }
 881 
 882     if (error != NULL)
 883     {
 884         int test_fd;
 885         char *fallback_prefix;
 886         gboolean fallback_ok = FALSE;
 887         vfs_path_t *test_vpath;
 888 
 889         if (*error)
 890             fprintf (stderr, error, buffer);
 891 
 892         /* Test if sys_tmp is suitable for temporary files */
 893         fallback_prefix = g_strdup_printf ("%s/mctest", sys_tmp);
 894         test_fd = mc_mkstemps (&test_vpath, fallback_prefix, NULL);
 895         g_free (fallback_prefix);
 896         if (test_fd != -1)
 897         {
 898             close (test_fd);
 899             test_fd = open (vfs_path_as_str (test_vpath), O_RDONLY);
 900             if (test_fd != -1)
 901             {
 902                 close (test_fd);
 903                 unlink (vfs_path_as_str (test_vpath));
 904                 fallback_ok = TRUE;
 905             }
 906         }
 907 
 908         if (fallback_ok)
 909         {
 910             fprintf (stderr, _("Temporary files will be created in %s\n"), sys_tmp);
 911             g_snprintf (buffer, sizeof (buffer), "%s", sys_tmp);
 912             error = NULL;
 913         }
 914         else
 915         {
 916             fprintf (stderr, _("Temporary files will not be created\n"));
 917             g_snprintf (buffer, sizeof (buffer), "%s", "/dev/null/");
 918         }
 919 
 920         vfs_path_free (test_vpath);
 921         fprintf (stderr, "%s\n", _("Press any key to continue..."));
 922         getc (stdin);
 923     }
 924 
 925     tmpdir = buffer;
 926 
 927     if (!error)
 928         g_setenv ("MC_TMPDIR", tmpdir, TRUE);
 929 
 930     return tmpdir;
 931 }
 932 
 933 /* --------------------------------------------------------------------------------------------- */

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