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