Path: utzoo!attcan!uunet!mcsun!hp4nl!nikhefh!n62 From: n62@nikhefh.nikhef.nl (Klamer Schutte) Newsgroups: comp.os.minix Subject: POSIX compatible tar(1) Message-ID: <261@nikhefh.nikhef.nl> Date: 22 Sep 89 11:39:47 GMT Reply-To: Schutte@nikhefh.nikhef.nl (Klamer Schutte) Organization: Nikhef-H, Amsterdam (the Netherlands). Lines: 1185 Here is a new version of tar(1). This version is to be POSIX compatible. Changes to the older tar: -- Can use - as filename for stdin/stdout (Done by Dale Schumacher). -- Can tar links, fifo's and block/character special files. -- Update the timestamp of the new files. The file tar.h is copied from the POSIX draft, I suggest placing him in /usr/include. The file getcwd.c is not written by me. It is included because it is not in the standard minix(-st) distribution. It should be in libc.a . This tar is only tested on minix-st. PC-minix should not give any problems. Since tar is now able to handle links, a complete tree with links can be moved by: $ (cd src; tar c -) | (cd dest; tar x -) When super-user tar will also fix the user name to the old one. Bugs: The prefix field in the header is not used (so filenames longer than 100 characters will not be handled correctly). When listing an old tar file regular files will be misunderstood. You can do the same but not catching this bug by using: $ tar x[v] /dev/null old.tar Not extensively tested. Please report bugs. Fixes will be appreciated. Klamer Schutte. Schutte@nikhef.nl (.signature at end) #! /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: # README # tar.h # tar.c # getcwd.c # This archive created: Fri Sep 22 13:36:49 1989 export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(1162 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else sed 's/^X//' << \SHAR_EOF > 'README' XHere is a new version of tar(1). X XThis version is to be POSIX compatible. XChanges to the older tar: X -- Can use - as filename for stdin/stdout (Done by Dale Schumacher). X -- Can tar links, fifo's and block/character special files. X -- Update the timestamp of the new files. X XThe file tar.h is copied from the POSIX draft, I suggest placing him in X/usr/include. XThe file getcwd.c is not written by me. It is included because it is Xnot in the standard minix(-st) distribution. It should be in libc.a . X XThis tar is only tested on minix-st. PC-minix should not give any Xproblems. X XSince tar is now able to handle links, a complete tree with links Xcan be moved by: X$ (cd src; tar c -) | (cd dest; tar x -) X XWhen super-user tar will also fix the user name to the old one. X XBugs: X The prefix field in the header is not used (so filenames longer than X 100 characters will not be handled correctly). X When listing an old tar file regular files will be misunderstood. X You can do the same but not catching this bug by using: X$ tar x[v] /dev/null old.tar X Not extensively tested. Please report bugs. Fixes will be appreciated. X XKlamer Schutte. XSchutte@nikhef.nl SHAR_EOF if test 1162 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 1162 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 echo shar: extracting "'tar.c'" '(17200 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] 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 * Bugs: X * verbose mode is not reporting consistent X * code needs cleanup X * prefix field is not used X * (add you favorite bug here (or two (or three (or ...)))) X */ X X#include /* need NULL */ X#include X#include X#include X#include X#include X X#include "tar.h" X#define POSIX_COMP /* POSIX compatible */ 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{ int dev, ino; 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] 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 Xint total_blocks; 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 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], 0644) : open(argv[2], 0); X X if (tar_fd < 0) X error("Cannot open ", argv[2]); X X if (creat_fl) { 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, &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 mkdir(mem_name); X } X else 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 '5': X verbose_print("","directory"); 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': X case 0: X if (verbose_flag) X string_print(NIL_PTR, "%d tape blocks\n", X block_size()); X skip_entry(); 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 /* warning -- should not occur because name should end with a / */ X if (mkdir(file) == 0) X { X do_chown( file ); X } 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 = 0, gid = 0; X X if(!chown_flag) { /* set correct owner and group -Dal */ X if (strcmp(TMAGIC,header.dbuf.magic)) X { struct passwd *pwd, *getpwnam(); X struct group *grp, *getgrnam(); X X pwd = getpwnam(header.dbuf.uname); X if (pwd != NULL) uid = pwd->pw_uid; X grp = getgrnam(header.dbuf.gname); X if (grp != NULL) gid = grp->gr_gid; X } else { X uid = (int)convert(header.member.m_uid, INT_TYPE); X gid = (int)convert(header.member.m_gid, INT_TYPE); X } X chown(file, uid, gid ); X } X chmod(file, (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 long times[2]; X X times[0] = times[1] = (long)convert(header.dbuf.mtime); 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 } else /* don't want to generate an error, but what? -- KS */ X return ac; X } X X return ac; X} X Xmkdir(dir_name) Xchar *dir_name; X{ X register int pid, w; X X if ((dir_name[0] == '.') && ((dir_name[1] == '\0') || (dir_name[1] == '.'))) X return; 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 find mkdir.", NIL_PTR); X } X X do { X w = wait((int *) 0); X } while (w != -1 && w != pid); 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 Xadd_file(file) Xregister char *file; X{ X struct stat st; X struct direct dir; X register int fd = -1; X char namebuf[16]; /* -Dal */ X char cwd[129]; /* -KS */ X X if (stat(file, &st) < 0) { X string_print(NIL_PTR, "Cannot find %s\n", file); X return; 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, &header, sizeof(header)); X copy(path_name(file), fd, tar_fd, 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, &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( file ); X verbose_print("read directory", file ); X add_path(file); 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 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, &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, &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, &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, &header, sizeof(header)); X break; X default: X string_print("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 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, &header, sizeof(header)); X#ifndef POSIX_COMP X while (total_blocks++ < BLOCK_BOUNDARY) X mwrite(tar_fd, &header, sizeof(header)); X#else X mwrite(tar_fd, &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/* VARARGS */ 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 17200 -ne "`wc -c < 'tar.c'`" then echo shar: error transmitting "'tar.c'" '(should have been 17200 characters)' fi fi # end of overwriting check echo shar: extracting "'getcwd.c'" '(2876 characters)' if test -f 'getcwd.c' then echo shar: will not over-write existing file "'getcwd.c'" else sed 's/^X//' << \SHAR_EOF > 'getcwd.c' X#include "lib.h" X X/* getcwd(3) X * X * Author: Terrence W. Holm Aug. 1988 X * X * Directly derived from Adri Koppes' pwd(1). X */ X X#include X#include X#include X#include X X#define NULL (char *) 0 X#define O_RDONLY 0 X#define DIRECT_SIZE ((int)sizeof (struct direct)) X#define PATH_MAX 127 X X#ifdef __STDC__ Xextern char *rindex(CONST char *, int); X#else Xextern char *rindex(); X#endif X Xextern int errno; X X Xchar *getcwd( buffer, size ) X char *buffer; X int size; X X { X static char path[ PATH_MAX + 1 ]; X struct stat current; X X if ( buffer == NULL || size == 0 ) X { X errno = EINVAL; X return( NULL ); X } X X path[0] = '\0'; X X /* Get the inode for the current directory */ X X if ( stat( ".", ¤t ) == -1 ) X return( NULL ); X X if ( (current.st_mode & S_IFMT) != S_IFDIR ) X return( NULL ); X X X /* Run backwards up the directory tree, grabbing */ X /* directory names on the way. */ X X while (1) X { X struct stat parent; X struct direct d; X int same_device = 0; X int found = 0; X int fd; X X /* Get the inode for the parent directory */ X X if ( chdir( ".." ) == -1 ) X return( NULL ); X X if ( stat( ".", &parent ) == -1 ) X return( NULL ); X X if ( (parent.st_mode & S_IFMT) != S_IFDIR ) X return( NULL ); X X if ( current.st_dev == parent.st_dev ) X same_device = 1; X X X /* At the root, "." is the same as ".." */ X X if ( same_device && current.st_ino == parent.st_ino ) X break; X X X /* Search the parent directory for the current entry */ X X if ( (fd = open( ".", O_RDONLY )) == -1 ) X return( NULL ); X X while ( ! found && read(fd, &d, DIRECT_SIZE) == DIRECT_SIZE ) X { X if ( same_device ) X { X if ( current.st_ino == d.d_ino ) X found = 1; X } X else X { X static char temp_name[ DIRSIZ + 1 ]; X static struct stat dir_entry; X X temp_name[0] = '\0'; X strncat( temp_name, d.d_name, DIRSIZ ); X X if ( stat( temp_name, &dir_entry ) == -1 ) X { X close( fd ); X return( NULL ); X } X X if ( current.st_dev == dir_entry.st_dev && X current.st_ino == dir_entry.st_ino ) X found = 1; X } X } X X close( fd ); X X if ( ! found ) X return( NULL ); X X if ( strlen(path) + DIRSIZ + 1 > PATH_MAX ) X { X errno = ERANGE; X return( NULL ); X } X X strcat( path, "/" ); X strncat( path, d.d_name, DIRSIZ ); X X current.st_dev = parent.st_dev; X current.st_ino = parent.st_ino; X } X X X /* Copy the reversed path name into */ X X if ( strlen(path) + 1 > size ) X { X errno = ERANGE; X return( NULL ); X } X X if ( strlen(path) == 0 ) X { X strcpy( buffer, "/" ); X return( buffer ); X } X X *buffer = '\0'; X X { X char *r; X X while ( (r = rindex( path, '/' )) != NULL ) X { X strcat( buffer, r ); X *r = '\0'; X } X } X X return( chdir( buffer ) ? NULL : buffer ); X } SHAR_EOF if test 2876 -ne "`wc -c < 'getcwd.c'`" then echo shar: error transmitting "'getcwd.c'" '(should have been 2876 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