root/lib/vfs/interface.c

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

DEFINITIONS

This source file includes following definitions.
  1. mc_def_getlocalcopy
  2. mc_def_ungetlocalcopy
  3. mc_open
  4. MC_NAMEOP
  5. MC_RENAMEOP
  6. mc_setctl
  7. mc_close
  8. mc_opendir
  9. mc_readdir
  10. mc_closedir
  11. MC_STATOP
  12. mc_ungetlocalcopy
  13. mc_chdir
  14. mc_lseek
  15. mc_mkstemps
  16. mc_tmpdir

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

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