making note of my changes.
[oweals/busybox.git] / tar.c
diff --git a/tar.c b/tar.c
index bbd86628ad10e3129dc1ebba647b5357bd08f690..a53370e85d1f364b00829cf5ac8c1b6a6e4b14ac 100644 (file)
--- a/tar.c
+++ b/tar.c
@@ -37,6 +37,7 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <time.h>
+#include <utime.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
 
@@ -106,8 +107,12 @@ static int warnedRoot;
 static int eofFlag;
 static long dataCc;
 static int outFd;
-static char outName[TAR_NAME_SIZE];
+static const char *outName;
 
+static int mode;
+static int uid;
+static int gid;
+static time_t mtime;
 
 /*
  * Static data associated with the tar file.
@@ -364,8 +369,9 @@ static void readTarFile (int fileCount, char **fileTable)
      * message is required on errors.
      */
     if (tostdoutFlag == FALSE) {
-       if (outFd >= 0)
-           (void) close (outFd);
+       if (outFd >= 0) {
+           close (outFd);
+       }
     }
 }
 
@@ -378,29 +384,25 @@ static void readTarFile (int fileCount, char **fileTable)
 static void
 readHeader (const TarHeader * hp, int fileCount, char **fileTable)
 {
-    int mode;
-    int uid;
-    int gid;
     int checkSum;
-    int major;
-    int minor;
-    long size;
-    time_t mtime;
-    const char *name;
     int cc;
     int hardLink;
     int softLink;
     int devFileFlag;
+    unsigned int major;
+    unsigned int minor;
+    long size;
+    struct utimbuf utb;
 
     /* 
      * 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;
+    outName = hp->name;
 
-    if (*name == '\0') {
+    if (*outName == '\0') {
        for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
-           if (*name++)
+           if (*outName++)
                return;
        }
 
@@ -447,16 +449,16 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
     /* 
      * Check for a directory.
      */
-    if (name[strlen (name) - 1] == '/')
+    if (outName[strlen (outName) - 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 (*outName == '/') {
+       while (*outName == '/')
+           outName++;
 
        if (warnedRoot==FALSE) {
            fprintf (stderr,
@@ -470,7 +472,7 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
      * See if we want this file to be restored.
      * If not, then set up to skip it.
      */
-    if (wantFileName (name, fileCount, fileTable) == FALSE) {
+    if (wantFileName (outName, 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;
@@ -488,10 +490,13 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
      */
     if (extractFlag==FALSE) {
        if (verboseFlag==TRUE) {
-           printf ("%s %3d/%-d %9ld %s %s", modeString (mode),
-                   uid, gid, size, timeString (mtime), name);
-       } else
-           printf ("%s", name);
+           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));
+       }
+       printf ("%s", outName);
 
        if (hardLink)
            printf (" (link to \"%s\")", hp->linkName);
@@ -512,39 +517,65 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
      * We really want to extract the file.
      */
     if (verboseFlag==TRUE)
-       printf ("x %s\n", name);
+       printf ("x %s\n", outName);
 
     if (hardLink) {
-       if (link (hp->linkName, name) < 0)
-           perror (name);
-
+       if (link (hp->linkName, outName) < 0)
+           perror (outName);
+       /* Set the file time */
+       utb.actime = mtime;
+       utb.modtime = mtime;
+       utime (outName, &utb);
+       /* Set the file permissions */
+       chown(outName, uid, gid);
+       chmod(outName, mode);
        return;
     }
 
     if (softLink) {
 #ifdef S_ISLNK
-       if (symlink (hp->linkName, name) < 0)
-           perror (name);
+       if (symlink (hp->linkName, outName) < 0)
+           perror (outName);
+       /* Try to change ownership of the symlink.
+        * If libs doesn't support that, don't bother.
+        * Changing the pointed-to file is the Wrong Thing(tm).
+        */
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+       lchown(outName, uid, gid);
+#endif
+
+       /* Do not change permissions or date on symlink,
+        * since it changes the pointed to file instead.  duh. */
 #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);
-
+       createPath (outName, mode);
+       /* Set the file time */
+       utb.actime = mtime;
+       utb.modtime = mtime;
+       utime (outName, &utb);
+       /* Set the file permissions */
+       chown(outName, uid, gid);
+       chmod(outName, mode);
        return;
     }
 
     /* 
      * There is a file to write.
-     * First create the path to it if necessary with a default permission.
+     * First create the path to it if necessary with default permissions.
      */
-    createPath (name, 0777);
+    createPath (outName, 0777);
 
     inHeader = (size == 0)? TRUE : FALSE;
     dataCc = size;
@@ -557,27 +588,34 @@ readHeader (const TarHeader * hp, int fileCount, char **fileTable)
     else {
        if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) {
            devFileFlag = TRUE;
-           outFd = mknod (name, mode, makedev(major, minor) );
+           outFd = mknod (outName, mode, makedev(major, minor) );
        }
        else if (S_ISFIFO(mode) ) {
            devFileFlag = TRUE;
-           outFd = mkfifo(name, mode);
+           outFd = mkfifo(outName, mode);
        } else {
-           outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
+           outFd = open (outName, O_WRONLY | O_CREAT | O_TRUNC, mode);
        }
+       if (outFd < 0) {
+           perror (outName);
+           skipFileFlag = TRUE;
+           return;
+       }
+       /* Set the file time */
+       utb.actime = mtime;
+       utb.modtime = mtime;
+       utime (outName, &utb);
+       /* Set the file permissions */
+       chown(outName, uid, gid);
+       chmod(outName, mode);
     }
 
-    if (outFd < 0) {
-       perror (name);
-       skipFileFlag = TRUE;
-       return;
-    }
 
     /* 
      * If the file is empty, then that's all we need to do.
      */
     if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
-       (void) close (outFd);
+       close (outFd);
        outFd = -1;
     }
 }
@@ -611,7 +649,7 @@ static void readData (const char *cp, int count)
     if (fullWrite (outFd, cp, count) < 0) {
        perror (outName);
        if (tostdoutFlag == FALSE) {
-           (void) close (outFd);
+           close (outFd);
            outFd = -1;
        }
        skipFileFlag = TRUE;
@@ -619,13 +657,21 @@ static void readData (const char *cp, int count)
     }
 
     /* 
-     * If the write failed, close the file and disable further
-     * writes to this file.
+     * Check if we are done writing to the file now.
      */
     if (dataCc <= 0 && tostdoutFlag == FALSE) {
+       struct utimbuf utb;
        if (close (outFd))
            perror (outName);
 
+       /* Set the file time */
+       utb.actime = mtime;
+       utb.modtime = mtime;
+       utime (outName, &utb);
+       /* Set the file permissions */
+       chown(outName, uid, gid);
+       chmod(outName, mode);
+
        outFd = -1;
     }
 }
@@ -672,7 +718,7 @@ static void writeTarFile (int fileCount, char **fileTable)
 
     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.
@@ -706,7 +752,6 @@ static void writeTarFile (int fileCount, char **fileTable)
 static void saveFile (const char *fileName, int seeLinks)
 {
     int status;
-    int mode;
     struct stat statbuf;
 
     if (verboseFlag==TRUE)