Ticket #1475: warningis fix
[midnight-commander.git] / vfs / tar.c
blob6c48db42692ed0f02f710e0de9b36e008f4eb473
1 /* Virtual File System: GNU Tar file system.
2 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
5 Written by: 1995 Jakub Jelinek
6 Rewritten by: 1998 Pavel Machek
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public License
10 as published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public
19 License along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 /**
23 * \file
24 * \brief Source: Virtual File System: GNU Tar file system
25 * \author Jakub Jelinek
26 * \author Pavel Machek
27 * \date 1995, 1998
29 * Namespace: init_tarfs
32 #include <config.h>
33 #include <sys/types.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <fcntl.h>
38 #ifdef hpux
39 /* major() and minor() macros (among other things) defined here for hpux */
40 #include <sys/mknod.h>
41 #endif
43 #include "../src/global.h"
44 #include "../src/tty.h" /* enable/disable interrupt key */
45 #include "../src/wtools.h" /* message() */
46 #include "../src/main.h" /* print_vfs_message */
47 #include "utilvfs.h"
48 #include "gc.h" /* vfs_rmstamp */
49 #include "xdirentry.h"
51 static struct vfs_class vfs_tarfs_ops;
53 enum {
54 TAR_UNKNOWN = 0,
55 TAR_V7,
56 TAR_USTAR,
57 TAR_POSIX,
58 TAR_GNU
62 * Header block on tape.
64 * I'm going to use traditional DP naming conventions here.
65 * A "block" is a big chunk of stuff that we do I/O on.
66 * A "record" is a piece of info that we care about.
67 * Typically many "record"s fit into a "block".
69 #define RECORDSIZE 512
70 #define NAMSIZ 100
71 #define PREFIX_SIZE 155
72 #define TUNMLEN 32
73 #define TGNMLEN 32
74 #define SPARSE_EXT_HDR 21
75 #define SPARSE_IN_HDR 4
77 struct sparse {
78 char offset[12];
79 char numbytes[12];
82 struct sp_array {
83 int offset;
84 int numbytes;
87 union record {
88 char charptr[RECORDSIZE];
89 struct header {
90 char arch_name[NAMSIZ];
91 char mode[8];
92 char uid[8];
93 char gid[8];
94 char size[12];
95 char mtime[12];
96 char chksum[8];
97 char linkflag;
98 char arch_linkname[NAMSIZ];
99 char magic[8];
100 char uname[TUNMLEN];
101 char gname[TGNMLEN];
102 char devmajor[8];
103 char devminor[8];
104 /* The following bytes of the tar header record were originally unused.
106 Archives following the ustar specification use almost all of those
107 bytes to support pathnames of 256 characters in length.
109 GNU tar archives use the "unused" space to support incremental
110 archives and sparse files. */
111 union unused {
112 char prefix[PREFIX_SIZE];
113 /* GNU extensions to the ustar (POSIX.1-1988) archive format. */
114 struct oldgnu {
115 char atime[12];
116 char ctime[12];
117 char offset[12];
118 char longnames[4];
119 char pad;
120 struct sparse sp[SPARSE_IN_HDR];
121 char isextended;
122 char realsize[12]; /* true size of the sparse file */
123 } oldgnu;
124 } unused;
125 } header;
126 struct extended_header {
127 struct sparse sp[21];
128 char isextended;
129 } ext_hdr;
132 /* The checksum field is filled with this while the checksum is computed. */
133 #define CHKBLANKS " " /* 8 blanks, no null */
135 /* The magic field is filled with this if uname and gname are valid. */
136 #define TMAGIC "ustar" /* ustar and a null */
137 #define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
139 /* The linkflag defines the type of file */
140 #define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */
141 #define LF_NORMAL '0' /* Normal disk file */
142 #define LF_LINK '1' /* Link to previously dumped file */
143 #define LF_SYMLINK '2' /* Symbolic link */
144 #define LF_CHR '3' /* Character special file */
145 #define LF_BLK '4' /* Block special file */
146 #define LF_DIR '5' /* Directory */
147 #define LF_FIFO '6' /* FIFO special file */
148 #define LF_CONTIG '7' /* Contiguous file */
149 #define LF_EXTHDR 'x' /* pax Extended Header */
150 #define LF_GLOBAL_EXTHDR 'g' /* pax Global Extended Header */
151 /* Further link types may be defined later. */
153 /* Note that the standards committee allows only capital A through
154 capital Z for user-defined expansion. This means that defining something
155 as, say '8' is a *bad* idea. */
156 #define LF_DUMPDIR 'D' /* This is a dir entry that contains
157 the names of files that were in
158 the dir at the time the dump
159 was made */
160 #define LF_LONGLINK 'K' /* Identifies the NEXT file on the tape
161 as having a long linkname */
162 #define LF_LONGNAME 'L' /* Identifies the NEXT file on the tape
163 as having a long name. */
164 #define LF_MULTIVOL 'M' /* This is the continuation
165 of a file that began on another
166 volume */
167 #define LF_NAMES 'N' /* For storing filenames that didn't
168 fit in 100 characters */
169 #define LF_SPARSE 'S' /* This is for sparse files */
170 #define LF_VOLHDR 'V' /* This file is a tape/volume header */
171 /* Ignore it on extraction */
174 * Exit codes from the "tar" program
176 #define EX_SUCCESS 0 /* success! */
177 #define EX_ARGSBAD 1 /* invalid args */
178 #define EX_BADFILE 2 /* invalid filename */
179 #define EX_BADARCH 3 /* bad archive */
180 #define EX_SYSTEM 4 /* system gave unexpected error */
181 #define EX_BADVOL 5 /* Special error code means
182 Tape volume doesn't match the one
183 specified on the command line */
185 #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
188 * Quick and dirty octal conversion.
190 * Result is -1 if the field is invalid (all blank, or nonoctal).
192 static long tar_from_oct (int digs, char *where)
194 register long value;
196 while (isspace ((unsigned char) *where)) { /* Skip spaces */
197 where++;
198 if (--digs <= 0)
199 return -1; /* All blank field */
201 value = 0;
202 while (digs > 0 && isodigit (*where)) { /* Scan till nonoctal */
203 value = (value << 3) | (*where++ - '0');
204 --digs;
207 if (digs > 0 && *where && !isspace ((unsigned char) *where))
208 return -1; /* Ended on non-space/nul */
210 return value;
213 static void tar_free_archive (struct vfs_class *me, struct vfs_s_super *archive)
215 (void) me;
217 if (archive->u.arch.fd != -1)
218 mc_close(archive->u.arch.fd);
221 /* As we open one archive at a time, it is safe to have this static */
222 static int current_tar_position = 0;
224 /* Returns fd of the open tar file */
225 static int
226 tar_open_archive_int (struct vfs_class *me, const char *name,
227 struct vfs_s_super *archive)
229 int result, type;
230 mode_t mode;
231 struct vfs_s_inode *root;
233 result = mc_open (name, O_RDONLY);
234 if (result == -1) {
235 message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), name);
236 ERRNOR (ENOENT, -1);
239 archive->name = g_strdup (name);
240 mc_stat (name, &(archive->u.arch.st));
241 archive->u.arch.fd = -1;
242 archive->u.arch.type = TAR_UNKNOWN;
244 /* Find out the method to handle this tar file */
245 type = get_compression_type (result);
246 mc_lseek (result, 0, SEEK_SET);
247 if (type != COMPRESSION_NONE) {
248 char *s;
249 mc_close (result);
250 s = g_strconcat (archive->name, decompress_extension (type), (char *) NULL);
251 result = mc_open (s, O_RDONLY);
252 if (result == -1)
253 message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), s);
254 g_free (s);
255 if (result == -1)
256 ERRNOR (ENOENT, -1);
259 archive->u.arch.fd = result;
260 mode = archive->u.arch.st.st_mode & 07777;
261 if (mode & 0400)
262 mode |= 0100;
263 if (mode & 0040)
264 mode |= 0010;
265 if (mode & 0004)
266 mode |= 0001;
267 mode |= S_IFDIR;
269 root = vfs_s_new_inode (me, archive, &archive->u.arch.st);
270 root->st.st_mode = mode;
271 root->data_offset = -1;
272 root->st.st_nlink++;
273 root->st.st_dev = MEDATA->rdev++;
275 archive->root = root;
277 return result;
280 static union record rec_buf;
282 static union record *
283 tar_get_next_record (struct vfs_s_super *archive, int tard)
285 int n;
287 (void) archive;
289 n = mc_read (tard, rec_buf.charptr, RECORDSIZE);
290 if (n != RECORDSIZE)
291 return NULL; /* An error has occurred */
292 current_tar_position += RECORDSIZE;
293 return &rec_buf;
296 static void tar_skip_n_records (struct vfs_s_super *archive, int tard, int n)
298 (void) archive;
300 mc_lseek (tard, n * RECORDSIZE, SEEK_CUR);
301 current_tar_position += n * RECORDSIZE;
304 static void
305 tar_fill_stat (struct vfs_s_super *archive, struct stat *st, union record *header,
306 size_t h_size)
308 st->st_mode = tar_from_oct (8, header->header.mode);
310 /* Adjust st->st_mode because there are tar-files with
311 * linkflag==LF_SYMLINK and S_ISLNK(mod)==0. I don't
312 * know about the other modes but I think I cause no new
313 * problem when I adjust them, too. -- Norbert.
315 if (header->header.linkflag == LF_DIR) {
316 st->st_mode |= S_IFDIR;
317 } else if (header->header.linkflag == LF_SYMLINK) {
318 st->st_mode |= S_IFLNK;
319 } else if (header->header.linkflag == LF_CHR) {
320 st->st_mode |= S_IFCHR;
321 } else if (header->header.linkflag == LF_BLK) {
322 st->st_mode |= S_IFBLK;
323 } else if (header->header.linkflag == LF_FIFO) {
324 st->st_mode |= S_IFIFO;
325 } else
326 st->st_mode |= S_IFREG;
328 st->st_rdev = 0;
329 switch (archive->u.arch.type) {
330 case TAR_USTAR:
331 case TAR_POSIX:
332 case TAR_GNU:
333 st->st_uid =
334 *header->header.uname ? vfs_finduid (header->header.
335 uname) : tar_from_oct (8,
336 header->
337 header.
338 uid);
339 st->st_gid =
340 *header->header.gname ? vfs_findgid (header->header.
341 gname) : tar_from_oct (8,
342 header->
343 header.
344 gid);
345 switch (header->header.linkflag) {
346 case LF_BLK:
347 case LF_CHR:
348 st->st_rdev =
349 (tar_from_oct (8, header->header.devmajor) << 8) |
350 tar_from_oct (8, header->header.devminor);
352 default:
353 st->st_uid = tar_from_oct (8, header->header.uid);
354 st->st_gid = tar_from_oct (8, header->header.gid);
356 st->st_size = h_size;
357 st->st_mtime = tar_from_oct (1 + 12, header->header.mtime);
358 st->st_atime = 0;
359 st->st_ctime = 0;
360 if (archive->u.arch.type == TAR_GNU) {
361 st->st_atime = tar_from_oct (1 + 12,
362 header->header.unused.oldgnu.atime);
363 st->st_ctime = tar_from_oct (1 + 12,
364 header->header.unused.oldgnu.ctime);
369 typedef enum {
370 STATUS_BADCHECKSUM,
371 STATUS_SUCCESS,
372 STATUS_EOFMARK,
373 STATUS_EOF
374 } ReadStatus;
376 * Return 1 for success, 0 if the checksum is bad, EOF on eof,
377 * 2 for a record full of zeros (EOF marker).
380 static ReadStatus
381 tar_read_header (struct vfs_class *me, struct vfs_s_super *archive,
382 int tard, size_t *h_size)
384 register int i;
385 register long sum, signed_sum, recsum;
386 register char *p;
387 register union record *header;
388 static char *next_long_name = NULL, *next_long_link = NULL;
390 recurse:
392 header = tar_get_next_record (archive, tard);
393 if (NULL == header)
394 return STATUS_EOF;
396 recsum = tar_from_oct (8, header->header.chksum);
398 sum = 0;
399 signed_sum = 0;
400 p = header->charptr;
401 for (i = sizeof (*header); --i >= 0;) {
403 * We can't use unsigned char here because of old compilers,
404 * e.g. V7.
406 signed_sum += *p;
407 sum += 0xFF & *p++;
410 /* Adjust checksum to count the "chksum" field as blanks. */
411 for (i = sizeof (header->header.chksum); --i >= 0;) {
412 sum -= 0xFF & header->header.chksum[i];
413 signed_sum -= (char) header->header.chksum[i];
415 sum += ' ' * sizeof header->header.chksum;
416 signed_sum += ' ' * sizeof header->header.chksum;
419 * This is a zeroed record...whole record is 0's except
420 * for the 8 blanks we faked for the checksum field.
422 if (sum == 8 * ' ')
423 return STATUS_EOFMARK;
425 if (sum != recsum && signed_sum != recsum)
426 return STATUS_BADCHECKSUM;
429 * Try to determine the archive format.
431 if (archive->u.arch.type == TAR_UNKNOWN) {
432 if (!strcmp (header->header.magic, TMAGIC)) {
433 if (header->header.linkflag == LF_GLOBAL_EXTHDR)
434 archive->u.arch.type = TAR_POSIX;
435 else
436 archive->u.arch.type = TAR_USTAR;
437 } else if (!strcmp (header->header.magic, OLDGNU_MAGIC)) {
438 archive->u.arch.type = TAR_GNU;
443 * linkflag on BSDI tar (pax) always '\000'
445 if (header->header.linkflag == '\000') {
446 if (header->header.arch_name[NAMSIZ - 1] != '\0')
447 i = NAMSIZ;
448 else
449 i = strlen (header->header.arch_name);
451 if (i && header->header.arch_name[i - 1] == '/')
452 header->header.linkflag = LF_DIR;
456 * Good record. Decode file size and return.
458 if (header->header.linkflag == LF_LINK
459 || header->header.linkflag == LF_DIR)
460 *h_size = 0; /* Links 0 size on tape */
461 else
462 *h_size = tar_from_oct (1 + 12, header->header.size);
465 * Skip over directory snapshot info records that
466 * are stored in incremental tar archives.
468 if (header->header.linkflag == LF_DUMPDIR) {
469 if (archive->u.arch.type == TAR_UNKNOWN)
470 archive->u.arch.type = TAR_GNU;
471 return STATUS_SUCCESS;
475 * Skip over pax extended header and global extended
476 * header records.
478 if (header->header.linkflag == LF_EXTHDR ||
479 header->header.linkflag == LF_GLOBAL_EXTHDR) {
480 if (archive->u.arch.type == TAR_UNKNOWN)
481 archive->u.arch.type = TAR_POSIX;
482 return STATUS_SUCCESS;
485 if (header->header.linkflag == LF_LONGNAME
486 || header->header.linkflag == LF_LONGLINK) {
487 char **longp;
488 char *bp, *data;
489 int size, written;
491 if (archive->u.arch.type == TAR_UNKNOWN)
492 archive->u.arch.type = TAR_GNU;
494 if (*h_size > MC_MAXPATHLEN) {
495 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
496 return STATUS_BADCHECKSUM;
499 longp = ((header->header.linkflag == LF_LONGNAME)
500 ? &next_long_name : &next_long_link);
502 g_free (*longp);
503 bp = *longp = g_malloc (*h_size + 1);
505 for (size = *h_size; size > 0; size -= written) {
506 data = tar_get_next_record (archive, tard)->charptr;
507 if (data == NULL) {
508 g_free (*longp);
509 *longp = NULL;
510 message (D_ERROR, MSG_ERROR,
511 _("Unexpected EOF on archive file"));
512 return STATUS_BADCHECKSUM;
514 written = RECORDSIZE;
515 if (written > size)
516 written = size;
518 memcpy (bp, data, written);
519 bp += written;
522 if (bp - *longp == MC_MAXPATHLEN && bp[-1] != '\0') {
523 g_free (*longp);
524 *longp = NULL;
525 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
526 return STATUS_BADCHECKSUM;
528 *bp = 0;
529 goto recurse;
530 } else {
531 struct stat st;
532 struct vfs_s_entry *entry;
533 struct vfs_s_inode *inode, *parent;
534 long data_position;
535 char *q;
536 int len;
537 char *current_file_name, *current_link_name;
539 current_link_name =
540 (next_long_link ? next_long_link :
541 g_strndup (header->header.arch_linkname, NAMSIZ));
542 len = strlen (current_link_name);
543 if (len > 1 && current_link_name[len - 1] == '/')
544 current_link_name[len - 1] = 0;
546 current_file_name = NULL;
547 switch (archive->u.arch.type) {
548 case TAR_USTAR:
549 case TAR_POSIX:
550 /* The ustar archive format supports pathnames of upto 256
551 * characters in length. This is achieved by concatenating
552 * the contents of the `prefix' and `arch_name' fields like
553 * this:
555 * prefix + path_separator + arch_name
557 * If the `prefix' field contains an empty string i.e. its
558 * first characters is '\0' the prefix field is ignored.
560 if (header->header.unused.prefix[0] != '\0') {
561 char *temp_name, *temp_prefix;
563 temp_name = g_strndup (header->header.arch_name, NAMSIZ);
564 temp_prefix = g_strndup (header->header.unused.prefix,
565 PREFIX_SIZE);
566 current_file_name = g_strconcat (temp_prefix, PATH_SEP_STR,
567 temp_name, (char *) NULL);
568 g_free (temp_name);
569 g_free (temp_prefix);
571 break;
572 case TAR_GNU:
573 if (next_long_name != NULL)
574 current_file_name = next_long_name;
575 break;
576 default:
577 break;
580 if (current_file_name == NULL)
581 current_file_name = g_strndup (header->header.arch_name, NAMSIZ);
583 canonicalize_pathname (current_file_name);
584 len = strlen (current_file_name);
586 data_position = current_tar_position;
588 p = strrchr (current_file_name, '/');
589 if (p == NULL) {
590 p = current_file_name;
591 q = current_file_name + len; /* "" */
592 } else {
593 *(p++) = 0;
594 q = current_file_name;
597 parent =
598 vfs_s_find_inode (me, archive, q, LINK_NO_FOLLOW, FL_MKDIR);
599 if (parent == NULL) {
600 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
601 return STATUS_BADCHECKSUM;
604 if (header->header.linkflag == LF_LINK) {
605 inode =
606 vfs_s_find_inode (me, archive, current_link_name,
607 LINK_NO_FOLLOW, 0);
608 if (inode == NULL) {
609 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
610 } else {
611 entry = vfs_s_new_entry (me, p, inode);
612 vfs_s_insert_entry (me, parent, entry);
613 g_free (current_link_name);
614 goto done;
618 tar_fill_stat (archive, &st, header, *h_size);
619 if (S_ISDIR(st.st_mode)) {
620 entry = MEDATA->find_entry (me, parent, p, LINK_NO_FOLLOW, FL_NONE);
621 if (entry)
622 goto done;
624 inode = vfs_s_new_inode (me, archive, &st);
626 inode->data_offset = data_position;
627 if (*current_link_name) {
628 inode->linkname = current_link_name;
629 } else if (current_link_name != next_long_link) {
630 g_free (current_link_name);
632 entry = vfs_s_new_entry (me, p, inode);
634 vfs_s_insert_entry (me, parent, entry);
635 g_free (current_file_name);
637 done:
638 next_long_link = next_long_name = NULL;
640 if (archive->u.arch.type == TAR_GNU &&
641 header->header.unused.oldgnu.isextended) {
642 while (tar_get_next_record (archive, tard)->ext_hdr.
643 isextended);
644 inode->data_offset = current_tar_position;
646 return STATUS_SUCCESS;
651 * Main loop for reading an archive.
652 * Returns 0 on success, -1 on error.
654 static int
655 tar_open_archive (struct vfs_class *me, struct vfs_s_super *archive,
656 const char *name, char *op)
658 /* Initial status at start of archive */
659 ReadStatus status = STATUS_EOFMARK;
660 ReadStatus prev_status;
661 int tard;
663 (void) op;
665 current_tar_position = 0;
666 /* Open for reading */
667 if ((tard = tar_open_archive_int (me, name, archive)) == -1)
668 return -1;
670 for (;;) {
671 size_t h_size;
673 prev_status = status;
674 status = tar_read_header (me, archive, tard, &h_size);
676 switch (status) {
678 case STATUS_SUCCESS:
679 tar_skip_n_records (archive, tard,
680 (h_size + RECORDSIZE -
681 1) / RECORDSIZE);
682 continue;
685 * Invalid header:
687 * If the previous header was good, tell them
688 * that we are skipping bad ones.
690 case STATUS_BADCHECKSUM:
691 switch (prev_status) {
693 /* Error on first record */
694 case STATUS_EOFMARK:
695 message (D_ERROR, MSG_ERROR,
697 ("Hmm,...\n%s\ndoesn't look like a tar archive."),
698 name);
699 /* FALL THRU */
701 /* Error after header rec */
702 case STATUS_SUCCESS:
703 /* Error after error */
705 case STATUS_BADCHECKSUM:
706 return -1;
708 case STATUS_EOF:
709 return 0;
712 /* Record of zeroes */
713 case STATUS_EOFMARK:
714 status = prev_status; /* If error after 0's */
715 /* FALL THRU */
717 case STATUS_EOF: /* End of archive */
718 break;
720 break;
722 return 0;
725 static void *
726 tar_super_check (struct vfs_class *me, const char *archive_name, char *op)
728 static struct stat stat_buf;
730 (void) me;
731 (void) op;
733 if (mc_stat (archive_name, &stat_buf))
734 return NULL;
735 return &stat_buf;
738 static int
739 tar_super_same (struct vfs_class *me, struct vfs_s_super *parc,
740 const char *archive_name, char *op, void *cookie)
742 struct stat *archive_stat = cookie; /* stat of main archive */
744 (void) me;
745 (void) op;
747 if (strcmp (parc->name, archive_name))
748 return 0;
750 /* Has the cached archive been changed on the disk? */
751 if (parc->u.arch.st.st_mtime < archive_stat->st_mtime) {
752 /* Yes, reload! */
753 (*vfs_tarfs_ops.free) ((vfsid) parc);
754 vfs_rmstamp (&vfs_tarfs_ops, (vfsid) parc);
755 return 2;
757 /* Hasn't been modified, give it a new timeout */
758 vfs_stamp (&vfs_tarfs_ops, (vfsid) parc);
759 return 1;
762 static ssize_t tar_read (void *fh, char *buffer, int count)
764 off_t begin = FH->ino->data_offset;
765 int fd = FH_SUPER->u.arch.fd;
766 struct vfs_class *me = FH_SUPER->me;
768 if (mc_lseek (fd, begin + FH->pos, SEEK_SET) !=
769 begin + FH->pos) ERRNOR (EIO, -1);
771 count = MIN(count, FH->ino->st.st_size - FH->pos);
773 if ((count = mc_read (fd, buffer, count)) == -1) ERRNOR (errno, -1);
775 FH->pos += count;
776 return count;
779 static int tar_fh_open (struct vfs_class *me, struct vfs_s_fh *fh, int flags, int mode)
781 (void) fh;
782 (void) mode;
784 if ((flags & O_ACCMODE) != O_RDONLY) ERRNOR (EROFS, -1);
785 return 0;
788 void
789 init_tarfs (void)
791 static struct vfs_s_subclass tarfs_subclass;
793 tarfs_subclass.flags = VFS_S_READONLY;
794 tarfs_subclass.archive_check = tar_super_check;
795 tarfs_subclass.archive_same = tar_super_same;
796 tarfs_subclass.open_archive = tar_open_archive;
797 tarfs_subclass.free_archive = tar_free_archive;
798 tarfs_subclass.fh_open = tar_fh_open;
800 vfs_s_init_class (&vfs_tarfs_ops, &tarfs_subclass);
801 vfs_tarfs_ops.name = "tarfs";
802 vfs_tarfs_ops.prefix = "utar";
803 vfs_tarfs_ops.read = tar_read;
804 vfs_tarfs_ops.setctl = NULL;
805 vfs_register_class (&vfs_tarfs_ops);