diff options
author | Manuel Menal <mmenal@hurdfr.org> | 2010-09-20 20:48:05 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2010-09-20 20:54:15 +0000 |
commit | 7fc534e167e8ebf3e7267fca5db7e34c9bc15538 (patch) | |
tree | 5fb72845589f1cbedfce403f0009aa97ff6c30fe | |
parent | 34da65652018854e2de8351b6040f1f9c242a7d4 (diff) |
Make tarfs actually work again
* tar.c: Import newer mc snapshot.
(strconcat): New function.
(tar_header_hook): Replace `off_t' parameter of function type with
`struct archive *'.
(tar_get_next_record): Initialize `buf' to NULL and n to 0 before calling
`store_read'.
* tar.c: Import newer mc snapshot.
(struct archive): New structure.
* tarfs.c (tar_header_hook): Replace `off_t' parameter of function type with
`struct archive *'.
(tarfs_add_header): Likewise. Pass `archive->current_tar_position'
instead of `offset' to `tar_make_item'. Call `tar_fill_stat' instead of
`tar_header2stat'.
-rw-r--r-- | tar.c | 663 | ||||
-rw-r--r-- | tar.h | 65 | ||||
-rw-r--r-- | tarfs.c | 10 |
3 files changed, 420 insertions, 318 deletions
@@ -1,5 +1,6 @@ /* GNU tar files parsing. - Copyright (C) 1995 The Free Software Foundation + Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2006, 2007 Free Software Foundation, Inc. Written by: 1995 Jakub Jelinek Rewritten by: 1998 Pavel Machek @@ -39,7 +40,7 @@ #include "debug.h" /* A hook which is called each time a header has been parsed. */ -int (*tar_header_hook) (tar_record_t *, off_t) = NULL; +int (*tar_header_hook) (tar_record_t *, struct archive *) = NULL; #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) @@ -48,141 +49,102 @@ int (*tar_header_hook) (tar_record_t *, off_t) = NULL; # define isspace(c) ( (c) == ' ' ) #endif +/* Taken from glibc. */ +char * +strconcat (const char *string1, ...) +{ + size_t l; + va_list args; + char *s; + char *concat; + char *ptr; + + if (!string1) + return NULL; + + l = 1 + strlen (string1); + va_start (args, string1); + s = va_arg (args, char *); + while (s) + { + l += strlen (s); + s = va_arg (args, char *); + } + va_end (args); + + concat = malloc (l); + ptr = concat; + + ptr = stpcpy (ptr, string1); + va_start (args, string1); + s = va_arg (args, char *); + while (s) + { + ptr = stpcpy (ptr, s); + s = va_arg (args, char *); + } + va_end (args); + + return concat; +} + /* * Quick and dirty octal conversion. * * Result is -1 if the field is invalid (all blank, or nonoctal). */ -static long -from_oct (int digs, char *where) +static long tar_from_oct (int digs, char *where) { - register long value; + register long value; - while (isspace (*where)) - { /* Skip spaces */ - where++; - if (--digs <= 0) - return -1; /* All blank field */ + while (isspace ((unsigned char) *where)) { /* Skip spaces */ + where++; + if (--digs <= 0) + return -1; /* All blank field */ } - value = 0; - while (digs > 0 && isodigit (*where)) - { /* Scan till nonoctal */ - value = (value << 3) | (*where++ - '0'); - --digs; + value = 0; + while (digs > 0 && isodigit (*where)) { /* Scan till nonoctal */ + value = (value << 3) | (*where++ - '0'); + --digs; } - if (digs > 0 && *where && !isspace (*where)) - return -1; /* Ended on non-space/nul */ + if (digs > 0 && *where && !isspace ((unsigned char) *where)) + return -1; /* Ended on non-space/nul */ - return value; + return value; } -/* As we open one archive at a time, it is safe to have this static */ -static store_offset_t current_tar_position = 0; -static tar_record_t rec_buf; - - -static tar_record_t * -get_next_record (struct store *tar_file) +static union record * +tar_get_next_record (struct archive *archive) { - error_t err; - size_t n; - void *buf; - - debug (("Reading at offset %lli", current_tar_position)); - buf = rec_buf.charptr; - err = store_read (tar_file, current_tar_position, RECORDSIZE, &buf, &n); - - if (err) - error (1, err, "Read error (offset=%lli)", current_tar_position); - assert (n <= RECORDSIZE); - - if (buf != rec_buf.charptr) - { - memcpy (rec_buf.charptr, buf, n); - munmap (buf, n); - } + error_t err; + void *buf = NULL; + size_t n = 0; - if (n != RECORDSIZE) - return NULL; /* An error has occurred */ + err = store_read (archive->tar_file, archive->current_tar_position, RECORDSIZE, &buf, &n); + if (err) + error (1, err, "Read error (offset=%lli)", archive->current_tar_position); + if (n != RECORDSIZE) + return NULL; /* An error has occurred */ - current_tar_position += n; + if (buf != archive->rec_buf.charptr) + { + memcpy (archive->rec_buf.charptr, buf, n); + munmap (buf, n); + } - return &rec_buf; -} + archive->current_tar_position += RECORDSIZE; -static void -skip_n_records (struct store *tar_file, int n) -{ - current_tar_position += n * RECORDSIZE; + return &(archive->rec_buf); } -void -tar_header2stat (io_statbuf_t *st, tar_record_t *header) +static void tar_skip_n_records (struct archive *archive, int n) { - st->st_mode = from_oct (8, header->header.mode); - - /* Adjust st->st_mode because there are tar-files with - * linkflag==LF_SYMLINK and S_ISLNK(mod)==0. I don't - * know about the other modes but I think I cause no new - * problem when I adjust them, too. -- Norbert. - */ - if (header->header.linkflag == LF_DIR) - { - st->st_mode |= S_IFDIR; - } - else if (header->header.linkflag == LF_SYMLINK) - { - st->st_mode |= S_IFLNK; - } - else if (header->header.linkflag == LF_CHR) - { - st->st_mode |= S_IFCHR; - } - else if (header->header.linkflag == LF_BLK) - { - st->st_mode |= S_IFBLK; - } - else if (header->header.linkflag == LF_FIFO) - { - st->st_mode |= S_IFIFO; - } - else - st->st_mode |= S_IFREG; - - st->st_rdev = 0; - if (!strcmp (header->header.magic, TMAGIC)) - { - st->st_uid = *header->header.uname ? finduid (header->header.uname) : - from_oct (8, header->header.uid); - st->st_gid = *header->header.gname ? findgid (header->header.gname) : - from_oct (8, header->header.gid); - switch (header->header.linkflag) - { - case LF_BLK: - case LF_CHR: - st->st_rdev = (from_oct (8, header->header.devmajor) << 8) | - from_oct (8, header->header.devminor); - } - } - else - { /* Old Unix tar */ - st->st_uid = from_oct (8, header->header.uid); - st->st_gid = from_oct (8, header->header.gid); - } - //st->st_size = hstat.st_size; - st->st_size = from_oct (1 + 12, header->header.size); - if (st->st_size > 0) - st->st_blocks = ((st->st_size - 1) / 512) + 1; - else - st->st_blocks = 0; - st->st_mtime = from_oct (1 + 12, header->header.mtime); - st->st_atime = from_oct (1 + 12, header->header.atime); - st->st_ctime = from_oct (1 + 12, header->header.ctime); + (void) archive; + archive->current_tar_position += n * RECORDSIZE; } - typedef enum { STATUS_BADCHECKSUM, @@ -197,153 +159,282 @@ ReadStatus; * */ static ReadStatus -read_header (struct store *tar_file) +tar_read_header (struct archive *archive, size_t *h_size) { - register int i; - register long sum, signed_sum, recsum; - register char *p; - register tar_record_t *header; - char *data; - int size, written; - static char *next_lonname = NULL, *next_lonlink = NULL; - char *current_file_name, *current_link_name; - struct stat hstat; /* Stat struct corresponding */ - char arch_name[NAMSIZ + 1]; - char arch_linkname[NAMSIZ + 1]; - - memcpy (arch_name, header->header.arch_name, NAMSIZ); - arch_name [NAMSIZ] = '\0'; - memcpy (arch_linkname, header->header.arch_linkname, NAMSIZ); - arch_linkname [NAMSIZ] = '\0'; - - -recurse: - - header = get_next_record (tar_file); - if (NULL == header) - return STATUS_EOF; - - recsum = from_oct (8, header->header.chksum); - - sum = 0; - signed_sum = 0; - p = header->charptr; - for (i = sizeof (*header); --i >= 0;) - { - /* - * We can't use unsigned char here because of old compilers, - * e.g. V7. - */ - signed_sum += *p; - sum += 0xFF & *p++; + register int i; + register long sum, signed_sum, recsum; + register char *p; + register union record *header; + static char *next_long_name = NULL, *next_long_link = NULL; + + recurse: + + header = tar_get_next_record (archive); + if (NULL == header) + return STATUS_EOF; + + recsum = tar_from_oct (8, header->header.chksum); + + sum = 0; + signed_sum = 0; + p = header->charptr; + for (i = sizeof (*header); --i >= 0;) { + /* + * We can't use unsigned char here because of old compilers, + * e.g. V7. + */ + signed_sum += *p; + sum += 0xFF & *p++; } - /* Adjust checksum to count the "chksum" field as blanks. */ - for (i = sizeof (header->header.chksum); --i >= 0;) - { - sum -= 0xFF & header->header.chksum[i]; - signed_sum -= (char) header->header.chksum[i]; + /* Adjust checksum to count the "chksum" field as blanks. */ + for (i = sizeof (header->header.chksum); --i >= 0;) { + sum -= 0xFF & header->header.chksum[i]; + signed_sum -= (char) header->header.chksum[i]; + } + sum += ' ' * sizeof header->header.chksum; + signed_sum += ' ' * sizeof header->header.chksum; + + /* + * This is a zeroed record...whole record is 0's except + * for the 8 blanks we faked for the checksum field. + */ + if (sum == 8 * ' ') + return STATUS_EOFMARK; + + if (sum != recsum && signed_sum != recsum) + return STATUS_BADCHECKSUM; + + /* + * Try to determine the archive format. + */ + if (archive->type == TAR_UNKNOWN) { + if (!strcmp (header->header.magic, TMAGIC)) { + if (header->header.linkflag == LF_GLOBAL_EXTHDR) + archive->type = TAR_POSIX; + else + archive->type = TAR_USTAR; + } else if (!strcmp (header->header.magic, OLDGNU_MAGIC)) { + archive->type = TAR_GNU; + } } - sum += ' ' * sizeof header->header.chksum; - signed_sum += ' ' * sizeof header->header.chksum; - - /* - * This is a zeroed record...whole record is 0's except - * for the 8 blanks we faked for the checksum field. - */ - if (sum == 8 * ' ') - return STATUS_EOFMARK; - - if (sum != recsum && signed_sum != recsum) - return STATUS_BADCHECKSUM; - - /* - * linkflag on BSDI tar (pax) always '\000' - */ - - if (header->header.linkflag == '\000' && - strlen (arch_name) && - arch_name[strlen (arch_name) - 1] == '/') - header->header.linkflag = LF_DIR; - /* - * Good record. Decode file size and return. - */ - if (header->header.linkflag == LF_LINK || header->header.linkflag == LF_DIR) - hstat.st_size = 0; /* Links 0 size on tape */ - else - hstat.st_size = from_oct (1 + 12, header->header.size); + /* + * linkflag on BSDI tar (pax) always '\000' + */ + if (header->header.linkflag == '\000') { + if (header->header.arch_name[NAMSIZ - 1] != '\0') + i = NAMSIZ; + else + i = strlen (header->header.arch_name); + + if (i && header->header.arch_name[i - 1] == '/') + header->header.linkflag = LF_DIR; + } - if (header->header.linkflag == LF_LONGNAME - || header->header.linkflag == LF_LONGLINK) - { - for (size = hstat.st_size; size > 0; size -= written) - { - data = get_next_record (tar_file)->charptr; - if (data == NULL) - { - error (0, 0, "Unexpected EOF on archive file"); - return STATUS_BADCHECKSUM; - } - written = RECORDSIZE; - if (written > size) - written = size; - } - goto recurse; + /* + * Good record. Decode file size and return. + */ + if (header->header.linkflag == LF_LINK + || header->header.linkflag == LF_DIR) + *h_size = 0; /* Links 0 size on tape */ + else + *h_size = tar_from_oct (1 + 12, header->header.size); + + /* + * Skip over directory snapshot info records that + * are stored in incremental tar archives. + */ + if (header->header.linkflag == LF_DUMPDIR) { + if (archive->type == TAR_UNKNOWN) + archive->type = TAR_GNU; + return STATUS_SUCCESS; + } + + /* + * Skip over pax extended header and global extended + * header records. + */ + if (header->header.linkflag == LF_EXTHDR || + header->header.linkflag == LF_GLOBAL_EXTHDR) { + if (archive->type == TAR_UNKNOWN) + archive->type = TAR_POSIX; + return STATUS_SUCCESS; } - else - { - long data_position; - char *p, *q; - int len; - int isdir = 0; - - current_file_name = (next_lonname - ? next_lonname - : strdup (arch_name)); - len = strlen (current_file_name); - if (current_file_name[len - 1] == '/') - { - current_file_name[len - 1] = 0; - isdir = 1; - } + if (header->header.linkflag == LF_LONGNAME + || header->header.linkflag == LF_LONGLINK) { + char **longp; + char *bp, *data; + int size, written; - current_link_name = (next_lonlink - ? next_lonlink - : strdup (arch_linkname)); - len = strlen (current_link_name); - if (len && current_link_name[len - 1] == '/') - current_link_name[len - 1] = 0; + if (archive->type == TAR_UNKNOWN) + archive->type = TAR_GNU; - next_lonlink = next_lonname = NULL; + longp = ((header->header.linkflag == LF_LONGNAME) + ? &next_long_name : &next_long_link); - data_position = current_tar_position; + free (*longp); + bp = *longp = malloc (*h_size + 1); + + for (size = *h_size; size > 0; size -= written) { + data = tar_get_next_record (archive)->charptr; + if (data == NULL) { + free (*longp); + *longp = NULL; + error (0, 0, "Unexpected EOF on archive file"); + return STATUS_BADCHECKSUM; + } + written = RECORDSIZE; + if (written > size) + written = size; - p = strrchr (current_file_name, '/'); - if (p == NULL) - { - p = current_file_name; - q = current_file_name + strlen (current_file_name); /* "" */ + memcpy (bp, data, written); + bp += written; } - else - { - *(p++) = 0; - q = current_file_name; + + *bp = 0; + goto recurse; + } else { + long data_position; + char *q; + int len; + char *current_file_name, *current_link_name; + + current_link_name = + (next_long_link ? next_long_link : + strndup (header->header.arch_linkname, NAMSIZ)); + len = strlen (current_link_name); + if (len > 1 && current_link_name[len - 1] == '/') + current_link_name[len - 1] = 0; + + current_file_name = NULL; + switch (archive->type) { + case TAR_USTAR: + case TAR_POSIX: + /* The ustar archive format supports pathnames of upto 256 + * characters in length. This is achieved by concatenating + * the contents of the `prefix' and `arch_name' fields like + * this: + * + * prefix + path_separator + arch_name + * + * If the `prefix' field contains an empty string i.e. its + * first characters is '\0' the prefix field is ignored. + */ + if (header->header.unused.prefix[0] != '\0') { + char *temp_name, *temp_prefix; + + temp_name = strndup (header->header.arch_name, NAMSIZ); + temp_prefix = strndup (header->header.unused.prefix, + PREFIX_SIZE); + current_file_name = strconcat (temp_prefix, "/", + temp_name, (char *) NULL); + free (temp_name); + free (temp_prefix); + } + break; + case TAR_GNU: + if (next_long_name != NULL) + current_file_name = next_long_name; + break; + default: + break; + } + + if (current_file_name == NULL) + current_file_name = strndup (header->header.arch_name, NAMSIZ); + + len = strlen (current_file_name); + + data_position = archive->current_tar_position; + + p = strrchr (current_file_name, '/'); + if (p == NULL) { + p = current_file_name; + q = current_file_name + len; /* "" */ + } else { + *(p++) = 0; + q = current_file_name; } - if (tar_header_hook) - tar_header_hook (header, current_tar_position); + if (tar_header_hook) + tar_header_hook (header, archive); + + free (current_file_name); - free (current_file_name); + /* done:*/ + next_long_link = next_long_name = NULL; -/* done: */ - if (header->header.isextended) - { - while (get_next_record (tar_file)->ext_hdr.isextended); + if (archive->type == TAR_GNU && + header->header.unused.oldgnu.isextended) { + while (tar_get_next_record (archive)->ext_hdr. + isextended); } - skip_n_records (tar_file, (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE); - return STATUS_SUCCESS; + return STATUS_SUCCESS; + } +} + +void +tar_fill_stat (struct archive *archive, struct stat *st, tar_record_t *header) +{ + st->st_mode = tar_from_oct (8, header->header.mode); + + /* Adjust st->st_mode because there are tar-files with + * linkflag==LF_SYMLINK and S_ISLNK(mod)==0. I don't + * know about the other modes but I think I cause no new + * problem when I adjust them, too. -- Norbert. + */ + if (header->header.linkflag == LF_DIR) { + st->st_mode |= S_IFDIR; + } else if (header->header.linkflag == LF_SYMLINK) { + st->st_mode |= S_IFLNK; + } else if (header->header.linkflag == LF_CHR) { + st->st_mode |= S_IFCHR; + } else if (header->header.linkflag == LF_BLK) { + st->st_mode |= S_IFBLK; + } else if (header->header.linkflag == LF_FIFO) { + st->st_mode |= S_IFIFO; + } else + st->st_mode |= S_IFREG; + + st->st_rdev = 0; + switch (archive->type) { + case TAR_USTAR: + case TAR_POSIX: + case TAR_GNU: + st->st_uid = + *header->header.uname ? finduid (header->header. + uname) : tar_from_oct (8, + header-> + header. + uid); + st->st_gid = + *header->header.gname ? findgid (header->header. + gname) : tar_from_oct (8, + header-> + header. + gid); + switch (header->header.linkflag) { + case LF_BLK: + case LF_CHR: + st->st_rdev = + (tar_from_oct (8, header->header.devmajor) << 8) | + tar_from_oct (8, header->header.devminor); + } + default: + st->st_uid = tar_from_oct (8, header->header.uid); + st->st_gid = tar_from_oct (8, header->header.gid); + } + st->st_size = tar_from_oct (1 + 12, header->header.size); + st->st_mtime = tar_from_oct (1 + 12, header->header.mtime); + st->st_atime = 0; + st->st_ctime = 0; + if (archive->type == TAR_GNU) { + st->st_atime = tar_from_oct (1 + 12, + header->header.unused.oldgnu.atime); + st->st_ctime = tar_from_oct (1 + 12, + header->header.unused.oldgnu.ctime); } } @@ -354,77 +445,65 @@ recurse: int tar_open_archive (struct store *tar_file) { - ReadStatus status = STATUS_EOFMARK; /* Initial status at start of archive */ - ReadStatus prev_status = STATUS_SUCCESS; + /* Initial status at start of archive */ + ReadStatus status = STATUS_EOFMARK; + ReadStatus prev_status; - current_tar_position = 0; + struct archive archive; + archive.tar_file = tar_file; + archive.current_tar_position = 0; + archive.type = TAR_UNKNOWN; - for (;;) - { - prev_status = status; - status = read_header (tar_file); + for (;;) { + size_t h_size; + prev_status = status; + status = tar_read_header (&archive, &h_size); - switch (status) - { + switch (status) { case STATUS_SUCCESS: - continue; - - /* - * Invalid header: - * - * If the previous header was good, tell them - * that we are skipping bad ones. - */ + tar_skip_n_records (&archive, + (h_size + RECORDSIZE - + 1) / RECORDSIZE); + continue; + + /* + * Invalid header: + * + * If the previous header was good, tell them + * that we are skipping bad ones. + */ case STATUS_BADCHECKSUM: - switch (prev_status) - { + switch (prev_status) { - /* Error on first record */ + /* Error on first record */ case STATUS_EOFMARK: - return -1; - /* FALL THRU */ + /* FALL THRU */ - /* Error after header rec */ + /* Error after header rec */ case STATUS_SUCCESS: - prev_status = status; - { - /* FIXME: Bad hack */ - size_t size; - tar_record_t *hdr; - current_tar_position -= RECORDSIZE; - error (0, 0, "Skipping to next header (offset=%lli)", - current_tar_position); - hdr = get_next_record (tar_file); - size = from_oct (8, hdr->header.size); - size = size % RECORDSIZE - ? size / RECORDSIZE - : (size / RECORDSIZE) + RECORDSIZE; - current_tar_position += size; - } - - /* Error after error */ + /* Error after error */ case STATUS_BADCHECKSUM: - error (1, 0, "Bad checksum (offset=%lli)", current_tar_position); - return -1; + return -1; case STATUS_EOF: - return 0; + return 0; } - /* Record of zeroes */ + /* Record of zeroes */ case STATUS_EOFMARK: - status = prev_status; /* If error after 0's */ - /* FALL THRU */ + status = prev_status; /* If error after 0's */ + /* FALL THRU */ case STATUS_EOF: /* End of archive */ - break; + break; } - break; + break; }; - return 0; + + return 0; } @@ -497,7 +576,7 @@ tar_make_header (tar_record_t *header, io_statbuf_t *st, char *name, else header->header.linkflag = LF_NORMAL; - strncpy (header->header.magic, TMAGIC, TMAGLEN); + strncpy (header->header.magic, TMAGIC, strlen(TMAGIC)); uid_to_uname (st->st_uid, header->header.uname); gid_to_gname (st->st_gid, header->header.gname); @@ -33,6 +33,14 @@ #include <sys/mknod.h> #endif +enum { + TAR_UNKNOWN = 0, + TAR_V7, + TAR_USTAR, + TAR_POSIX, + TAR_GNU +}; + /* * Header block on tape. * @@ -43,6 +51,7 @@ */ #define RECORDSIZE 512 #define NAMSIZ 100 +#define PREFIX_SIZE 155 #define TUNMLEN 32 #define TGNMLEN 32 #define SPARSE_EXT_HDR 21 @@ -75,20 +84,27 @@ union record { char gname[TGNMLEN]; char devmajor[8]; char devminor[8]; - /* these following fields were added by JF for gnu */ - /* and are NOT standard */ - char atime[12]; - char ctime[12]; - char offset[12]; - char longnames[4]; -#ifdef NEEDPAD - char pad; -#endif - struct sparse sp[SPARSE_IN_HDR]; - char isextended; - char realsize[12]; /* true size of the sparse file */ - /* char ending_blanks[12];*//* number of nulls at the - end of the file, if any */ + /* The following bytes of the tar header record were originally unused. + + Archives following the ustar specification use almost all of those + bytes to support pathnames of 256 characters in length. + + GNU tar archives use the "unused" space to support incremental + archives and sparse files. */ + union unused { + char prefix[PREFIX_SIZE]; + /* GNU extensions to the ustar (POSIX.1-1988) archive format. */ + struct oldgnu { + char atime[12]; + char ctime[12]; + char offset[12]; + char longnames[4]; + char pad; + struct sparse sp[SPARSE_IN_HDR]; + char isextended; + char realsize[12]; /* true size of the sparse file */ + } oldgnu; + } unused; } header; struct extended_header { struct sparse sp[21]; @@ -100,10 +116,8 @@ union record { #define CHKBLANKS " " /* 8 blanks, no null */ /* The magic field is filled with this if uname and gname are valid. */ -#define TMAGIC "ustar " /* 7 chars and a null */ -#define TMAGLEN 6 -#define TVERSION "00" /* 00 and no null */ -#define TVERSLEN 2 +#define TMAGIC "ustar" /* ustar and a null */ +#define OLDGNU_MAGIC "ustar " /* 7 chars and a null */ /* The linkflag defines the type of file */ #define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */ @@ -115,6 +129,8 @@ union record { #define LF_DIR '5' /* Directory */ #define LF_FIFO '6' /* FIFO special file */ #define LF_CONTIG '7' /* Contiguous file */ +#define LF_EXTHDR 'x' /* pax Extended Header */ +#define LF_GLOBAL_EXTHDR 'g' /* pax Global Extended Header */ /* Further link types may be defined later. */ /* Note that the standards committee allows only capital A through @@ -137,8 +153,6 @@ union record { #define LF_VOLHDR 'V' /* This file is a tape/volume header */ /* Ignore it on extraction */ -#define LF_TRANS 'T' /* GNU/Hurd passive translator */ - /* * Exit codes from the "tar" program */ @@ -151,6 +165,8 @@ union record { Tape volume doesn't match the one specified on the command line */ +#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) + /* * We default to Unix Standard format rather than 4.2BSD tar format. * The code can actually produce all three: @@ -171,8 +187,15 @@ union record { typedef union record tar_record_t; +struct archive { + struct store *tar_file; + int type; + store_offset_t current_tar_position; + tar_record_t rec_buf; +}; + extern int tar_open_archive (struct store *tar_file); -extern void tar_header2stat (io_statbuf_t *st, tar_record_t *header); +extern void tar_fill_stat (struct archive *archive, io_statbuf_t *st, tar_record_t *header); /* Create a tar header based on ST and NAME where NAME is a path. If NAME is a hard link (resp. symlink), HARDLINK (resp. @@ -80,7 +80,7 @@ static struct store *tar_file; static struct mutex tar_file_lock; /* Archive parsing hook (see tar.c) */ -extern int (* tar_header_hook) (tar_record_t *, off_t); +extern int (* tar_header_hook) (tar_record_t *, struct archive *); /* List of tar items for this file */ static struct tar_list tar_list; @@ -325,7 +325,7 @@ error_t tarfs_create_node (struct node **newnode, struct node *dir, It simply creates the node corresponding to the header. OFFSET denotes the offset of the header in the archive. */ int -tarfs_add_header (tar_record_t *hdr, off_t offset) +tarfs_add_header (tar_record_t *hdr, struct archive *archive) { error_t err; static struct tar_item *last_item = NULL; @@ -412,7 +412,7 @@ tarfs_add_header (tar_record_t *hdr, off_t offset) /* Add the tar item into the list. */ err = tar_make_item (&NODE_INFO(new)->tar, new, - 0, offset); + 0, archive->current_tar_position); assert_perror (err); } } @@ -431,7 +431,7 @@ tarfs_add_header (tar_record_t *hdr, off_t offset) if (new) { NEW_NODE_INFO (new); - tar_header2stat (&new->nn_stat, hdr); + tar_fill_stat (archive, &new->nn_stat, hdr); /* Create a cache for the new node. */ err = cache_create (new); @@ -440,7 +440,7 @@ tarfs_add_header (tar_record_t *hdr, off_t offset) /* Add the tar item into the list. */ err = tar_make_item (&NODE_INFO(new)->tar, new, - new->nn_stat.st_size, offset); + new->nn_stat.st_size, archive->current_tar_position); assert_perror (err); } } |