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