summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/cpio/tar.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/cpio/tar.c')
-rw-r--r--gnu/usr.bin/cpio/tar.c522
1 files changed, 0 insertions, 522 deletions
diff --git a/gnu/usr.bin/cpio/tar.c b/gnu/usr.bin/cpio/tar.c
deleted file mode 100644
index 84cb0ad..0000000
--- a/gnu/usr.bin/cpio/tar.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/* tar.c - read in write tar headers for cpio
- Copyright (C) 1992 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "filetypes.h"
-#include "system.h"
-#include "cpiohdr.h"
-#include "dstring.h"
-#include "extern.h"
-#include "rmt.h"
-#include "tarhdr.h"
-
-static void to_oct ();
-static char *stash_tar_linkname ();
-static char *stash_tar_filename ();
-
-/* Compute and return a checksum for TAR_HDR,
- counting the checksum bytes as if they were spaces. */
-
-unsigned long
-tar_checksum (tar_hdr)
- struct tar_header *tar_hdr;
-{
- unsigned long sum = 0;
- char *p = (char *) tar_hdr;
- char *q = p + TARRECORDSIZE;
- int i;
-
- while (p < tar_hdr->chksum)
- sum += *p++ & 0xff;
- for (i = 0; i < 8; ++i)
- {
- sum += ' ';
- ++p;
- }
- while (p < q)
- sum += *p++ & 0xff;
- return sum;
-}
-
-/* Write out header FILE_HDR, including the file name, to file
- descriptor OUT_DES. */
-
-void
-write_out_tar_header (file_hdr, out_des)
- struct new_cpio_header *file_hdr;
- int out_des;
-{
- int name_len;
- union tar_record tar_rec;
- struct tar_header *tar_hdr = (struct tar_header *) &tar_rec;
-
- bzero ((char *) &tar_rec, TARRECORDSIZE);
-
- /* process_copy_out must ensure that file_hdr->c_name is short enough,
- or we will lose here. */
-
- name_len = strlen (file_hdr->c_name);
- if (name_len <= TARNAMESIZE)
- {
- strncpy (tar_hdr->name, file_hdr->c_name, name_len);
- }
- else
- {
- /* Fit as much as we can into `name', the rest into `prefix'. */
- char *suffix = file_hdr->c_name + name_len - TARNAMESIZE;
-
- /* We have to put the boundary at a slash. */
- name_len = TARNAMESIZE;
- while (*suffix != '/')
- {
- --name_len;
- ++suffix;
- }
- strncpy (tar_hdr->name, suffix + 1, name_len);
- strncpy (tar_hdr->prefix, file_hdr->c_name, suffix - file_hdr->c_name);
- }
-
- /* SVR4 seems to want the whole mode, not just protection modes.
- Nobody else seems to care, so we might as well put it all in. */
- to_oct (file_hdr->c_mode, 8, tar_hdr->mode);
- to_oct (file_hdr->c_uid, 8, tar_hdr->uid);
- to_oct (file_hdr->c_gid, 8, tar_hdr->gid);
- to_oct (file_hdr->c_filesize, 12, tar_hdr->size);
- to_oct (file_hdr->c_mtime, 12, tar_hdr->mtime);
-
- switch (file_hdr->c_mode & CP_IFMT)
- {
- case CP_IFREG:
- if (file_hdr->c_tar_linkname)
- {
- /* process_copy_out makes sure that c_tar_linkname is shorter
- than TARLINKNAMESIZE. */
- strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname,
- TARLINKNAMESIZE);
- tar_hdr->typeflag = LNKTYPE;
- to_oct (0, 12, tar_hdr->size);
- }
- else
- tar_hdr->typeflag = REGTYPE;
- break;
- case CP_IFDIR:
- tar_hdr->typeflag = DIRTYPE;
- break;
-#ifndef __MSDOS__
- case CP_IFCHR:
- tar_hdr->typeflag = CHRTYPE;
- break;
- case CP_IFBLK:
- tar_hdr->typeflag = BLKTYPE;
- break;
-#ifdef CP_IFIFO
- case CP_IFIFO:
- tar_hdr->typeflag = FIFOTYPE;
- break;
-#endif /* CP_IFIFO */
-#ifdef CP_IFLNK
- case CP_IFLNK:
- tar_hdr->typeflag = SYMTYPE;
- /* process_copy_out makes sure that c_tar_linkname is shorter
- than TARLINKNAMESIZE. */
- strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname,
- TARLINKNAMESIZE);
- to_oct (0, 12, tar_hdr->size);
- break;
-#endif /* CP_IFLNK */
-#endif /* !__MSDOS__ */
- }
-
- if (archive_format == arf_ustar)
- {
- char *name;
-
- strncpy (tar_hdr->magic, TMAGIC, TMAGLEN);
- strncpy (tar_hdr->magic + TMAGLEN, TVERSION, TVERSLEN);
-
-#ifndef __MSDOS__
- name = getuser (file_hdr->c_uid);
- if (name)
- strcpy (tar_hdr->uname, name);
- name = getgroup (file_hdr->c_gid);
- if (name)
- strcpy (tar_hdr->gname, name);
-#endif
-
- to_oct (file_hdr->c_rdev_maj, 8, tar_hdr->devmajor);
- to_oct (file_hdr->c_rdev_min, 8, tar_hdr->devminor);
- }
-
- to_oct (tar_checksum (tar_hdr), 8, tar_hdr->chksum);
-
- copy_buf_out ((char *) &tar_rec, out_des, TARRECORDSIZE);
-}
-
-/* Return nonzero iff all the bytes in BLOCK are NUL.
- SIZE is the number of bytes to check in BLOCK; it must be a
- multiple of sizeof (long). */
-
-int
-null_block (block, size)
- long *block;
- int size;
-{
- register long *p = block;
- register int i = size / sizeof (long);
-
- while (i--)
- if (*p++)
- return 0;
- return 1;
-}
-
-/* Read a tar header, including the file name, from file descriptor IN_DES
- into FILE_HDR. */
-
-void
-read_in_tar_header (file_hdr, in_des)
- struct new_cpio_header *file_hdr;
- int in_des;
-{
- long bytes_skipped = 0;
- int warned = FALSE;
- union tar_record tar_rec;
- struct tar_header *tar_hdr = (struct tar_header *) &tar_rec;
-#ifndef __MSDOS__
- uid_t *uidp;
- gid_t *gidp;
-#endif
-
- copy_in_buf ((char *) &tar_rec, in_des, TARRECORDSIZE);
-
- /* Check for a block of 0's. */
- if (null_block ((long *) &tar_rec, TARRECORDSIZE))
- {
-#if 0
- /* Found one block of 512 0's. If the next block is also all 0's
- then this is the end of the archive. If not, assume the
- previous block was all corruption and continue reading
- the archive. */
- /* Commented out because GNU tar sometimes creates archives with
- only one block of 0's at the end. This happened for the
- cpio 2.0 distribution! */
- copy_in_buf ((char *) &tar_rec, in_des, TARRECORDSIZE);
- if (null_block ((long *) &tar_rec, TARRECORDSIZE))
-#endif
- {
- file_hdr->c_name = "TRAILER!!!";
- return;
- }
-#if 0
- bytes_skipped = TARRECORDSIZE;
-#endif
- }
-
- while (1)
- {
- otoa (tar_hdr->chksum, &file_hdr->c_chksum);
-
- if (file_hdr->c_chksum != tar_checksum (tar_hdr))
- {
- /* If the checksum is bad, skip 1 byte and try again. When
- we try again we do not look for an EOF record (all zeros),
- because when we start skipping bytes in a corrupted archive
- the chances are pretty good that we might stumble across
- 2 blocks of 512 zeros (that probably is not really the last
- record) and it is better to miss the EOF and give the user
- a "premature EOF" error than to give up too soon on a corrupted
- archive. */
- if (!warned)
- {
- error (0, 0, "invalid header: checksum error");
- warned = TRUE;
- }
- bcopy (((char *) &tar_rec) + 1, (char *) &tar_rec,
- TARRECORDSIZE - 1);
- copy_in_buf (((char *) &tar_rec) + (TARRECORDSIZE - 1), in_des, 1);
- ++bytes_skipped;
- continue;
- }
-
- if (archive_format != arf_ustar)
- file_hdr->c_name = stash_tar_filename (NULL, tar_hdr->name);
- else
- file_hdr->c_name = stash_tar_filename (tar_hdr->prefix, tar_hdr->name);
- file_hdr->c_nlink = 1;
- otoa (tar_hdr->mode, &file_hdr->c_mode);
- file_hdr->c_mode = file_hdr->c_mode & 07777;
-#ifndef __MSDOS__
- if (archive_format == arf_ustar
- && (uidp = getuidbyname (tar_hdr->uname)))
- file_hdr->c_uid = *uidp;
- else
-#endif
- otoa (tar_hdr->uid, &file_hdr->c_uid);
-#ifndef __MSDOS__
- if (archive_format == arf_ustar
- && (gidp = getgidbyname (tar_hdr->gname)))
- file_hdr->c_gid = *gidp;
- else
-#endif
- otoa (tar_hdr->gid, &file_hdr->c_gid);
- otoa (tar_hdr->size, &file_hdr->c_filesize);
- otoa (tar_hdr->mtime, &file_hdr->c_mtime);
- otoa (tar_hdr->devmajor, (unsigned long *) &file_hdr->c_rdev_maj);
- otoa (tar_hdr->devminor, (unsigned long *) &file_hdr->c_rdev_min);
- file_hdr->c_tar_linkname = NULL;
-
- switch (tar_hdr->typeflag)
- {
- case REGTYPE:
- case CONTTYPE: /* For now, punt. */
- default:
- file_hdr->c_mode |= CP_IFREG;
- break;
- case DIRTYPE:
- file_hdr->c_mode |= CP_IFDIR;
- break;
-#ifndef __MSDOS__
- case CHRTYPE:
- file_hdr->c_mode |= CP_IFCHR;
- /* If a POSIX tar header has a valid linkname it's always supposed
- to set typeflag to be LNKTYPE. System V.4 tar seems to
- be broken, and for device files with multiple links it
- puts the name of the link into linkname, but leaves typeflag
- as CHRTYPE, BLKTYPE, FIFOTYPE, etc. */
- file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
-
- /* Does POSIX say that the filesize must be 0 for devices? We
- assume so, but HPUX's POSIX tar sets it to be 1 which causes
- us problems (when reading an archive we assume we can always
- skip to the next file by skipping filesize bytes). For
- now at least, it's easier to clear filesize for devices,
- rather than check everywhere we skip in copyin.c. */
- file_hdr->c_filesize = 0;
- break;
- case BLKTYPE:
- file_hdr->c_mode |= CP_IFBLK;
- file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
- file_hdr->c_filesize = 0;
- break;
-#ifdef CP_IFIFO
- case FIFOTYPE:
- file_hdr->c_mode |= CP_IFIFO;
- file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
- file_hdr->c_filesize = 0;
- break;
-#endif
- case SYMTYPE:
-#ifdef CP_IFLNK
- file_hdr->c_mode |= CP_IFLNK;
- file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
- file_hdr->c_filesize = 0;
- break;
- /* Else fall through. */
-#endif
- case LNKTYPE:
- file_hdr->c_mode |= CP_IFREG;
- file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
- file_hdr->c_filesize = 0;
- break;
-#endif /* !__MSDOS__ */
- case AREGTYPE:
- /* Old tar format; if the last char in filename is '/' then it is
- a directory, otherwise it's a regular file. */
- if (file_hdr->c_name[strlen (file_hdr->c_name) - 1] == '/')
- file_hdr->c_mode |= CP_IFDIR;
- else
- file_hdr->c_mode |= CP_IFREG;
- break;
- }
- break;
- }
- if (bytes_skipped > 0)
- error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
-}
-
-/* Stash the tar linkname in static storage. */
-
-static char *
-stash_tar_linkname (linkname)
- char *linkname;
-{
- static char hold_tar_linkname[TARLINKNAMESIZE + 1];
-
- strncpy (hold_tar_linkname, linkname, TARLINKNAMESIZE);
- hold_tar_linkname[TARLINKNAMESIZE] = '\0';
- return hold_tar_linkname;
-}
-
-/* Stash the tar filename and optional prefix in static storage. */
-
-static char *
-stash_tar_filename (prefix, filename)
- char *prefix;
- char *filename;
-{
- static char hold_tar_filename[TARNAMESIZE + TARPREFIXSIZE + 2];
- if (prefix == NULL || *prefix == '\0')
- {
- strncpy (hold_tar_filename, filename, TARNAMESIZE);
- hold_tar_filename[TARNAMESIZE] = '\0';
- }
- else
- {
- strncpy (hold_tar_filename, prefix, TARPREFIXSIZE);
- hold_tar_filename[TARPREFIXSIZE] = '\0';
- strcat (hold_tar_filename, "/");
- strncat (hold_tar_filename, filename, TARNAMESIZE);
- hold_tar_filename[TARPREFIXSIZE + TARNAMESIZE] = '\0';
- }
- return hold_tar_filename;
-}
-
-/* Convert the string of octal digits S into a number and store
- it in *N. Return nonzero if the whole string was converted,
- zero if there was something after the number.
- Skip leading and trailing spaces. */
-
-int
-otoa (s, n)
- char *s;
- unsigned long *n;
-{
- unsigned long val = 0;
-
- while (*s == ' ')
- ++s;
- while (*s >= '0' && *s <= '7')
- val = 8 * val + *s++ - '0';
- while (*s == ' ')
- ++s;
- *n = val;
- return *s == '\0';
-}
-
-/* Convert a number into a string of octal digits.
- Convert long VALUE into a DIGITS-digit field at WHERE,
- including a trailing space and room for a NUL. DIGITS==3 means
- 1 digit, a space, and room for a NUL.
-
- We assume the trailing NUL is already there and don't fill it in.
- This fact is used by start_header and finish_header, so don't change it!
-
- This is be equivalent to:
- sprintf (where, "%*lo ", digits - 2, value);
- except that sprintf fills in the trailing NUL and we don't. */
-
-static void
-to_oct (value, digits, where)
- register long value;
- register int digits;
- register char *where;
-{
- --digits; /* Leave the trailing NUL slot alone. */
- where[--digits] = ' '; /* Put in the space, though. */
-
- /* Produce the digits -- at least one. */
- do
- {
- where[--digits] = '0' + (char) (value & 7); /* One octal digit. */
- value >>= 3;
- }
- while (digits > 0 && value != 0);
-
- /* Add leading spaces, if necessary. */
- while (digits > 0)
- where[--digits] = ' ';
-}
-
-/* Return
- 2 if BUF is a valid POSIX tar header (the checksum is correct
- and it has the "ustar" magic string),
- 1 if BUF is a valid old tar header (the checksum is correct),
- 0 otherwise. */
-
-int
-is_tar_header (buf)
- char *buf;
-{
- struct tar_header *tar_hdr = (struct tar_header *) buf;
- unsigned long chksum;
-
- otoa (tar_hdr->chksum, &chksum);
-
- if (chksum != tar_checksum (tar_hdr))
- return 0;
-
- /* GNU tar 1.10 and previous set the magic field to be "ustar " instead
- of "ustar\0". Only look at the first 5 characters of the magic
- field so we can recognize old GNU tar ustar archives. */
- if (!strncmp (tar_hdr->magic, TMAGIC, TMAGLEN - 1))
- return 2;
- return 1;
-}
-
-/* Return TRUE if the filename is too long to fit in a tar header.
- For old tar headers, if the filename's length is less than or equal
- to 100 then it will fit, otherwise it will not. For POSIX tar headers,
- if the filename's length is less than or equal to 100 then it
- will definitely fit, and if it is greater than 256 then it
- will definitely not fit. If the length is between 100 and 256,
- then the filename will fit only if it is possible to break it
- into a 155 character "prefix" and 100 character "name". There
- must be a slash between the "prefix" and the "name", although
- the slash is not stored or counted in either the "prefix" or
- the "name", and there must be at least one character in both
- the "prefix" and the "name". If it is not possible to break down
- the filename like this then it will not fit. */
-
-int
-is_tar_filename_too_long (name)
- char *name;
-{
- int whole_name_len;
- int prefix_name_len;
- char *p;
-
- whole_name_len = strlen (name);
- if (whole_name_len <= TARNAMESIZE)
- return FALSE;
-
- if (archive_format != arf_ustar)
- return TRUE;
-
- if (whole_name_len > TARNAMESIZE + TARPREFIXSIZE + 1)
- return TRUE;
-
- /* See whether we can split up the name into acceptably-sized
- `prefix' and `name' (`p') pieces. Start out by making `name'
- as big as possible, then shrink it by looking for the first '/'. */
- p = name + whole_name_len - TARNAMESIZE;
- while (*p != '/' && *p != '\0')
- ++p;
- if (*p == '\0')
- /* The last component of the path is longer than TARNAMESIZE. */
- return TRUE;
-
- prefix_name_len = p - name - 1;
- /* Interestingly, a name consisting of a slash followed by
- TARNAMESIZE characters can't be stored, because the prefix
- would be empty, and thus ignored. */
- if (prefix_name_len > TARPREFIXSIZE || prefix_name_len == 0)
- return TRUE;
-
- return FALSE;
-}
OpenPOWER on IntegriCloud