root/src/vfs/local/local.c

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

DEFINITIONS

This source file includes following definitions.
  1. local_open
  2. local_opendir
  3. local_readdir
  4. local_closedir
  5. local_stat
  6. local_lstat
  7. local_chmod
  8. local_chown
  9. local_fgetflags
  10. local_fsetflags
  11. local_utime
  12. local_readlink
  13. local_unlink
  14. local_symlink
  15. local_write
  16. local_rename
  17. local_chdir
  18. local_mknod
  19. local_link
  20. local_mkdir
  21. local_rmdir
  22. local_getlocalcopy
  23. local_ungetlocalcopy
  24. local_which
  25. local_read
  26. local_close
  27. local_errno
  28. local_fstat
  29. local_lseek
  30. local_nothingisopen
  31. vfs_init_localfs

   1 /*
   2    Virtual File System: local file system.
   3 
   4    Copyright (C) 1995-2025
   5    Free Software Foundation, Inc.
   6 
   7    This file is part of the Midnight Commander.
   8 
   9    The Midnight Commander is free software: you can redistribute it
  10    and/or modify it under the terms of the GNU General Public License as
  11    published by the Free Software Foundation, either version 3 of the License,
  12    or (at your option) any later version.
  13 
  14    The Midnight Commander is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18 
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  21  */
  22 
  23 /**
  24  * \file
  25  * \brief Source: local FS
  26  */
  27 
  28 #include <config.h>
  29 
  30 #include <errno.h>
  31 #include <sys/types.h>
  32 #include <unistd.h>
  33 #include <stdio.h>
  34 #include <string.h>
  35 #ifdef ENABLE_EXT2FS_ATTR
  36 #    include <e2p/e2p.h>  // fgetflags(), fsetflags()
  37 #endif
  38 
  39 #include "lib/global.h"
  40 
  41 #include "lib/vfs/xdirentry.h"  // vfs_s_subclass
  42 #include "lib/vfs/utilvfs.h"
  43 
  44 #include "local.h"
  45 
  46 /*** global variables ****************************************************************************/
  47 
  48 /*** file scope macro definitions ****************************************************************/
  49 
  50 /*** file scope type declarations ****************************************************************/
  51 
  52 /*** forward declarations (file scope functions) *************************************************/
  53 
  54 /*** file scope variables ************************************************************************/
  55 
  56 static struct vfs_s_subclass local_subclass;
  57 static struct vfs_class *vfs_local_ops = VFS_CLASS (&local_subclass);
  58 
  59 /* --------------------------------------------------------------------------------------------- */
  60 /*** file scope functions ************************************************************************/
  61 /* --------------------------------------------------------------------------------------------- */
  62 
  63 static void *
  64 local_open (const vfs_path_t *vpath, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
  65 {
  66     int *local_info;
  67     int fd;
  68     const char *path;
  69 
  70     path = vfs_path_get_last_path_str (vpath);
  71     fd = open (path, NO_LINEAR (flags), mode);
  72     if (fd == -1)
  73         return 0;
  74 
  75     local_info = g_new (int, 1);
  76     *local_info = fd;
  77 
  78     return local_info;
  79 }
  80 
  81 /* --------------------------------------------------------------------------------------------- */
  82 
  83 static void *
  84 local_opendir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
  85 {
  86     DIR **local_info;
  87     DIR *dir = NULL;
  88     const char *path;
  89 
  90     path = vfs_path_get_last_path_str (vpath);
  91 
  92     /* According to POSIX, `opendir` and `readdir` can't return EINTR (unlike `closedir`).
  93      *
  94      * Unfortunately, in practice, at least `readdir` is known to return EINTR on Linux >= 5.1 on
  95      * networked filesystems such as CIFS. Networked FUSE-based systems appear to be affected as
  96      * well. What's worse is that when you retry `readdir`, the file list still comes out empty.
  97      *
  98      * So our only option seems to be to try `readdir` immediately after `opendir` and use
  99      * `rewinddir` if successful, otherwise reopen the directory, which usually leads to correct
 100      * file listing.
 101      *
 102      * However, this has caused problems on FUSE-based systems that do not properly implement
 103      * `rewinddir` in the past. No silver bullet...
 104      */
 105     while (dir == NULL)
 106     {
 107         dir = opendir (path);
 108         if (dir == NULL)
 109             return NULL;
 110 
 111         if (readdir (dir) == NULL && errno == EINTR)
 112         {
 113             closedir (dir);
 114             dir = NULL;
 115         }
 116         else
 117             rewinddir (dir);
 118     }
 119 
 120     local_info = (DIR **) g_new (DIR *, 1);
 121     *local_info = dir;
 122 
 123     return local_info;
 124 }
 125 
 126 /* --------------------------------------------------------------------------------------------- */
 127 
 128 static struct vfs_dirent *
 129 local_readdir (void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 130 {
 131     struct dirent *d;
 132 
 133     d = readdir (*(DIR **) data);
 134 
 135     return (d != NULL ? vfs_dirent_init (NULL, d->d_name, d->d_ino) : NULL);
 136 }
 137 
 138 /* --------------------------------------------------------------------------------------------- */
 139 
 140 static int
 141 local_closedir (void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 142 {
 143     int i;
 144 
 145     i = closedir (*(DIR **) data);
 146     g_free (data);
 147     return i;
 148 }
 149 
 150 /* --------------------------------------------------------------------------------------------- */
 151 
 152 static int
 153 local_stat (const vfs_path_t *vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 154 {
 155     const char *path;
 156 
 157     path = vfs_path_get_last_path_str (vpath);
 158     return stat (path, buf);
 159 }
 160 
 161 /* --------------------------------------------------------------------------------------------- */
 162 
 163 static int
 164 local_lstat (const vfs_path_t *vpath, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 165 {
 166     const char *path;
 167 
 168     path = vfs_path_get_last_path_str (vpath);
 169 #ifndef HAVE_STATLSTAT
 170     return lstat (path, buf);
 171 #else
 172     return statlstat (path, buf);
 173 #endif
 174 }
 175 
 176 /* --------------------------------------------------------------------------------------------- */
 177 
 178 static int
 179 local_chmod (const vfs_path_t *vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 180 {
 181     const char *path;
 182 
 183     path = vfs_path_get_last_path_str (vpath);
 184     return chmod (path, mode);
 185 }
 186 
 187 /* --------------------------------------------------------------------------------------------- */
 188 
 189 static int
 190 local_chown (const vfs_path_t *vpath, uid_t owner, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help]  */
 191 {
 192     const char *path;
 193 
 194     path = vfs_path_get_last_path_str (vpath);
 195     return chown (path, owner, group);
 196 }
 197 
 198 /* --------------------------------------------------------------------------------------------- */
 199 
 200 #ifdef ENABLE_EXT2FS_ATTR
 201 
 202 static int
 203 local_fgetflags (const vfs_path_t *vpath, unsigned long *flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
 204 {
 205     const char *path;
 206 
 207     path = vfs_path_get_last_path_str (vpath);
 208     return fgetflags (path, flags);
 209 }
 210 
 211 /* --------------------------------------------------------------------------------------------- */
 212 
 213 static int
 214 local_fsetflags (const vfs_path_t *vpath, unsigned long flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
 215 {
 216     const char *path;
 217 
 218     path = vfs_path_get_last_path_str (vpath);
 219     return fsetflags (path, flags);
 220 }
 221 
 222 #endif
 223 
 224 /* --------------------------------------------------------------------------------------------- */
 225 
 226 static int
 227 local_utime (const vfs_path_t *vpath, mc_timesbuf_t *times)
     /* [previous][next][first][last][top][bottom][index][help]  */
 228 {
 229     return vfs_utime (vfs_path_get_last_path_str (vpath), times);
 230 }
 231 
 232 /* --------------------------------------------------------------------------------------------- */
 233 
 234 static int
 235 local_readlink (const vfs_path_t *vpath, char *buf, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 236 {
 237     const char *path;
 238 
 239     path = vfs_path_get_last_path_str (vpath);
 240     return readlink (path, buf, size);
 241 }
 242 
 243 /* --------------------------------------------------------------------------------------------- */
 244 
 245 static int
 246 local_unlink (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 247 {
 248     const char *path;
 249 
 250     path = vfs_path_get_last_path_str (vpath);
 251     return unlink (path);
 252 }
 253 
 254 /* --------------------------------------------------------------------------------------------- */
 255 
 256 static int
 257 local_symlink (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 258 {
 259     const char *path1, *path2;
 260 
 261     path1 = vfs_path_get_last_path_str (vpath1);
 262     path2 = vfs_path_get_last_path_str (vpath2);
 263     return symlink (path1, path2);
 264 }
 265 
 266 /* --------------------------------------------------------------------------------------------- */
 267 
 268 static ssize_t
 269 local_write (void *data, const char *buf, size_t nbyte)
     /* [previous][next][first][last][top][bottom][index][help]  */
 270 {
 271     int fd;
 272     int n;
 273 
 274     if (data == NULL)
 275         return (-1);
 276 
 277     fd = *(int *) data;
 278 
 279     while ((n = write (fd, buf, nbyte)) == -1)
 280     {
 281 #ifdef EAGAIN
 282         if (errno == EAGAIN)
 283             continue;
 284 #endif
 285 #ifdef EINTR
 286         if (errno == EINTR)
 287             continue;
 288 #endif
 289         break;
 290     }
 291 
 292     return n;
 293 }
 294 
 295 /* --------------------------------------------------------------------------------------------- */
 296 
 297 static int
 298 local_rename (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 299 {
 300     const char *path1, *path2;
 301 
 302     path1 = vfs_path_get_last_path_str (vpath1);
 303     path2 = vfs_path_get_last_path_str (vpath2);
 304     return rename (path1, path2);
 305 }
 306 
 307 /* --------------------------------------------------------------------------------------------- */
 308 
 309 static int
 310 local_chdir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 311 {
 312     const char *path;
 313 
 314     path = vfs_path_get_last_path_str (vpath);
 315     return chdir (path);
 316 }
 317 
 318 /* --------------------------------------------------------------------------------------------- */
 319 
 320 static int
 321 local_mknod (const vfs_path_t *vpath, mode_t mode, dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help]  */
 322 {
 323     const char *path;
 324 
 325     path = vfs_path_get_last_path_str (vpath);
 326     return mknod (path, mode, dev);
 327 }
 328 
 329 /* --------------------------------------------------------------------------------------------- */
 330 
 331 static int
 332 local_link (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 333 {
 334     const char *path1, *path2;
 335 
 336     path1 = vfs_path_get_last_path_str (vpath1);
 337     path2 = vfs_path_get_last_path_str (vpath2);
 338     return link (path1, path2);
 339 }
 340 
 341 /* --------------------------------------------------------------------------------------------- */
 342 
 343 static int
 344 local_mkdir (const vfs_path_t *vpath, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 345 {
 346     const char *path;
 347 
 348     path = vfs_path_get_last_path_str (vpath);
 349     return mkdir (path, mode);
 350 }
 351 
 352 /* --------------------------------------------------------------------------------------------- */
 353 
 354 static int
 355 local_rmdir (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 356 {
 357     const char *path;
 358 
 359     path = vfs_path_get_last_path_str (vpath);
 360     return rmdir (path);
 361 }
 362 
 363 /* --------------------------------------------------------------------------------------------- */
 364 
 365 static vfs_path_t *
 366 local_getlocalcopy (const vfs_path_t *vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 367 {
 368     return vfs_path_clone (vpath);
 369 }
 370 
 371 /* --------------------------------------------------------------------------------------------- */
 372 
 373 static int
 374 local_ungetlocalcopy (const vfs_path_t *vpath, const vfs_path_t *local, gboolean has_changed)
     /* [previous][next][first][last][top][bottom][index][help]  */
 375 {
 376     (void) vpath;
 377     (void) local;
 378     (void) has_changed;
 379 
 380     return 0;
 381 }
 382 
 383 /* --------------------------------------------------------------------------------------------- */
 384 
 385 static int
 386 local_which (struct vfs_class *me, const char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
 387 {
 388     (void) me;
 389     (void) path;
 390 
 391     return 0;  // Every path which other systems do not like is expected to be ours
 392 }
 393 
 394 /* --------------------------------------------------------------------------------------------- */
 395 /*** public functions ****************************************************************************/
 396 /* --------------------------------------------------------------------------------------------- */
 397 
 398 ssize_t
 399 local_read (void *data, char *buffer, size_t count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 400 {
 401     int n;
 402     int fd;
 403 
 404     if (data == NULL)
 405         return (-1);
 406 
 407     fd = *(int *) data;
 408 
 409     while ((n = read (fd, buffer, count)) == -1)
 410     {
 411 #ifdef EAGAIN
 412         if (errno == EAGAIN)
 413             continue;
 414 #endif
 415 #ifdef EINTR
 416         if (errno == EINTR)
 417             continue;
 418 #endif
 419         return (-1);
 420     }
 421 
 422     return n;
 423 }
 424 
 425 /* --------------------------------------------------------------------------------------------- */
 426 
 427 int
 428 local_close (void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 429 {
 430     int fd;
 431 
 432     if (data == NULL)
 433         return (-1);
 434 
 435     fd = *(int *) data;
 436     g_free (data);
 437     return close (fd);
 438 }
 439 
 440 /* --------------------------------------------------------------------------------------------- */
 441 
 442 int
 443 local_errno (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 444 {
 445     (void) me;
 446     return errno;
 447 }
 448 
 449 /* --------------------------------------------------------------------------------------------- */
 450 
 451 int
 452 local_fstat (void *data, struct stat *buf)
     /* [previous][next][first][last][top][bottom][index][help]  */
 453 {
 454     int fd = *(int *) data;
 455 
 456     return fstat (fd, buf);
 457 }
 458 
 459 /* --------------------------------------------------------------------------------------------- */
 460 
 461 off_t
 462 local_lseek (void *data, off_t offset, int whence)
     /* [previous][next][first][last][top][bottom][index][help]  */
 463 {
 464     int fd = *(int *) data;
 465 
 466     return lseek (fd, offset, whence);
 467 }
 468 
 469 /* --------------------------------------------------------------------------------------------- */
 470 
 471 static gboolean
 472 local_nothingisopen (vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 473 {
 474     (void) id;
 475 
 476     return TRUE;
 477 }
 478 
 479 /* --------------------------------------------------------------------------------------------- */
 480 
 481 void
 482 vfs_init_localfs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 483 {
 484     // NULLize vfs_s_subclass members
 485     memset (&local_subclass, 0, sizeof (local_subclass));
 486 
 487     vfs_init_class (vfs_local_ops, "localfs", VFSF_LOCAL, NULL);
 488     vfs_local_ops->which = local_which;
 489     vfs_local_ops->open = local_open;
 490     vfs_local_ops->close = local_close;
 491     vfs_local_ops->read = local_read;
 492     vfs_local_ops->write = local_write;
 493     vfs_local_ops->opendir = local_opendir;
 494     vfs_local_ops->readdir = local_readdir;
 495     vfs_local_ops->closedir = local_closedir;
 496     vfs_local_ops->stat = local_stat;
 497     vfs_local_ops->lstat = local_lstat;
 498     vfs_local_ops->fstat = local_fstat;
 499     vfs_local_ops->chmod = local_chmod;
 500     vfs_local_ops->chown = local_chown;
 501 #ifdef ENABLE_EXT2FS_ATTR
 502     vfs_local_ops->fgetflags = local_fgetflags;
 503     vfs_local_ops->fsetflags = local_fsetflags;
 504 #endif
 505     vfs_local_ops->utime = local_utime;
 506     vfs_local_ops->readlink = local_readlink;
 507     vfs_local_ops->symlink = local_symlink;
 508     vfs_local_ops->link = local_link;
 509     vfs_local_ops->unlink = local_unlink;
 510     vfs_local_ops->rename = local_rename;
 511     vfs_local_ops->chdir = local_chdir;
 512     vfs_local_ops->ferrno = local_errno;
 513     vfs_local_ops->lseek = local_lseek;
 514     vfs_local_ops->mknod = local_mknod;
 515     vfs_local_ops->getlocalcopy = local_getlocalcopy;
 516     vfs_local_ops->ungetlocalcopy = local_ungetlocalcopy;
 517     vfs_local_ops->mkdir = local_mkdir;
 518     vfs_local_ops->rmdir = local_rmdir;
 519     vfs_local_ops->nothingisopen = local_nothingisopen;
 520     vfs_register_class (vfs_local_ops);
 521 }
 522 
 523 /* --------------------------------------------------------------------------------------------- */

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