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