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_assign (vfs_str_buffer, entry->d_name);
 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 /* --------------------------------------------------------------------------------------------- */
 558 
 559 vfs_path_t *
 560 mc_getlocalcopy (const vfs_path_t * pathname_vpath)
 561 {
 562     vfs_path_t *result = NULL;
 563     struct vfs_class *me;
 564 
 565     if (pathname_vpath == NULL)
 566         return NULL;
 567 
 568     me = VFS_CLASS (vfs_path_get_last_path_vfs (pathname_vpath));
 569     if (me != NULL)
 570     {
 571         result = me->getlocalcopy != NULL ?
 572             me->getlocalcopy (pathname_vpath) : mc_def_getlocalcopy (pathname_vpath);
 573         if (result == NULL)
 574             errno = vfs_ferrno (me);
 575     }
 576     return result;
 577 }
 578 
 579 /* --------------------------------------------------------------------------------------------- */
 580 
 581 int
 582 mc_ungetlocalcopy (const vfs_path_t * pathname_vpath, const vfs_path_t * local_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 583                    gboolean has_changed)
 584 {
 585     int result = -1;
 586     const struct vfs_class *me;
 587 
 588     if (pathname_vpath == NULL)
 589         return (-1);
 590 
 591     me = vfs_path_get_last_path_vfs (pathname_vpath);
 592     if (me != NULL)
 593         result = me->ungetlocalcopy != NULL ?
 594             me->ungetlocalcopy (pathname_vpath, local_vpath, has_changed) :
 595             mc_def_ungetlocalcopy (pathname_vpath, local_vpath, has_changed);
 596 
 597     return result;
 598 }
 599 
 600 /* --------------------------------------------------------------------------------------------- */
 601 /**
 602  * VFS chdir.
 603  *
 604  * @param vpath VFS path.
 605  *              May be NULL. In this case NULL is returned and errno set to 0.
 606  *
 607  * @return 0 on success, -1 on failure.
 608  */
 609 
 610 int
 611 mc_chdir (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 612 {
 613     struct vfs_class *old_vfs;
 614     vfsid old_vfsid;
 615     int result;
 616     struct vfs_class *me;
 617     const vfs_path_element_t *path_element;
 618     vfs_path_t *cd_vpath;
 619 
 620     if (vpath == NULL)
 621     {
 622         errno = 0;
 623         return (-1);
 624     }
 625 
 626     if (vpath->relative)
 627         cd_vpath = vfs_path_to_absolute (vpath);
 628     else
 629         cd_vpath = vfs_path_clone (vpath);
 630 
 631     me = VFS_CLASS (vfs_path_get_last_path_vfs (cd_vpath));
 632     if (me == NULL)
 633     {
 634         errno = EINVAL;
 635         goto error_end;
 636     }
 637 
 638     if (me->chdir == NULL)
 639     {
 640         errno = ENOTSUP;
 641         goto error_end;
 642     }
 643 
 644     result = me->chdir (cd_vpath);
 645     if (result == -1)
 646     {
 647         errno = vfs_ferrno (me);
 648         goto error_end;
 649     }
 650 
 651     old_vfsid = vfs_getid (vfs_get_raw_current_dir ());
 652     old_vfs = current_vfs;
 653 
 654     /* Actually change directory */
 655     vfs_set_raw_current_dir (cd_vpath);
 656     current_vfs = me;
 657 
 658     /* This function uses the new current_dir implicitly */
 659     vfs_stamp_create (old_vfs, old_vfsid);
 660 
 661     /* Sometimes we assume no trailing slash on cwd */
 662     path_element = vfs_path_get_by_index (vfs_get_raw_current_dir (), -1);
 663     if (vfs_path_element_valid (path_element))
 664     {
 665         if (*path_element->path != '\0')
 666         {
 667             char *p;
 668 
 669             p = strchr (path_element->path, 0) - 1;
 670             if (IS_PATH_SEP (*p) && p > path_element->path)
 671                 *p = '\0';
 672         }
 673 
 674 #ifdef ENABLE_VFS_NET
 675         {
 676             struct vfs_s_super *super;
 677 
 678             super = vfs_get_super_by_vpath (vpath);
 679             if (super != NULL && super->path_element != NULL)
 680             {
 681                 g_free (super->path_element->path);
 682                 super->path_element->path = g_strdup (path_element->path);
 683             }
 684         }
 685 #endif /* ENABLE_VFS_NET */
 686     }
 687 
 688     return 0;
 689 
 690   error_end:
 691     vfs_path_free (cd_vpath, TRUE);
 692     return (-1);
 693 }
 694 
 695 /* --------------------------------------------------------------------------------------------- */
 696 
 697 off_t
 698 mc_lseek (int fd, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
 699 {
 700     struct vfs_class *vfs;
 701     void *fsinfo = NULL;
 702     off_t result;
 703 
 704     if (fd == -1)
 705         return (-1);
 706 
 707     vfs = vfs_class_find_by_handle (fd, &fsinfo);
 708     if (vfs == NULL)
 709         return (-1);
 710 
 711     result = vfs->lseek ? vfs->lseek (fsinfo, offset, whence) : -1;
 712     if (result == -1)
 713         errno = vfs->lseek ? vfs_ferrno (vfs) : ENOTSUP;
 714     return result;
 715 }
 716 
 717 /* --------------------------------------------------------------------------------------------- */
 718 /* Following code heavily borrows from libiberty, mkstemps.c */
 719 /*
 720  * Arguments:
 721  * pname (output) - pointer to the name of the temp file (needs g_free).
 722  *                  NULL if the function fails.
 723  * prefix - part of the filename before the random part.
 724  *          Prepend $TMPDIR or /tmp if there are no path separators.
 725  * suffix - if not NULL, part of the filename after the random part.
 726  *
 727  * Result:
 728  * handle of the open file or -1 if couldn't open any.
 729  */
 730 
 731 int
 732 mc_mkstemps (vfs_path_t ** pname_vpath, const char *prefix, const char *suffix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 733 {
 734     char *p1, *p2;
 735     int fd;
 736 
 737     if (strchr (prefix, PATH_SEP) != NULL)
 738         p1 = g_strdup (prefix);
 739     else
 740     {
 741         /* Add prefix first to find the position of XXXXXX */
 742         p1 = g_build_filename (mc_tmpdir (), prefix, (char *) NULL);
 743     }
 744 
 745     p2 = g_strconcat (p1, "XXXXXX", suffix, (char *) NULL);
 746     g_free (p1);
 747 
 748     fd = g_mkstemp (p2);
 749     if (fd >= 0)
 750         *pname_vpath = vfs_path_from_str (p2);
 751     else
 752     {
 753         *pname_vpath = NULL;
 754         fd = -1;
 755     }
 756 
 757     g_free (p2);
 758 
 759     return fd;
 760 }
 761 
 762 /* --------------------------------------------------------------------------------------------- */
 763 /**
 764  * Return the directory where mc should keep its temporary files.
 765  * This directory is (in Bourne shell terms) "${TMPDIR=/tmp}/mc-$USER"
 766  * When called the first time, the directory is created if needed.
 767  * The first call should be done early, since we are using fprintf()
 768  * and not message() to report possible problems.
 769  */
 770 
 771 const char *
 772 mc_tmpdir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 773 {
 774     static char buffer[PATH_MAX];
 775     static const char *tmpdir = NULL;
 776     const char *sys_tmp;
 777     struct passwd *pwd;
 778     struct stat st;
 779     const char *error = NULL;
 780 
 781     /* Check if already correctly initialized */
 782     if (tmpdir != NULL && lstat (tmpdir, &st) == 0 && S_ISDIR (st.st_mode) &&
 783         st.st_uid == getuid () && (st.st_mode & 0777) == 0700)
 784         return tmpdir;
 785 
 786     sys_tmp = getenv ("MC_TMPDIR");
 787     if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
 788     {
 789         sys_tmp = getenv ("TMPDIR");
 790         if (sys_tmp == NULL || !IS_PATH_SEP (sys_tmp[0]))
 791             sys_tmp = TMPDIR_DEFAULT;
 792     }
 793 
 794     pwd = getpwuid (getuid ());
 795     if (pwd != NULL)
 796         g_snprintf (buffer, sizeof (buffer), "%s/mc-%s", sys_tmp, pwd->pw_name);
 797     else
 798         g_snprintf (buffer, sizeof (buffer), "%s/mc-%lu", sys_tmp, (unsigned long) getuid ());
 799 
 800     canonicalize_pathname (buffer);
 801 
 802     /* Try to create directory */
 803     if (mkdir (buffer, S_IRWXU) != 0)
 804     {
 805         if (errno == EEXIST && lstat (buffer, &st) == 0)
 806         {
 807             /* Sanity check for existing directory */
 808             if (!S_ISDIR (st.st_mode))
 809                 error = _("%s is not a directory\n");
 810             else if (st.st_uid != getuid ())
 811                 error = _("Directory %s is not owned by you\n");
 812             else if (((st.st_mode & 0777) != 0700) && (chmod (buffer, 0700) != 0))
 813                 error = _("Cannot set correct permissions for directory %s\n");
 814         }
 815         else
 816         {
 817             fprintf (stderr,
 818                      _("Cannot create temporary directory %s: %s\n"),
 819                      buffer, unix_error_string (errno));
 820             error = "";
 821         }
 822     }
 823 
 824     if (error != NULL)
 825     {
 826         int test_fd;
 827         char *fallback_prefix;
 828         gboolean fallback_ok = FALSE;
 829         vfs_path_t *test_vpath;
 830 
 831         if (*error != '\0')
 832             fprintf (stderr, error, buffer);
 833 
 834         /* Test if sys_tmp is suitable for temporary files */
 835         fallback_prefix = g_strdup_printf ("%s/mctest", sys_tmp);
 836         test_fd = mc_mkstemps (&test_vpath, fallback_prefix, NULL);
 837         g_free (fallback_prefix);
 838         if (test_fd != -1)
 839         {
 840             close (test_fd);
 841             test_fd = open (vfs_path_as_str (test_vpath), O_RDONLY);
 842             if (test_fd != -1)
 843             {
 844                 close (test_fd);
 845                 unlink (vfs_path_as_str (test_vpath));
 846                 fallback_ok = TRUE;
 847             }
 848         }
 849 
 850         if (fallback_ok)
 851         {
 852             fprintf (stderr, _("Temporary files will be created in %s\n"), sys_tmp);
 853             g_snprintf (buffer, sizeof (buffer), "%s", sys_tmp);
 854             error = NULL;
 855         }
 856         else
 857         {
 858             fprintf (stderr, _("Temporary files will not be created\n"));
 859             g_snprintf (buffer, sizeof (buffer), "%s", "/dev/null/");
 860         }
 861 
 862         vfs_path_free (test_vpath, TRUE);
 863         fprintf (stderr, "%s\n", _("Press any key to continue..."));
 864         getc (stdin);
 865     }
 866 
 867     tmpdir = buffer;
 868 
 869     if (error == NULL)
 870         g_setenv ("MC_TMPDIR", tmpdir, TRUE);
 871 
 872     return tmpdir;
 873 }
 874 
 875 /* --------------------------------------------------------------------------------------------- */

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