replaced calls to g_strdup() by mhl_str_dup()
[midnight-commander.git] / vfs / cpio.c
blob0019b4bf1e6667cb5cec3c7970e1760bf25dd9b7
1 /* Virtual File System: GNU Tar file system.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
3 Free Software Foundation, Inc.
5 Written by: 2000 Jan Hudec
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License
9 as published by the Free Software Foundation; either version 2 of
10 the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
21 #include <config.h>
23 #include <errno.h>
25 #include <mhl/string.h>
27 #include "../src/global.h"
28 #include "../src/tty.h" /* enable/disable interrupt key */
29 #include "../src/wtools.h" /* message() */
30 #include "../src/main.h" /* print_vfs_message */
31 #include "utilvfs.h"
32 #include "vfs-impl.h"
33 #include "gc.h" /* vfs_rmstamp */
34 #include "xdirentry.h"
35 #include "../src/unixcompat.h"
37 enum {
38 STATUS_START,
39 STATUS_OK,
40 STATUS_TRAIL,
41 STATUS_FAIL,
42 STATUS_EOF
45 enum {
46 CPIO_UNKNOWN = 0, /* Not determined yet */
47 CPIO_BIN, /* Binary format */
48 CPIO_BINRE, /* Binary format, reverse endianity */
49 CPIO_OLDC, /* Old ASCII format */
50 CPIO_NEWC, /* New ASCII format */
51 CPIO_CRC /* New ASCII format + CRC */
54 static struct vfs_class vfs_cpiofs_ops;
56 struct old_cpio_header
58 unsigned short c_magic;
59 short c_dev;
60 unsigned short c_ino;
61 unsigned short c_mode;
62 unsigned short c_uid;
63 unsigned short c_gid;
64 unsigned short c_nlink;
65 short c_rdev;
66 unsigned short c_mtimes[2];
67 unsigned short c_namesize;
68 unsigned short c_filesizes[2];
71 struct new_cpio_header
73 unsigned short c_magic;
74 unsigned long c_ino;
75 unsigned long c_mode;
76 unsigned long c_uid;
77 unsigned long c_gid;
78 unsigned long c_nlink;
79 unsigned long c_mtime;
80 unsigned long c_filesize;
81 long c_dev;
82 long c_devmin;
83 long c_rdev;
84 long c_rdevmin;
85 unsigned long c_namesize;
86 unsigned long c_chksum;
89 struct defer_inode {
90 struct defer_inode *next;
91 unsigned long inumber;
92 unsigned short device;
93 struct vfs_s_inode *inode;
96 /* FIXME: should be off_t instead of int. */
97 static int cpio_position;
99 static int cpio_find_head(struct vfs_class *me, struct vfs_s_super *super);
100 static int cpio_create_entry(struct vfs_class *me, struct vfs_s_super *super, struct stat *, char *name);
101 static ssize_t cpio_read_bin_head(struct vfs_class *me, struct vfs_s_super *super);
102 static ssize_t cpio_read_oldc_head(struct vfs_class *me, struct vfs_s_super *super);
103 static ssize_t cpio_read_crc_head(struct vfs_class *me, struct vfs_s_super *super);
104 static ssize_t cpio_read(void *fh, char *buffer, int count);
106 #define CPIO_POS(super) cpio_position
107 /* If some time reentrancy should be needed change it to */
108 /* #define CPIO_POS(super) (super)->u.arch.fd */
110 #define CPIO_SEEK_SET(super, where) mc_lseek((super)->u.arch.fd, CPIO_POS(super) = (where), SEEK_SET)
111 #define CPIO_SEEK_CUR(super, where) mc_lseek((super)->u.arch.fd, CPIO_POS(super) += (where), SEEK_SET)
113 static struct defer_inode *
114 cpio_defer_find (struct defer_inode *l, struct defer_inode *i)
116 while (l && (l->inumber != i->inumber || l->device != i->device))
117 l = l->next;
118 return l;
121 static int cpio_skip_padding(struct vfs_s_super *super)
123 switch(super->u.arch.type) {
124 case CPIO_BIN:
125 case CPIO_BINRE:
126 return CPIO_SEEK_CUR(super, (2 - (CPIO_POS(super) % 2)) % 2);
127 case CPIO_NEWC:
128 case CPIO_CRC:
129 return CPIO_SEEK_CUR(super, (4 - (CPIO_POS(super) % 4)) % 4);
130 case CPIO_OLDC:
131 return CPIO_POS(super);
132 default:
133 g_assert_not_reached();
134 return 42; /* & the compiler is happy :-) */
138 static void cpio_free_archive(struct vfs_class *me, struct vfs_s_super *super)
140 struct defer_inode *l, *lnext;
142 (void) me;
144 if(super->u.arch.fd != -1)
145 mc_close(super->u.arch.fd);
146 super->u.arch.fd = -1;
147 for (l = super->u.arch.deferred; l; l = lnext) {
148 lnext = l->next;
149 g_free (l);
151 super->u.arch.deferred = NULL;
154 static int
155 cpio_open_cpio_file (struct vfs_class *me, struct vfs_s_super *super,
156 const char *name)
158 int fd, type;
159 mode_t mode;
160 struct vfs_s_inode *root;
162 if ((fd = mc_open (name, O_RDONLY)) == -1) {
163 message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), name);
164 return -1;
167 super->name = mhl_str_dup (name);
168 super->u.arch.fd = -1; /* for now */
169 mc_stat (name, &(super->u.arch.st));
170 super->u.arch.type = CPIO_UNKNOWN;
172 type = get_compression_type (fd);
173 if (type != COMPRESSION_NONE) {
174 char *s;
176 mc_close (fd);
177 s = g_strconcat (name, decompress_extension (type), (char *) NULL);
178 if ((fd = mc_open (s, O_RDONLY)) == -1) {
179 message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), s);
180 g_free (s);
181 return -1;
183 g_free (s);
186 super->u.arch.fd = fd;
187 mode = super->u.arch.st.st_mode & 07777;
188 mode |= (mode & 0444) >> 2; /* set eXec where Read is */
189 mode |= S_IFDIR;
191 root = vfs_s_new_inode (me, super, &(super->u.arch.st));
192 root->st.st_mode = mode;
193 root->data_offset = -1;
194 root->st.st_nlink++;
195 root->st.st_dev = MEDATA->rdev++;
197 super->root = root;
199 CPIO_SEEK_SET (super, 0);
201 return fd;
204 static ssize_t cpio_read_head(struct vfs_class *me, struct vfs_s_super *super)
206 switch(cpio_find_head(me, super)) {
207 case CPIO_UNKNOWN:
208 return -1;
209 case CPIO_BIN:
210 case CPIO_BINRE:
211 return cpio_read_bin_head(me, super);
212 case CPIO_OLDC:
213 return cpio_read_oldc_head(me, super);
214 case CPIO_NEWC:
215 case CPIO_CRC:
216 return cpio_read_crc_head(me, super);
217 default:
218 g_assert_not_reached();
219 return 42; /* & the compiler is happy :-) */
223 #define MAGIC_LENGTH (6) /* How many bytes we have to read ahead */
224 #define SEEKBACK CPIO_SEEK_CUR(super, ptr - top)
225 #define RETURN(x) return(super->u.arch.type = (x))
226 #define TYPEIS(x) ((super->u.arch.type == CPIO_UNKNOWN) || (super->u.arch.type == (x)))
227 static int cpio_find_head(struct vfs_class *me, struct vfs_s_super *super)
229 char buf[256];
230 int ptr = 0;
231 int top;
232 int tmp;
234 top = mc_read (super->u.arch.fd, buf, 256);
235 if (top > 0)
236 CPIO_POS (super) += top;
237 for(;;) {
238 if(ptr + MAGIC_LENGTH >= top) {
239 if(top > 128) {
240 memmove(buf, buf + top - 128, 128);
241 ptr -= top - 128;
242 top = 128;
244 if((tmp = mc_read(super->u.arch.fd, buf, top)) == 0 || tmp == -1) {
245 message (D_ERROR, MSG_ERROR, _("Premature end of cpio archive\n%s"), super->name);
246 cpio_free_archive(me, super);
247 return CPIO_UNKNOWN;
249 top += tmp;
251 if(TYPEIS(CPIO_BIN) && ((*(unsigned short *)(buf + ptr)) == 070707)) {
252 SEEKBACK; RETURN(CPIO_BIN);
253 } else if(TYPEIS(CPIO_BINRE) && ((*(unsigned short *)(buf + ptr)) == GUINT16_SWAP_LE_BE_CONSTANT(070707))) {
254 SEEKBACK; RETURN(CPIO_BINRE);
255 } else if(TYPEIS(CPIO_OLDC) && (!strncmp(buf + ptr, "070707", 6))) {
256 SEEKBACK; RETURN(CPIO_OLDC);
257 } else if(TYPEIS(CPIO_NEWC) && (!strncmp(buf + ptr, "070701", 6))) {
258 SEEKBACK; RETURN(CPIO_NEWC);
259 } else if(TYPEIS(CPIO_CRC) && (!strncmp(buf + ptr, "070702", 6))) {
260 SEEKBACK; RETURN(CPIO_CRC);
262 ptr++;
265 #undef RETURN
266 #undef SEEKBACK
268 #define HEAD_LENGTH (26)
269 static ssize_t cpio_read_bin_head(struct vfs_class *me, struct vfs_s_super *super)
271 union {
272 struct old_cpio_header buf;
273 short shorts[HEAD_LENGTH >> 1];
274 } u;
275 int len;
276 char *name;
277 struct stat st;
279 if((len = mc_read(super->u.arch.fd, (char *)&u.buf, HEAD_LENGTH)) < HEAD_LENGTH)
280 return STATUS_EOF;
281 CPIO_POS(super) += len;
282 if(super->u.arch.type == CPIO_BINRE) {
283 int i;
284 for(i = 0; i < (HEAD_LENGTH >> 1); i++)
285 u.shorts[i] = GUINT16_SWAP_LE_BE_CONSTANT(u.shorts[i]);
287 g_assert(u.buf.c_magic == 070707);
289 if (u.buf.c_namesize == 0 || u.buf.c_namesize > MC_MAXPATHLEN) {
290 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
291 super->name);
292 return STATUS_FAIL;
294 name = g_malloc(u.buf.c_namesize);
295 if((len = mc_read(super->u.arch.fd, name, u.buf.c_namesize)) < u.buf.c_namesize) {
296 g_free(name);
297 return STATUS_EOF;
299 name[u.buf.c_namesize - 1] = '\0';
300 CPIO_POS(super) += len;
301 cpio_skip_padding(super);
303 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
304 g_free(name);
305 return STATUS_TRAIL;
308 st.st_dev = u.buf.c_dev;
309 st.st_ino = u.buf.c_ino;
310 st.st_mode = u.buf.c_mode;
311 st.st_nlink = u.buf.c_nlink;
312 st.st_uid = u.buf.c_uid;
313 st.st_gid = u.buf.c_gid;
314 st.st_rdev = u.buf.c_rdev;
315 st.st_size = (u.buf.c_filesizes[0] << 16) | u.buf.c_filesizes[1];
316 st.st_atime = st.st_mtime = st.st_ctime = (u.buf.c_mtimes[0] << 16) | u.buf.c_mtimes[1];
318 return cpio_create_entry(me, super, &st, name);
320 #undef HEAD_LENGTH
322 #define HEAD_LENGTH (76)
323 static ssize_t cpio_read_oldc_head(struct vfs_class *me, struct vfs_s_super *super)
325 struct new_cpio_header hd;
326 union {
327 struct stat st;
328 char buf[HEAD_LENGTH + 1];
329 } u;
330 int len;
331 char *name;
333 if (mc_read (super->u.arch.fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
334 return STATUS_EOF;
335 CPIO_POS (super) += HEAD_LENGTH;
336 u.buf[HEAD_LENGTH] = 0;
338 if (sscanf (u.buf, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
339 &hd.c_dev, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
340 &hd.c_nlink, &hd.c_rdev, &hd.c_mtime,
341 &hd.c_namesize, &hd.c_filesize) < 10) {
342 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
343 super->name);
344 return STATUS_FAIL;
347 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN) {
348 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
349 super->name);
350 return STATUS_FAIL;
352 name = g_malloc(hd.c_namesize);
353 if((len = mc_read(super->u.arch.fd, name, hd.c_namesize)) == -1 ||
354 (unsigned long) len < hd.c_namesize) {
355 g_free (name);
356 return STATUS_EOF;
358 name[hd.c_namesize - 1] = '\0';
359 CPIO_POS(super) += len;
360 cpio_skip_padding(super);
362 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
363 g_free(name);
364 return STATUS_TRAIL;
367 u.st.st_dev = hd.c_dev;
368 u.st.st_ino = hd.c_ino;
369 u.st.st_mode = hd.c_mode;
370 u.st.st_nlink = hd.c_nlink;
371 u.st.st_uid = hd.c_uid;
372 u.st.st_gid = hd.c_gid;
373 u.st.st_rdev = hd.c_rdev;
374 u.st.st_size = hd.c_filesize;
375 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
377 return cpio_create_entry (me, super, &u.st, name);
379 #undef HEAD_LENGTH
381 #define HEAD_LENGTH (110)
382 static ssize_t cpio_read_crc_head(struct vfs_class *me, struct vfs_s_super *super)
384 struct new_cpio_header hd;
385 union {
386 struct stat st;
387 char buf[HEAD_LENGTH + 1];
388 } u;
389 int len;
390 char *name;
392 if (mc_read (super->u.arch.fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
393 return STATUS_EOF;
394 CPIO_POS (super) += HEAD_LENGTH;
395 u.buf[HEAD_LENGTH] = 0;
397 if (sscanf (u.buf, "%6ho%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
398 &hd.c_magic, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
399 &hd.c_nlink, &hd.c_mtime, &hd.c_filesize,
400 &hd.c_dev, &hd.c_devmin, &hd.c_rdev, &hd.c_rdevmin,
401 &hd.c_namesize, &hd.c_chksum) < 14) {
402 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
403 super->name);
404 return STATUS_FAIL;
407 if((super->u.arch.type == CPIO_NEWC && hd.c_magic != 070701) ||
408 (super->u.arch.type == CPIO_CRC && hd.c_magic != 070702))
409 return STATUS_FAIL;
411 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN) {
412 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
413 super->name);
414 return STATUS_FAIL;
417 name = g_malloc(hd.c_namesize);
418 if((len = mc_read (super->u.arch.fd, name, hd.c_namesize)) == -1 ||
419 (unsigned long) len < hd.c_namesize) {
420 g_free (name);
421 return STATUS_EOF;
423 name[hd.c_namesize - 1] = '\0';
424 CPIO_POS(super) += len;
425 cpio_skip_padding(super);
427 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
428 g_free(name);
429 return STATUS_TRAIL;
432 u.st.st_dev = makedev (hd.c_dev, hd.c_devmin);
433 u.st.st_ino = hd.c_ino;
434 u.st.st_mode = hd.c_mode;
435 u.st.st_nlink = hd.c_nlink;
436 u.st.st_uid = hd.c_uid;
437 u.st.st_gid = hd.c_gid;
438 u.st.st_rdev = makedev (hd.c_rdev, hd.c_rdevmin);
439 u.st.st_size = hd.c_filesize;
440 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
442 return cpio_create_entry (me, super, &u.st, name);
445 static int
446 cpio_create_entry (struct vfs_class *me, struct vfs_s_super *super,
447 struct stat *st, char *name)
449 struct vfs_s_inode *inode = NULL;
450 struct vfs_s_inode *root = super->root;
451 struct vfs_s_entry *entry = NULL;
452 char *tn;
454 switch (st->st_mode & S_IFMT) { /* For case of HP/UX archives */
455 case S_IFCHR:
456 case S_IFBLK:
457 #ifdef S_IFSOCK
458 case S_IFSOCK:
459 #endif
460 #ifdef S_IFIFO
461 case S_IFIFO:
462 #endif
463 #ifdef S_IFNAM
464 case S_IFNAM:
465 #endif
466 if ((st->st_size != 0) && (st->st_rdev == 0x0001)) {
467 /* FIXME: representation of major/minor differs between */
468 /* different operating systems. */
469 st->st_rdev = (unsigned) st->st_size;
470 st->st_size = 0;
472 break;
473 default:
474 break;
477 if ((st->st_nlink > 1) && (super->u.arch.type == CPIO_NEWC || super->u.arch.type == CPIO_CRC)) { /* For case of hardlinked files */
478 struct defer_inode i, *l;
479 i.inumber = st->st_ino;
480 i.device = st->st_dev;
481 i.inode = NULL;
482 if ((l = cpio_defer_find (super->u.arch.deferred, &i)) != NULL) {
483 inode = l->inode;
484 if (inode->st.st_size && st->st_size
485 && (inode->st.st_size != st->st_size)) {
486 message (D_ERROR, MSG_ERROR,
488 ("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
489 name, super->name);
490 inode = NULL;
491 } else if (!inode->st.st_size)
492 inode->st.st_size = st->st_size;
496 for (tn = name + strlen (name) - 1; tn >= name && *tn == PATH_SEP; tn--)
497 *tn = 0;
498 if ((tn = strrchr (name, PATH_SEP))) {
499 *tn = 0;
500 root = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_MKDIR);
501 *tn = PATH_SEP;
502 tn++;
503 } else
504 tn = name;
506 entry = MEDATA->find_entry (me, root, tn, LINK_FOLLOW, FL_NONE); /* In case entry is already there */
508 if (entry) { /* This shouldn't happen! (well, it can happen if there is a record for a
509 file and than a record for a directory it is in; cpio would die with
510 'No such file or directory' is such case) */
512 if (!S_ISDIR (entry->ino->st.st_mode)) { /* This can be considered archive inconsistency */
513 message (D_ERROR, MSG_ERROR,
514 _("%s contains duplicate entries! Skipping!"),
515 super->name);
516 } else {
517 entry->ino->st.st_mode = st->st_mode;
518 entry->ino->st.st_uid = st->st_uid;
519 entry->ino->st.st_gid = st->st_gid;
520 entry->ino->st.st_atime = st->st_atime;
521 entry->ino->st.st_mtime = st->st_mtime;
522 entry->ino->st.st_ctime = st->st_ctime;
525 } else { /* !entry */
527 if (!inode) {
528 inode = vfs_s_new_inode (me, super, st);
529 if ((st->st_nlink > 0) && (super->u.arch.type == CPIO_NEWC || super->u.arch.type == CPIO_CRC)) { /* For case of hardlinked files */
530 struct defer_inode *i;
531 i = g_new (struct defer_inode, 1);
532 i->inumber = st->st_ino;
533 i->device = st->st_dev;
534 i->inode = inode;
535 i->next = super->u.arch.deferred;
536 super->u.arch.deferred = i;
540 if (st->st_size)
541 inode->data_offset = CPIO_POS (super);
543 entry = vfs_s_new_entry (me, tn, inode);
544 vfs_s_insert_entry (me, root, entry);
546 if (S_ISLNK (st->st_mode)) {
547 inode->linkname = g_malloc (st->st_size + 1);
548 if (mc_read (super->u.arch.fd, inode->linkname, st->st_size)
549 < st->st_size) {
550 inode->linkname[0] = 0;
551 g_free (name);
552 return STATUS_EOF;
554 inode->linkname[st->st_size] = 0; /* Linkname stored without terminating \0 !!! */
555 CPIO_POS (super) += st->st_size;
556 cpio_skip_padding (super);
557 } else {
558 CPIO_SEEK_CUR (super, st->st_size);
561 } /* !entry */
563 g_free (name);
564 return STATUS_OK;
567 /* Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
569 static int
570 cpio_open_archive (struct vfs_class *me, struct vfs_s_super *super,
571 const char *name, char *op)
573 int status = STATUS_START;
575 (void) op;
577 if (cpio_open_cpio_file (me, super, name) == -1)
578 return -1;
580 for (;;) {
581 status = cpio_read_head (me, super);
583 switch (status) {
584 case STATUS_EOF:
585 message (D_ERROR, MSG_ERROR, _("Unexpected end of file\n%s"), name);
586 return 0;
587 case STATUS_OK:
588 continue;
589 case STATUS_TRAIL:
590 break;
592 break;
595 return 0;
598 /* Remaining functions are exactly same as for tarfs (and were in fact just copied) */
599 static void *
600 cpio_super_check (struct vfs_class *me, const char *archive_name, char *op)
602 static struct stat sb;
604 (void) me;
605 (void) op;
607 if (mc_stat (archive_name, &sb))
608 return NULL;
609 return &sb;
612 static int
613 cpio_super_same (struct vfs_class *me, struct vfs_s_super *parc,
614 const char *archive_name, char *op, void *cookie)
616 struct stat *archive_stat = cookie; /* stat of main archive */
618 (void) me;
619 (void) op;
621 if (strcmp (parc->name, archive_name))
622 return 0;
624 /* Has the cached archive been changed on the disk? */
625 if (parc->u.arch.st.st_mtime < archive_stat->st_mtime) {
626 /* Yes, reload! */
627 (*vfs_cpiofs_ops.free) ((vfsid) parc);
628 vfs_rmstamp (&vfs_cpiofs_ops, (vfsid) parc);
629 return 2;
631 /* Hasn't been modified, give it a new timeout */
632 vfs_stamp (&vfs_cpiofs_ops, (vfsid) parc);
633 return 1;
636 static ssize_t cpio_read(void *fh, char *buffer, int count)
638 off_t begin = FH->ino->data_offset;
639 int fd = FH_SUPER->u.arch.fd;
640 struct vfs_class *me = FH_SUPER->me;
642 if (mc_lseek (fd, begin + FH->pos, SEEK_SET) !=
643 begin + FH->pos) ERRNOR (EIO, -1);
645 count = MIN(count, FH->ino->st.st_size - FH->pos);
647 if ((count = mc_read (fd, buffer, count)) == -1) ERRNOR (errno, -1);
649 FH->pos += count;
650 return count;
653 static int cpio_fh_open(struct vfs_class *me, struct vfs_s_fh *fh, int flags, int mode)
655 (void) fh;
656 (void) mode;
658 if ((flags & O_ACCMODE) != O_RDONLY) ERRNOR (EROFS, -1);
659 return 0;
662 void
663 init_cpiofs (void)
665 static struct vfs_s_subclass cpio_subclass;
667 cpio_subclass.flags = VFS_S_READONLY;
668 cpio_subclass.archive_check = cpio_super_check;
669 cpio_subclass.archive_same = cpio_super_same;
670 cpio_subclass.open_archive = cpio_open_archive;
671 cpio_subclass.free_archive = cpio_free_archive;
672 cpio_subclass.fh_open = cpio_fh_open;
674 vfs_s_init_class (&vfs_cpiofs_ops, &cpio_subclass);
675 vfs_cpiofs_ops.name = "cpiofs";
676 vfs_cpiofs_ops.prefix = "ucpio";
677 vfs_cpiofs_ops.read = cpio_read;
678 vfs_cpiofs_ops.setctl = NULL;
679 vfs_register_class (&vfs_cpiofs_ops);