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

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