n62@nikhefh.nikhef.nl (Klamer Schutte) (10/18/89)
Here is a new version of tar. The difference with the version posted
22 september is a lot of bugs.
Needed besides this posting:
getcwd.c Posted with the previous posting of tar (22/9)
directory(3) Posted several times. When you don't have them
undefine DIRECT_3.
This is not posted as cdiffs to the previous posting; this posting is only
5 kbytes bigger so i think this will save others (that's you) a lot of trouble.
Klamer. (.signature at end).
------------------------------------ cut here -------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# tar.c
# tar.h
# This archive created: Wed Oct 18 15:15:22 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'tar.c'" '(21445 characters)'
if test -f 'tar.c'
then
echo shar: will not over-write existing file "'tar.c'"
else
sed 's/^X//' << \SHAR_EOF > 'tar.c'
X/* tar - tape archiver Author: Michiel Huisjes */
X
X/* Usage: tar [cxt][vo][F][f] tapefile [files]
X *
X * attempt to make tar to conform to POSIX 1003.1
X * disclaimer: based on an old (1986) POSIX draft.
X * Klamer Schutte, 20/9/89
X *
X * Changes:
X * Changed to handle the original minix-tar format. KS 22/9/89
X * Changed to handle BSD4.3 tar format. KS 22/9/89
X * Conform to current umask if not super-user. KS 22/9/89
X * Update usage message to show f option KS 22/9/89
X *
X *
X1) tar will back itself up, should check archive inode num(&dev) and
X then check the target inode number. In verbose mode, issue
X warning, in all cases ignore target.
X marks@mgse Mon Sep 25 10:38:58 CDT 1989
X added global varaibles, made changes to main() and add_file();
X maks@mgse Mon Sep 25 12:09:20 CDT 1989
X
X2) tar will not notice that a file has changed size while it was being
X backed up. should issue warning.
X marks@mgse Mon Sep 25 10:38:58 CDT 1989
X
X3) the 'f' option was not documented in usage[].
X marks@mgse Mon Sep 25 12:03:20 CDT 1989
X changed both usage[] defines. Why are there two (one is commented out)?
X ( deleted by me (was done twice) -- KS, 2/10/89 )
X *
X * changed stat on tar_fd to an fstat KS 2/10/89
X * deleted mkfifo() code -- belongs in libc.a KS 2/10/89
X * made ar_dev default to -1 : an illegal device KS 2/10/89
X * made impossible to chown if normal user KS 2/10/89
X * if names in owner fields not known use numirical values KS 2/10/89
X * creat with mask 666 -- use umask if to liberal KS 2/10/89
X * allow to make directories as ../directory KS 2/10/89
X * allow tmagic field to end with a space (instead of \0) KS 2/10/89
X * correct usage of tmagic field KS 3/10/89
X * made mkdir() to return a value if directory == "." KS 3/10/89
X * made lint complains less (On a BSD 4.3 system) KS 3/10/89
X * use of directory(3) routines KS 3/10/89
X * deleted use of d_namlen selector of struct dirent KS 18/10/89
X *
X * Bugs:
X * verbose mode is not reporting consistent
X * code needs cleanup
X * prefix field is not used
X * timestamp of a directory will not be correct if there are files to be
X * unpacked in the directory
X * (add you favorite bug here (or two (or three (or ...))))
X*/
X
X#include <stdio.h> /* need NULL */
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <pwd.h>
X#include <grp.h>
X#include "tar.h"
X
X#define POSIX_COMP /* POSIX compatible */
X#define DIRECT_3 /* use directory(3) routines */
X
X#ifdef DIRECT_3
X#ifndef BSD
X/* To all minix users: i am sorry, developed this piece of code on a
X * BSD system. KS 18/10/89 */
X#include <dirent.h>
X#define direct dirent /* stupid BSD non-POSIX compatible name! */
X#else /* BSD */
X#include <sys/dir.h>
X#include <dir.h>
X#endif /* BSD */
X#endif /* DIRECT_3 */
X
X#ifdef S_IFIFO
X#define HAVE_FIFO /* have incorporated Simon Pooles' changes */
X#endif
X
Xtypedef char BOOL;
X#define TRUE 1
X#define FALSE 0
X
X#define HEADER_SIZE TBLOCK
X#define NAME_SIZE NAMSIZ
X/* #define BLOCK_BOUNDARY 20 -- not in POSIX ! */
X
Xtypedef union hblock HEADER;
X
X/* make the MINIX member names overlap to the POSIX names */
X#define m_name name
X#define m_mode mode
X#define m_uid uid
X#define m_gid gid
X#define m_size size
X#define m_time mtime
X#define m_checksum chksum
X#define m_linked typeflag
X#define m_link linkname
X#define hdr_block dummy
X#define m header
X#define member dbuf
X
X#if 0 /* original structure -- see tar.h for new structure */
Xtypedef union {
X char hdr_block[HEADER_SIZE];
X struct m {
X char m_name[NAME_SIZE];
X char m_mode[8];
X char m_uid[8];
X char m_gid[8];
X char m_size[12];
X char m_time[12];
X char m_checksum[8];
X char m_linked;
X char m_link[NAME_SIZE];
X } member;
X} HEADER;
X#endif
X
X/* structure used to note links */
Xstruct link
X{
X ino_t ino;
X dev_t dev;
X char name[NAMSIZ];
X struct link *next;
X} *link_top = NULL;
X
XHEADER header;
X
X#define INT_TYPE (sizeof(header.member.m_uid))
X#define LONG_TYPE (sizeof(header.member.m_size))
X
X#define MKDIR "/bin/mkdir"
X
X#define NIL_HEADER ((HEADER *) 0)
X#define NIL_PTR ((char *) 0)
X#define BLOCK_SIZE TBLOCK
X
X#define flush() print(NIL_PTR)
X
XBOOL show_fl, creat_fl, ext_fl;
X
Xint tar_fd;
X/* char usage[] = "Usage: tar [cxt] tarfile [files]."; */
Xchar usage[] = "Usage: tar [cxt][vo][F][f] tarfile [files].";
Xchar io_buffer[BLOCK_SIZE];
Xchar path[NAME_SIZE];
Xchar pathname[NAME_SIZE];
Xint force_flag = 0;
X#ifdef ORIGINAL_DEFAULTS
Xint chown_flag = 1;
Xint verbose_flag = 1;
X#else
Xint chown_flag = 0;
Xint verbose_flag = 0;
X#endif
X
X/* make sure we don't tar ourselves. marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
Xino_t ar_inode; /* archive inode number */
Xdev_t ar_dev; /* archive device number */
X
Xint total_blocks;
Xint u_mask; /* one's complement of current umask */
X
Xlong convert();
X
X#define block_size() (int) ((convert(header.member.m_size, LONG_TYPE) \
X + (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE)
X
Xerror(s1, s2)
Xchar *s1, *s2;
X{
X string_print(NIL_PTR, "%s %s\n", s1, s2 ? s2 : "");
X flush();
X exit(1);
X}
X
Xmain(argc, argv)
Xint argc;
Xregister char *argv[];
X{
X register char *ptr;
X struct stat st;
X int i;
X
X if (argc < 3)
X error(usage, NIL_PTR);
X
X for (ptr = argv[1]; *ptr; ptr++) {
X switch (*ptr) {
X case 'c' :
X creat_fl = TRUE;
X break;
X case 'x' :
X ext_fl = TRUE;
X break;
X case 't' :
X show_fl = TRUE;
X break;
X case 'v' : /* verbose output -Dal */
X verbose_flag = !verbose_flag;
X break;
X case 'o' : /* chown/chgrp files -Dal */
X chown_flag = TRUE;
X break;
X case 'F' : /* IGNORE ERRORS -Dal */
X force_flag = TRUE;
X break;
X case 'f': /* standard U*IX usage -KS */
X break;
X default :
X error(usage, NIL_PTR);
X }
X }
X
X if (creat_fl + ext_fl + show_fl != 1)
X error(usage, NIL_PTR);
X
X if (strcmp(argv[2], "-") == 0) /* only - means stdin/stdout - KS */
X tar_fd = creat_fl ? 1 : 0; /* '-' means used stdin/stdout -Dal */
X else
X tar_fd = creat_fl ? creat(argv[2], 0666) : open(argv[2], 0);
X
X if (tar_fd < 0)
X error("Cannot open ", argv[2]);
X
X if (geteuid()) /* check if super-user */
X { int save_umask;
X save_umask = umask( 0 );
X u_mask = ~ save_umask;
X umask( save_umask );
X chown_flag = TRUE; /* normal user can't chown */
X } else
X u_mask = 0777; /* don't restrict if 'privileged utiliy' */
X
X ar_dev = -1; /* impossible device nr */
X if (creat_fl) {
X if (tar_fd > 1 && fstat(tar_fd, &st) < 0)
X error("Can't stat ", argv[2]); /* will never be here, right? */
X else { /* get archive inode & device */
X ar_inode= st.st_ino; /* save files inode */
X ar_dev = st.st_dev; /* save files device */
X } /* marks@mgse Mon Sep 25 11:30:45 CDT 1989 */
X
X for (i = 3; i < argc; i++) {
X add_file(argv[i]);
X path[0] = '\0';
X }
X adjust_boundary();
X }
X else
X tarfile();
X
X flush();
X exit(0);
X}
X
XBOOL get_header()
X{
X register int check;
X
X mread(tar_fd, (char *) &header, sizeof(header));
X if (header.member.m_name[0] == '\0')
X return FALSE;
X
X if (force_flag) /* skip checksum verification -Dal */
X return TRUE;
X
X check = (int) convert(header.member.m_checksum, INT_TYPE);
X
X if (check != checksum())
X error("Tar: header checksum error.", NIL_PTR);
X
X return TRUE;
X}
X
Xtarfile()
X{
X register char *ptr;
X register char *mem_name;
X
X while (get_header()) {
X mem_name = header.member.m_name;
X if (ext_fl) {
X if (is_dir(mem_name)) {
X for (ptr = mem_name; *ptr; ptr++)
X ;
X *(ptr - 1) = '\0';
X header.dbuf.typeflag = '5';
X }
X extract(mem_name);
X }
X else {
X string_print(NIL_PTR, "%s%s", mem_name,
X (verbose_flag ? " " : "\n"));
X switch(header.dbuf.typeflag)
X { case '1':
X verbose_print("linked to", header.dbuf.linkname );
X break;
X case '6':
X verbose_print("","fifo");
X break;
X case '3':
X case '4':
X if (verbose_flag)
X string_print(NIL_PTR,
X "%s special file major %s minor %s\n",
X (header.dbuf.typeflag == '3' ?
X "character" : "block" ),
X header.dbuf.devmajor, header.dbuf.devminor );
X break;
X case '0': /* official POSIX */
X case 0: /* also mentioned in POSIX */
X case ' ': /* ofetn used */
X if (!is_dir(mem_name))
X {
X if (verbose_flag)
X string_print(NIL_PTR, "%d tape blocks\n",
X block_size());
X skip_entry();
X break;
X } else /* FALL TROUGH */
X case '5':
X verbose_print("","directory");
X break;
X default:
X string_print(NIL_PTR,"not recogised item %d\n",
X header.dbuf.typeflag );
X }
X }
X flush();
X }
X}
X
Xskip_entry()
X{
X register int blocks = block_size();
X
X while (blocks--)
X (void) read(tar_fd, io_buffer, BLOCK_SIZE);
X}
X
Xextract(file)
Xregister char *file;
X{
X register int fd;
X
X switch( header.dbuf.typeflag )
X { case '1': /* Link */
X if (link(header.member.m_link, file) < 0)
X string_print(NIL_PTR, "Cannot link %s to %s\n",
X header.member.m_link, file);
X else if (verbose_flag)
X string_print(NIL_PTR, "Linked %s to %s\n",
X header.member.m_link, file);
X return;
X case '5': /* directory */
X if (mkdir(file) == 0)
X {
X do_chown( file );
X verbose_print("created directory", file );
X } /* no else: mkdir will print a message if it fails */
X return;
X case '3': /* character special */
X case '4': /* block special */
X { int dmajor, dminor, mode;
X
X dmajor = (int)convert(header.dbuf.devmajor, INT_TYPE);
X dminor = (int)convert(header.dbuf.devminor, INT_TYPE);
X mode = (header.dbuf.typeflag == '3' ? S_IFCHR : S_IFBLK);
X if (mknod( file, mode, (dmajor << 8 | dminor)) == 0)
X {
X if (verbose_flag)
X string_print( NIL_PTR,
X "made %s special file major %s minor %s\n",
X (header.dbuf.typeflag == '3' ?
X "character" : "block" ),
X header.dbuf.devmajor, header.dbuf.devminor );
X do_chown( file );
X }
X return;
X }
X case '2': /* symbolic link */
X case '7': /* contiguous file -- what is this (KS) */
X print("Not implemented file type\n");
X return; /* not implemented, but break out */
X#ifdef HAVE_FIFO
X case '6': /* fifo */
X if (mkfifo(file,0) == 0) /* is chmod'ed in do_chown */
X {
X do_chown( file );
X verbose_print("made fifo", file );
X }
X else
X string_print(NIL_PTR, "Can't make fifo %s\n", file );
X return;
X#endif
X }
X
X /* security change: creat with mode 0600, chown and then chmod -- KS */
X if ((fd = creat(file, 0600)) < 0) {
X string_print(NIL_PTR, "Cannot create %s\n", file);
X return;
X }
X
X copy(file, tar_fd, fd, convert(header.member.m_size, LONG_TYPE));
X (void) close(fd);
X
X do_chown( file );
X}
X
Xdo_chown( file )
Xchar *file;
X{ int uid = -1, gid = -1; /* these are illegal ??? -- KS */
X
X if(!chown_flag) { /* set correct owner and group -Dal */
X if (header.dbuf.magic[TMAGLEN] == ' ')
X header.dbuf.magic[TMAGLEN] == '\0'; /* some tars out there ... */
X if (strncmp(TMAGIC, header.dbuf.magic, TMAGLEN))
X { struct passwd *pwd, *getpwnam();
X struct group *grp, *getgrnam();
X
X pwd = getpwnam(header.dbuf.uname);
X if (pwd != NULL)
X uid = pwd->pw_uid;
X grp = getgrnam(header.dbuf.gname);
X if (grp != NULL)
X gid = grp->gr_gid;
X }
X if (uid == -1)
X uid = (int)convert(header.member.m_uid, INT_TYPE);
X if (gid == -1)
X gid = (int)convert(header.member.m_gid, INT_TYPE);
X chown(file, uid, gid );
X }
X chmod(file, u_mask & (int)convert(header.member.m_mode, INT_TYPE));
X
X /* should there be a timestamp if the chown failes? -- KS */
X timestamp(file);
X
X}
X
Xtimestamp( file )
Xchar *file;
X{
X time_t times[2];
X
X times[0] = times[1] = (long)convert(header.dbuf.mtime, LONG_TYPE);
X utime( file, times );
X}
X
Xcopy(file, from, to, bytes)
Xchar *file;
Xint from, to;
Xregister long bytes;
X{
X register int rest;
X int blocks = (int) ((bytes + (long) BLOCK_SIZE - 1) / (long) BLOCK_SIZE);
X
X if (verbose_flag)
X string_print(NIL_PTR, "%s, %d tape blocks\n", file, blocks);
X
X while (blocks--) {
X (void) read(from, io_buffer, BLOCK_SIZE);
X rest = (bytes > (long) BLOCK_SIZE) ? BLOCK_SIZE : (int) bytes;
X mwrite(to, io_buffer, (to == tar_fd) ? BLOCK_SIZE : rest);
X bytes -= (long) rest;
X }
X}
X
Xlong convert(str, type)
Xchar str[];
Xint type;
X{
X register long ac = 0L;
X register int i;
X
X for (i = 0; i < type; i++) {
X if (str[i] >= '0' && str[i] <= '7') {
X ac <<= 3;
X ac += (long) (str[i] - '0');
X }
X }
X
X return ac;
X}
X
Xmkdir(dir_name)
Xchar *dir_name;
X{
X register int pid, w;
X int ret;
X
X /* why not allow to mkdir(../directory)? -- changed now KS 2/10/89 */
X if ((dir_name[0] == '.') && (dir_name[1] == '\0'))
X return 0;
X
X if ((pid = fork()) < 0)
X error("Cannot fork().", NIL_PTR);
X
X if (pid == 0) {
X execl(MKDIR, "mkdir", dir_name, (char *) 0);
X error("Cannot execute mkdir.", NIL_PTR);
X }
X
X do {
X w = wait(&ret);
X } while (w != -1 && w != pid);
X
X return ret;
X}
X
Xchecksum()
X{
X register char *ptr = header.member.m_checksum;
X register int ac = 0;
X
X while (ptr < &header.member.m_checksum[INT_TYPE])
X *ptr++ = ' ';
X
X ptr = header.hdr_block;
X while (ptr < &header.hdr_block[BLOCK_SIZE])
X ac += *ptr++;
X
X return ac;
X}
X
Xis_dir(file)
Xregister char *file;
X{
X while (*file++ != '\0')
X ;
X
X return (*(file - 2) == '/');
X}
X
X
Xchar *path_name(file)
Xregister char *file;
X{
X
X string_print(pathname, "%s%s", path, file);
X return pathname;
X}
X
Xadd_path(name)
Xregister char *name;
X{
X register char *path_ptr = path;
X
X while (*path_ptr)
X path_ptr++;
X
X if (name == NIL_PTR) {
X while (*path_ptr-- != '/')
X ;
X while (*path_ptr != '/' && path_ptr != path)
X path_ptr--;
X if (*path_ptr == '/')
X path_ptr++;
X *path_ptr = '\0';
X }
X else {
X while (*name) {
X if (path_ptr == &path[NAME_SIZE])
X error("Pathname too long", NIL_PTR);
X *path_ptr++ = *name++;
X }
X *path_ptr++ = '/';
X *path_ptr = '\0';
X }
X}
X
X/*
X * add a file to the archive
X*/
Xadd_file(file)
Xregister char *file;
X{
X struct stat st;
X#ifdef DIRECT_3
X struct direct dir;
X#endif
X register int fd = -1;
X char namebuf[16]; /* -Dal */
X char cwd[129]; /* -KS */
X char *getcwd(); /* marks@mgse Mon Sep 25 10:06:08 CDT 1989 */
X
X if (stat(file, &st) < 0) {
X string_print(NIL_PTR, "Cannot find %s\n", file);
X return;
X }
X
X if (st.st_dev == ar_dev && st.st_ino == ar_inode) {
X string_print(NIL_PTR, "Cannot tar current archive file (%s)\n", file);
X return;
X } /* marks@mgse Mon Sep 25 12:06:28 CDT 1989 */
X
X if ((fd = add_open(file,&st)) < 0) {
X string_print(NIL_PTR, "Cannot open %s\n", file);
X return;
X }
X
X make_header(path_name(file), &st);
X switch(st.st_mode & S_IFMT)
X { case S_IFREG:
X header.dbuf.typeflag = '0';
X string_print(header.member.m_checksum, "%I ", checksum());
X mwrite(tar_fd, (char *) &header, sizeof(header));
X copy(path_name(file), fd, tar_fd, (long)st.st_size);
X break;
X case S_IFDIR:
X header.dbuf.typeflag = '5';
X string_print(header.member.m_checksum, "%I ", checksum());
X mwrite(tar_fd, (char *) &header, sizeof(header));
X if (NULL == getcwd( cwd, 129 ))
X string_print(NIL_PTR, "Error: cannot getcwd()\n" );
X else if (chdir(file) < 0)
X string_print(NIL_PTR, "Cannot chdir to %s\n", file);
X else {
X is_added( &st, file );
X verbose_print("read directory", file );
X add_path(file);
X#ifdef DIRECT_3
X { DIR *dirp;
X struct direct *dp;
X
X dirp = opendir( "." );
X while( NULL != (dp = readdir(dirp)) )
X if ((strcmp(dp->d_name, ".") == 0) ||
X (strcmp(dp->d_name, "..") == 0))
X continue;
X else
X { strcpy(namebuf, dp->d_name);
X add_file( namebuf );
X }
X closedir( dirp );
X }
X#else
X mread(fd, &dir, sizeof(dir)); /* "." */
X mread(fd, &dir, sizeof(dir)); /* ".." */
X while (read(fd, &dir, sizeof(dir)) == sizeof(dir))
X if (dir.d_ino) {
X strncpy(namebuf, dir.d_name, 14);
X namebuf[14] = '\0';
X add_file(namebuf);
X }
X#endif
X chdir(cwd);
X add_path(NIL_PTR);
X *file = 0;
X }
X break;
X#ifdef HAVE_FIFO
X case S_IFIFO:
X header.dbuf.typeflag = '6';
X verbose_print("read fifo", file );
X string_print(header.member.m_checksum, "%I ", checksum());
X mwrite(tar_fd, (char *) &header, sizeof(header));
X break;
X#endif
X case S_IFBLK:
X header.dbuf.typeflag = '4';
X if (verbose_flag)
X string_print(NIL_PTR,
X "read block device %s major %s minor %s\n",
X file, header.dbuf.devmajor, header.dbuf.devminor );
X string_print(header.member.m_checksum, "%I ", checksum());
X mwrite(tar_fd, (char *) &header, sizeof(header));
X break;
X case S_IFCHR:
X header.dbuf.typeflag = '3';
X if (verbose_flag)
X string_print(NIL_PTR,
X "read character device %s major %s minor %s\n",
X file, header.dbuf.devmajor, header.dbuf.devminor );
X string_print(header.member.m_checksum, "%I ", checksum());
X mwrite(tar_fd, (char *) &header, sizeof(header));
X break;
X case -1 & S_IFMT:
X header.dbuf.typeflag = '1';
X if (verbose_flag)
X string_print(NIL_PTR, "linked %s to %s\n",
X header.dbuf.linkname, file );
X string_print(header.member.m_checksum, "%I ", checksum());
X mwrite(tar_fd, (char *) &header, sizeof(header));
X break;
X default:
X string_print(NIL_PTR, "Tar: %s unknown file type. Not added.\n", file);
X *file = 0;
X }
X
X flush();
X is_added( &st, file );
X add_close(fd);
X}
X
Xverbose_print( s1, s2 )
Xchar *s1, *s2;
X{
X if (verbose_flag)
X string_print(NIL_PTR, "%s: %s\n", s1, s2 );
X}
X
Xadd_close( fd )
Xint fd;
X{
X if (fd != 0)
X close( fd );
X}
X
X/*
X * open file 'file' to be added to archive, return file descriptor
X*/
Xadd_open( file, st )
Xchar *file;
Xstruct stat *st;
X{
X int fd;
X if (((st->st_mode & S_IFMT) != S_IFREG) &&
X ((st->st_mode & S_IFMT) != S_IFDIR))
X return 0;
X fd = open(file, 0);
X return fd;
X}
X
Xmake_header(file, st)
Xchar *file;
Xregister struct stat *st;
X{
X register char *ptr = header.member.m_name;
X char *is_linked();
X struct passwd *pwd, *getpwuid();
X struct group *grp, *getgrgid();
X
X clear_header();
X
X while (*ptr++ = *file++)
X ;
X
X if ((st->st_mode & S_IFMT) == S_IFDIR) { /* fixed test -Dal */
X *(ptr - 1) = '/';
X }
X
X string_print(header.member.m_mode, "%I ", st->st_mode & 07777);
X string_print(header.member.m_uid, "%I ", st->st_uid);
X string_print(header.member.m_gid, "%I ", st->st_gid);
X if ((st->st_mode & S_IFMT) == S_IFREG)
X string_print(header.member.m_size, "%L ", st->st_size);
X else
X strncpy(header.dbuf.size, "0", TSIZLEN );
X string_print(header.member.m_time, "%L ", st->st_mtime);
X /* header.member.m_linked = ''; */
X if ((ptr = is_linked(st)) != NULL)
X { strncpy( header.dbuf.linkname, ptr, NAMSIZ );
X st->st_mode = -1; /* invalid value */
X }
X strncpy(header.dbuf.magic, TMAGIC, TMAGLEN );
X header.dbuf.version[0] = 0;
X header.dbuf.version[1] = 0;
X pwd = getpwuid( st->st_uid );
X strncpy(header.dbuf.uname, (pwd!=NULL?pwd->pw_name:"nobody"), TUNMLEN );
X grp = getgrgid( st->st_gid );
X strncpy(header.dbuf.gname, (grp!=NULL?grp->gr_name:"nobody"), TGNMLEN );
X if (st->st_mode & (S_IFBLK | S_IFCHR))
X { string_print(header.dbuf.devmajor, "%I ", (st->st_rdev >> 8));
X string_print(header.dbuf.devminor, "%I ", (st->st_rdev & 0xFF));
X }
X header.dbuf.prefix[0] = 0;
X}
X
Xis_added( st, file )
Xstruct stat *st;
Xchar *file;
X{
X struct link *new;
X char *malloc();
X
X if (*file == 0)
X return;
X new = (struct link *) malloc(sizeof(struct link));
X if (new == NULL)
X { print("Out of memory\n");
X return;
X }
X new->next = link_top;
X new->dev = st->st_dev;
X new->ino = st->st_ino;
X strncpy( new->name, path_name(file), NAMSIZ );
X link_top = new;
X}
X
Xchar * is_linked( st )
Xstruct stat *st;
X{
X struct link *cur = link_top;
X
X while( cur != NULL )
X if ((cur->dev == st->st_dev) && (cur->ino == st->st_ino))
X return cur->name;
X else
X cur = cur->next;
X return NULL;
X}
X
Xclear_header()
X{
X register char *ptr = header.hdr_block;
X
X while (ptr < &header.hdr_block[BLOCK_SIZE])
X *ptr++ = '\0';
X}
X
Xadjust_boundary()
X{
X clear_header();
X mwrite(tar_fd, (char *) &header, sizeof(header));
X#ifndef POSIX_COMP
X while (total_blocks++ < BLOCK_BOUNDARY)
X mwrite(tar_fd, (char *) &header, sizeof(header));
X#else
X mwrite(tar_fd, (char *) &header, sizeof(header));
X#endif
X (void) close(tar_fd);
X}
X
Xmread(fd, address, bytes)
Xint fd, bytes;
Xchar *address;
X{
X if (read(fd, address, bytes) != bytes)
X error("Tar: read error.", NIL_PTR);
X}
X
Xmwrite(fd, address, bytes)
Xint fd, bytes;
Xchar *address;
X{
X if (write(fd, address, bytes) != bytes)
X error("Tar: write error.", NIL_PTR);
X
X total_blocks++;
X}
X
Xchar output[BLOCK_SIZE];
Xprint(str) /* changed to use stderr rather than stdout -Dal */
Xregister char *str;
X{
X static int index = 0;
X
X if (str == NIL_PTR) {
X write(2, output, index);
X index = 0;
X return;
X }
X
X while (*str) {
X output[index++] = *str++;
X if (index == BLOCK_SIZE) {
X write(2, output, BLOCK_SIZE);
X index = 0;
X }
X }
X}
X
Xchar *num_out(number)
Xregister long number;
X{
X static char num_buf[12];
X register int i;
X
X for (i = 11; i--; ) {
X num_buf[i] = (number & 07) + '0';
X number >>= 3;
X }
X
X return num_buf;
X}
X
X/*VARARGS2*/
Xstring_print(buffer, fmt, args)
Xchar *buffer;
Xregister char *fmt;
Xint args;
X{
X register char *buf_ptr;
X char *scan_ptr;
X char buf[NAME_SIZE];
X char *argptr = (char *)&args;
X BOOL pr_fl, i;
X
X if (pr_fl = (buffer == NIL_PTR))
X buffer = buf;
X
X buf_ptr = buffer;
X while (*fmt) {
X if (*fmt == '%') {
X fmt++;
X switch (*fmt++) {
X case 's':
X scan_ptr = *((char **)argptr);
X argptr += sizeof(char *);
X break;
X case 'I':
X scan_ptr = num_out((long) *((int *)argptr));
X argptr += sizeof(int);
X for (i = 0; i < 5; i++)
X scan_ptr++;
X break;
X case 'L':
X scan_ptr = num_out(*((long *) argptr));
X argptr += sizeof(long);
X break;
X case 'd' :
X scan_ptr = num_out((long) *((int *)argptr));
X argptr += sizeof(int);
X while (*scan_ptr == '0')
X scan_ptr++;
X scan_ptr--;
X break;
X default:
X scan_ptr = "";
X }
X while (*buf_ptr++ = *scan_ptr++)
X ;
X buf_ptr--;
X }
X else
X *buf_ptr++ = *fmt++;
X }
X *buf_ptr = '\0';
X
X if (pr_fl)
X print(buffer);
X}
X
SHAR_EOF
if test 21445 -ne "`wc -c < 'tar.c'`"
then
echo shar: error transmitting "'tar.c'" '(should have been 21445 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tar.h'" '(1390 characters)'
if test -f 'tar.h'
then
echo shar: will not over-write existing file "'tar.h'"
else
sed 's/^X//' << \SHAR_EOF > 'tar.h'
X/*
X * tar.h -- Standard Archive Format
X * USTAR - Uniform Standard Tape Archive
X *
X * As published in POSIX standard IEEE Std 1003.1 (draft 1986)
X *
X * Klamer Schutte 3/'89
X */
X
X#define TBLOCK 512
X#define NAMSIZ 100
X#define PFXSIZ 155
X
X#define TMODLEN 8
X#define TUIDLEN 8
X#define TGIDLEN 8
X#define TSIZLEN 12
X#define TMTMLEN 12
X#define TCKSLEN 8
X
X#define TMAGIC "ustar"
X#define TMAGLEN 6
X#define TVERSION "00"
X#define TVERSLEN 2
X#define TUNMLEN 32
X#define TGNMLEN 32
X#define TDEVLEN 8
X
X#define REGTYPE '0'
X#define AREGTYPE '\0'
X#define LNKTYPE '1'
X#define SYMTYPE '2'
X#define CHRTYPE '3'
X#define BLKTYPE '4'
X#define DIRTYPE '5'
X#define FIFOTYPE '6'
X#define CONTTYPE '7'
X
X#define TSUID 04000
X#define TSGID 02000
X#define TSVTX 01000
X
X#define TUREAD 00400
X#define TUWRITE 00200
X#define TUEXEC 00100
X#define TGREAD 00040
X#define TGWRITE 00020
X#define TGEXEC 00010
X#define TOREAD 00004
X#define TOWRITE 00002
X#define TOEXEC 00001
X
Xunion hblock {
X char dummy[TBLOCK];
X struct header {
X char name[NAMSIZ];
X char mode[TMODLEN];
X char uid[TUIDLEN];
X char gid[TGIDLEN];
X char size[TSIZLEN];
X char mtime[TMTMLEN];
X char chksum[TCKSLEN];
X char typeflag;
X char linkname[NAMSIZ];
X char magic[TMAGLEN];
X char version[TVERSLEN];
X char uname[TUNMLEN];
X char gname[TGNMLEN];
X char devmajor[TDEVLEN];
X char devminor[TDEVLEN];
X char prefix[PFXSIZ];
X } dbuf;
X};
SHAR_EOF
if test 1390 -ne "`wc -c < 'tar.h'`"
then
echo shar: error transmitting "'tar.h'" '(should have been 1390 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
--
_____________________Yes, mail address changed again :-(________________________
Klamer Schutte mcvax!nikhefh!{n62,Schutte} {Schutte,n62}@nikhef.nl