1 /*
2 Virtual File System: local file system.
3
4 Copyright (C) 1995-2021
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 <http://www.gnu.org/licenses/>.
21 */
22
23 /**
24 * \file
25 * \brief Source: local FS
26 */
27
28 #include <config.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include "lib/global.h"
36
37 #include "lib/vfs/xdirentry.h" /* vfs_s_subclass */
38 #include "lib/vfs/utilvfs.h"
39
40 #include "local.h"
41
42 /*** global variables ****************************************************************************/
43
44 /*** file scope macro definitions ****************************************************************/
45
46 /*** file scope type declarations ****************************************************************/
47
48 /*** file scope variables ************************************************************************/
49
50 static struct vfs_s_subclass local_subclass;
51 static struct vfs_class *vfs_local_ops = VFS_CLASS (&local_subclass);
52
53 /* --------------------------------------------------------------------------------------------- */
54 /*** file scope functions ************************************************************************/
55 /* --------------------------------------------------------------------------------------------- */
56
57 /**
58 * Note: Some of this functions are not static. This has rather good
59 * reason: exactly same functions would have to appear in sfs.c. This
60 * saves both computer's memory and my work. <pavel@ucw.cz>
61 */
62
63
64 /* --------------------------------------------------------------------------------------------- */
65
66 static void *
local_open(const vfs_path_t * vpath,int flags,mode_t mode)67 local_open (const vfs_path_t * vpath, int flags, mode_t mode)
68 {
69 int *local_info;
70 int fd;
71 const vfs_path_element_t *path_element;
72
73 path_element = vfs_path_get_by_index (vpath, -1);
74 fd = open (path_element->path, NO_LINEAR (flags), mode);
75 if (fd == -1)
76 return 0;
77
78 local_info = g_new (int, 1);
79 *local_info = fd;
80
81 return local_info;
82 }
83
84 /* --------------------------------------------------------------------------------------------- */
85
86 static void *
local_opendir(const vfs_path_t * vpath)87 local_opendir (const vfs_path_t * vpath)
88 {
89 DIR **local_info;
90 DIR *dir = NULL;
91 const vfs_path_element_t *path_element;
92
93 path_element = vfs_path_get_by_index (vpath, -1);
94
95 /* On Linux >= 5.1, MC sometimes shows empty directpries on mounted CIFS shares.
96 * Rereading directory restores the directory content.
97 *
98 * Reopen directory, if first readdir() returns NULL and errno == EINTR.
99 */
100 while (dir == NULL)
101 {
102 dir = opendir (path_element->path);
103 if (dir == NULL)
104 return NULL;
105
106 if (readdir (dir) == NULL && errno == EINTR)
107 {
108 closedir (dir);
109 dir = NULL;
110 }
111 else
112 rewinddir (dir);
113 }
114
115 local_info = (DIR **) g_new (DIR *, 1);
116 *local_info = dir;
117
118 return local_info;
119 }
120
121 /* --------------------------------------------------------------------------------------------- */
122
123 static struct vfs_dirent *
local_readdir(void * data)124 local_readdir (void *data)
125 {
126 struct dirent *d;
127
128 d = readdir (*(DIR **) data);
129
130 return (d != NULL ? vfs_dirent_init (NULL, d->d_name, d->d_ino) : NULL);
131 }
132
133 /* --------------------------------------------------------------------------------------------- */
134
135 static int
local_closedir(void * data)136 local_closedir (void *data)
137 {
138 int i;
139
140 i = closedir (*(DIR **) data);
141 g_free (data);
142 return i;
143 }
144
145 /* --------------------------------------------------------------------------------------------- */
146
147 static int
local_stat(const vfs_path_t * vpath,struct stat * buf)148 local_stat (const vfs_path_t * vpath, struct stat *buf)
149 {
150 const vfs_path_element_t *path_element;
151
152 path_element = vfs_path_get_by_index (vpath, -1);
153 return stat (path_element->path, buf);
154 }
155
156 /* --------------------------------------------------------------------------------------------- */
157
158 static int
local_lstat(const vfs_path_t * vpath,struct stat * buf)159 local_lstat (const vfs_path_t * vpath, struct stat *buf)
160 {
161 const vfs_path_element_t *path_element;
162
163 path_element = vfs_path_get_by_index (vpath, -1);
164 #ifndef HAVE_STATLSTAT
165 return lstat (path_element->path, buf);
166 #else
167 return statlstat (path_element->path, buf);
168 #endif
169 }
170
171 /* --------------------------------------------------------------------------------------------- */
172
173 static int
local_chmod(const vfs_path_t * vpath,mode_t mode)174 local_chmod (const vfs_path_t * vpath, mode_t mode)
175 {
176 const vfs_path_element_t *path_element;
177
178 path_element = vfs_path_get_by_index (vpath, -1);
179 return chmod (path_element->path, mode);
180 }
181
182 /* --------------------------------------------------------------------------------------------- */
183
184 static int
local_chown(const vfs_path_t * vpath,uid_t owner,gid_t group)185 local_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
186 {
187 const vfs_path_element_t *path_element;
188
189 path_element = vfs_path_get_by_index (vpath, -1);
190 return chown (path_element->path, owner, group);
191 }
192
193 /* --------------------------------------------------------------------------------------------- */
194
195 static int
local_utime(const vfs_path_t * vpath,mc_timesbuf_t * times)196 local_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
197 {
198 int ret;
199 const vfs_path_element_t *path_element;
200
201 path_element = vfs_path_get_by_index (vpath, -1);
202 #ifdef HAVE_UTIMENSAT
203 ret = utimensat (AT_FDCWD, path_element->path, *times, AT_SYMLINK_NOFOLLOW);
204 #else
205 ret = utime (path_element->path, times);
206 #endif
207 return ret;
208 }
209
210 /* --------------------------------------------------------------------------------------------- */
211
212 static int
local_readlink(const vfs_path_t * vpath,char * buf,size_t size)213 local_readlink (const vfs_path_t * vpath, char *buf, size_t size)
214 {
215 const vfs_path_element_t *path_element;
216
217 path_element = vfs_path_get_by_index (vpath, -1);
218 return readlink (path_element->path, buf, size);
219 }
220
221 /* --------------------------------------------------------------------------------------------- */
222
223 static int
local_unlink(const vfs_path_t * vpath)224 local_unlink (const vfs_path_t * vpath)
225 {
226 const vfs_path_element_t *path_element;
227
228 path_element = vfs_path_get_by_index (vpath, -1);
229 return unlink (path_element->path);
230 }
231
232 /* --------------------------------------------------------------------------------------------- */
233
234 static int
local_symlink(const vfs_path_t * vpath1,const vfs_path_t * vpath2)235 local_symlink (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
236 {
237 const vfs_path_element_t *path_element1, *path_element2;
238
239 path_element1 = vfs_path_get_by_index (vpath1, -1);
240 path_element2 = vfs_path_get_by_index (vpath2, -1);
241 return symlink (path_element1->path, path_element2->path);
242 }
243
244 /* --------------------------------------------------------------------------------------------- */
245
246 static ssize_t
local_write(void * data,const char * buf,size_t nbyte)247 local_write (void *data, const char *buf, size_t nbyte)
248 {
249 int fd;
250 int n;
251
252 if (data == NULL)
253 return (-1);
254
255 fd = *(int *) data;
256
257 while ((n = write (fd, buf, nbyte)) == -1)
258 {
259 #ifdef EAGAIN
260 if (errno == EAGAIN)
261 continue;
262 #endif
263 #ifdef EINTR
264 if (errno == EINTR)
265 continue;
266 #endif
267 break;
268 }
269
270 return n;
271 }
272
273 /* --------------------------------------------------------------------------------------------- */
274
275 static int
local_rename(const vfs_path_t * vpath1,const vfs_path_t * vpath2)276 local_rename (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
277 {
278 const vfs_path_element_t *path_element1, *path_element2;
279
280 path_element1 = vfs_path_get_by_index (vpath1, -1);
281 path_element2 = vfs_path_get_by_index (vpath2, -1);
282 return rename (path_element1->path, path_element2->path);
283 }
284
285 /* --------------------------------------------------------------------------------------------- */
286
287 static int
local_chdir(const vfs_path_t * vpath)288 local_chdir (const vfs_path_t * vpath)
289 {
290 const vfs_path_element_t *path_element;
291
292 path_element = vfs_path_get_by_index (vpath, -1);
293 return chdir (path_element->path);
294 }
295
296 /* --------------------------------------------------------------------------------------------- */
297
298 static int
local_mknod(const vfs_path_t * vpath,mode_t mode,dev_t dev)299 local_mknod (const vfs_path_t * vpath, mode_t mode, dev_t dev)
300 {
301 const vfs_path_element_t *path_element;
302
303 path_element = vfs_path_get_by_index (vpath, -1);
304 return mknod (path_element->path, mode, dev);
305 }
306
307 /* --------------------------------------------------------------------------------------------- */
308
309 static int
local_link(const vfs_path_t * vpath1,const vfs_path_t * vpath2)310 local_link (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
311 {
312 const vfs_path_element_t *path_element1, *path_element2;
313
314 path_element1 = vfs_path_get_by_index (vpath1, -1);
315 path_element2 = vfs_path_get_by_index (vpath2, -1);
316 return link (path_element1->path, path_element2->path);
317 }
318
319 /* --------------------------------------------------------------------------------------------- */
320
321 static int
local_mkdir(const vfs_path_t * vpath,mode_t mode)322 local_mkdir (const vfs_path_t * vpath, mode_t mode)
323 {
324 const vfs_path_element_t *path_element;
325
326 path_element = vfs_path_get_by_index (vpath, -1);
327 return mkdir (path_element->path, mode);
328 }
329
330 /* --------------------------------------------------------------------------------------------- */
331
332 static int
local_rmdir(const vfs_path_t * vpath)333 local_rmdir (const vfs_path_t * vpath)
334 {
335 const vfs_path_element_t *path_element;
336
337 path_element = vfs_path_get_by_index (vpath, -1);
338 return rmdir (path_element->path);
339 }
340
341 /* --------------------------------------------------------------------------------------------- */
342
343 static vfs_path_t *
local_getlocalcopy(const vfs_path_t * vpath)344 local_getlocalcopy (const vfs_path_t * vpath)
345 {
346 return vfs_path_clone (vpath);
347 }
348
349 /* --------------------------------------------------------------------------------------------- */
350
351 static int
local_ungetlocalcopy(const vfs_path_t * vpath,const vfs_path_t * local,gboolean has_changed)352 local_ungetlocalcopy (const vfs_path_t * vpath, const vfs_path_t * local, gboolean has_changed)
353 {
354 (void) vpath;
355 (void) local;
356 (void) has_changed;
357
358 return 0;
359 }
360
361 /* --------------------------------------------------------------------------------------------- */
362
363 static int
local_which(struct vfs_class * me,const char * path)364 local_which (struct vfs_class *me, const char *path)
365 {
366 (void) me;
367 (void) path;
368
369 return 0; /* Every path which other systems do not like is expected to be ours */
370 }
371
372 /* --------------------------------------------------------------------------------------------- */
373 /*** public functions ****************************************************************************/
374 /* --------------------------------------------------------------------------------------------- */
375
376 ssize_t
local_read(void * data,char * buffer,size_t count)377 local_read (void *data, char *buffer, size_t count)
378 {
379 int n;
380 int fd;
381
382 if (data == NULL)
383 return (-1);
384
385 fd = *(int *) data;
386
387 while ((n = read (fd, buffer, count)) == -1)
388 {
389 #ifdef EAGAIN
390 if (errno == EAGAIN)
391 continue;
392 #endif
393 #ifdef EINTR
394 if (errno == EINTR)
395 continue;
396 #endif
397 return (-1);
398 }
399
400 return n;
401 }
402
403 /* --------------------------------------------------------------------------------------------- */
404
405 int
local_close(void * data)406 local_close (void *data)
407 {
408 int fd;
409
410 if (data == NULL)
411 return (-1);
412
413 fd = *(int *) data;
414 g_free (data);
415 return close (fd);
416 }
417
418 /* --------------------------------------------------------------------------------------------- */
419
420 int
local_errno(struct vfs_class * me)421 local_errno (struct vfs_class *me)
422 {
423 (void) me;
424 return errno;
425 }
426
427 /* --------------------------------------------------------------------------------------------- */
428
429 int
local_fstat(void * data,struct stat * buf)430 local_fstat (void *data, struct stat *buf)
431 {
432 int fd = *(int *) data;
433
434 return fstat (fd, buf);
435 }
436
437 /* --------------------------------------------------------------------------------------------- */
438
439 off_t
local_lseek(void * data,off_t offset,int whence)440 local_lseek (void *data, off_t offset, int whence)
441 {
442 int fd = *(int *) data;
443
444 return lseek (fd, offset, whence);
445 }
446
447 /* --------------------------------------------------------------------------------------------- */
448
449 static gboolean
local_nothingisopen(vfsid id)450 local_nothingisopen (vfsid id)
451 {
452 (void) id;
453
454 return TRUE;
455 }
456
457 /* --------------------------------------------------------------------------------------------- */
458
459 void
vfs_init_localfs(void)460 vfs_init_localfs (void)
461 {
462 /* NULLize vfs_s_subclass members */
463 memset (&local_subclass, 0, sizeof (local_subclass));
464
465 vfs_init_class (vfs_local_ops, "localfs", VFSF_LOCAL, NULL);
466 vfs_local_ops->which = local_which;
467 vfs_local_ops->open = local_open;
468 vfs_local_ops->close = local_close;
469 vfs_local_ops->read = local_read;
470 vfs_local_ops->write = local_write;
471 vfs_local_ops->opendir = local_opendir;
472 vfs_local_ops->readdir = local_readdir;
473 vfs_local_ops->closedir = local_closedir;
474 vfs_local_ops->stat = local_stat;
475 vfs_local_ops->lstat = local_lstat;
476 vfs_local_ops->fstat = local_fstat;
477 vfs_local_ops->chmod = local_chmod;
478 vfs_local_ops->chown = local_chown;
479 vfs_local_ops->utime = local_utime;
480 vfs_local_ops->readlink = local_readlink;
481 vfs_local_ops->symlink = local_symlink;
482 vfs_local_ops->link = local_link;
483 vfs_local_ops->unlink = local_unlink;
484 vfs_local_ops->rename = local_rename;
485 vfs_local_ops->chdir = local_chdir;
486 vfs_local_ops->ferrno = local_errno;
487 vfs_local_ops->lseek = local_lseek;
488 vfs_local_ops->mknod = local_mknod;
489 vfs_local_ops->getlocalcopy = local_getlocalcopy;
490 vfs_local_ops->ungetlocalcopy = local_ungetlocalcopy;
491 vfs_local_ops->mkdir = local_mkdir;
492 vfs_local_ops->rmdir = local_rmdir;
493 vfs_local_ops->nothingisopen = local_nothingisopen;
494 vfs_register_class (vfs_local_ops);
495 }
496
497 /* --------------------------------------------------------------------------------------------- */
498