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 "lib/vfs/vfs.h"
51 #include "lib/vfs/utilvfs.h"
52 #include "lib/vfs/xdirentry.h"
53 #include "src/vfs/local/local.h"
54 #include "lib/vfs/gc.h"
55
56 #include "sfs.h"
57
58
59
60
61
62 #define MAXFS 32
63
64 typedef enum
65 {
66 F_NONE = 0x0,
67 F_1 = 0x1,
68 F_2 = 0x2,
69 F_NOLOCALCOPY = 0x4,
70 F_FULLMATCH = 0x8
71 } sfs_flags_t;
72
73 #define COPY_CHAR \
74 if ((size_t) (t - pad) > sizeof (pad)) \
75 { \
76 g_free (pqname); \
77 return (-1); \
78 } \
79 else \
80 *t++ = *s_iter;
81
82 #define COPY_STRING(a) \
83 if ((t - pad) + strlen (a) > sizeof (pad)) \
84 { \
85 g_free (pqname); \
86 return (-1); \
87 } \
88 else \
89 { \
90 strcpy (t, a); \
91 t += strlen (a); \
92 }
93
94
95
96 typedef struct cachedfile
97 {
98 char *name;
99 char *cache;
100 } cachedfile;
101
102
103
104
105
106 static GSList *head = NULL;
107
108 static struct vfs_s_subclass sfs_subclass;
109 static struct vfs_class *vfs_sfs_ops = VFS_CLASS (&sfs_subclass);
110
111 static int sfs_no = 0;
112 static struct
113 {
114 char *prefix;
115 char *command;
116 sfs_flags_t flags;
117 } sfs_info[MAXFS];
118
119
120
121
122
123 static int
124 cachedfile_compare (const void *a, const void *b)
125 {
126 const cachedfile *cf = (const cachedfile *) a;
127 const char *name = (const char *) b;
128
129 return strcmp (name, cf->name);
130 }
131
132
133
134 static int
135 sfs_vfmake (const vfs_path_t *vpath, vfs_path_t *cache_vpath)
136 {
137 int w;
138 char pad[BUF_10K];
139 char *s_iter, *t = pad;
140 gboolean was_percent = FALSE;
141 vfs_path_t *pname;
142 GString *quoted;
143 char *pqname;
144 const vfs_path_element_t *path_element;
145 mc_pipe_t *pip;
146 GError *error = NULL;
147
148 path_element = vfs_path_get_by_index (vpath, -1);
149 pname = vfs_path_clone (vpath);
150 vfs_path_remove_element_by_index (pname, -1);
151
152 w = path_element->class->which (path_element->class, path_element->vfs_prefix);
153 if (w == -1)
154 vfs_die ("This cannot happen... Hopefully.\n");
155
156 if ((sfs_info[w].flags & F_1) == 0
157 && strcmp (vfs_path_get_last_path_str (pname), PATH_SEP_STR) != 0)
158 {
159 vfs_path_free (pname, TRUE);
160 return (-1);
161 }
162
163
164 if ((sfs_info[w].flags & F_NOLOCALCOPY) != 0)
165 quoted = name_quote (vfs_path_as_str (pname), FALSE);
166 else
167 {
168 vfs_path_t *s;
169
170 s = mc_getlocalcopy (pname);
171 if (s == NULL)
172 {
173 vfs_path_free (pname, TRUE);
174 return (-1);
175 }
176
177 quoted = name_quote (vfs_path_get_last_path_str (s), FALSE);
178 vfs_path_free (s, TRUE);
179 }
180
181 vfs_path_free (pname, TRUE);
182
183 pqname = g_string_free (quoted, FALSE);
184
185 for (s_iter = sfs_info[w].command; *s_iter != '\0'; s_iter++)
186 {
187 if (was_percent)
188 {
189 const char *ptr = NULL;
190
191 was_percent = FALSE;
192
193 switch (*s_iter)
194 {
195 case '1':
196 ptr = pqname;
197 break;
198 case '2':
199 ptr = path_element->path;
200 break;
201 case '3':
202 ptr = vfs_path_get_last_path_str (cache_vpath);
203 break;
204 case '%':
205 COPY_CHAR;
206 continue;
207 default:
208 break;
209 }
210
211 if (ptr != NULL)
212 {
213 COPY_STRING (ptr);
214 }
215 }
216 else if (*s_iter == '%')
217 was_percent = TRUE;
218 else
219 {
220 COPY_CHAR;
221 }
222 }
223
224 g_free (pqname);
225
226
227 pip = mc_popen (pad, FALSE, TRUE, &error);
228 if (pip == NULL)
229 {
230 message (D_ERROR, MSG_ERROR, _ ("SFS virtual file system:\n%s"), error->message);
231 g_error_free (error);
232 return (-1);
233 }
234
235 pip->err.null_term = TRUE;
236
237 mc_pread (pip, &error);
238 if (error != NULL)
239 {
240 message (D_ERROR, MSG_ERROR, _ ("SFS virtual file system:\n%s"), error->message);
241 g_error_free (error);
242 mc_pclose (pip, NULL);
243 return (-1);
244 }
245
246 if (pip->err.len > 0)
247 message (D_ERROR, MSG_ERROR, _ ("SFS virtual file system:\n%s"), pip->err.buf);
248
249 mc_pclose (pip, NULL);
250 return 0;
251 }
252
253
254
255 static const char *
256 sfs_redirect (const vfs_path_t *vpath)
257 {
258 GSList *cur;
259 cachedfile *cf;
260 vfs_path_t *cache_vpath;
261 int handle;
262
263 cur = g_slist_find_custom (head, vfs_path_as_str (vpath), cachedfile_compare);
264
265 if (cur != NULL)
266 {
267 cf = (cachedfile *) cur->data;
268 vfs_stamp (vfs_sfs_ops, cf);
269 return cf->cache;
270 }
271
272 handle = vfs_mkstemps (&cache_vpath, "sfs", vfs_path_get_last_path_str (vpath));
273
274 if (handle == -1)
275 return "/SOMEONE_PLAYING_DIRTY_TMP_TRICKS_ON_US";
276
277 close (handle);
278
279 if (sfs_vfmake (vpath, cache_vpath) == 0)
280 {
281 cf = g_new (cachedfile, 1);
282 cf->name = g_strdup (vfs_path_as_str (vpath));
283 cf->cache = vfs_path_free (cache_vpath, FALSE);
284 head = g_slist_prepend (head, cf);
285
286 vfs_stamp_create (vfs_sfs_ops, (cachedfile *) head->data);
287 return cf->cache;
288 }
289
290 mc_unlink (cache_vpath);
291 vfs_path_free (cache_vpath, TRUE);
292 return "/I_MUST_NOT_EXIST";
293 }
294
295
296
297 static void *
298 sfs_open (const vfs_path_t *vpath , int flags,
299 mode_t mode)
300 {
301 int *info;
302 int fd;
303
304 fd = open (sfs_redirect (vpath), NO_LINEAR (flags), mode);
305 if (fd == -1)
306 return NULL;
307
308 info = g_new (int, 1);
309 *info = fd;
310
311 return info;
312 }
313
314
315
316 static int
317 sfs_stat (const vfs_path_t *vpath, struct stat *buf)
318 {
319 return stat (sfs_redirect (vpath), buf);
320 }
321
322
323
324 static int
325 sfs_lstat (const vfs_path_t *vpath, struct stat *buf)
326 {
327 #ifndef HAVE_STATLSTAT
328 return lstat (sfs_redirect (vpath), buf);
329 #else
330 return statlstat (sfs_redirect (vpath), buf);
331 #endif
332 }
333
334
335
336 static int
337 sfs_chmod (const vfs_path_t *vpath, mode_t mode)
338 {
339 return chmod (sfs_redirect (vpath), mode);
340 }
341
342
343
344 static int
345 sfs_chown (const vfs_path_t *vpath, uid_t owner, gid_t group)
346 {
347 return chown (sfs_redirect (vpath), owner, group);
348 }
349
350
351
352 static int
353 sfs_utime (const vfs_path_t *vpath, mc_timesbuf_t *times)
354 {
355 return vfs_utime (sfs_redirect (vpath), times);
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