Tar now works perfectly. It behaves much better now then it
authorErik Andersen <andersen@codepoet.org>
Wed, 5 Apr 2000 01:00:52 +0000 (01:00 -0000)
committerErik Andersen <andersen@codepoet.org>
Wed, 5 Apr 2000 01:00:52 +0000 (01:00 -0000)
used to.  Only thing left to do is add in exclude (-X) option.
 -Erik

TODO
applets/busybox.c
archival/tar.c
busybox.c
kill.c
procps/kill.c
tar.c
utility.c

diff --git a/TODO b/TODO
index 87f48db38487c78f8dd7041cad446db62a371793..421c402e3b2522d87b5a94cef72fa3b44cf167ec 100644 (file)
--- a/TODO
+++ b/TODO
@@ -15,15 +15,12 @@ around to it some time. If you have any good ideas, please let me know.
 
 -----------
 
-* Allow tar to create archives with sockets, devices, and other special files
 * Make insmod actually work
 * dnsdomainname
 * traceroute/netstat
 * rdate
 * hwclock
-* killall
 * stty
-* tr
 * cut
 * expr (maybe?)  (ash builtin?)
 
@@ -40,58 +37,17 @@ and then start with the biggest things and make them smaller...
 
 busybox.defs.h is too big and hard to follow.
 
-I either need to add a better build system (like the Linux kernel?)
-or I need to split up busybox.defs.h into coherent chunks (i.e.
-busybox.defs.h just has a bunch of: 
-
-#include "fileutils.h"
-#include "shellutils.h"
-
-which would then have smaller sets of #defines...
-Hmm.  Needs to be carefully thought out.
+Perhaps I need to add a better build system (like the Linux kernel?)
 
 -----------------------
 
 
--rw-r--r-- 1000/1000      4398 2000-01-06 21:55 uniq.c
--rw-r--r-- 1000/1000      1568 1999-10-20 18:08 update.c
--rw-r----- 0/1000         1168 2000-01-29 21:03 update.o
--rw-r--r-- 1000/1000     22820 2000-01-05 11:36 utility.c
--rw-r----- 0/1000         7372 2000-01-29 21:03 utility.o
-tar: Skipping to next file header
-tar: Skipping to next file header
-tar: Archive - EOF not on block boundary
-tar: Error is not recoverable: exiting now
-
-
-#1 You are storing by id instead of name like normal tar. Did you realize this?
-(or am I missing some compile option? )ctar did not do this, and I don't think
-it's a good idea for LRP.
-
-#2
-ctar did not produce the EOF error like your tar does. I believe you need to
-pad the end of the archive with at least 2 tarsized (512byte) blocks. (I
-think???)
-
-#3
 There is no exclude file(s) option to tar. LRP's packaging system can not
 function without this. Will you have the time to add this soon?
 
 
 -----------------------
 
-cd /mnt
-mkdir BACKUP
-mv * BACKUP
-
-Today, "mv" behaved as a cp -a and my disk becomed full. It does not
-work properly either when renaming a directory into something else
-(it produces a lot of disk activity when doing this).
-
-
------------------------
-
-
 Feature request:
 
 /bin/busybox --install -s    which makes all links to commands that it
@@ -114,13 +70,6 @@ I'll add this to the TODO list,
 -----------------------
 
 
- In utility.c:copyFile: It uses followLinks for both source and
- destination files... is that right for `mv'?  Will need to revisit
- the GNU, freeBSD, and MINIX versions for this... Should read the
- Unix98 and POSIX specs also.
-
------------------------
-
  I think that the add_inode &c in utility.c needs to also stow the
  st_dev field, and that du.c should NOT call `reset_inode_list'
  because there can be hard links from inside one argv/ to inside
index c2477a537285e511d25d0c75bb1dff0175bb035d..9a48f496146cb24390fe956df7374099d4259a30 100644 (file)
@@ -382,8 +382,8 @@ int busybox_main(int argc, char **argv)
                fprintf(stderr, "Usage: busybox [function] [arguments]...\n");
                fprintf(stderr, "   or: [function] [arguments]...\n\n");
                fprintf(stderr,
-                               "\tMost people will create a link to busybox for each\n"
-                               "\tfunction name, and busybox will act like whatever you invoke it as.\n");
+                               "\tMost people will create a link to busybox for each function\n"
+                               "\tname, and busybox will act like whatever you invoke it as.\n");
                fprintf(stderr, "\nCurrently defined functions:\n");
 
                while (a->name != 0) {
index f9b3e18138bee18329dc98f7c45a6a5d920fd099..979821ec0af3de053b8c26451b80fd479e88ef89 100644 (file)
@@ -56,7 +56,8 @@
 
 static const char tar_usage[] =
        "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n"
-       "Create, extract, or list files from a tar file.\n\n"
+       "Create, extract, or list files from a tar file.  Note that\n"
+       "this version of tar packs hard links as separate files.\n\n"
        "Options:\n"
 
        "\tc=create, x=extract, t=list contents, v=verbose,\n"
@@ -110,10 +111,10 @@ typedef struct TarHeader TarHeader;
 
 /* A few useful constants */
 #define TAR_MAGIC          "ustar"        /* ustar and a null */
-#define TAR_VERSION        "00"           /* 00 and no null */
+//#define TAR_VERSION      "00"           /* 00 and no null */
+#define TAR_VERSION        "  "           /* Be compatable with old GNU format */
 #define TAR_MAGIC_LEN       6
 #define TAR_VERSION_LEN     2
-#define TAR_NAME_LEN        100
 #define TAR_BLOCK_SIZE      512
 
 /* A nice enum with all the possible tar file content types */
@@ -366,7 +367,8 @@ tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag)
                return;
 
        if (link(header->linkname, header->name) < 0) {
-               errorMsg("Error creating hard link '%s': %s\n", header->linkname, strerror(errno)); 
+               errorMsg("Error creating hard link '%s' to '%s': %s\n", 
+                               header->name, header->linkname, strerror(errno)); 
                return;
        }
 
@@ -382,7 +384,8 @@ tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag)
 
 #ifdef S_ISLNK
        if (symlink(header->linkname, header->name) < 0) {
-               errorMsg("Error creating symlink '%s': %s\n", header->linkname, strerror(errno)); 
+               errorMsg("Error creating symlink '%s' to '%s': %s\n", 
+                               header->name, header->linkname, strerror(errno)); 
                return;
        }
        /* Try to change ownership of the symlink.
@@ -644,18 +647,15 @@ typedef struct TarBallInfo TarBallInfo;
 static int putOctal (char *cp, int len, long value)
 {
        int tempLength;
-       char *tempString;
        char tempBuffer[32];
+       char *tempString = tempBuffer;
 
        /* 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;
+       sprintf (tempString, "%0*lo", len - 1, value);
 
        /* If the string is too large, suppress the leading space.  */
+       tempLength = strlen (tempString) + 1;
        if (tempLength > len) {
                tempLength--;
                tempString++;
@@ -677,10 +677,14 @@ static int putOctal (char *cp, int len, long value)
 
 /* Write out a tar header for the specified file/directory/whatever */
 static int
-writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *statbuf)
+writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *statbuf)
 {
-       //int i;
-       //long chksum, sum;
+       long chksum=0;
+       struct TarHeader header;
+       const unsigned char *cp = (const unsigned char *) &header;
+       ssize_t size = sizeof(struct TarHeader);
+
+       memset( &header, 0, size);
 
        if (*fileName=='/') {
                static int alreadyWarned=FALSE;
@@ -688,66 +692,88 @@ writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *stat
                        errorMsg("tar: Removing leading '/' from member names\n");
                        alreadyWarned=TRUE;
                }
-               strcpy(header->name, fileName+1); 
+               strcpy(header.name, fileName+1); 
        }
        else {
-               strcpy(header->name, fileName); 
+               strcpy(header.name, fileName); 
        }
-       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);
-
+       putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
+       putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
+       putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
+       putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */
+       putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
+       strncpy(header.magic, TAR_MAGIC TAR_VERSION, 
+                       TAR_MAGIC_LEN + TAR_VERSION_LEN );
+
+       my_getpwuid(header.uname, statbuf->st_uid);
+       /* Put some sort of sane fallback in place... */
+       if (! *header.uname)
+               strncpy(header.uname, "root", 5);
+       my_getgrgid(header.gname, statbuf->st_gid);
+       if (! *header.uname)
+               strncpy(header.uname, "root", 5);
+
+       // FIXME: (or most likely not) I break Hard Links
        if (S_ISLNK(statbuf->st_mode)) {
-               header->typeflag  = LNKTYPE;
-               // TODO -- Handle SYMTYPE
+               char buffer[BUFSIZ];
+               header.typeflag  = SYMTYPE;
+               if ( readlink(fileName, buffer, sizeof(buffer) - 1) < 0) {
+                       errorMsg("Error reading symlink '%s': %s\n", header.name, strerror(errno));
+                       return ( FALSE);
+               }
+               strncpy(header.linkname, buffer, sizeof(header.linkname)); 
        } else if (S_ISDIR(statbuf->st_mode)) {
-               header->typeflag  = DIRTYPE;
-               strncat(header->name, "/", sizeof(header->name)); 
+               header.typeflag  = DIRTYPE;
+               strncat(header.name, "/", sizeof(header.name)); 
        } else if (S_ISCHR(statbuf->st_mode)) {
-               header->typeflag  = CHRTYPE;
-               putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev));
-               putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev));
+               header.typeflag  = CHRTYPE;
+               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
+               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
        } else if (S_ISBLK(statbuf->st_mode)) {
-               header->typeflag  = BLKTYPE;
-               putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev));
-               putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev));
+               header.typeflag  = BLKTYPE;
+               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
+               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
        } else if (S_ISFIFO(statbuf->st_mode)) {
-               header->typeflag  = FIFOTYPE;
-       } else if (S_ISLNK(statbuf->st_mode)) {
-               header->typeflag  = LNKTYPE;
-       } else if (S_ISLNK(statbuf->st_mode)) {
-               header->typeflag  = REGTYPE;
+               header.typeflag  = FIFOTYPE;
+       } else if (S_ISREG(statbuf->st_mode)) {
+               header.typeflag  = REGTYPE;
+               putOctal(header.size, sizeof(header.size), statbuf->st_size);
        } else {
+               errorMsg("tar: %s: Unknown file type\n", fileName);
                return ( FALSE);
        }
-       return ( TRUE);
-
-#if 0  
-       header->linkname  = rawHeader->linkname;
-       header->devmajor  = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor));
-       header->devminor  = getOctal(rawHeader->devminor, sizeof(rawHeader->devminor));
 
-       /* Write out the checksum */
-       chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum));
+       /* Calculate and store the checksum (i.e. the sum of all of the bytes of
+        * the header).  The checksum field must be filled with blanks for the
+        * calculation.  The checksum field is formatted differently from the
+        * other fields: it has [6] digits, a null, then a space -- rather than
+        * digits, followed by a null like the other fields... */
+       memset(header.chksum, ' ', sizeof(header.chksum));
+       cp = (const unsigned char *) &header;
+       while (size-- > 0)
+               chksum += *cp++;
+       putOctal(header.chksum, 7, chksum);
+       
+       /* Now write the header out to disk */
+       if ((size=fullWrite(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) {
+               errorMsg(io_error, fileName, strerror(errno)); 
+               return ( FALSE);
+       }
+       /* Pad the header up to the tar block size */
+       for (; size<TAR_BLOCK_SIZE; size++) {
+               write(tbInfo->tarFd, "\0", 1);
+       }
+       /* Now do the verbose thing (or not) */
+       if (tbInfo->verboseFlag==TRUE)
+               fprintf(stdout, "%s\n", header.name);
 
        return ( TRUE);
-#endif
 }
 
 
 static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData)
 {
-       int inputFileFd;
        struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
-       char header[sizeof(struct TarHeader)];
-
-       /* First open the file we want to archive, and make sure all is well */
-       if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
-               errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno));
-               return( TRUE);
-       }
 
        /* It is against the rules to archive a socket */
        if (S_ISSOCK(statbuf->st_mode)) {
@@ -764,13 +790,41 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
                return( TRUE);
        }
 
-       memset( header, 0, sizeof(struct TarHeader));
-       if (writeTarHeader((struct TarHeader *)header, fileName, statbuf)==FALSE) {
-               dprintf(tbInfo->tarFd, "%s", header);
+       if (writeTarHeader(tbInfo, fileName, statbuf)==FALSE) {
+               return( FALSE);
        } 
-       /* Now do the verbose thing (or not) */
-       if (tbInfo->verboseFlag==TRUE)
-               fprintf(stdout, "%s\n", ((struct TarHeader *)header)->name);
+
+       /* Now, if the file is a regular file, copy it out to the tarball */
+       if (S_ISREG(statbuf->st_mode)) {
+               int  inputFileFd;
+               char buffer[BUFSIZ];
+               ssize_t size=0, readSize=0;
+
+               /* open the file we want to archive, and make sure all is well */
+               if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
+                       errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno));
+                       return( FALSE);
+               }
+               
+               /* write the file to the archive */
+               while ( (size = fullRead(inputFileFd, buffer, sizeof(buffer))) > 0 ) {
+                       if (fullWrite(tbInfo->tarFd, buffer, size) != size ) {
+                               /* Output file seems to have a problem */
+                               errorMsg(io_error, fileName, strerror(errno)); 
+                               return( FALSE);
+                       }
+                       readSize+=size;
+               }
+               if (size == -1) {
+                       errorMsg(io_error, fileName, strerror(errno)); 
+                       return( FALSE);
+               }
+               /* Pad the file up to the tar block size */
+               for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) {
+                       write(tbInfo->tarFd, "\0", 1);
+               }
+               close( inputFileFd);
+       }
 
        return( TRUE);
 }
@@ -780,6 +834,7 @@ static int writeTarFile(const char* tarName, int tostdoutFlag,
 {
        int tarFd=-1;
        int errorFlag=FALSE;
+       ssize_t size;
        //int skipFileFlag=FALSE;
        struct TarBallInfo tbInfo;
        tbInfo.verboseFlag = verboseFlag;
@@ -814,6 +869,10 @@ static int writeTarFile(const char* tarName, int tostdoutFlag,
                        errorFlag = TRUE;
                }
        }
+       /* Write two empty blocks to the end of the archive */
+       for (size=0; size<(2*TAR_BLOCK_SIZE); size++) {
+               write(tbInfo.tarFd, "\0", 1);
+       }
        /* Hang up the tools, close up shop, head home */
        close(tarFd);
        if (errorFlag == TRUE) {
index c2477a537285e511d25d0c75bb1dff0175bb035d..9a48f496146cb24390fe956df7374099d4259a30 100644 (file)
--- a/busybox.c
+++ b/busybox.c
@@ -382,8 +382,8 @@ int busybox_main(int argc, char **argv)
                fprintf(stderr, "Usage: busybox [function] [arguments]...\n");
                fprintf(stderr, "   or: [function] [arguments]...\n\n");
                fprintf(stderr,
-                               "\tMost people will create a link to busybox for each\n"
-                               "\tfunction name, and busybox will act like whatever you invoke it as.\n");
+                               "\tMost people will create a link to busybox for each function\n"
+                               "\tname, and busybox will act like whatever you invoke it as.\n");
                fprintf(stderr, "\nCurrently defined functions:\n");
 
                while (a->name != 0) {
diff --git a/kill.c b/kill.c
index 10343a150ad6bd170bf78e4f63c680544f9d0bb9..260f4a07428dd85e116de10660b6af6bd7c8138a 100644 (file)
--- a/kill.c
+++ b/kill.c
@@ -1,6 +1,6 @@
 /* vi: set sw=4 ts=4: */
 /*
- * Mini kill implementation for busybox
+ * Mini kill/killall implementation for busybox
  *
  * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
  *
index 10343a150ad6bd170bf78e4f63c680544f9d0bb9..260f4a07428dd85e116de10660b6af6bd7c8138a 100644 (file)
@@ -1,6 +1,6 @@
 /* vi: set sw=4 ts=4: */
 /*
- * Mini kill implementation for busybox
+ * Mini kill/killall implementation for busybox
  *
  * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
  *
diff --git a/tar.c b/tar.c
index f9b3e18138bee18329dc98f7c45a6a5d920fd099..979821ec0af3de053b8c26451b80fd479e88ef89 100644 (file)
--- a/tar.c
+++ b/tar.c
@@ -56,7 +56,8 @@
 
 static const char tar_usage[] =
        "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n"
-       "Create, extract, or list files from a tar file.\n\n"
+       "Create, extract, or list files from a tar file.  Note that\n"
+       "this version of tar packs hard links as separate files.\n\n"
        "Options:\n"
 
        "\tc=create, x=extract, t=list contents, v=verbose,\n"
@@ -110,10 +111,10 @@ typedef struct TarHeader TarHeader;
 
 /* A few useful constants */
 #define TAR_MAGIC          "ustar"        /* ustar and a null */
-#define TAR_VERSION        "00"           /* 00 and no null */
+//#define TAR_VERSION      "00"           /* 00 and no null */
+#define TAR_VERSION        "  "           /* Be compatable with old GNU format */
 #define TAR_MAGIC_LEN       6
 #define TAR_VERSION_LEN     2
-#define TAR_NAME_LEN        100
 #define TAR_BLOCK_SIZE      512
 
 /* A nice enum with all the possible tar file content types */
@@ -366,7 +367,8 @@ tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag)
                return;
 
        if (link(header->linkname, header->name) < 0) {
-               errorMsg("Error creating hard link '%s': %s\n", header->linkname, strerror(errno)); 
+               errorMsg("Error creating hard link '%s' to '%s': %s\n", 
+                               header->name, header->linkname, strerror(errno)); 
                return;
        }
 
@@ -382,7 +384,8 @@ tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag)
 
 #ifdef S_ISLNK
        if (symlink(header->linkname, header->name) < 0) {
-               errorMsg("Error creating symlink '%s': %s\n", header->linkname, strerror(errno)); 
+               errorMsg("Error creating symlink '%s' to '%s': %s\n", 
+                               header->name, header->linkname, strerror(errno)); 
                return;
        }
        /* Try to change ownership of the symlink.
@@ -644,18 +647,15 @@ typedef struct TarBallInfo TarBallInfo;
 static int putOctal (char *cp, int len, long value)
 {
        int tempLength;
-       char *tempString;
        char tempBuffer[32];
+       char *tempString = tempBuffer;
 
        /* 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;
+       sprintf (tempString, "%0*lo", len - 1, value);
 
        /* If the string is too large, suppress the leading space.  */
+       tempLength = strlen (tempString) + 1;
        if (tempLength > len) {
                tempLength--;
                tempString++;
@@ -677,10 +677,14 @@ static int putOctal (char *cp, int len, long value)
 
 /* Write out a tar header for the specified file/directory/whatever */
 static int
-writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *statbuf)
+writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *statbuf)
 {
-       //int i;
-       //long chksum, sum;
+       long chksum=0;
+       struct TarHeader header;
+       const unsigned char *cp = (const unsigned char *) &header;
+       ssize_t size = sizeof(struct TarHeader);
+
+       memset( &header, 0, size);
 
        if (*fileName=='/') {
                static int alreadyWarned=FALSE;
@@ -688,66 +692,88 @@ writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *stat
                        errorMsg("tar: Removing leading '/' from member names\n");
                        alreadyWarned=TRUE;
                }
-               strcpy(header->name, fileName+1); 
+               strcpy(header.name, fileName+1); 
        }
        else {
-               strcpy(header->name, fileName); 
+               strcpy(header.name, fileName); 
        }
-       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);
-
+       putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
+       putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
+       putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
+       putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */
+       putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
+       strncpy(header.magic, TAR_MAGIC TAR_VERSION, 
+                       TAR_MAGIC_LEN + TAR_VERSION_LEN );
+
+       my_getpwuid(header.uname, statbuf->st_uid);
+       /* Put some sort of sane fallback in place... */
+       if (! *header.uname)
+               strncpy(header.uname, "root", 5);
+       my_getgrgid(header.gname, statbuf->st_gid);
+       if (! *header.uname)
+               strncpy(header.uname, "root", 5);
+
+       // FIXME: (or most likely not) I break Hard Links
        if (S_ISLNK(statbuf->st_mode)) {
-               header->typeflag  = LNKTYPE;
-               // TODO -- Handle SYMTYPE
+               char buffer[BUFSIZ];
+               header.typeflag  = SYMTYPE;
+               if ( readlink(fileName, buffer, sizeof(buffer) - 1) < 0) {
+                       errorMsg("Error reading symlink '%s': %s\n", header.name, strerror(errno));
+                       return ( FALSE);
+               }
+               strncpy(header.linkname, buffer, sizeof(header.linkname)); 
        } else if (S_ISDIR(statbuf->st_mode)) {
-               header->typeflag  = DIRTYPE;
-               strncat(header->name, "/", sizeof(header->name)); 
+               header.typeflag  = DIRTYPE;
+               strncat(header.name, "/", sizeof(header.name)); 
        } else if (S_ISCHR(statbuf->st_mode)) {
-               header->typeflag  = CHRTYPE;
-               putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev));
-               putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev));
+               header.typeflag  = CHRTYPE;
+               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
+               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
        } else if (S_ISBLK(statbuf->st_mode)) {
-               header->typeflag  = BLKTYPE;
-               putOctal(header->devmajor, sizeof(header->devmajor), MAJOR(statbuf->st_rdev));
-               putOctal(header->devminor, sizeof(header->devminor), MINOR(statbuf->st_rdev));
+               header.typeflag  = BLKTYPE;
+               putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
+               putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
        } else if (S_ISFIFO(statbuf->st_mode)) {
-               header->typeflag  = FIFOTYPE;
-       } else if (S_ISLNK(statbuf->st_mode)) {
-               header->typeflag  = LNKTYPE;
-       } else if (S_ISLNK(statbuf->st_mode)) {
-               header->typeflag  = REGTYPE;
+               header.typeflag  = FIFOTYPE;
+       } else if (S_ISREG(statbuf->st_mode)) {
+               header.typeflag  = REGTYPE;
+               putOctal(header.size, sizeof(header.size), statbuf->st_size);
        } else {
+               errorMsg("tar: %s: Unknown file type\n", fileName);
                return ( FALSE);
        }
-       return ( TRUE);
-
-#if 0  
-       header->linkname  = rawHeader->linkname;
-       header->devmajor  = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor));
-       header->devminor  = getOctal(rawHeader->devminor, sizeof(rawHeader->devminor));
 
-       /* Write out the checksum */
-       chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum));
+       /* Calculate and store the checksum (i.e. the sum of all of the bytes of
+        * the header).  The checksum field must be filled with blanks for the
+        * calculation.  The checksum field is formatted differently from the
+        * other fields: it has [6] digits, a null, then a space -- rather than
+        * digits, followed by a null like the other fields... */
+       memset(header.chksum, ' ', sizeof(header.chksum));
+       cp = (const unsigned char *) &header;
+       while (size-- > 0)
+               chksum += *cp++;
+       putOctal(header.chksum, 7, chksum);
+       
+       /* Now write the header out to disk */
+       if ((size=fullWrite(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) {
+               errorMsg(io_error, fileName, strerror(errno)); 
+               return ( FALSE);
+       }
+       /* Pad the header up to the tar block size */
+       for (; size<TAR_BLOCK_SIZE; size++) {
+               write(tbInfo->tarFd, "\0", 1);
+       }
+       /* Now do the verbose thing (or not) */
+       if (tbInfo->verboseFlag==TRUE)
+               fprintf(stdout, "%s\n", header.name);
 
        return ( TRUE);
-#endif
 }
 
 
 static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData)
 {
-       int inputFileFd;
        struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData;
-       char header[sizeof(struct TarHeader)];
-
-       /* First open the file we want to archive, and make sure all is well */
-       if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
-               errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno));
-               return( TRUE);
-       }
 
        /* It is against the rules to archive a socket */
        if (S_ISSOCK(statbuf->st_mode)) {
@@ -764,13 +790,41 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, void*
                return( TRUE);
        }
 
-       memset( header, 0, sizeof(struct TarHeader));
-       if (writeTarHeader((struct TarHeader *)header, fileName, statbuf)==FALSE) {
-               dprintf(tbInfo->tarFd, "%s", header);
+       if (writeTarHeader(tbInfo, fileName, statbuf)==FALSE) {
+               return( FALSE);
        } 
-       /* Now do the verbose thing (or not) */
-       if (tbInfo->verboseFlag==TRUE)
-               fprintf(stdout, "%s\n", ((struct TarHeader *)header)->name);
+
+       /* Now, if the file is a regular file, copy it out to the tarball */
+       if (S_ISREG(statbuf->st_mode)) {
+               int  inputFileFd;
+               char buffer[BUFSIZ];
+               ssize_t size=0, readSize=0;
+
+               /* open the file we want to archive, and make sure all is well */
+               if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
+                       errorMsg("tar: %s: Cannot open: %s\n", fileName, strerror(errno));
+                       return( FALSE);
+               }
+               
+               /* write the file to the archive */
+               while ( (size = fullRead(inputFileFd, buffer, sizeof(buffer))) > 0 ) {
+                       if (fullWrite(tbInfo->tarFd, buffer, size) != size ) {
+                               /* Output file seems to have a problem */
+                               errorMsg(io_error, fileName, strerror(errno)); 
+                               return( FALSE);
+                       }
+                       readSize+=size;
+               }
+               if (size == -1) {
+                       errorMsg(io_error, fileName, strerror(errno)); 
+                       return( FALSE);
+               }
+               /* Pad the file up to the tar block size */
+               for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) {
+                       write(tbInfo->tarFd, "\0", 1);
+               }
+               close( inputFileFd);
+       }
 
        return( TRUE);
 }
@@ -780,6 +834,7 @@ static int writeTarFile(const char* tarName, int tostdoutFlag,
 {
        int tarFd=-1;
        int errorFlag=FALSE;
+       ssize_t size;
        //int skipFileFlag=FALSE;
        struct TarBallInfo tbInfo;
        tbInfo.verboseFlag = verboseFlag;
@@ -814,6 +869,10 @@ static int writeTarFile(const char* tarName, int tostdoutFlag,
                        errorFlag = TRUE;
                }
        }
+       /* Write two empty blocks to the end of the archive */
+       for (size=0; size<(2*TAR_BLOCK_SIZE); size++) {
+               write(tbInfo.tarFd, "\0", 1);
+       }
        /* Hang up the tools, close up shop, head home */
        close(tarFd);
        if (errorFlag == TRUE) {
index 0d4799f2db5d71fbab26505b66ffad2f2522f51d..b91da4ce46c157124ac80d47ffb3ea13f6232d12 100644 (file)
--- a/utility.c
+++ b/utility.c
@@ -783,7 +783,7 @@ extern int parse_mode(const char *s, mode_t * theMode)
 
 
 
-#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_PS)
+#if defined BB_CHMOD_CHOWN_CHGRP || defined BB_PS || defined BB_LS || defined BB_TAR 
 
 /* Use this to avoid needing the glibc NSS stuff 
  * This uses storage buf to hold things.
@@ -858,7 +858,7 @@ void my_getgrgid(char *group, gid_t gid)
 }
 
 
-#endif                                                 /* BB_CHMOD_CHOWN_CHGRP || BB_PS */
+#endif                                                 /* BB_CHMOD_CHOWN_CHGRP || BB_PS || BB_LS || BB_TAR */