This source file includes following definitions.
- cpio_defer_find
- cpio_skip_padding
- cpio_new_archive
- cpio_free_archive
- cpio_open_cpio_file
- cpio_read_head
- cpio_find_head
- cpio_create_entry
- cpio_read_bin_head
- cpio_read_oldc_head
- cpio_read_crc_head
- cpio_open_archive
- cpio_super_check
- cpio_super_same
- cpio_read
- cpio_fh_open
- vfs_init_cpiofs
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 #include <config.h>
34
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38
39 #include "lib/global.h"
40 #include "lib/unixcompat.h"
41 #include "lib/util.h"
42 #include "lib/widget.h"
43
44 #include "lib/vfs/vfs.h"
45 #include "lib/vfs/utilvfs.h"
46 #include "lib/vfs/xdirentry.h"
47 #include "lib/vfs/gc.h"
48
49 #include "cpio.h"
50
51
52
53
54
55 #define CPIO_SUPER(super) ((cpio_super_t *) (super))
56
57 #define CPIO_POS(super) cpio_position
58
59
60
61 #define CPIO_SEEK_SET(super, where) \
62 mc_lseek (CPIO_SUPER (super)->fd, CPIO_POS (super) = (where), SEEK_SET)
63 #define CPIO_SEEK_CUR(super, where) \
64 mc_lseek (CPIO_SUPER (super)->fd, CPIO_POS (super) += (where), SEEK_SET)
65
66 #define MAGIC_LENGTH (6)
67 #define SEEKBACK CPIO_SEEK_CUR (super, ptr - top)
68 #define RETURN(x) return (CPIO_SUPER (super)->type = (x))
69 #define TYPEIS(x) ((CPIO_SUPER (super)->type == CPIO_UNKNOWN) || (CPIO_SUPER (super)->type == (x)))
70
71 #define HEAD_LENGTH (26)
72
73
74
75 enum
76 {
77 STATUS_START,
78 STATUS_OK,
79 STATUS_TRAIL,
80 STATUS_FAIL,
81 STATUS_EOF
82 };
83
84 enum
85 {
86 CPIO_UNKNOWN = 0,
87 CPIO_BIN,
88 CPIO_BINRE,
89 CPIO_OLDC,
90 CPIO_NEWC,
91 CPIO_CRC
92 };
93
94 struct old_cpio_header
95 {
96 unsigned short c_magic;
97 short c_dev;
98 unsigned short c_ino;
99 unsigned short c_mode;
100 unsigned short c_uid;
101 unsigned short c_gid;
102 unsigned short c_nlink;
103 short c_rdev;
104 unsigned short c_mtimes[2];
105 unsigned short c_namesize;
106 unsigned short c_filesizes[2];
107 };
108
109 struct new_cpio_header
110 {
111 unsigned short c_magic;
112 unsigned long c_ino;
113 unsigned long c_mode;
114 unsigned long c_uid;
115 unsigned long c_gid;
116 unsigned long c_nlink;
117 unsigned long c_mtime;
118 unsigned long c_filesize;
119 long c_dev;
120 long c_devmin;
121 long c_rdev;
122 long c_rdevmin;
123 unsigned long c_namesize;
124 unsigned long c_chksum;
125 };
126
127 typedef struct
128 {
129 unsigned long inumber;
130 dev_t device;
131 struct vfs_s_inode *inode;
132 } defer_inode;
133
134 typedef struct
135 {
136 struct vfs_s_super base;
137
138 int fd;
139 struct stat st;
140 int type;
141 GSList *deferred;
142 } cpio_super_t;
143
144
145
146 static ssize_t cpio_find_head (struct vfs_class *me, struct vfs_s_super *super);
147 static ssize_t cpio_read_bin_head (struct vfs_class *me, struct vfs_s_super *super);
148 static ssize_t cpio_read_oldc_head (struct vfs_class *me, struct vfs_s_super *super);
149 static ssize_t cpio_read_crc_head (struct vfs_class *me, struct vfs_s_super *super);
150
151
152
153 static struct vfs_s_subclass cpio_subclass;
154 static struct vfs_class *vfs_cpiofs_ops = VFS_CLASS (&cpio_subclass);
155
156 static off_t cpio_position;
157
158
159
160
161
162 static int
163 cpio_defer_find (const void *a, const void *b)
164 {
165 const defer_inode *a1 = (const defer_inode *) a;
166 const defer_inode *b1 = (const defer_inode *) b;
167
168 return (a1->inumber == b1->inumber && a1->device == b1->device) ? 0 : 1;
169 }
170
171
172
173 static ssize_t
174 cpio_skip_padding (struct vfs_s_super *super)
175 {
176 switch (CPIO_SUPER (super)->type)
177 {
178 case CPIO_BIN:
179 case CPIO_BINRE:
180 return CPIO_SEEK_CUR (super, (2 - (CPIO_POS (super) % 2)) % 2);
181 case CPIO_NEWC:
182 case CPIO_CRC:
183 return CPIO_SEEK_CUR (super, (4 - (CPIO_POS (super) % 4)) % 4);
184 case CPIO_OLDC:
185 return CPIO_POS (super);
186 default:
187 g_assert_not_reached ();
188 return 42;
189 }
190 }
191
192
193
194 static struct vfs_s_super *
195 cpio_new_archive (struct vfs_class *me)
196 {
197 cpio_super_t *arch;
198
199 arch = g_new0 (cpio_super_t, 1);
200 arch->base.me = me;
201 arch->fd = -1;
202 arch->type = CPIO_UNKNOWN;
203
204 return VFS_SUPER (arch);
205 }
206
207
208
209 static void
210 cpio_free_archive (struct vfs_class *me, struct vfs_s_super *super)
211 {
212 cpio_super_t *arch = CPIO_SUPER (super);
213
214 (void) me;
215
216 if (arch->fd != -1)
217 {
218 mc_close (arch->fd);
219 arch->fd = -1;
220 }
221
222 g_clear_slist (&arch->deferred, g_free);
223 }
224
225
226
227 static int
228 cpio_open_cpio_file (struct vfs_class *me, struct vfs_s_super *super, const vfs_path_t *vpath)
229 {
230 int fd, type;
231 cpio_super_t *arch;
232 mode_t mode;
233 struct vfs_s_inode *root;
234
235 fd = mc_open (vpath, O_RDONLY);
236 if (fd == -1)
237 {
238 message (D_ERROR, MSG_ERROR, _ ("Cannot open cpio archive\n%s"), vfs_path_as_str (vpath));
239 return -1;
240 }
241
242 super->name = g_strdup (vfs_path_as_str (vpath));
243 arch = CPIO_SUPER (super);
244 mc_stat (vpath, &arch->st);
245
246 type = get_compression_type (fd, super->name);
247 if (type == COMPRESSION_NONE)
248 mc_lseek (fd, 0, SEEK_SET);
249 else
250 {
251 char *s;
252 vfs_path_t *tmp_vpath;
253
254 mc_close (fd);
255 s = g_strconcat (super->name, decompress_extension (type), (char *) NULL);
256 tmp_vpath = vfs_path_from_str_flags (s, VPF_NO_CANON);
257 fd = mc_open (tmp_vpath, O_RDONLY);
258 vfs_path_free (tmp_vpath, TRUE);
259 if (fd == -1)
260 {
261 message (D_ERROR, MSG_ERROR, _ ("Cannot open cpio archive\n%s"), s);
262 g_free (s);
263 MC_PTR_FREE (super->name);
264 return -1;
265 }
266 g_free (s);
267 }
268
269 arch->fd = fd;
270 mode = arch->st.st_mode & 07777;
271 mode |= (mode & 0444) >> 2;
272 mode |= S_IFDIR;
273
274 root = vfs_s_new_inode (me, super, &arch->st);
275 root->st.st_mode = mode;
276 root->data_offset = -1;
277 root->st.st_nlink++;
278 root->st.st_dev = VFS_SUBCLASS (me)->rdev++;
279
280 super->root = root;
281
282 CPIO_SEEK_SET (super, 0);
283
284 return fd;
285 }
286
287
288
289 static ssize_t
290 cpio_read_head (struct vfs_class *me, struct vfs_s_super *super)
291 {
292 switch (cpio_find_head (me, super))
293 {
294 case CPIO_UNKNOWN:
295 return -1;
296 case CPIO_BIN:
297 case CPIO_BINRE:
298 return cpio_read_bin_head (me, super);
299 case CPIO_OLDC:
300 return cpio_read_oldc_head (me, super);
301 case CPIO_NEWC:
302 case CPIO_CRC:
303 return cpio_read_crc_head (me, super);
304 default:
305 g_assert_not_reached ();
306 return 42;
307 }
308 }
309
310
311
312 static ssize_t
313 cpio_find_head (struct vfs_class *me, struct vfs_s_super *super)
314 {
315 cpio_super_t *arch = CPIO_SUPER (super);
316 char buf[BUF_SMALL * 2];
317 ssize_t ptr = 0;
318 ssize_t top;
319 ssize_t tmp;
320
321 top = mc_read (arch->fd, buf, sizeof (buf));
322 if (top > 0)
323 CPIO_POS (super) += top;
324
325 while (TRUE)
326 {
327 if (ptr + MAGIC_LENGTH >= top)
328 {
329 if (top > (ssize_t) (sizeof (buf) / 2))
330 {
331 memmove (buf, buf + top - sizeof (buf) / 2, sizeof (buf) / 2);
332 ptr -= top - sizeof (buf) / 2;
333 top = sizeof (buf) / 2;
334 }
335 tmp = mc_read (arch->fd, buf, top);
336 if (tmp == 0 || tmp == -1)
337 {
338 message (D_ERROR, MSG_ERROR, _ ("Premature end of cpio archive\n%s"), super->name);
339 cpio_free_archive (me, super);
340 return CPIO_UNKNOWN;
341 }
342 top += tmp;
343 }
344 if (TYPEIS (CPIO_BIN) && ((*(unsigned short *) (buf + ptr)) == 070707))
345 {
346 SEEKBACK;
347 RETURN (CPIO_BIN);
348 }
349 else if (TYPEIS (CPIO_BINRE)
350 && ((*(unsigned short *) (buf + ptr)) == GUINT16_SWAP_LE_BE_CONSTANT (070707)))
351 {
352 SEEKBACK;
353 RETURN (CPIO_BINRE);
354 }
355 else if (TYPEIS (CPIO_OLDC) && (strncmp (buf + ptr, "070707", 6) == 0))
356 {
357 SEEKBACK;
358 RETURN (CPIO_OLDC);
359 }
360 else if (TYPEIS (CPIO_NEWC) && (strncmp (buf + ptr, "070701", 6) == 0))
361 {
362 SEEKBACK;
363 RETURN (CPIO_NEWC);
364 }
365 else if (TYPEIS (CPIO_CRC) && (strncmp (buf + ptr, "070702", 6) == 0))
366 {
367 SEEKBACK;
368 RETURN (CPIO_CRC);
369 };
370 ptr++;
371 }
372 }
373
374
375
376 static int
377 cpio_create_entry (struct vfs_class *me, struct vfs_s_super *super, struct stat *st, char *name)
378 {
379 cpio_super_t *arch = CPIO_SUPER (super);
380 struct vfs_s_inode *inode = NULL;
381 struct vfs_s_inode *root = super->root;
382 struct vfs_s_entry *entry = NULL;
383 char *tn;
384
385
386
387 if (S_ISLNK (st->st_mode) && (st->st_size < 0 || st->st_size > MC_MAXPATHLEN))
388 {
389 message (D_ERROR, MSG_ERROR, _ ("Corrupted cpio header encountered in\n%s"), super->name);
390 g_free (name);
391 return STATUS_FAIL;
392 }
393
394 switch (st->st_mode & S_IFMT)
395 {
396 case S_IFCHR:
397 case S_IFBLK:
398 #ifdef S_IFSOCK
399 case S_IFSOCK:
400 #endif
401 #ifdef S_IFIFO
402 case S_IFIFO:
403 #endif
404 #ifdef S_IFNAM
405 case S_IFNAM:
406 #endif
407 #ifdef HAVE_STRUCT_STAT_ST_RDEV
408 if ((st->st_size != 0) && (st->st_rdev == 0x0001))
409 {
410
411 st->st_rdev = (unsigned) st->st_size;
412 st->st_size = 0;
413 }
414 #endif
415 break;
416 default:
417 break;
418 }
419
420 if ((st->st_nlink > 1) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
421 {
422 defer_inode i = { st->st_ino, st->st_dev, NULL };
423 GSList *l;
424
425 l = g_slist_find_custom (arch->deferred, &i, cpio_defer_find);
426 if (l != NULL)
427 {
428 inode = ((defer_inode *) l->data)->inode;
429 if (inode->st.st_size != 0 && st->st_size != 0 && (inode->st.st_size != st->st_size))
430 {
431 message (D_ERROR, MSG_ERROR,
432 _ ("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"), name,
433 super->name);
434 inode = NULL;
435 }
436 else if (inode->st.st_size == 0)
437 inode->st.st_size = st->st_size;
438 }
439 }
440
441
442 for (tn = name + strlen (name) - 1; tn >= name && IS_PATH_SEP (*tn); tn--)
443 *tn = '\0';
444
445 tn = strrchr (name, PATH_SEP);
446 if (tn == NULL)
447 tn = name;
448 else if (tn == name + 1)
449 {
450
451 tn++;
452 }
453 else
454 {
455 *tn = '\0';
456 root = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_MKDIR);
457 *tn = PATH_SEP;
458 tn++;
459 }
460
461 entry = VFS_SUBCLASS (me)->find_entry (me, root, tn, LINK_FOLLOW,
462 FL_NONE);
463
464 if (entry != NULL)
465 {
466
467
468
469
470 if (!S_ISDIR (entry->ino->st.st_mode))
471 {
472
473 message (D_ERROR, MSG_ERROR, _ ("%s contains duplicate entries! Skipping!"),
474 super->name);
475 }
476 else
477 {
478 entry->ino->st.st_mode = st->st_mode;
479 entry->ino->st.st_uid = st->st_uid;
480 entry->ino->st.st_gid = st->st_gid;
481
482 vfs_copy_stat_times (st, &entry->ino->st);
483 }
484
485 g_free (name);
486 }
487 else
488 {
489
490
491
492
493 if (root != NULL)
494 {
495 if (inode == NULL)
496 {
497 inode = vfs_s_new_inode (me, super, st);
498 if ((st->st_nlink > 0) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
499 {
500
501 defer_inode *i;
502
503 i = g_new (defer_inode, 1);
504 i->inumber = st->st_ino;
505 i->device = st->st_dev;
506 i->inode = inode;
507
508 arch->deferred = g_slist_prepend (arch->deferred, i);
509 }
510 }
511
512 if (st->st_size != 0)
513 inode->data_offset = CPIO_POS (super);
514
515 entry = vfs_s_new_entry (me, tn, inode);
516 vfs_s_insert_entry (me, root, entry);
517 }
518
519 g_free (name);
520
521 if (!S_ISLNK (st->st_mode))
522 CPIO_SEEK_CUR (super, st->st_size);
523 else
524 {
525 if (inode != NULL)
526 {
527
528
529
530
531 inode->linkname = g_realloc (inode->linkname, (gsize) st->st_size + 1);
532
533 if (mc_read (arch->fd, inode->linkname, st->st_size) < st->st_size)
534 {
535 inode->linkname[0] = '\0';
536 return STATUS_EOF;
537 }
538
539 inode->linkname[st->st_size] = '\0';
540 }
541
542 CPIO_POS (super) += st->st_size;
543 cpio_skip_padding (super);
544 }
545 }
546
547 return STATUS_OK;
548 }
549
550
551
552 static ssize_t
553 cpio_read_bin_head (struct vfs_class *me, struct vfs_s_super *super)
554 {
555 union
556 {
557 struct old_cpio_header buf;
558 short shorts[HEAD_LENGTH >> 1];
559 } u;
560
561 cpio_super_t *arch = CPIO_SUPER (super);
562 ssize_t len;
563 char *name;
564 struct stat st;
565
566 len = mc_read (arch->fd, (char *) &u.buf, HEAD_LENGTH);
567 if (len < HEAD_LENGTH)
568 return STATUS_EOF;
569 CPIO_POS (super) += len;
570 if (arch->type == CPIO_BINRE)
571 {
572 int i;
573
574 for (i = 0; i < (HEAD_LENGTH >> 1); i++)
575 u.shorts[i] = GUINT16_SWAP_LE_BE_CONSTANT (u.shorts[i]);
576 }
577
578 if (u.buf.c_magic != 070707 || u.buf.c_namesize == 0 || u.buf.c_namesize > MC_MAXPATHLEN)
579 {
580 message (D_ERROR, MSG_ERROR, _ ("Corrupted cpio header encountered in\n%s"), super->name);
581 return STATUS_FAIL;
582 }
583 name = g_malloc (u.buf.c_namesize);
584 len = mc_read (arch->fd, name, u.buf.c_namesize);
585 if (len < u.buf.c_namesize)
586 {
587 g_free (name);
588 return STATUS_EOF;
589 }
590 name[u.buf.c_namesize - 1] = '\0';
591 CPIO_POS (super) += len;
592 cpio_skip_padding (super);
593
594 if (strcmp ("TRAILER!!!", name) == 0)
595 {
596 g_free (name);
597 return STATUS_TRAIL;
598 }
599
600 st.st_dev = u.buf.c_dev;
601 st.st_ino = u.buf.c_ino;
602 st.st_mode = u.buf.c_mode;
603 st.st_nlink = u.buf.c_nlink;
604 st.st_uid = u.buf.c_uid;
605 st.st_gid = u.buf.c_gid;
606 #ifdef HAVE_STRUCT_STAT_ST_RDEV
607 st.st_rdev = u.buf.c_rdev;
608 #endif
609 st.st_size = ((off_t) u.buf.c_filesizes[0] << 16) | u.buf.c_filesizes[1];
610
611 vfs_zero_stat_times (&st);
612
613 st.st_atime = st.st_mtime = st.st_ctime =
614 ((time_t) u.buf.c_mtimes[0] << 16) | u.buf.c_mtimes[1];
615
616 return cpio_create_entry (me, super, &st, name);
617 }
618
619
620
621 #undef HEAD_LENGTH
622 #define HEAD_LENGTH (76)
623
624 static ssize_t
625 cpio_read_oldc_head (struct vfs_class *me, struct vfs_s_super *super)
626 {
627 cpio_super_t *arch = CPIO_SUPER (super);
628 struct new_cpio_header hd;
629 union
630 {
631 struct stat st;
632 char buf[HEAD_LENGTH + 1];
633 } u;
634 ssize_t len;
635 char *name;
636
637 if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
638 return STATUS_EOF;
639 CPIO_POS (super) += HEAD_LENGTH;
640 u.buf[HEAD_LENGTH] = 0;
641
642 if (sscanf (u.buf, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
643 (unsigned long *) &hd.c_dev, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
644 &hd.c_nlink, (unsigned long *) &hd.c_rdev, &hd.c_mtime, &hd.c_namesize,
645 &hd.c_filesize)
646 < 10)
647 {
648 message (D_ERROR, MSG_ERROR, _ ("Corrupted cpio header encountered in\n%s"), super->name);
649 return STATUS_FAIL;
650 }
651
652 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
653 {
654 message (D_ERROR, MSG_ERROR, _ ("Corrupted cpio header encountered in\n%s"), super->name);
655 return STATUS_FAIL;
656 }
657 name = g_malloc (hd.c_namesize);
658 len = mc_read (arch->fd, name, hd.c_namesize);
659 if ((len == -1) || ((unsigned long) len < hd.c_namesize))
660 {
661 g_free (name);
662 return STATUS_EOF;
663 }
664 name[hd.c_namesize - 1] = '\0';
665 CPIO_POS (super) += len;
666 cpio_skip_padding (super);
667
668 if (strcmp ("TRAILER!!!", name) == 0)
669 {
670 g_free (name);
671 return STATUS_TRAIL;
672 }
673
674 u.st.st_dev = hd.c_dev;
675 u.st.st_ino = hd.c_ino;
676 u.st.st_mode = hd.c_mode;
677 u.st.st_nlink = hd.c_nlink;
678 u.st.st_uid = hd.c_uid;
679 u.st.st_gid = hd.c_gid;
680 #ifdef HAVE_STRUCT_STAT_ST_RDEV
681 u.st.st_rdev = hd.c_rdev;
682 #endif
683 u.st.st_size = hd.c_filesize;
684
685 vfs_zero_stat_times (&u.st);
686 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
687
688 return cpio_create_entry (me, super, &u.st, name);
689 }
690
691
692
693 #undef HEAD_LENGTH
694 #define HEAD_LENGTH (110)
695
696 static ssize_t
697 cpio_read_crc_head (struct vfs_class *me, struct vfs_s_super *super)
698 {
699 cpio_super_t *arch = CPIO_SUPER (super);
700 struct new_cpio_header hd;
701 union
702 {
703 struct stat st;
704 char buf[HEAD_LENGTH + 1];
705 } u;
706 ssize_t len;
707 char *name;
708
709 if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
710 return STATUS_EOF;
711
712 CPIO_POS (super) += HEAD_LENGTH;
713 u.buf[HEAD_LENGTH] = '\0';
714
715 if (sscanf (u.buf, "%6ho%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx", &hd.c_magic,
716 &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid, &hd.c_nlink, &hd.c_mtime,
717 &hd.c_filesize, (unsigned long *) &hd.c_dev, (unsigned long *) &hd.c_devmin,
718 (unsigned long *) &hd.c_rdev, (unsigned long *) &hd.c_rdevmin, &hd.c_namesize,
719 &hd.c_chksum)
720 < 14)
721 {
722 message (D_ERROR, MSG_ERROR, _ ("Corrupted cpio header encountered in\n%s"), super->name);
723 return STATUS_FAIL;
724 }
725
726 if ((arch->type == CPIO_NEWC && hd.c_magic != 070701)
727 || (arch->type == CPIO_CRC && hd.c_magic != 070702))
728 return STATUS_FAIL;
729
730 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
731 {
732 message (D_ERROR, MSG_ERROR, _ ("Corrupted cpio header encountered in\n%s"), super->name);
733 return STATUS_FAIL;
734 }
735
736 name = g_malloc (hd.c_namesize);
737 len = mc_read (arch->fd, name, hd.c_namesize);
738
739 if ((len == -1) || ((unsigned long) len < hd.c_namesize))
740 {
741 g_free (name);
742 return STATUS_EOF;
743 }
744 name[hd.c_namesize - 1] = '\0';
745 CPIO_POS (super) += len;
746 cpio_skip_padding (super);
747
748 if (strcmp ("TRAILER!!!", name) == 0)
749 {
750 g_free (name);
751 return STATUS_TRAIL;
752 }
753
754 u.st.st_dev = makedev (hd.c_dev, hd.c_devmin);
755 u.st.st_ino = hd.c_ino;
756 u.st.st_mode = hd.c_mode;
757 u.st.st_nlink = hd.c_nlink;
758 u.st.st_uid = hd.c_uid;
759 u.st.st_gid = hd.c_gid;
760 #ifdef HAVE_STRUCT_STAT_ST_RDEV
761 u.st.st_rdev = makedev (hd.c_rdev, hd.c_rdevmin);
762 #endif
763 u.st.st_size = hd.c_filesize;
764
765 vfs_zero_stat_times (&u.st);
766 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
767
768 return cpio_create_entry (me, super, &u.st, name);
769 }
770
771
772
773
774 static int
775 cpio_open_archive (struct vfs_s_super *super, const vfs_path_t *vpath,
776 const vfs_path_element_t *vpath_element)
777 {
778 (void) vpath_element;
779
780 if (cpio_open_cpio_file (vpath_element->class, super, vpath) == -1)
781 return -1;
782
783 while (TRUE)
784 {
785 ssize_t status;
786
787 status = cpio_read_head (vpath_element->class, super);
788 if (status < 0)
789 return (-1);
790
791 switch (status)
792 {
793 case STATUS_EOF:
794 {
795 message (D_ERROR, MSG_ERROR, _ ("Unexpected end of file\n%s"), vfs_path_as_str (vpath));
796 return 0;
797 }
798 case STATUS_OK:
799 continue;
800 case STATUS_TRAIL:
801 break;
802 default:
803 break;
804 }
805 break;
806 }
807
808 return 0;
809 }
810
811
812
813
814 static void *
815 cpio_super_check (const vfs_path_t *vpath)
816 {
817 static struct stat sb;
818 int stat_result;
819
820 stat_result = mc_stat (vpath, &sb);
821 return (stat_result == 0 ? &sb : NULL);
822 }
823
824
825
826 static int
827 cpio_super_same (const vfs_path_element_t *vpath_element, struct vfs_s_super *parc,
828 const vfs_path_t *vpath, void *cookie)
829 {
830 struct stat *archive_stat = cookie;
831
832 (void) vpath_element;
833
834 if (strcmp (parc->name, vfs_path_as_str (vpath)))
835 return 0;
836
837
838 if (parc != NULL && CPIO_SUPER (parc)->st.st_mtime < archive_stat->st_mtime)
839 {
840
841 vfs_cpiofs_ops->free ((vfsid) parc);
842 vfs_rmstamp (vfs_cpiofs_ops, (vfsid) parc);
843 return 2;
844 }
845
846
847 vfs_stamp (vfs_cpiofs_ops, (vfsid) parc);
848 return 1;
849 }
850
851
852
853 static ssize_t
854 cpio_read (void *fh, char *buffer, size_t count)
855 {
856 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
857 struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
858 int fd = CPIO_SUPER (VFS_FILE_HANDLER_SUPER (fh))->fd;
859 off_t begin = file->ino->data_offset;
860 ssize_t res;
861
862 if (mc_lseek (fd, begin + file->pos, SEEK_SET) != begin + file->pos)
863 ERRNOR (EIO, -1);
864
865 count = MIN (count, (size_t) (file->ino->st.st_size - file->pos));
866
867 res = mc_read (fd, buffer, count);
868 if (res == -1)
869 ERRNOR (errno, -1);
870
871 file->pos += res;
872 return res;
873 }
874
875
876
877 static int
878 cpio_fh_open (struct vfs_class *me, vfs_file_handler_t *fh, int flags, mode_t mode)
879 {
880 (void) fh;
881 (void) mode;
882
883 if ((flags & O_ACCMODE) != O_RDONLY)
884 ERRNOR (EROFS, -1);
885 return 0;
886 }
887
888
889
890
891
892 void
893 vfs_init_cpiofs (void)
894 {
895
896 vfs_init_subclass (&cpio_subclass, "cpiofs", VFSF_READONLY, "ucpio");
897 vfs_cpiofs_ops->read = cpio_read;
898 vfs_cpiofs_ops->setctl = NULL;
899 cpio_subclass.archive_check = cpio_super_check;
900 cpio_subclass.archive_same = cpio_super_same;
901 cpio_subclass.new_archive = cpio_new_archive;
902 cpio_subclass.open_archive = cpio_open_archive;
903 cpio_subclass.free_archive = cpio_free_archive;
904 cpio_subclass.fh_open = cpio_fh_open;
905 vfs_register_class (vfs_cpiofs_ops);
906 }
907
908