This source file includes following definitions.
- cachedfile_compare
- sfs_vfmake
- sfs_redirect
- sfs_open
- sfs_stat
- sfs_lstat
- sfs_chmod
- sfs_chown
- sfs_utime
- sfs_readlink
- sfs_getid
- sfs_free
- sfs_fill_names
- sfs_nothingisopen
- sfs_getlocalcopy
- sfs_ungetlocalcopy
- sfs_init
- sfs_done
- sfs_which
- vfs_init_sfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 #include <config.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include <string.h>
46
47 #include "lib/global.h"
48 #include "lib/util.h"
49 #include "lib/widget.h"
50
51 #include "src/execute.h"
52
53 #include "lib/vfs/vfs.h"
54 #include "lib/vfs/utilvfs.h"
55 #include "lib/vfs/xdirentry.h"
56 #include "src/vfs/local/local.h"
57 #include "lib/vfs/gc.h"
58
59 #include "sfs.h"
60
61
62
63
64
65 #define MAXFS 32
66
67 typedef enum
68 {
69 F_NONE = 0x0,
70 F_1 = 0x1,
71 F_2 = 0x2,
72 F_NOLOCALCOPY = 0x4,
73 F_FULLMATCH = 0x8
74 } sfs_flags_t;
75
76 #define COPY_CHAR \
77 if ((size_t) (t - pad) > sizeof (pad)) \
78 { \
79 g_free (pqname); \
80 return (-1); \
81 } \
82 else \
83 *t++ = *s_iter;
84
85 #define COPY_STRING(a) \
86 if ((t - pad) + strlen (a) > sizeof (pad)) \
87 { \
88 g_free (pqname); \
89 return (-1); \
90 } \
91 else \
92 { \
93 strcpy (t, a); \
94 t += strlen (a); \
95 }
96
97
98
99 typedef struct cachedfile
100 {
101 char *name;
102 char *cache;
103 } cachedfile;
104
105
106
107 static GSList *head = NULL;
108
109 static struct vfs_s_subclass sfs_subclass;
110 static struct vfs_class *vfs_sfs_ops = VFS_CLASS (&sfs_subclass);
111
112 static int sfs_no = 0;
113 static struct
114 {
115 char *prefix;
116 char *command;
117 sfs_flags_t flags;
118 } sfs_info[MAXFS];
119
120
121
122 static int
123 cachedfile_compare (const void *a, const void *b)
124 {
125 const cachedfile *cf = (const cachedfile *) a;
126 const char *name = (const char *) b;
127
128 return strcmp (name, cf->name);
129 }
130
131
132
133 static int
134 sfs_vfmake (const vfs_path_t * vpath, vfs_path_t * cache_vpath)
135 {
136 int w;
137 char pad[10240];
138 char *s_iter, *t = pad;
139 gboolean was_percent = FALSE;
140 vfs_path_t *pname;
141 char *pqname;
142 const vfs_path_element_t *path_element;
143 mc_pipe_t *pip;
144 GError *error = NULL;
145
146 path_element = vfs_path_get_by_index (vpath, -1);
147 pname = vfs_path_clone (vpath);
148 vfs_path_remove_element_by_index (pname, -1);
149
150 w = path_element->class->which (path_element->class, path_element->vfs_prefix);
151 if (w == -1)
152 vfs_die ("This cannot happen... Hopefully.\n");
153
154 if ((sfs_info[w].flags & F_1) == 0
155 && strcmp (vfs_path_get_last_path_str (pname), PATH_SEP_STR) != 0)
156 {
157 vfs_path_free (pname, TRUE);
158 return (-1);
159 }
160
161
162 if ((sfs_info[w].flags & F_NOLOCALCOPY) != 0)
163 pqname = name_quote (vfs_path_as_str (pname), FALSE);
164 else
165 {
166 vfs_path_t *s;
167
168 s = mc_getlocalcopy (pname);
169 if (s == NULL)
170 {
171 vfs_path_free (pname, TRUE);
172 return (-1);
173 }
174
175 pqname = name_quote (vfs_path_get_last_path_str (s), FALSE);
176 vfs_path_free (s, TRUE);
177 }
178
179 vfs_path_free (pname, TRUE);
180
181 for (s_iter = sfs_info[w].command; *s_iter != '\0'; s_iter++)
182 {
183 if (was_percent)
184 {
185 const char *ptr = NULL;
186
187 was_percent = FALSE;
188
189 switch (*s_iter)
190 {
191 case '1':
192 ptr = pqname;
193 break;
194 case '2':
195 ptr = path_element->path;
196 break;
197 case '3':
198 ptr = vfs_path_get_by_index (cache_vpath, -1)->path;
199 break;
200 case '%':
201 COPY_CHAR;
202 continue;
203 default:
204 break;
205 }
206
207 if (ptr != NULL)
208 {
209 COPY_STRING (ptr);
210 }
211 }
212 else if (*s_iter == '%')
213 was_percent = TRUE;
214 else
215 {
216 COPY_CHAR;
217 }
218 }
219
220 g_free (pqname);
221
222
223 pip = mc_popen (pad, FALSE, TRUE, &error);
224 if (pip == NULL)
225 {
226 message (D_ERROR, MSG_ERROR, _("SFS virtual file system:\n%s"), error->message);
227 g_error_free (error);
228 return (-1);
229 }
230
231 mc_pread (pip, &error);
232 if (error != NULL)
233 {
234 message (D_ERROR, MSG_ERROR, _("SFS virtual file system:\n%s"), error->message);
235 g_error_free (error);
236 mc_pclose (pip, NULL);
237 return (-1);
238 }
239
240 if (pip->err.len > 0)
241 message (D_ERROR, MSG_ERROR, _("SFS virtual file system:\n%s"), pip->err.buf);
242
243 mc_pclose (pip, NULL);
244 return 0;
245 }
246
247
248
249 static const char *
250 sfs_redirect (const vfs_path_t * vpath)
251 {
252 GSList *cur;
253 cachedfile *cf;
254 vfs_path_t *cache_vpath;
255 int handle;
256 const vfs_path_element_t *path_element;
257
258 path_element = vfs_path_get_by_index (vpath, -1);
259 cur = g_slist_find_custom (head, vfs_path_as_str (vpath), cachedfile_compare);
260
261 if (cur != NULL)
262 {
263 cf = (cachedfile *) cur->data;
264 vfs_stamp (vfs_sfs_ops, cf);
265 return cf->cache;
266 }
267
268 handle = vfs_mkstemps (&cache_vpath, "sfs", path_element->path);
269
270 if (handle == -1)
271 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
272
273 close (handle);
274
275 if (sfs_vfmake (vpath, cache_vpath) == 0)
276 {
277 cf = g_new (cachedfile, 1);
278 cf->name = g_strdup (vfs_path_as_str (vpath));
279 cf->cache = vfs_path_free (cache_vpath, FALSE);
280 head = g_slist_prepend (head, cf);
281
282 vfs_stamp_create (vfs_sfs_ops, (cachedfile *) head->data);
283 return cf->cache;
284 }
285
286 mc_unlink (cache_vpath);
287 vfs_path_free (cache_vpath, TRUE);
288 return "/I_MUST_NOT_EXIST";
289 }
290
291
292
293 static void *
294 sfs_open (const vfs_path_t * vpath , int flags,
295 mode_t mode)
296 {
297 int *info;
298 int fd;
299
300 fd = open (sfs_redirect (vpath), NO_LINEAR (flags), mode);
301 if (fd == -1)
302 return NULL;
303
304 info = g_new (int, 1);
305 *info = fd;
306
307 return info;
308 }
309
310
311
312 static int
313 sfs_stat (const vfs_path_t * vpath, struct stat *buf)
314 {
315 return stat (sfs_redirect (vpath), buf);
316 }
317
318
319
320 static int
321 sfs_lstat (const vfs_path_t * vpath, struct stat *buf)
322 {
323 #ifndef HAVE_STATLSTAT
324 return lstat (sfs_redirect (vpath), buf);
325 #else
326 return statlstat (sfs_redirect (vpath), buf);
327 #endif
328 }
329
330
331
332 static int
333 sfs_chmod (const vfs_path_t * vpath, mode_t mode)
334 {
335 return chmod (sfs_redirect (vpath), mode);
336 }
337
338
339
340 static int
341 sfs_chown (const vfs_path_t * vpath, uid_t owner, gid_t group)
342 {
343 return chown (sfs_redirect (vpath), owner, group);
344 }
345
346
347
348 static int
349 sfs_utime (const vfs_path_t * vpath, mc_timesbuf_t * times)
350 {
351 #ifdef HAVE_UTIMENSAT
352 return utimensat (AT_FDCWD, sfs_redirect (vpath), *times, 0);
353 #else
354 return utime (sfs_redirect (vpath), times);
355 #endif
356 }
357
358
359
360 static int
361 sfs_readlink (const vfs_path_t * vpath, char *buf, size_t size)
362 {
363 return readlink (sfs_redirect (vpath), buf, size);
364 }
365
366
367
368 static vfsid
369 sfs_getid (const vfs_path_t * vpath)
370 {
371 GSList *cur;
372
373 cur = g_slist_find_custom (head, vfs_path_as_str (vpath), cachedfile_compare);
374
375 return (vfsid) (cur != NULL ? cur->data : NULL);
376 }
377
378
379
380 static void
381 sfs_free (vfsid id)
382 {
383 struct cachedfile *which;
384 GSList *cur;
385
386 which = (struct cachedfile *) id;
387 cur = g_slist_find (head, which);
388 if (cur == NULL)
389 vfs_die ("Free of thing which is unknown to me\n");
390
391 which = (struct cachedfile *) cur->data;
392 unlink (which->cache);
393 g_free (which->cache);
394 g_free (which->name);
395 g_free (which);
396
397 head = g_slist_delete_link (head, cur);
398 }
399
400
401
402 static void
403 sfs_fill_names (struct vfs_class *me, fill_names_f func)
404 {
405 GSList *cur;
406
407 (void) me;
408
409 for (cur = head; cur != NULL; cur = g_slist_next (cur))
410 func (((cachedfile *) cur->data)->name);
411 }
412
413
414
415 static gboolean
416 sfs_nothingisopen (vfsid id)
417 {
418
419
420 (void) id;
421 return TRUE;
422 }
423
424
425
426 static vfs_path_t *
427 sfs_getlocalcopy (const vfs_path_t * vpath)
428 {
429 return vfs_path_from_str (sfs_redirect (vpath));
430 }
431
432
433
434 static int
435 sfs_ungetlocalcopy (const vfs_path_t * vpath, const vfs_path_t * local, gboolean has_changed)
436 {
437 (void) vpath;
438 (void) local;
439 (void) has_changed;
440 return 0;
441 }
442
443
444
445 static int
446 sfs_init (struct vfs_class *me)
447 {
448 char *mc_sfsini;
449 FILE *cfg;
450 char key[256];
451
452 (void) me;
453
454 mc_sfsini = g_build_filename (mc_global.sysconfig_dir, "sfs.ini", (char *) NULL);
455 cfg = fopen (mc_sfsini, "r");
456
457 if (cfg == NULL)
458 {
459 fprintf (stderr, _("%s: Warning: file %s not found\n"), "sfs_init()", mc_sfsini);
460 g_free (mc_sfsini);
461 return 0;
462 }
463 g_free (mc_sfsini);
464
465 sfs_no = 0;
466 while (sfs_no < MAXFS && fgets (key, sizeof (key), cfg) != NULL)
467 {
468 char *c, *semi = NULL;
469 sfs_flags_t flags = F_NONE;
470
471 if (*key == '#' || *key == '\n')
472 continue;
473
474 for (c = key; *c != '\0'; c++)
475 if (*c == ':' || IS_PATH_SEP (*c))
476 {
477 semi = c;
478 if (IS_PATH_SEP (*c))
479 {
480 *c = '\0';
481 flags |= F_FULLMATCH;
482 }
483 break;
484 }
485
486 if (semi == NULL)
487 {
488 invalid_line:
489 fprintf (stderr, _("Warning: Invalid line in %s:\n%s\n"), "sfs.ini", key);
490 continue;
491 }
492
493 for (c = semi + 1; *c != '\0' && !whitespace (*c); c++)
494 switch (*c)
495 {
496 case '1':
497 flags |= F_1;
498 break;
499 case '2':
500 flags |= F_2;
501 break;
502 case 'R':
503 flags |= F_NOLOCALCOPY;
504 break;
505 default:
506 fprintf (stderr, _("Warning: Invalid flag %c in %s:\n%s\n"), *c, "sfs.ini", key);
507 }
508
509 if (*c == '\0')
510 goto invalid_line;
511
512 c++;
513 *(semi + 1) = '\0';
514 semi = strchr (c, '\n');
515 if (semi != NULL)
516 *semi = '\0';
517
518 sfs_info[sfs_no].prefix = g_strdup (key);
519 sfs_info[sfs_no].command = g_strdup (c);
520 sfs_info[sfs_no].flags = flags;
521 sfs_no++;
522 }
523 fclose (cfg);
524
525 return 1;
526 }
527
528
529
530 static void
531 sfs_done (struct vfs_class *me)
532 {
533 int i;
534
535 (void) me;
536
537 for (i = 0; i < sfs_no; i++)
538 {
539 MC_PTR_FREE (sfs_info[i].prefix);
540 MC_PTR_FREE (sfs_info[i].command);
541 }
542 sfs_no = 0;
543 }
544
545
546
547 static int
548 sfs_which (struct vfs_class *me, const char *path)
549 {
550 int i;
551
552 (void) me;
553
554 for (i = 0; i < sfs_no; i++)
555 if ((sfs_info[i].flags & F_FULLMATCH) != 0)
556 {
557 if (strcmp (path, sfs_info[i].prefix) == 0)
558 return i;
559 }
560 else if (strncmp (path, sfs_info[i].prefix, strlen (sfs_info[i].prefix)) == 0)
561 return i;
562
563 return (-1);
564 }
565
566
567
568
569
570 void
571 vfs_init_sfs (void)
572 {
573
574 memset (&sfs_subclass, 0, sizeof (sfs_subclass));
575
576 vfs_init_class (vfs_sfs_ops, "sfs", VFSF_UNKNOWN, NULL);
577 vfs_sfs_ops->init = sfs_init;
578 vfs_sfs_ops->done = sfs_done;
579 vfs_sfs_ops->fill_names = sfs_fill_names;
580 vfs_sfs_ops->which = sfs_which;
581 vfs_sfs_ops->open = sfs_open;
582 vfs_sfs_ops->close = local_close;
583 vfs_sfs_ops->read = local_read;
584 vfs_sfs_ops->stat = sfs_stat;
585 vfs_sfs_ops->lstat = sfs_lstat;
586 vfs_sfs_ops->fstat = local_fstat;
587 vfs_sfs_ops->chmod = sfs_chmod;
588 vfs_sfs_ops->chown = sfs_chown;
589 vfs_sfs_ops->utime = sfs_utime;
590 vfs_sfs_ops->readlink = sfs_readlink;
591 vfs_sfs_ops->ferrno = local_errno;
592 vfs_sfs_ops->lseek = local_lseek;
593 vfs_sfs_ops->getid = sfs_getid;
594 vfs_sfs_ops->nothingisopen = sfs_nothingisopen;
595 vfs_sfs_ops->free = sfs_free;
596 vfs_sfs_ops->getlocalcopy = sfs_getlocalcopy;
597 vfs_sfs_ops->ungetlocalcopy = sfs_ungetlocalcopy;
598 vfs_register_class (vfs_sfs_ops);
599 }
600
601