implemented numeric sort (sort -g)
[oweals/busybox.git] / tar.c
diff --git a/tar.c b/tar.c
index 03da96735e6913bacdd9491c43504d0278667e4b..438770c034460f6253a11ed1811bb4a86cee89da 100644 (file)
--- a/tar.c
+++ b/tar.c
@@ -1,34 +1,54 @@
 /*
+ * Mini tar implementation for busybox based on code taken from sash.
+ *
  * Copyright (c) 1999 by David I. Bell
  * Permission is granted to use, distribute, or modify this source,
  * provided that this copyright notice remains intact.
  *
- * The "tar" command, taken from sash.
- * This allows creation, extraction, and listing of tar files.
- *
  * Permission to distribute this code under the GPL has been granted.
- * Modified for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com>
+ *
+ * Modified for busybox by Erik Andersen <andersee@debian.org>
+ * Adjusted to grok stdin/stdout options.
+ *
+ * Modified to handle device special files by Matt Porter
+ * <porter@debian.org>
+ *
+ * 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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
  */
 
 
 #include "internal.h"
-
-#ifdef BB_TAR
-
-const char tar_usage[] = 
-"Create, extract, or list files from a TAR file\n\n"
-"usage: tar -[cxtvOf] [tarFileName] [FILE] ...\n"
-"\tc=create, x=extract, t=list contents, v=verbose,\n"
-"\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
-
-
-
 #include <stdio.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <time.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+
+
+static const char tar_usage[] =
+"tar -[cxtvOf] [tarFileName] [FILE] ...\n\n"
+"Create, extract, or list files from a tar file\n\n"
+"Options:\n"
+"\tc=create, x=extract, t=list contents, v=verbose,\n"
+"\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
+
+
 
 /*
  * Tar file constants.
@@ -42,24 +62,23 @@ const char tar_usage[] =
  * This structure is always embedded in a TAR_BLOCK_SIZE sized block
  * with zero padding.  We only process this information minimally.
  */
-typedef struct
-{
-       char    name[TAR_NAME_SIZE];
-       char    mode[8];
-       char    uid[8];
-       char    gid[8];
-       char    size[12];
-       char    mtime[12];
-       char    checkSum[8];
-       char    typeFlag;
-       char    linkName[TAR_NAME_SIZE];
-       char    magic[6];
-       char    version[2];
-       char    uname[32];
-       char    gname[32];
-       char    devMajor[8];
-       char    devMinor[8];
-       char    prefix[155];
+typedef struct {
+    char name[TAR_NAME_SIZE];
+    char mode[8];
+    char uid[8];
+    char gid[8];
+    char size[12];
+    char mtime[12];
+    char checkSum[8];
+    char typeFlag;
+    char linkName[TAR_NAME_SIZE];
+    char magic[6];
+    char version[2];
+    char uname[32];
+    char gname[32];
+    char devMajor[8];
+    char devMinor[8];
+    char prefix[155];
 } TarHeader;
 
 #define        TAR_MAGIC       "ustar"
@@ -73,172 +92,161 @@ typedef struct
 /*
  * Static data.
  */
-static BOOL            listFlag;
-static BOOL            extractFlag;
-static BOOL            createFlag;
-static BOOL            verboseFlag;
-static BOOL            tostdoutFlag;
-
-static BOOL            inHeader;
-static BOOL            badHeader;
-static BOOL            errorFlag;
-static BOOL            skipFileFlag;
-static BOOL            warnedRoot;
-static BOOL            eofFlag;
-static long            dataCc;
-static int             outFd;
-static char            outName[TAR_NAME_SIZE];
+static int listFlag;
+static int extractFlag;
+static int createFlag;
+static int verboseFlag;
+static int tostdoutFlag;
+
+static int inHeader; // <- check me
+static int badHeader;
+static int errorFlag;
+static int skipFileFlag;
+static int warnedRoot;
+static int eofFlag;
+static long dataCc;
+static int outFd;
+static char outName[TAR_NAME_SIZE];
 
 
 /*
  * Static data associated with the tar file.
  */
-static const char *    tarName;
-static int             tarFd;
-static dev_t           tarDev;
-static ino_t           tarInode;
+static const char *tarName;
+static int tarFd;
+static dev_t tarDev;
+static ino_t tarInode;
 
 
 /*
  * Local procedures to restore files from a tar file.
  */
-static void    readTarFile(int fileCount, char ** fileTable);
-static void    readData(const char * cp, int count);
-static void    createPath(const char * name, int mode);
-static long    getOctal(const char * cp, int len);
+static void readTarFile (int fileCount, char **fileTable);
+static void readData (const char *cp, int count);
+static long getOctal (const char *cp, int len);
 
-static void    readHeader(const TarHeader * hp,
-                       int fileCount, char ** fileTable);
+static void readHeader (const TarHeader * hp,
+                       int fileCount, char **fileTable);
 
 
 /*
  * Local procedures to save files into a tar file.
  */
-static void    saveFile(const char * fileName, BOOL seeLinks);
+static void saveFile (const char *fileName, int seeLinks);
 
-static void    saveRegularFile(const char * fileName,
-                       const struct stat * statbuf);
+static void saveRegularFile (const char *fileName,
+                            const struct stat *statbuf);
 
-static void    saveDirectory(const char * fileName,
-                       const struct stat * statbuf);
+static void saveDirectory (const char *fileName,
+                          const struct stat *statbuf);
 
-static BOOL    wantFileName(const char * fileName,
-                       int fileCount, char ** fileTable);
+static int wantFileName (const char *fileName,
+                        int fileCount, char **fileTable);
 
-static void    writeHeader(const char * fileName,
-                       const struct stat * statbuf);
+static void writeHeader (const char *fileName, const struct stat *statbuf);
 
-static void    writeTarFile(int fileCount, char ** fileTable);
-static void    writeTarBlock(const char * buf, int len);
-static BOOL    putOctal(char * cp, int len, long value);
-extern  const char *    modeString(int mode);
-extern  const char *    timeString(time_t timeVal);
-extern  int             fullWrite(int fd, const char * buf, int len);
-extern  int             fullRead(int fd, char * buf, int len);
+static void writeTarFile (int fileCount, char **fileTable);
+static void writeTarBlock (const char *buf, int len);
+static int putOctal (char *cp, int len, long value);
 
 
-extern int 
-tar_main(struct FileInfo *unused, int argc, char ** argv)
+extern int tar_main (int argc, char **argv)
 {
-       const char *    options;
-
+    const char *options;
+
+    argc--;
+    argv++;
+
+    if (argc < 1)
+       usage( tar_usage);
+
+
+    errorFlag = FALSE;
+    extractFlag = FALSE;
+    createFlag = FALSE;
+    listFlag = FALSE;
+    verboseFlag = FALSE;
+    tostdoutFlag = FALSE;
+    tarName = NULL;
+    tarDev = 0;
+    tarInode = 0;
+    tarFd = -1;
+
+    /* 
+     * Parse the options.
+     */
+    if (**argv == '-') {
+       options = (*argv++) + 1;
        argc--;
-       argv++;
-
-       if (argc < 1)
-       {
-               fprintf(stderr, "%s", tar_usage);
-               return 1;
-       }
-
-
-       errorFlag = FALSE;
-       extractFlag = FALSE;
-       createFlag = FALSE;
-       listFlag = FALSE;
-       verboseFlag = FALSE;
-       tostdoutFlag = FALSE;
-       tarName = NULL;
-       tarDev = 0;
-       tarInode = 0;
-       tarFd = -1;
-
-       /*
-        * Parse the options.
-        */
-       options = *argv++;
-       argc--;
-
-       if (**argv == '-') {
-               for (; *options; options++)
-               {
-                       switch (*options)
-                       {
-                               case 'f':
-                                       if (tarName != NULL)
-                                       {
-                                               fprintf(stderr, "Only one 'f' option allowed\n");
-
-                                               return 1;
-                                       }
+       for (; *options; options++) {
+           switch (*options) {
+           case 'f':
+               if (tarName != NULL) {
+                   fprintf (stderr, "Only one 'f' option allowed\n");
 
-                                       tarName = *argv++;
-                                       argc--;
-
-                                       break;
+                   exit (FALSE);
+               }
 
-                               case 't':
-                                       listFlag = TRUE;
-                                       break;
+               tarName = *argv++;
+               argc--;
 
-                               case 'x':
-                                       extractFlag = TRUE;
-                                       break;
+               break;
 
-                               case 'c':
-                                       createFlag = TRUE;
-                                       break;
+           case 't':
+               listFlag = TRUE;
+               break;
 
-                               case 'v':
-                                       verboseFlag = TRUE;
-                                       break;
+           case 'x':
+               extractFlag = TRUE;
+               break;
 
-                               case 'O':
-                                       tostdoutFlag = TRUE;
-                                       break;
+           case 'c':
+               createFlag = TRUE;
+               break;
 
-                               case '-':
-                                       break;
+           case 'v':
+               verboseFlag = TRUE;
+               break;
 
-                               default:
-                                       fprintf(stderr, "Unknown tar flag '%c'\n", *options);
+           case 'O':
+               tostdoutFlag = TRUE;
+               break;
 
-                                       return 1;
-                       }
-               }
-       }
+           case '-':
+               usage( tar_usage);
+               break;
 
-       /*
-        * Validate the options.
-        */
-       if (extractFlag + listFlag + createFlag != 1)
-       {
-               fprintf(stderr, "Exactly one of 'c', 'x' or 't' must be specified\n");
+           default:
+               fprintf (stderr, "Unknown tar flag '%c'\n"
+                       "Try `tar --help' for more information\n", 
+                       *options);
 
-               return 1;
+               exit (FALSE);
+           }
        }
-
-       /*
-        * Do the correct type of action supplying the rest of the
-        * command line arguments as the list of files to process.
-        */
-       if (createFlag)
-               writeTarFile(argc, argv);
-       else
-               readTarFile(argc, argv);
-       if (errorFlag)
-               fprintf(stderr, "\n");
-       return( errorFlag);
+    }
+
+    /* 
+     * Validate the options.
+     */
+    if (extractFlag + listFlag + createFlag != (TRUE+FALSE+FALSE)) {
+       fprintf (stderr,
+                "Exactly one of 'c', 'x' or 't' must be specified\n");
+
+       exit (FALSE);
+    }
+
+    /* 
+     * Do the correct type of action supplying the rest of the
+     * command line arguments as the list of files to process.
+     */
+    if (createFlag==TRUE)
+       writeTarFile (argc, argv);
+    else
+       readTarFile (argc, argv);
+    if (errorFlag==TRUE)
+       fprintf (stderr, "\n");
+    exit (!errorFlag);
 }
 
 
@@ -246,128 +254,119 @@ tar_main(struct FileInfo *unused, int argc, char ** argv)
  * Read a tar file and extract or list the specified files within it.
  * If the list is empty than all files are extracted or listed.
  */
-static void
-readTarFile(int fileCount, char ** fileTable)
+static void readTarFile (int fileCount, char **fileTable)
 {
-       const char *    cp;
-       int             cc;
-       int             inCc;
-       int             blockSize;
-       char            buf[BUF_SIZE];
-
-       skipFileFlag = FALSE;
-       badHeader = FALSE;
-       warnedRoot = FALSE;
-       eofFlag = FALSE;
-       inHeader = TRUE;
-       inCc = 0;
-       dataCc = 0;
-       outFd = -1;
-       blockSize = sizeof(buf);
-       cp = buf;
-
-       /*
-        * Open the tar file for reading.
-        */
-       if ( (tarName==NULL) || !strcmp( tarName, "-") ) {
-               tarFd = STDIN;
-       }
-       else 
-               tarFd = open(tarName, O_RDONLY);
+    const char *cp;
+    int cc;
+    int inCc;
+    int blockSize;
+    char buf[BUF_SIZE];
+
+    skipFileFlag = FALSE;
+    badHeader = FALSE;
+    warnedRoot = FALSE;
+    eofFlag = FALSE;
+    inHeader = TRUE;
+    inCc = 0;
+    dataCc = 0;
+    outFd = -1;
+    blockSize = sizeof (buf);
+    cp = buf;
+
+    /* 
+     * Open the tar file for reading.
+     */
+    if ((tarName == NULL) || !strcmp (tarName, "-")) {
+       tarFd = fileno(stdin);
+    } else
+       tarFd = open (tarName, O_RDONLY);
+
+    if (tarFd < 0) {
+       perror (tarName);
+       errorFlag = TRUE;
+       return;
+    }
+
+    /* 
+     * Read blocks from the file until an end of file header block
+     * has been seen.  (A real end of file from a read is an error.)
+     */
+    while (eofFlag==FALSE) {
+       /* 
+        * Read the next block of data if necessary.
+        * This will be a large block if possible, which we will
+        * then process in the small tar blocks.
+        */
+       if (inCc <= 0) {
+           cp = buf;
+           inCc = fullRead (tarFd, buf, blockSize);
+
+           if (inCc < 0) {
+               perror (tarName);
+               errorFlag = TRUE;
+               goto done;
+           }
 
-       if (tarFd < 0)
-       {
-               perror(tarName);
+           if (inCc == 0) {
+               fprintf (stderr,
+                        "Unexpected end of file from \"%s\"", tarName);
                errorFlag = TRUE;
-               return;
+               goto done;
+           }
        }
 
-       /*
-        * Read blocks from the file until an end of file header block
-        * has been seen.  (A real end of file from a read is an error.)
+       /* 
+        * If we are expecting a header block then examine it.
         */
-       while (!eofFlag)
-       {
-               /*
-                * Read the next block of data if necessary.
-                * This will be a large block if possible, which we will
-                * then process in the small tar blocks.
-                */
-               if (inCc <= 0)
-               {
-                       cp = buf;
-                       inCc = fullRead(tarFd, buf, blockSize);
-
-                       if (inCc < 0)
-                       {
-                               perror(tarName);
-                               errorFlag=TRUE;
-                               goto done;
-                       }
-
-                       if (inCc == 0)
-                       {
-                               fprintf(stderr,
-                                       "Unexpected end of file from \"%s\"",
-                                       tarName);
-                               errorFlag=TRUE;
-                               goto done;
-                       }
-               }
+       if (inHeader==TRUE) {
+           readHeader ((const TarHeader *) cp, fileCount, fileTable);
 
-               /*
-                * If we are expecting a header block then examine it.
-                */
-               if (inHeader)
-               {
-                       readHeader((const TarHeader *) cp, fileCount, fileTable);
+           cp += TAR_BLOCK_SIZE;
+           inCc -= TAR_BLOCK_SIZE;
 
-                       cp += TAR_BLOCK_SIZE;
-                       inCc -= TAR_BLOCK_SIZE;
-
-                       continue;
-               }
-
-               /*
-                * We are currently handling the data for a file.
-                * Process the minimum of the amount of data we have available
-                * and the amount left to be processed for the file.
-                */
-               cc = inCc;
-
-               if (cc > dataCc)
-                       cc = dataCc;
-
-               readData(cp, cc);
-
-               /*
-                * If the amount left isn't an exact multiple of the tar block
-                * size then round it up to the next block boundary since there
-                * is padding at the end of the file.
-                */
-               if (cc % TAR_BLOCK_SIZE)
-                       cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
-
-               cp += cc;
-               inCc -= cc;
+           continue;
        }
 
-done:
-       /*
-        * Close the tar file if needed.
-        */
-       if ((tarFd >= 0) && (close(tarFd) < 0))
-               perror(tarName);
-
-       /*
-        * Close the output file if needed.
-        * This is only done here on a previous error and so no
-        * message is required on errors.
-        */
-       if (tostdoutFlag==FALSE) {
-           if (outFd >= 0)
-                   (void) close(outFd);
-       }
+       /* 
+        * We are currently handling the data for a file.
+        * Process the minimum of the amount of data we have available
+        * and the amount left to be processed for the file.
+        */
+       cc = inCc;
+
+       if (cc > dataCc)
+           cc = dataCc;
+
+       readData (cp, cc);
+
+       /* 
+        * If the amount left isn't an exact multiple of the tar block
+        * size then round it up to the next block boundary since there
+        * is padding at the end of the file.
+        */
+       if (cc % TAR_BLOCK_SIZE)
+           cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
+
+       cp += cc;
+       inCc -= cc;
+    }
+
+  done:
+    /* 
+     * Close the tar file if needed.
+     */
+    if ((tarFd >= 0) && (close (tarFd) < 0))
+       perror (tarName);
+
+    /* 
+     * Close the output file if needed.
+     * This is only done here on a previous error and so no
+     * message is required on errors.
+     */
+    if (tostdoutFlag == FALSE) {
+       if (outFd >= 0)
+           (void) close (outFd);
+    }
 }
 
 
@@ -377,332 +376,339 @@ done:
  * the end of the tar file.
  */
 static void
-readHeader(const TarHeader * hp, int fileCount, char ** fileTable)
+readHeader (const TarHeader * hp, int fileCount, char **fileTable)
 {
-       int             mode;
-       int             uid;
-       int             gid;
-       int             checkSum;
-       long            size;
-       time_t          mtime;
-       const char *    name;
-       int             cc;
-       BOOL            hardLink;
-       BOOL            softLink;
-
-       /*
-        * If the block is completely empty, then this is the end of the
-        * archive file.  If the name is null, then just skip this header.
-        */
-       name = hp->name;
-
-       if (*name == '\0')
-       {
-               for (cc = TAR_BLOCK_SIZE; cc > 0; cc--)
-               {
-                       if (*name++)
-                               return;
-               }
-
-               eofFlag = TRUE;
-
+    int mode;
+    int uid;
+    int gid;
+    int checkSum;
+    unsigned int major;
+    unsigned int minor;
+    long size;
+    time_t mtime;
+    const char *name;
+    int cc;
+    int hardLink;
+    int softLink;
+    int devFileFlag;
+
+    /* 
+     * If the block is completely empty, then this is the end of the
+     * archive file.  If the name is null, then just skip this header.
+     */
+    name = hp->name;
+
+    if (*name == '\0') {
+       for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
+           if (*name++)
                return;
        }
 
-       /*
-        * There is another file in the archive to examine.
-        * Extract the encoded information and check it.
-        */
-       mode = getOctal(hp->mode, sizeof(hp->mode));
-       uid = getOctal(hp->uid, sizeof(hp->uid));
-       gid = getOctal(hp->gid, sizeof(hp->gid));
-       size = getOctal(hp->size, sizeof(hp->size));
-       mtime = getOctal(hp->mtime, sizeof(hp->mtime));
-       checkSum = getOctal(hp->checkSum, sizeof(hp->checkSum));
-
-       if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0))
-       {
-               if (!badHeader)
-                       fprintf(stderr, "Bad tar header, skipping\n");
-
-               badHeader = TRUE;
-
-               return;
-       }
-
-       badHeader = FALSE;
-       skipFileFlag = FALSE;
-
-       /*
-        * Check for the file modes.
-        */
-       hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
+       eofFlag = TRUE;
+
+       return;
+    }
+
+    /* 
+     * There is another file in the archive to examine.
+     * Extract the encoded information and check it.
+     */
+    mode = getOctal (hp->mode, sizeof (hp->mode));
+    uid = getOctal (hp->uid, sizeof (hp->uid));
+    gid = getOctal (hp->gid, sizeof (hp->gid));
+    size = getOctal (hp->size, sizeof (hp->size));
+    mtime = getOctal (hp->mtime, sizeof (hp->mtime));
+    checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
+    major = getOctal (hp->devMajor, sizeof (hp->devMajor));
+    minor = getOctal (hp->devMinor, sizeof (hp->devMinor));
+
+    if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
+       if (badHeader==FALSE)
+           fprintf (stderr, "Bad tar header, skipping\n");
+
+       badHeader = TRUE;
+
+       return;
+    }
+
+    badHeader = FALSE;
+    skipFileFlag = FALSE;
+    devFileFlag = FALSE;
+
+    /* 
+     * Check for the file modes.
+     */
+    hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
                (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
 
-       softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
+    softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
                (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
 
-       /*
-        * Check for a directory or a regular file.
-        */
-       if (name[strlen(name) - 1] == '/')
-               mode |= S_IFDIR;
-       else if ((mode & S_IFMT) == 0)
-               mode |= S_IFREG;
-
-       /*
-        * Check for absolute paths in the file.
-        * If we find any, then warn the user and make them relative.
-        */
-       if (*name == '/')
-       {
-               while (*name == '/')
-                       name++;
-
-               if (!warnedRoot)
-               {
-                       fprintf(stderr,
-                       "Absolute path detected, removing leading slashes\n");
-               }
-
-               warnedRoot = TRUE;
+    /* 
+     * Check for a directory.
+     */
+    if (name[strlen (name) - 1] == '/')
+       mode |= S_IFDIR;
+
+    /* 
+     * Check for absolute paths in the file.
+     * If we find any, then warn the user and make them relative.
+     */
+    if (*name == '/') {
+       while (*name == '/')
+           name++;
+
+       if (warnedRoot==FALSE) {
+           fprintf (stderr,
+                    "Absolute path detected, removing leading slashes\n");
        }
 
-       /*
-        * See if we want this file to be restored.
-        * If not, then set up to skip it.
-        */
-       if (!wantFileName(name, fileCount, fileTable))
-       {
-               if (!hardLink && !softLink && S_ISREG(mode))
-               {
-                       inHeader = (size == 0);
-                       dataCc = size;
-               }
-
-               skipFileFlag = TRUE;
-
-               return;
+       warnedRoot = TRUE;
+    }
+
+    /* 
+     * See if we want this file to be restored.
+     * If not, then set up to skip it.
+     */
+    if (wantFileName (name, fileCount, fileTable) == FALSE) {
+       if ( !hardLink && !softLink && (S_ISREG (mode) || S_ISCHR (mode)
+                   || S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) {
+           inHeader = (size == 0)? TRUE : FALSE;
+           dataCc = size;
        }
 
-       /*
-        * This file is to be handled.
-        * If we aren't extracting then just list information about the file.
-        */
-       if (!extractFlag)
-       {
-               if (verboseFlag)
-               {
-                       printf("%s %3d/%-d %9ld %s %s", modeString(mode),
-                               uid, gid, size, timeString(mtime), name);
-               }
-               else
-                       printf("%s", name);
-
-               if (hardLink)
-                       printf(" (link to \"%s\")", hp->linkName);
-               else if (softLink)
-                       printf(" (symlink to \"%s\")", hp->linkName);
-               else if (S_ISREG(mode))
-               {
-                       inHeader = (size == 0);
-                       dataCc = size;
-               }
-
-               printf("\n");
-
-               return;
+       skipFileFlag = TRUE;
+
+       return;
+    }
+
+    /* 
+     * This file is to be handled.
+     * If we aren't extracting then just list information about the file.
+     */
+    if (extractFlag==FALSE) {
+       if (verboseFlag==TRUE) {
+           printf ("%s %3d/%-d ", modeString (mode), uid, gid);
+           if( S_ISCHR (mode) || S_ISBLK (mode) )
+               printf ("%4d,%4d %s ", major,minor, timeString (mtime));
+           else
+               printf ("%9ld %s ", size, timeString (mtime));
        }
-
-       /*
-        * We really want to extract the file.
-        */
-       if (verboseFlag)
-               printf("x %s\n", name);
+       printf ("%s", name);
 
        if (hardLink)
-       {
-               if (link(hp->linkName, name) < 0)
-                       perror(name);
-
-               return;
+           printf (" (link to \"%s\")", hp->linkName);
+       else if (softLink)
+           printf (" (symlink to \"%s\")", hp->linkName);
+       else if (S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode) || 
+               S_ISSOCK(mode) || S_ISFIFO(mode) ) {
+           inHeader = (size == 0)? TRUE : FALSE;
+           dataCc = size;
        }
 
-       if (softLink)
-       {
-#ifdef S_ISLNK
-               if (symlink(hp->linkName, name) < 0)
-                       perror(name);
-#else
-               fprintf(stderr, "Cannot create symbolic links\n");
-#endif
-               return;
-       }
-
-       /*
-        * If the file is a directory, then just create the path.
-        */
-       if (S_ISDIR(mode))
-       {
-               createPath(name, mode);
+       printf ("\n");
 
-               return;
-       }
+       return;
+    }
 
-       /*
-        * There is a file to write.
-        * First create the path to it if necessary with a default permission.
-        */
-       createPath(name, 0777);
+    /* 
+     * We really want to extract the file.
+     */
+    if (verboseFlag==TRUE)
+       printf ("x %s\n", name);
 
-       inHeader = (size == 0);
-       dataCc = size;
+    if (hardLink) {
+       if (link (hp->linkName, name) < 0)
+           perror (name);
+       chmod(name, mode);
+       chown(name, uid, gid);
+       return;
+    }
 
-       /*
-        * Start the output file.
-        */
-       if (tostdoutFlag==TRUE)
-           outFd = STDOUT;
-       else
-           outFd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
-
-       if (outFd < 0)
-       {
-               perror(name);
-               skipFileFlag = TRUE;
-               return;
+    if (softLink) {
+#ifdef S_ISLNK
+       if (symlink (hp->linkName, name) < 0)
+           perror (name);
+       chmod(name, mode);
+       chown(name, uid, gid);
+#else
+       fprintf (stderr, "Cannot create symbolic links\n");
+#endif
+       return;
+    }
+
+    /* Set the umask for this process so it doesn't 
+     * screw things up. */
+    umask(0);
+
+    /* 
+     * If the file is a directory, then just create the path.
+     */
+    if (S_ISDIR (mode)) {
+       createPath (name, mode);
+       chmod(name, mode);
+       chown(name, uid, gid);
+
+       return;
+    }
+
+    /* 
+     * There is a file to write.
+     * First create the path to it if necessary with default permissions.
+     */
+    createPath (name, 0777);
+
+    inHeader = (size == 0)? TRUE : FALSE;
+    dataCc = size;
+
+    /* 
+     * Start the output file.
+     */
+    if (tostdoutFlag == TRUE)
+       outFd = fileno(stdout);
+    else {
+       if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) {
+           devFileFlag = TRUE;
+           outFd = mknod (name, mode, makedev(major, minor) );
        }
-
-       /*
-        * If the file is empty, then that's all we need to do.
-        */
-       if (size == 0 && tostdoutFlag == FALSE)
-       {
-               (void) close(outFd);
-               outFd = -1;
+       else if (S_ISFIFO(mode) ) {
+           devFileFlag = TRUE;
+           outFd = mkfifo(name, mode);
+       } else {
+           outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
        }
+    }
+
+    if (outFd < 0) {
+       perror (name);
+       skipFileFlag = TRUE;
+       return;
+    }
+    if (tostdoutFlag == FALSE) {
+       fchmod(outFd, mode);
+       fchown(outFd, uid, gid);
+    }
+
+    /* 
+     * If the file is empty, then that's all we need to do.
+     */
+    if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
+       (void) close (outFd);
+       outFd = -1;
+    }
 }
 
 
 /*
  * Handle a data block of some specified size that was read.
  */
-static void
-readData(const char * cp, int count)
+static void readData (const char *cp, int count)
 {
-       /*
-        * Reduce the amount of data left in this file.
-        * If there is no more data left, then we need to read
-        * the header again.
-        */
-       dataCc -= count;
-
-       if (dataCc <= 0)
-               inHeader = TRUE;
-
-       /*
-        * If we aren't extracting files or this file is being
-        * skipped then do nothing more.
-        */
-       if (!extractFlag || skipFileFlag)
-               return;
+    /* 
+     * Reduce the amount of data left in this file.
+     * If there is no more data left, then we need to read
+     * the header again.
+     */
+    dataCc -= count;
+
+    if (dataCc <= 0)
+       inHeader = TRUE;
 
-       /*
-        * Write the data to the output file.
-        */
-       if (fullWrite(outFd, cp, count) < 0)
-       {
-               perror(outName);
-               if (tostdoutFlag==FALSE) {
-                   (void) close(outFd);
-                   outFd = -1;
-               }
-               skipFileFlag = TRUE;
-               return;
+    /* 
+     * If we aren't extracting files or this file is being
+     * skipped then do nothing more.
+     */
+    if (extractFlag==FALSE || skipFileFlag==TRUE)
+       return;
+
+    /* 
+     * Write the data to the output file.
+     */
+    if (fullWrite (outFd, cp, count) < 0) {
+       perror (outName);
+       if (tostdoutFlag == FALSE) {
+           (void) close (outFd);
+           outFd = -1;
        }
+       skipFileFlag = TRUE;
+       return;
+    }
+
+    /* 
+     * If the write failed, close the file and disable further
+     * writes to this file.
+     */
+    if (dataCc <= 0 && tostdoutFlag == FALSE) {
+       if (close (outFd))
+           perror (outName);
 
-       /*
-        * If the write failed, close the file and disable further
-        * writes to this file.
-        */
-       if (dataCc <= 0 && tostdoutFlag==FALSE)
-       {
-               if (close(outFd))
-                       perror(outName);
-
-               outFd = -1;
-       }
+       outFd = -1;
+    }
 }
 
 
 /*
  * Write a tar file containing the specified files.
  */
-static void
-writeTarFile(int fileCount, char ** fileTable)
+static void writeTarFile (int fileCount, char **fileTable)
 {
-       struct  stat    statbuf;
-
-       /*
-        * Make sure there is at least one file specified.
-        */
-       if (fileCount <= 0)
-       {
-               fprintf(stderr, "No files specified to be saved\n");
-               errorFlag=TRUE;
-       }
-
-       /*
-        * Create the tar file for writing.
-        */
-       if ( (tarName==NULL) || !strcmp( tarName, "-") ) {
-               tostdoutFlag = TRUE;
-               tarFd = STDOUT;
-       }
-       else 
-               tarFd = open(tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
-
-       if (tarFd < 0)
-       {
-               perror(tarName);
-               errorFlag=TRUE;
-               return;
-       }
-
-       /*
-        * Get the device and inode of the tar file for checking later.
-        */
-       if (fstat(tarFd, &statbuf) < 0)
-       {
-               perror(tarName);
-               errorFlag = TRUE;
-               goto done;
-       }
-
-       tarDev = statbuf.st_dev;
-       tarInode = statbuf.st_ino;
-
-       /*
-        * Append each file name into the archive file.
-        * Follow symbolic links for these top level file names.
-        */
-       while (!errorFlag && (fileCount-- > 0))
-       {
-               saveFile(*fileTable++, FALSE);
-       }
-
-       /*
-        * Now write an empty block of zeroes to end the archive.
-        */
-       writeTarBlock("", 1);
-
-
-done:
-       /*
-        * Close the tar file and check for errors if it was opened.
-        */
-       if ( (tostdoutFlag==FALSE) && (tarFd >= 0) && (close(tarFd) < 0))
-               perror(tarName);
+    struct stat statbuf;
+
+    /* 
+     * Make sure there is at least one file specified.
+     */
+    if (fileCount <= 0) {
+       fprintf (stderr, "No files specified to be saved\n");
+       errorFlag = TRUE;
+    }
+
+    /* 
+     * Create the tar file for writing.
+     */
+    if ((tarName == NULL) || !strcmp (tarName, "-")) {
+       tostdoutFlag = TRUE;
+       tarFd = fileno(stdout);
+    } else
+       tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+    if (tarFd < 0) {
+       perror (tarName);
+       errorFlag = TRUE;
+       return;
+    }
+
+    /* 
+     * Get the device and inode of the tar file for checking later.
+     */
+    if (fstat (tarFd, &statbuf) < 0) {
+       perror (tarName);
+       errorFlag = TRUE;
+       goto done;
+    }
+
+    tarDev = statbuf.st_dev;
+    tarInode = statbuf.st_ino;
+               
+    /* 
+     * Append each file name into the archive file.
+     * Follow symbolic links for these top level file names.
+     */
+    while (errorFlag==FALSE && (fileCount-- > 0)) {
+       saveFile (*fileTable++, FALSE);
+    }
+
+    /* 
+     * Now write an empty block of zeroes to end the archive.
+     */
+    writeTarBlock ("", 1);
+
+
+  done:
+    /* 
+     * Close the tar file and check for errors if it was opened.
+     */
+    if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
+       perror (tarName);
 }
 
 
@@ -713,76 +719,74 @@ done:
  * flag indicates whether or not we want to see symbolic links as
  * they really are, instead of blindly following them.
  */
-static void
-saveFile(const char * fileName, BOOL seeLinks)
+static void saveFile (const char *fileName, int seeLinks)
 {
-       int             status;
-       int             mode;
-       struct stat     statbuf;
+    int status;
+    int mode;
+    struct stat statbuf;
 
-       if (verboseFlag)
-               printf("a %s\n", fileName);
+    if (verboseFlag==TRUE)
+       printf ("a %s\n", fileName);
 
-       /*
-        * Check that the file name will fit in the header.
-        */
-       if (strlen(fileName) >= TAR_NAME_SIZE)
-       {
-               fprintf(stderr, "%s: File name is too long\n", fileName);
+    /* 
+     * Check that the file name will fit in the header.
+     */
+    if (strlen (fileName) >= TAR_NAME_SIZE) {
+       fprintf (stderr, "%s: File name is too long\n", fileName);
 
-               return;
-       }
+       return;
+    }
 
-       /*
-        * Find out about the file.
-        */
+    /* 
+     * Find out about the file.
+     */
 #ifdef S_ISLNK
-       if (seeLinks)
-               status = lstat(fileName, &statbuf);
-       else
+    if (seeLinks==TRUE)
+       status = lstat (fileName, &statbuf);
+    else
 #endif
-               status = stat(fileName, &statbuf);
-
-       if (status < 0)
-       {
-               perror(fileName);
-
-               return;
-       }
-
-       /*
-        * Make sure we aren't trying to save our file into itself.
-        */
-       if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode))
-       {
-               fprintf(stderr, "Skipping saving of archive file itself\n");
-
-               return;
-       }
-
-       /*
-        * Check the type of file.
-        */
-       mode = statbuf.st_mode;
-
-       if (S_ISDIR(mode))
-       {
-               saveDirectory(fileName, &statbuf);
-
-               return;
-       }
-
-       if (S_ISREG(mode))
-       {
-               saveRegularFile(fileName, &statbuf);
-
-               return;
-       }
-
-       /*
-        * The file is a strange type of file, ignore it.
-        */
-       fprintf(stderr, "%s: not a directory or regular file\n", fileName);
+       status = stat (fileName, &statbuf);
+
+    if (status < 0) {
+       perror (fileName);
+
+       return;
+    }
+
+    /* 
+     * Make sure we aren't trying to save our file into itself.
+     */
+    if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
+       fprintf (stderr, "Skipping saving of archive file itself\n");
+
+       return;
+    }
+
+    /* 
+     * Check the type of file.
+     */
+    mode = statbuf.st_mode;
+
+    if (S_ISDIR (mode)) {
+       saveDirectory (fileName, &statbuf);
+
+       return;
+    }
+    if (S_ISREG (mode)) {
+       saveRegularFile (fileName, &statbuf);
+
+       return;
+    }
+    
+    /* Some day add support for tarring these up... but not today. :) */
+//  if (S_ISLNK(mode) || S_ISFIFO(mode) || S_ISBLK(mode) || S_ISCHR (mode) ) {
+//     fprintf (stderr, "%s: This version of tar can't store this type of file\n", fileName);
+//  }
+
+    /* 
+     * The file is a strange type of file, ignore it.
+     */
+    fprintf (stderr, "%s: not a directory or regular file\n", fileName);
 }
 
 
@@ -790,183 +794,173 @@ saveFile(const char * fileName, BOOL seeLinks)
  * Save a regular file to the tar file.
  */
 static void
-saveRegularFile(const char * fileName, const struct stat * statbuf)
+saveRegularFile (const char *fileName, const struct stat *statbuf)
 {
-       BOOL            sawEof;
-       int             fileFd;
-       int             cc;
-       int             dataCount;
-       long            fullDataCount;
-       char            data[TAR_BLOCK_SIZE * 16];
-
-       /*
-        * Open the file for reading.
-        */
-       fileFd = open(fileName, O_RDONLY);
-
-       if (fileFd < 0)
-       {
-               perror(fileName);
+    int sawEof;
+    int fileFd;
+    int cc;
+    int dataCount;
+    long fullDataCount;
+    char data[TAR_BLOCK_SIZE * 16];
+
+    /* 
+     * Open the file for reading.
+     */
+    fileFd = open (fileName, O_RDONLY);
+
+    if (fileFd < 0) {
+       perror (fileName);
+
+       return;
+    }
+
+    /* 
+     * Write out the header for the file.
+     */
+    writeHeader (fileName, statbuf);
+
+    /* 
+     * Write the data blocks of the file.
+     * We must be careful to write the amount of data that the stat
+     * buffer indicated, even if the file has changed size.  Otherwise
+     * the tar file will be incorrect.
+     */
+    fullDataCount = statbuf->st_size;
+    sawEof = FALSE;
+
+    while (fullDataCount > 0) {
+       /* 
+        * Get the amount to write this iteration which is
+        * the minumum of the amount left to write and the
+        * buffer size.
+        */
+       dataCount = sizeof (data);
+
+       if (dataCount > fullDataCount)
+           dataCount = (int) fullDataCount;
+
+       /* 
+        * Read the data from the file if we haven't seen the
+        * end of file yet.
+        */
+       cc = 0;
+
+       if (sawEof==FALSE) {
+           cc = fullRead (fileFd, data, dataCount);
+
+           if (cc < 0) {
+               perror (fileName);
+
+               (void) close (fileFd);
+               errorFlag = TRUE;
 
                return;
+           }
+
+           /* 
+            * If the file ended too soon, complain and set
+            * a flag so we will zero fill the rest of it.
+            */
+           if (cc < dataCount) {
+               fprintf (stderr,
+                        "%s: Short read - zero filling", fileName);
+
+               sawEof = TRUE;
+           }
        }
 
-       /*
-        * Write out the header for the file.
+       /* 
+        * Zero fill the rest of the data if necessary.
         */
-       writeHeader(fileName, statbuf);
+       if (cc < dataCount)
+           memset (data + cc, 0, dataCount - cc);
 
-       /*
-        * Write the data blocks of the file.
-        * We must be careful to write the amount of data that the stat
-        * buffer indicated, even if the file has changed size.  Otherwise
-        * the tar file will be incorrect.
+       /* 
+        * Write the buffer to the TAR file.
         */
-       fullDataCount = statbuf->st_size;
-       sawEof = FALSE;
-
-       while (fullDataCount > 0)
-       {
-               /*
-                * Get the amount to write this iteration which is
-                * the minumum of the amount left to write and the
-                * buffer size.
-                */
-               dataCount = sizeof(data);
-
-               if (dataCount > fullDataCount)
-                       dataCount = (int) fullDataCount;
-
-               /*
-                * Read the data from the file if we haven't seen the
-                * end of file yet.
-                */
-               cc = 0;
-
-               if (!sawEof)
-               {
-                       cc = fullRead(fileFd, data, dataCount);
-
-                       if (cc < 0)
-                       {
-                               perror(fileName);
-
-                               (void) close(fileFd);
-                               errorFlag = TRUE;
-
-                               return;
-                       }
-
-                       /*
-                        * If the file ended too soon, complain and set
-                        * a flag so we will zero fill the rest of it.
-                        */
-                       if (cc < dataCount)
-                       {
-                               fprintf(stderr,
-                                       "%s: Short read - zero filling",
-                                       fileName);
-
-                               sawEof = TRUE;
-                       }
-               }
-
-               /*
-                * Zero fill the rest of the data if necessary.
-                */
-               if (cc < dataCount)
-                       memset(data + cc, 0, dataCount - cc);
-
-               /*
-                * Write the buffer to the TAR file.
-                */
-               writeTarBlock(data, dataCount);
+       writeTarBlock (data, dataCount);
 
-               fullDataCount -= dataCount;
-       }
+       fullDataCount -= dataCount;
+    }
 
-       /*
-        * Close the file.
-        */
-       if ( (tostdoutFlag==FALSE) && close(fileFd) < 0)
-               fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno));
+    /* 
+     * Close the file.
+     */
+    if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
+       fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
 }
 
 
 /*
  * Save a directory and all of its files to the tar file.
  */
-static void
-saveDirectory(const char * dirName, const struct stat * statbuf)
+static void saveDirectory (const char *dirName, const struct stat *statbuf)
 {
-       DIR *           dir;
-       struct dirent * entry;
-       BOOL            needSlash;
-       char            fullName[PATH_LEN];
-
-       /*
-        * Construct the directory name as used in the tar file by appending
-        * a slash character to it.
-        */
-       strcpy(fullName, dirName);
-       strcat(fullName, "/");
-
-       /*
-        * Write out the header for the directory entry.
-        */
-       writeHeader(fullName, statbuf);
-
-       /*
-        * Open the directory.
-        */
-       dir = opendir(dirName);
-
-       if (dir == NULL)
-       {
-               fprintf(stderr, "Cannot read directory \"%s\": %s\n",
-                       dirName, strerror(errno));
-
-               return;
+    DIR *dir;
+    struct dirent *entry;
+    int needSlash;
+    char fullName[NAME_MAX];
+
+    /* 
+     * Construct the directory name as used in the tar file by appending
+     * a slash character to it.
+     */
+    strcpy (fullName, dirName);
+    strcat (fullName, "/");
+
+    /* 
+     * Write out the header for the directory entry.
+     */
+    writeHeader (fullName, statbuf);
+
+    /* 
+     * Open the directory.
+     */
+    dir = opendir (dirName);
+
+    if (dir == NULL) {
+       fprintf (stderr, "Cannot read directory \"%s\": %s\n",
+                dirName, strerror (errno));
+
+       return;
+    }
+
+    /* 
+     * See if a slash is needed.
+     */
+    needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
+
+    /* 
+     * Read all of the directory entries and check them,
+     * except for the current and parent directory entries.
+     */
+    while (errorFlag==FALSE && ((entry = readdir (dir)) != NULL)) {
+       if ((strcmp (entry->d_name, ".") == 0) ||
+           (strcmp (entry->d_name, "..") == 0)) {
+           continue;
        }
 
-       /*
-        * See if a slash is needed.
+       /* 
+        * Build the full path name to the file.
         */
-       needSlash = (*dirName && (dirName[strlen(dirName) - 1] != '/'));
+       strcpy (fullName, dirName);
 
-       /*
-        * Read all of the directory entries and check them,
-        * except for the current and parent directory entries.
-        */
-       while (!errorFlag && ((entry = readdir(dir)) != NULL))
-       {
-               if ((strcmp(entry->d_name, ".") == 0) ||
-                       (strcmp(entry->d_name, "..") == 0))
-               {
-                       continue;
-               }
-
-               /*
-                * Build the full path name to the file.
-                */
-               strcpy(fullName, dirName);
+       if (needSlash)
+           strcat (fullName, "/");
 
-               if (needSlash)
-                       strcat(fullName, "/");
+       strcat (fullName, entry->d_name);
 
-               strcat(fullName, entry->d_name);
-
-               /*
-                * Write this file to the tar file, noticing whether or not
-                * the file is a symbolic link.
-                */
-               saveFile(fullName, TRUE);
-       }
-
-       /*
-        * All done, close the directory.
+       /* 
+        * Write this file to the tar file, noticing whether or not
+        * the file is a symbolic link.
         */
-       closedir(dir);
+       saveFile (fullName, TRUE);
+    }
+
+    /* 
+     * All done, close the directory.
+     */
+    closedir (dir);
 }
 
 
@@ -974,55 +968,54 @@ saveDirectory(const char * dirName, const struct stat * statbuf)
  * Write a tar header for the specified file name and status.
  * It is assumed that the file name fits.
  */
-static void
-writeHeader(const char * fileName, const struct stat * statbuf)
+static void writeHeader (const char *fileName, const struct stat *statbuf)
 {
-       long                    checkSum;
-       const unsigned char *   cp;
-       int                     len;
-       TarHeader               header;
-
-       /*
-        * Zero the header block in preparation for filling it in.
-        */
-       memset((char *) &header, 0, sizeof(header));
-
-       /*
-        * Fill in the header.
-        */
-       strcpy(header.name, fileName);
-
-       strncpy(header.magic, TAR_MAGIC, sizeof(header.magic));
-       strncpy(header.version, TAR_VERSION, sizeof(header.version));
-
-       putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777);
-       putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
-       putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
-       putOctal(header.size, sizeof(header.size), statbuf->st_size);
-       putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
-
-       header.typeFlag = TAR_TYPE_REGULAR;
-
-       /*
-        * Calculate and store the checksum.
-        * This is the sum of all of the bytes of the header,
-        * with the checksum field itself treated as blanks.
-        */
-       memset(header.checkSum, ' ', sizeof(header.checkSum));
-
-       cp = (const unsigned char *) &header;
-       len = sizeof(header);
-       checkSum = 0;
-
-       while (len-- > 0)
-               checkSum += *cp++;
-
-       putOctal(header.checkSum, sizeof(header.checkSum), checkSum);
-
-       /*
-        * Write the tar header.
-        */
-       writeTarBlock((const char *) &header, sizeof(header));
+    long checkSum;
+    const unsigned char *cp;
+    int len;
+    TarHeader header;
+
+    /* 
+     * Zero the header block in preparation for filling it in.
+     */
+    memset ((char *) &header, 0, sizeof (header));
+
+    /* 
+     * Fill in the header.
+     */
+    strcpy (header.name, fileName);
+
+    strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
+    strncpy (header.version, TAR_VERSION, sizeof (header.version));
+
+    putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
+    putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
+    putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
+    putOctal (header.size, sizeof (header.size), statbuf->st_size);
+    putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
+
+    header.typeFlag = TAR_TYPE_REGULAR;
+
+    /* 
+     * Calculate and store the checksum.
+     * This is the sum of all of the bytes of the header,
+     * with the checksum field itself treated as blanks.
+     */
+    memset (header.checkSum, ' ', sizeof (header.checkSum));
+
+    cp = (const unsigned char *) &header;
+    len = sizeof (header);
+    checkSum = 0;
+
+    while (len-- > 0)
+       checkSum += *cp++;
+
+    putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
+
+    /* 
+     * Write the tar header.
+     */
+    writeTarBlock ((const char *) &header, sizeof (header));
 }
 
 
@@ -1031,91 +1024,56 @@ writeHeader(const char * fileName, const struct stat * statbuf)
  * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
  * The errorFlag static variable is set on an error.
  */
-static void
-writeTarBlock(const char * buf, int len)
+static void writeTarBlock (const char *buf, int len)
 {
-       int     partialLength;
-       int     completeLength;
-       char    fullBlock[TAR_BLOCK_SIZE];
-
-       /*
-        * If we had a write error before, then do nothing more.
-        */
-       if (errorFlag)
-               return;
-
-       /*
-        * Get the amount of complete and partial blocks.
-        */
-       partialLength = len % TAR_BLOCK_SIZE;
-       completeLength = len - partialLength;
-
-       /*
-        * Write all of the complete blocks.
-        */
-       if ((completeLength > 0) && !fullWrite(tarFd, buf, completeLength))
-       {
-               perror(tarName);
-
-               errorFlag = TRUE;
-
-               return;
-       }
-
-       /*
-        * If there are no partial blocks left, we are done.
-        */
-       if (partialLength == 0)
-               return;
-
-       /*
-        * Copy the partial data into a complete block, and pad the rest
-        * of it with zeroes.
-        */
-       memcpy(fullBlock, buf + completeLength, partialLength);
-       memset(fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
-
-       /*
-        * Write the last complete block.
-        */
-       if (!fullWrite(tarFd, fullBlock, TAR_BLOCK_SIZE))
-       {
-               perror(tarName);
-
-               errorFlag = TRUE;
-       }
-}
-
-
-/*
- * Attempt to create the directories along the specified path, except for
- * the final component.  The mode is given for the final directory only,
- * while all previous ones get default protections.  Errors are not reported
- * here, as failures to restore files can be reported later.
- */
-static void
-createPath(const char * name, int mode)
-{
-       char *  cp;
-       char *  cpOld;
-       char    buf[TAR_NAME_SIZE];
-
-       strcpy(buf, name);
-
-       cp = strchr(buf, '/');
-
-       while (cp)
-       {
-               cpOld = cp;
-               cp = strchr(cp + 1, '/');
-
-               *cpOld = '\0';
-
-               if (mkdir(buf, cp ? 0777 : mode) == 0)
-                       printf("Directory \"%s\" created\n", buf);
-
-               *cpOld = '/';
-       }
+    int partialLength;
+    int completeLength;
+    char fullBlock[TAR_BLOCK_SIZE];
+
+    /* 
+     * If we had a write error before, then do nothing more.
+     */
+    if (errorFlag==TRUE)
+       return;
+
+    /* 
+     * Get the amount of complete and partial blocks.
+     */
+    partialLength = len % TAR_BLOCK_SIZE;
+    completeLength = len - partialLength;
+
+    /* 
+     * Write all of the complete blocks.
+     */
+    if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
+       perror (tarName);
+
+       errorFlag = TRUE;
+
+       return;
+    }
+
+    /* 
+     * If there are no partial blocks left, we are done.
+     */
+    if (partialLength == 0)
+       return;
+
+    /* 
+     * Copy the partial data into a complete block, and pad the rest
+     * of it with zeroes.
+     */
+    memcpy (fullBlock, buf + completeLength, partialLength);
+    memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
+
+    /* 
+     * Write the last complete block.
+     */
+    if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
+       perror (tarName);
+
+       errorFlag = TRUE;
+    }
 }
 
 
@@ -1124,38 +1082,34 @@ createPath(const char * name, int mode)
  * spaces on both sides of the number and with an optional null character
  * at the end.  Returns -1 on an illegal format.
  */
-static long
-getOctal(const char * cp, int len)
+static long getOctal (const char *cp, int len)
 {
-       long    val;
+    long val;
 
-       while ((len > 0) && (*cp == ' '))
-       {
-               cp++;
-               len--;
-       }
+    while ((len > 0) && (*cp == ' ')) {
+       cp++;
+       len--;
+    }
 
-       if ((len == 0) || !isOctal(*cp))
-               return -1;
+    if ((len == 0) || !isOctal (*cp))
+       return -1;
 
-       val = 0;
+    val = 0;
 
-       while ((len > 0) && isOctal(*cp))
-       {
-               val = val * 8 + *cp++ - '0';
-               len--;
-       }
+    while ((len > 0) && isOctal (*cp)) {
+       val = val * 8 + *cp++ - '0';
+       len--;
+    }
 
-       while ((len > 0) && (*cp == ' '))
-       {
-               cp++;
-               len--;
-       }
+    while ((len > 0) && (*cp == ' ')) {
+       cp++;
+       len--;
+    }
 
-       if ((len > 0) && *cp)
-               return -1;
+    if ((len > 0) && *cp)
+       return -1;
 
-       return val;
+    return val;
 }
 
 
@@ -1164,50 +1118,48 @@ getOctal(const char * cp, int len)
  * The number is zero and space padded and possibly null padded.
  * Returns TRUE if successful.
  */
-static BOOL
-putOctal(char * cp, int len, long value)
+static int putOctal (char *cp, int len, long value)
 {
-       int     tempLength;
-       char *  tempString;
-       char    tempBuffer[32];
-
-       /*
-        * Create a string of the specified length with an initial space,
-        * leading zeroes and the octal number, and a trailing null.
-        */
-       tempString = tempBuffer;
-
-       sprintf(tempString, " %0*lo", len - 2, value);
-
-       tempLength = strlen(tempString) + 1;
-
-       /*
-        * If the string is too large, suppress the leading space.
-        */
-       if (tempLength > len)
-       {
-               tempLength--;
-               tempString++;
-       }
-
-       /*
-        * If the string is still too large, suppress the trailing null.
-        */
-       if (tempLength > len)
-               tempLength--;
-
-       /*
-        * If the string is still too large, fail.
-        */
-       if (tempLength > len)
-               return FALSE;
+    int tempLength;
+    char *tempString;
+    char tempBuffer[32];
+
+    /* 
+     * Create a string of the specified length with an initial space,
+     * leading zeroes and the octal number, and a trailing null.
+     */
+    tempString = tempBuffer;
+
+    sprintf (tempString, " %0*lo", len - 2, value);
+
+    tempLength = strlen (tempString) + 1;
+
+    /* 
+     * If the string is too large, suppress the leading space.
+     */
+    if (tempLength > len) {
+       tempLength--;
+       tempString++;
+    }
+
+    /* 
+     * If the string is still too large, suppress the trailing null.
+     */
+    if (tempLength > len)
+       tempLength--;
+
+    /* 
+     * If the string is still too large, fail.
+     */
+    if (tempLength > len)
+       return FALSE;
 
-       /*
-        * Copy the string to the field.
-        */
-       memcpy(cp, tempString, len);
+    /* 
+     * Copy the string to the field.
+     */
+    memcpy (cp, tempString, len);
 
-       return TRUE;
+    return TRUE;
 }
 
 
@@ -1216,210 +1168,43 @@ putOctal(char * cp, int len, long value)
  * of path prefixes.  An empty list implies that all files are wanted.
  * Returns TRUE if the file is selected.
  */
-static BOOL
-wantFileName(const char * fileName, int fileCount, char ** fileTable)
-{
-       const char *    pathName;
-       int             fileLength;
-       int             pathLength;
-
-       /*
-        * If there are no files in the list, then the file is wanted.
-        */
-       if (fileCount == 0)
-               return TRUE;
-
-       fileLength = strlen(fileName);
-
-       /*
-        * Check each of the test paths.
-        */
-       while (fileCount-- > 0)
-       {
-               pathName = *fileTable++;
-
-               pathLength = strlen(pathName);
-
-               if (fileLength < pathLength)
-                       continue;
-
-               if (memcmp(fileName, pathName, pathLength) != 0)
-                       continue;
-
-               if ((fileLength == pathLength) ||
-                       (fileName[pathLength] == '/'))
-               {
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-
-
-/*
- * Return the standard ls-like mode string from a file mode.
- * This is static and so is overwritten on each call.
- */
-const char *
-modeString(int mode)
+static int
+wantFileName (const char *fileName, int fileCount, char **fileTable)
 {
-       static  char    buf[12];
-
-       strcpy(buf, "----------");
-
-       /*
-        * Fill in the file type.
-        */
-       if (S_ISDIR(mode))
-               buf[0] = 'd';
-       if (S_ISCHR(mode))
-               buf[0] = 'c';
-       if (S_ISBLK(mode))
-               buf[0] = 'b';
-       if (S_ISFIFO(mode))
-               buf[0] = 'p';
-#ifdef S_ISLNK
-       if (S_ISLNK(mode))
-               buf[0] = 'l';
-#endif
-#ifdef S_ISSOCK
-       if (S_ISSOCK(mode))
-               buf[0] = 's';
-#endif
-
-       /*
-        * Now fill in the normal file permissions.
-        */
-       if (mode & S_IRUSR)
-               buf[1] = 'r';
-       if (mode & S_IWUSR)
-               buf[2] = 'w';
-       if (mode & S_IXUSR)
-               buf[3] = 'x';
-       if (mode & S_IRGRP)
-               buf[4] = 'r';
-       if (mode & S_IWGRP)
-               buf[5] = 'w';
-       if (mode & S_IXGRP)
-               buf[6] = 'x';
-       if (mode & S_IROTH)
-               buf[7] = 'r';
-       if (mode & S_IWOTH)
-               buf[8] = 'w';
-       if (mode & S_IXOTH)
-               buf[9] = 'x';
-
-       /*
-        * Finally fill in magic stuff like suid and sticky text.
-        */
-       if (mode & S_ISUID)
-               buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
-       if (mode & S_ISGID)
-               buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
-       if (mode & S_ISVTX)
-               buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
-
-       return buf;
-}
-
-
-/*
- * Get the time string to be used for a file.
- * This is down to the minute for new files, but only the date for old files.
- * The string is returned from a static buffer, and so is overwritten for
- * each call.
- */
-const char *
-timeString(time_t timeVal)
-{
-       time_t          now;
-       char *          str;
-       static  char    buf[26];
-
-       time(&now);
-
-       str = ctime(&timeVal);
-
-       strcpy(buf, &str[4]);
-       buf[12] = '\0';
-
-       if ((timeVal > now) || (timeVal < now - 365*24*60*60L))
-       {
-               strcpy(&buf[7], &str[20]);
-               buf[11] = '\0';
-       }
-
-       return buf;
-}
-
-
-
-/*
- * Write all of the supplied buffer out to a file.
- * This does multiple writes as necessary.
- * Returns the amount written, or -1 on an error.
- */
-int
-fullWrite(int fd, const char * buf, int len)
-{
-       int     cc;
-       int     total;
-
-       total = 0;
-
-       while (len > 0)
-       {
-               cc = write(fd, buf, len);
-
-               if (cc < 0)
-                       return -1;
-
-               buf += cc;
-               total+= cc;
-               len -= cc;
-       }
-
-       return total;
-}
-
+    const char *pathName;
+    int fileLength;
+    int pathLength;
+
+    /* 
+     * If there are no files in the list, then the file is wanted.
+     */
+    if (fileCount == 0)
+       return TRUE;
 
-/*
- * Read all of the supplied buffer from a file.
- * This does multiple reads as necessary.
- * Returns the amount read, or -1 on an error.
- * A short read is returned on an end of file.
- */
-int
-fullRead(int fd, char * buf, int len)
-{
-       int     cc;
-       int     total;
+    fileLength = strlen (fileName);
 
-       total = 0;
+    /* 
+     * Check each of the test paths.
+     */
+    while (fileCount-- > 0) {
+       pathName = *fileTable++;
 
-       while (len > 0)
-       {
-               cc = read(fd, buf, len);
+       pathLength = strlen (pathName);
 
-               if (cc < 0)
-                       return -1;
+       if (fileLength < pathLength)
+           continue;
 
-               if (cc == 0)
-                       break;
+       if (memcmp (fileName, pathName, pathLength) != 0)
+           continue;
 
-               buf += cc;
-               total+= cc;
-               len -= cc;
+       if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
+           return TRUE;
        }
+    }
 
-       return total;
+    return FALSE;
 }
 
 
 
-#endif
 /* END CODE */
-
-