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