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