Revert overriding RPM target. It can lead to broken packages.
[midnight-commander.git] / vfs / cpio.c
blob15910c094462109e096033c0da5b03c43a01fac9
1 /* Virtual File System: GNU Tar file system.
2 Copyright (C) 2000 The Free Software Foundation
4 Written by: 2000 Jan Hudec
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License
8 as published by the Free Software Foundation; either version 2 of
9 the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #include <config.h>
21 #include <errno.h>
23 #include "../src/global.h"
24 #include "../src/tty.h" /* enable/disable interrupt key */
25 #include "../src/wtools.h" /* message() */
26 #include "../src/main.h" /* print_vfs_message */
27 #include "utilvfs.h"
28 #include "vfs-impl.h"
29 #include "gc.h" /* vfs_rmstamp */
30 #include "xdirentry.h"
31 #include "../src/unixcompat.h"
33 enum {
34 STATUS_START,
35 STATUS_OK,
36 STATUS_TRAIL,
37 STATUS_FAIL,
38 STATUS_EOF
41 enum {
42 CPIO_UNKNOWN = 0, /* Not determined yet */
43 CPIO_BIN, /* Binary format */
44 CPIO_BINRE, /* Binary format, reverse endianity */
45 CPIO_OLDC, /* Old ASCII format */
46 CPIO_NEWC, /* New ASCII format */
47 CPIO_CRC /* New ASCII format + CRC */
50 static struct vfs_class vfs_cpiofs_ops;
52 struct old_cpio_header
54 unsigned short c_magic;
55 short c_dev;
56 unsigned short c_ino;
57 unsigned short c_mode;
58 unsigned short c_uid;
59 unsigned short c_gid;
60 unsigned short c_nlink;
61 short c_rdev;
62 unsigned short c_mtimes[2];
63 unsigned short c_namesize;
64 unsigned short c_filesizes[2];
67 struct new_cpio_header
69 unsigned short c_magic;
70 unsigned long c_ino;
71 unsigned long c_mode;
72 unsigned long c_uid;
73 unsigned long c_gid;
74 unsigned long c_nlink;
75 unsigned long c_mtime;
76 unsigned long c_filesize;
77 long c_dev;
78 long c_devmin;
79 long c_rdev;
80 long c_rdevmin;
81 unsigned long c_namesize;
82 unsigned long c_chksum;
85 struct defer_inode {
86 struct defer_inode *next;
87 unsigned long inumber;
88 unsigned short device;
89 struct vfs_s_inode *inode;
92 /* FIXME: should be off_t instead of int. */
93 static int cpio_position;
95 static int cpio_find_head(struct vfs_class *me, struct vfs_s_super *super);
96 static int cpio_read_bin_head(struct vfs_class *me, struct vfs_s_super *super);
97 static int cpio_read_oldc_head(struct vfs_class *me, struct vfs_s_super *super);
98 static int cpio_read_crc_head(struct vfs_class *me, struct vfs_s_super *super);
99 static int cpio_create_entry(struct vfs_class *me, struct vfs_s_super *super, struct stat *, char *name);
100 static int cpio_read(void *fh, char *buffer, int count);
102 #define CPIO_POS(super) cpio_position
103 /* If some time reentrancy should be needed change it to */
104 /* #define CPIO_POS(super) (super)->u.arch.fd */
106 #define CPIO_SEEK_SET(super, where) mc_lseek((super)->u.arch.fd, CPIO_POS(super) = (where), SEEK_SET)
107 #define CPIO_SEEK_CUR(super, where) mc_lseek((super)->u.arch.fd, CPIO_POS(super) += (where), SEEK_SET)
109 static struct defer_inode *
110 cpio_defer_find (struct defer_inode *l, struct defer_inode *i)
112 while (l && (l->inumber != i->inumber || l->device != i->device))
113 l = l->next;
114 return l;
117 static int cpio_skip_padding(struct vfs_s_super *super)
119 switch(super->u.arch.type) {
120 case CPIO_BIN:
121 case CPIO_BINRE:
122 return CPIO_SEEK_CUR(super, (2 - (CPIO_POS(super) % 2)) % 2);
123 case CPIO_NEWC:
124 case CPIO_CRC:
125 return CPIO_SEEK_CUR(super, (4 - (CPIO_POS(super) % 4)) % 4);
126 case CPIO_OLDC:
127 return CPIO_POS(super);
128 default:
129 g_assert_not_reached();
130 return 42; /* & the compiler is happy :-) */
134 static void cpio_free_archive(struct vfs_class *me, struct vfs_s_super *super)
136 struct defer_inode *l, *lnext;
138 (void) me;
140 if(super->u.arch.fd != -1)
141 mc_close(super->u.arch.fd);
142 super->u.arch.fd = -1;
143 for (l = super->u.arch.deferred; l; l = lnext) {
144 lnext = l->next;
145 g_free (l);
147 super->u.arch.deferred = NULL;
150 static int
151 cpio_open_cpio_file (struct vfs_class *me, struct vfs_s_super *super,
152 const char *name)
154 int fd, type;
155 mode_t mode;
156 struct vfs_s_inode *root;
158 if ((fd = mc_open (name, O_RDONLY)) == -1) {
159 message (1, MSG_ERROR, _("Cannot open cpio archive\n%s"), name);
160 return -1;
163 super->name = g_strdup (name);
164 super->u.arch.fd = -1; /* for now */
165 mc_stat (name, &(super->u.arch.st));
166 super->u.arch.type = CPIO_UNKNOWN;
168 type = get_compression_type (fd);
169 if (type != COMPRESSION_NONE) {
170 char *s;
172 mc_close (fd);
173 s = g_strconcat (name, decompress_extension (type), (char *) NULL);
174 if ((fd = mc_open (s, O_RDONLY)) == -1) {
175 message (1, MSG_ERROR, _("Cannot open cpio archive\n%s"), s);
176 g_free (s);
177 return -1;
179 g_free (s);
182 super->u.arch.fd = fd;
183 mode = super->u.arch.st.st_mode & 07777;
184 mode |= (mode & 0444) >> 2; /* set eXec where Read is */
185 mode |= S_IFDIR;
187 root = vfs_s_new_inode (me, super, &(super->u.arch.st));
188 root->st.st_mode = mode;
189 root->data_offset = -1;
190 root->st.st_nlink++;
191 root->st.st_dev = MEDATA->rdev++;
193 super->root = root;
195 CPIO_SEEK_SET (super, 0);
197 return fd;
200 static int cpio_read_head(struct vfs_class *me, struct vfs_s_super *super)
202 switch(cpio_find_head(me, super)) {
203 case CPIO_UNKNOWN:
204 return -1;
205 case CPIO_BIN:
206 case CPIO_BINRE:
207 return cpio_read_bin_head(me, super);
208 case CPIO_OLDC:
209 return cpio_read_oldc_head(me, super);
210 case CPIO_NEWC:
211 case CPIO_CRC:
212 return cpio_read_crc_head(me, super);
213 default:
214 g_assert_not_reached();
215 return 42; /* & the compiler is happy :-) */
219 #define MAGIC_LENGTH (6) /* How many bytes we have to read ahead */
220 #define SEEKBACK CPIO_SEEK_CUR(super, ptr - top)
221 #define RETURN(x) return(super->u.arch.type = (x))
222 #define TYPEIS(x) ((super->u.arch.type == CPIO_UNKNOWN) || (super->u.arch.type == (x)))
223 static int cpio_find_head(struct vfs_class *me, struct vfs_s_super *super)
225 char buf[256];
226 int ptr = 0;
227 int top;
228 int tmp;
230 top = mc_read (super->u.arch.fd, buf, 256);
231 if (top > 0)
232 CPIO_POS (super) += top;
233 for(;;) {
234 if(ptr + MAGIC_LENGTH >= top) {
235 if(top > 128) {
236 memmove(buf, buf + top - 128, 128);
237 ptr -= top - 128;
238 top = 128;
240 if((tmp = mc_read(super->u.arch.fd, buf, top)) == 0 || tmp == -1) {
241 message (1, MSG_ERROR, _("Premature end of cpio archive\n%s"), super->name);
242 cpio_free_archive(me, super);
243 return CPIO_UNKNOWN;
245 top += tmp;
247 if(TYPEIS(CPIO_BIN) && ((*(unsigned short *)(buf + ptr)) == 070707)) {
248 SEEKBACK; RETURN(CPIO_BIN);
249 } else if(TYPEIS(CPIO_BINRE) && ((*(unsigned short *)(buf + ptr)) == GUINT16_SWAP_LE_BE_CONSTANT(070707))) {
250 SEEKBACK; RETURN(CPIO_BINRE);
251 } else if(TYPEIS(CPIO_OLDC) && (!strncmp(buf + ptr, "070707", 6))) {
252 SEEKBACK; RETURN(CPIO_OLDC);
253 } else if(TYPEIS(CPIO_NEWC) && (!strncmp(buf + ptr, "070701", 6))) {
254 SEEKBACK; RETURN(CPIO_NEWC);
255 } else if(TYPEIS(CPIO_CRC) && (!strncmp(buf + ptr, "070702", 6))) {
256 SEEKBACK; RETURN(CPIO_CRC);
258 ptr++;
261 #undef RETURN
262 #undef SEEKBACK
264 #define HEAD_LENGTH (26)
265 static int cpio_read_bin_head(struct vfs_class *me, struct vfs_s_super *super)
267 union {
268 struct old_cpio_header buf;
269 short shorts[HEAD_LENGTH >> 1];
270 } u;
271 int len;
272 char *name;
273 struct stat st;
275 if((len = mc_read(super->u.arch.fd, (char *)&u.buf, HEAD_LENGTH)) < HEAD_LENGTH)
276 return STATUS_EOF;
277 CPIO_POS(super) += len;
278 if(super->u.arch.type == CPIO_BINRE) {
279 int i;
280 for(i = 0; i < (HEAD_LENGTH >> 1); i++)
281 u.shorts[i] = GUINT16_SWAP_LE_BE_CONSTANT(u.shorts[i]);
283 g_assert(u.buf.c_magic == 070707);
285 if (u.buf.c_namesize == 0 || u.buf.c_namesize > MC_MAXPATHLEN) {
286 message (1, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
287 super->name);
288 return STATUS_FAIL;
290 name = g_malloc(u.buf.c_namesize);
291 if((len = mc_read(super->u.arch.fd, name, u.buf.c_namesize)) < u.buf.c_namesize) {
292 g_free(name);
293 return STATUS_EOF;
295 name[u.buf.c_namesize - 1] = '\0';
296 CPIO_POS(super) += len;
297 cpio_skip_padding(super);
299 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
300 g_free(name);
301 return STATUS_TRAIL;
304 st.st_dev = u.buf.c_dev;
305 st.st_ino = u.buf.c_ino;
306 st.st_mode = u.buf.c_mode;
307 st.st_nlink = u.buf.c_nlink;
308 st.st_uid = u.buf.c_uid;
309 st.st_gid = u.buf.c_gid;
310 st.st_rdev = u.buf.c_rdev;
311 st.st_size = (u.buf.c_filesizes[0] << 16) | u.buf.c_filesizes[1];
312 st.st_atime = st.st_mtime = st.st_ctime = (u.buf.c_mtimes[0] << 16) | u.buf.c_mtimes[1];
314 return cpio_create_entry(me, super, &st, name);
316 #undef HEAD_LENGTH
318 #define HEAD_LENGTH (76)
319 static int cpio_read_oldc_head(struct vfs_class *me, struct vfs_s_super *super)
321 struct new_cpio_header hd;
322 union {
323 struct stat st;
324 char buf[HEAD_LENGTH + 1];
325 } u;
326 int len;
327 char *name;
329 if (mc_read (super->u.arch.fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
330 return STATUS_EOF;
331 CPIO_POS (super) += HEAD_LENGTH;
332 u.buf[HEAD_LENGTH] = 0;
334 if (sscanf (u.buf, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
335 &hd.c_dev, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
336 &hd.c_nlink, &hd.c_rdev, &hd.c_mtime,
337 &hd.c_namesize, &hd.c_filesize) < 10) {
338 message (1, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
339 super->name);
340 return STATUS_FAIL;
343 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN) {
344 message (1, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
345 super->name);
346 return STATUS_FAIL;
348 name = g_malloc(hd.c_namesize);
349 if((len = mc_read(super->u.arch.fd, name, hd.c_namesize)) == -1 ||
350 (unsigned long) len < hd.c_namesize) {
351 g_free (name);
352 return STATUS_EOF;
354 name[hd.c_namesize - 1] = '\0';
355 CPIO_POS(super) += len;
356 cpio_skip_padding(super);
358 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
359 g_free(name);
360 return STATUS_TRAIL;
363 u.st.st_dev = hd.c_dev;
364 u.st.st_ino = hd.c_ino;
365 u.st.st_mode = hd.c_mode;
366 u.st.st_nlink = hd.c_nlink;
367 u.st.st_uid = hd.c_uid;
368 u.st.st_gid = hd.c_gid;
369 u.st.st_rdev = hd.c_rdev;
370 u.st.st_size = hd.c_filesize;
371 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
373 return cpio_create_entry (me, super, &u.st, name);
375 #undef HEAD_LENGTH
377 #define HEAD_LENGTH (110)
378 static int cpio_read_crc_head(struct vfs_class *me, struct vfs_s_super *super)
380 struct new_cpio_header hd;
381 union {
382 struct stat st;
383 char buf[HEAD_LENGTH + 1];
384 } u;
385 int len;
386 char *name;
388 if (mc_read (super->u.arch.fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
389 return STATUS_EOF;
390 CPIO_POS (super) += HEAD_LENGTH;
391 u.buf[HEAD_LENGTH] = 0;
393 if (sscanf (u.buf, "%6ho%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
394 &hd.c_magic, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
395 &hd.c_nlink, &hd.c_mtime, &hd.c_filesize,
396 &hd.c_dev, &hd.c_devmin, &hd.c_rdev, &hd.c_rdevmin,
397 &hd.c_namesize, &hd.c_chksum) < 14) {
398 message (1, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
399 super->name);
400 return STATUS_FAIL;
403 if((super->u.arch.type == CPIO_NEWC && hd.c_magic != 070701) ||
404 (super->u.arch.type == CPIO_CRC && hd.c_magic != 070702))
405 return STATUS_FAIL;
407 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN) {
408 message (1, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
409 super->name);
410 return STATUS_FAIL;
413 name = g_malloc(hd.c_namesize);
414 if((len = mc_read (super->u.arch.fd, name, hd.c_namesize)) == -1 ||
415 (unsigned long) len < hd.c_namesize) {
416 g_free (name);
417 return STATUS_EOF;
419 name[hd.c_namesize - 1] = '\0';
420 CPIO_POS(super) += len;
421 cpio_skip_padding(super);
423 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
424 g_free(name);
425 return STATUS_TRAIL;
428 u.st.st_dev = makedev (hd.c_dev, hd.c_devmin);
429 u.st.st_ino = hd.c_ino;
430 u.st.st_mode = hd.c_mode;
431 u.st.st_nlink = hd.c_nlink;
432 u.st.st_uid = hd.c_uid;
433 u.st.st_gid = hd.c_gid;
434 u.st.st_rdev = makedev (hd.c_rdev, hd.c_rdevmin);
435 u.st.st_size = hd.c_filesize;
436 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
438 return cpio_create_entry (me, super, &u.st, name);
441 static int
442 cpio_create_entry (struct vfs_class *me, struct vfs_s_super *super,
443 struct stat *st, char *name)
445 struct vfs_s_inode *inode = NULL;
446 struct vfs_s_inode *root = super->root;
447 struct vfs_s_entry *entry = NULL;
448 char *tn;
450 switch (st->st_mode & S_IFMT) { /* For case of HP/UX archives */
451 case S_IFCHR:
452 case S_IFBLK:
453 #ifdef S_IFSOCK
454 case S_IFSOCK:
455 #endif
456 #ifdef S_IFIFO
457 case S_IFIFO:
458 #endif
459 #ifdef S_IFNAM
460 case S_IFNAM:
461 #endif
462 if ((st->st_size != 0) && (st->st_rdev == 0x0001)) {
463 /* FIXME: representation of major/minor differs between */
464 /* different operating systems. */
465 st->st_rdev = (unsigned) st->st_size;
466 st->st_size = 0;
468 break;
469 default:
470 break;
473 if ((st->st_nlink > 1) && (super->u.arch.type == CPIO_NEWC || super->u.arch.type == CPIO_CRC)) { /* For case of hardlinked files */
474 struct defer_inode i, *l;
475 i.inumber = st->st_ino;
476 i.device = st->st_dev;
477 i.inode = NULL;
478 if ((l = cpio_defer_find (super->u.arch.deferred, &i)) != NULL) {
479 inode = l->inode;
480 if (inode->st.st_size && st->st_size
481 && (inode->st.st_size != st->st_size)) {
482 message (1, MSG_ERROR,
484 ("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
485 name, super->name);
486 inode = NULL;
487 } else if (!inode->st.st_size)
488 inode->st.st_size = st->st_size;
492 for (tn = name + strlen (name) - 1; tn >= name && *tn == PATH_SEP; tn--)
493 *tn = 0;
494 if ((tn = strrchr (name, PATH_SEP))) {
495 *tn = 0;
496 root = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_MKDIR);
497 *tn = PATH_SEP;
498 tn++;
499 } else
500 tn = name;
502 entry = MEDATA->find_entry (me, root, tn, LINK_FOLLOW, FL_NONE); /* In case entry is already there */
504 if (entry) { /* This shouldn't happen! (well, it can happen if there is a record for a
505 file and than a record for a directory it is in; cpio would die with
506 'No such file or directory' is such case) */
508 if (!S_ISDIR (entry->ino->st.st_mode)) { /* This can be considered archive inconsistency */
509 message (1, MSG_ERROR,
510 _("%s contains duplicate entries! Skipping!"),
511 super->name);
512 } else {
513 entry->ino->st.st_mode = st->st_mode;
514 entry->ino->st.st_uid = st->st_uid;
515 entry->ino->st.st_gid = st->st_gid;
516 entry->ino->st.st_atime = st->st_atime;
517 entry->ino->st.st_mtime = st->st_mtime;
518 entry->ino->st.st_ctime = st->st_ctime;
521 } else { /* !entry */
523 if (!inode) {
524 inode = vfs_s_new_inode (me, super, st);
525 if ((st->st_nlink > 0) && (super->u.arch.type == CPIO_NEWC || super->u.arch.type == CPIO_CRC)) { /* For case of hardlinked files */
526 struct defer_inode *i;
527 i = g_new (struct defer_inode, 1);
528 i->inumber = st->st_ino;
529 i->device = st->st_dev;
530 i->inode = inode;
531 i->next = super->u.arch.deferred;
532 super->u.arch.deferred = i;
536 if (st->st_size)
537 inode->data_offset = CPIO_POS (super);
539 entry = vfs_s_new_entry (me, tn, inode);
540 vfs_s_insert_entry (me, root, entry);
542 if (S_ISLNK (st->st_mode)) {
543 inode->linkname = g_malloc (st->st_size + 1);
544 if (mc_read (super->u.arch.fd, inode->linkname, st->st_size)
545 < st->st_size) {
546 inode->linkname[0] = 0;
547 g_free (name);
548 return STATUS_EOF;
550 inode->linkname[st->st_size] = 0; /* Linkname stored without terminating \0 !!! */
551 CPIO_POS (super) += st->st_size;
552 cpio_skip_padding (super);
553 } else {
554 CPIO_SEEK_CUR (super, st->st_size);
557 } /* !entry */
559 g_free (name);
560 return STATUS_OK;
563 /* Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
565 static int
566 cpio_open_archive (struct vfs_class *me, struct vfs_s_super *super,
567 const char *name, char *op)
569 int status = STATUS_START;
571 (void) op;
573 if (cpio_open_cpio_file (me, super, name) == -1)
574 return -1;
576 for (;;) {
577 status = cpio_read_head (me, super);
579 switch (status) {
580 case STATUS_EOF:
581 message (1, MSG_ERROR, _("Unexpected end of file\n%s"), name);
582 return 0;
583 case STATUS_OK:
584 continue;
585 case STATUS_TRAIL:
586 break;
588 break;
591 return 0;
594 /* Remaining functions are exactly same as for tarfs (and were in fact just copied) */
595 static void *
596 cpio_super_check (struct vfs_class *me, const char *archive_name, char *op)
598 static struct stat sb;
600 (void) me;
601 (void) op;
603 if (mc_stat (archive_name, &sb))
604 return NULL;
605 return &sb;
608 static int
609 cpio_super_same (struct vfs_class *me, struct vfs_s_super *parc,
610 const char *archive_name, char *op, void *cookie)
612 struct stat *archive_stat = cookie; /* stat of main archive */
614 (void) me;
615 (void) op;
617 if (strcmp (parc->name, archive_name))
618 return 0;
620 /* Has the cached archive been changed on the disk? */
621 if (parc->u.arch.st.st_mtime < archive_stat->st_mtime) {
622 /* Yes, reload! */
623 (*vfs_cpiofs_ops.free) ((vfsid) parc);
624 vfs_rmstamp (&vfs_cpiofs_ops, (vfsid) parc);
625 return 2;
627 /* Hasn't been modified, give it a new timeout */
628 vfs_stamp (&vfs_cpiofs_ops, (vfsid) parc);
629 return 1;
632 static int cpio_read(void *fh, char *buffer, int count)
634 off_t begin = FH->ino->data_offset;
635 int fd = FH_SUPER->u.arch.fd;
636 struct vfs_class *me = FH_SUPER->me;
638 if (mc_lseek (fd, begin + FH->pos, SEEK_SET) !=
639 begin + FH->pos) ERRNOR (EIO, -1);
641 count = MIN(count, FH->ino->st.st_size - FH->pos);
643 if ((count = mc_read (fd, buffer, count)) == -1) ERRNOR (errno, -1);
645 FH->pos += count;
646 return count;
649 static int cpio_fh_open(struct vfs_class *me, struct vfs_s_fh *fh, int flags, int mode)
651 (void) fh;
652 (void) mode;
654 if ((flags & O_ACCMODE) != O_RDONLY) ERRNOR (EROFS, -1);
655 return 0;
658 void
659 init_cpiofs (void)
661 static struct vfs_s_subclass cpio_subclass;
663 cpio_subclass.flags = VFS_S_READONLY;
664 cpio_subclass.archive_check = cpio_super_check;
665 cpio_subclass.archive_same = cpio_super_same;
666 cpio_subclass.open_archive = cpio_open_archive;
667 cpio_subclass.free_archive = cpio_free_archive;
668 cpio_subclass.fh_open = cpio_fh_open;
670 vfs_s_init_class (&vfs_cpiofs_ops, &cpio_subclass);
671 vfs_cpiofs_ops.name = "cpiofs";
672 vfs_cpiofs_ops.prefix = "ucpio";
673 vfs_cpiofs_ops.read = cpio_read;
674 vfs_cpiofs_ops.setctl = NULL;
675 vfs_register_class (&vfs_cpiofs_ops);