Update tar so creation of tarballs is much closer to working...
-Erik
diff --git a/archival/tar.c b/archival/tar.c
index af0e4f8..f9b3e18 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -1,12 +1,12 @@
/* vi: set sw=4 ts=4: */
/*
+ * Mini tar implementation for busybox
*
- * Mini tar implementation for busybox Note, that as of BusyBox 0.43 tar has
- * been completely rewritten from the ground up. It still has remnents of the
- * old code lying about, but it pretty different (i.e. cleaner, less global
- * variables, etc)
+ * Note, that as of BusyBox 0.43 tar has been completely rewritten from the
+ * ground up. It still has remnents of the old code lying about, but it pretty
+ * different (i.e. cleaner, less global variables, etc)
*
- * Copyright (C) 1999 by Lineo, inc.
+ * Copyright (C) 2000 by Lineo, inc.
* Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
*
* Based in part in the tar implementation in sash
@@ -15,7 +15,7 @@
* provided that this copyright notice remains intact.
* Permission to distribute sash derived code under the GPL has been granted.
*
- * Based in part on the tar implementation in busybox-0.28
+ * Based in part on the tar implementation from busybox-0.28
* Copyright (C) 1995 Bruce Perens
* This is free software under the GNU General Public License.
*
@@ -162,8 +162,8 @@
#ifdef BB_FEATURE_TAR_CREATE
/* Local procedures to save files into a tar file. */
-static int writeTarFile(const char* tarName, int extractFlag, int listFlag,
- int tostdoutFlag, int verboseFlag, int argc, char **argv);
+static int writeTarFile(const char* tarName, int tostdoutFlag,
+ int verboseFlag, int argc, char **argv);
static int putOctal(char *cp, int len, long value);
#endif
@@ -249,7 +249,7 @@
#ifndef BB_FEATURE_TAR_CREATE
fatalError( "This version of tar was not compiled with tar creation support.\n");
#else
- exit(writeTarFile(tarName, extractFlag, listFlag, tostdoutFlag, verboseFlag, argc, argv));
+ exit(writeTarFile(tarName, tostdoutFlag, verboseFlag, argc, argv));
#endif
} else {
exit(readTarFile(tarName, extractFlag, listFlag, tostdoutFlag, verboseFlag));
@@ -410,8 +410,6 @@
mknod(header->name, header->mode, makedev(header->devmajor, header->devminor));
} else if (S_ISFIFO(header->mode)) {
mkfifo(header->name, header->mode);
- } else {
- open(header->name, O_WRONLY | O_CREAT | O_TRUNC, header->mode);
}
/* Now set permissions etc for the new directory */
@@ -625,6 +623,21 @@
#ifdef BB_FEATURE_TAR_CREATE
+/* Some info to be carried along when creating a new tarball */
+struct TarBallInfo
+{
+ char* fileName; /* File name of the tarball */
+ int tarFd; /* Open-for-write file descriptor
+ for the tarball */
+ struct stat statBuf; /* Stat info for the tarball, letting
+ us know the inode and device that the
+ tarball lives, so we can avoid trying
+ to include the tarball into itself */
+ int verboseFlag; /* Whether to print extra stuff or not */
+};
+typedef struct TarBallInfo TarBallInfo;
+
+
/* Put an octal string into the specified buffer.
* The number is zero and space padded and possibly null padded.
* Returns TRUE if successful. */
@@ -662,41 +675,55 @@
return TRUE;
}
-/* Write out a tar header for the specified file */
+/* Write out a tar header for the specified file/directory/whatever */
static int
-writeTarHeader(struct TarHeader *rawHeader, struct TarInfo *header)
+writeTarHeader(struct TarHeader *header, const char *fileName, struct stat *statbuf)
{
- int i;
- long chksum, sum;
- unsigned char *s = (unsigned char *)rawHeader;
+ //int i;
+ //long chksum, sum;
- struct TarHeader header;
-
- 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);
-
- if (S_ISLNK(statbuf.st_mode)) {
- header.type = LNKTYPE;
- // Handle SYMTYPE
- } else if (S_ISDIR(statbuf.st_mode)) {
- header.type = DIRTYPE;
- } else if (S_ISCHR(statbuf.st_mode)) {
- header.type = CHRTYPE;
- } else if (S_ISBLK(statbuf.st_mode)) {
- header.type = BLKTYPE;
- } else if (S_ISFIFO(statbuf.st_mode)) {
- header.type = FIFOTYPE;
- } else if (S_ISSOCK(statbuf.st_mode)) {
- header.type = S_ISSOCK;
- } else if (S_ISLNK(statbuf.st_mode)) {
- header.type = LNKTYPE;
- } else if (S_ISLNK(statbuf.st_mode)) {
- header.type = REGTYPE;
+ if (*fileName=='/') {
+ static int alreadyWarned=FALSE;
+ if (alreadyWarned==FALSE) {
+ errorMsg("tar: Removing leading '/' from member names\n");
+ alreadyWarned=TRUE;
+ }
+ strcpy(header->name, fileName+1);
}
+ else {
+ 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);
+
+ if (S_ISLNK(statbuf->st_mode)) {
+ header->typeflag = LNKTYPE;
+ // TODO -- Handle SYMTYPE
+ } else if (S_ISDIR(statbuf->st_mode)) {
+ 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));
+ } 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));
+ } 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;
+ } else {
+ return ( FALSE);
+ }
+ return ( TRUE);
+
#if 0
header->linkname = rawHeader->linkname;
header->devmajor = getOctal(rawHeader->devmajor, sizeof(rawHeader->devmajor));
@@ -704,31 +731,58 @@
/* Write out the checksum */
chksum = getOctal(rawHeader->chksum, sizeof(rawHeader->chksum));
-#endif
return ( TRUE);
+#endif
}
-static int fileAction(const char *fileName, struct stat *statbuf, void* userData)
+static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData)
{
- int *tarFd=(int*)userData;
- dprintf(*tarFd, "%s\n", fileName);
- return (TRUE);
+ 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)) {
+ errorMsg("tar: %s: socket ignored\n", fileName);
+ return( TRUE);
+ }
+
+ /* It is a bad idea to store the archive we are in the process of creating,
+ * so check the device and inode to be sure that this particular file isn't
+ * the new tarball */
+ if (tbInfo->statBuf.st_dev == statbuf->st_dev &&
+ tbInfo->statBuf.st_ino == statbuf->st_ino) {
+ errorMsg("tar: %s: file is the archive; skipping\n", fileName);
+ return( TRUE);
+ }
+
+ memset( header, 0, sizeof(struct TarHeader));
+ if (writeTarHeader((struct TarHeader *)header, fileName, statbuf)==FALSE) {
+ dprintf(tbInfo->tarFd, "%s", header);
+ }
+ /* Now do the verbose thing (or not) */
+ if (tbInfo->verboseFlag==TRUE)
+ fprintf(stdout, "%s\n", ((struct TarHeader *)header)->name);
+
+ return( TRUE);
}
-static int writeTarFile(const char* tarName, int extractFlag, int listFlag,
- int tostdoutFlag, int verboseFlag, int argc, char **argv)
+static int writeTarFile(const char* tarName, int tostdoutFlag,
+ int verboseFlag, int argc, char **argv)
{
int tarFd=-1;
- //int errorFlag=FALSE;
- //TarHeader rawHeader;
- //TarInfo header;
- //int alreadyWarned=FALSE;
+ int errorFlag=FALSE;
//int skipFileFlag=FALSE;
- struct stat tarballStat;
- dev_t tarDev = 0;
- ino_t tarInode = 0;
+ struct TarBallInfo tbInfo;
+ tbInfo.verboseFlag = verboseFlag;
/* Make sure there is at least one file to tar up. */
if (argc <= 0)
@@ -736,19 +790,17 @@
/* Open the tar file for writing. */
if (tostdoutFlag == TRUE)
- tarFd = fileno(stdout);
+ tbInfo.tarFd = fileno(stdout);
else
- tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (tarFd < 0) {
- errorMsg( "Error opening '%s': %s\n", tarName, strerror(errno));
+ tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (tbInfo.tarFd < 0) {
+ errorMsg( "tar: Error opening '%s': %s\n", tarName, strerror(errno));
return ( FALSE);
}
- /* Store the device and inode of the tarball, so we can be sure
- * not to try and include it into itself.... */
- if (fstat(tarFd, &tarballStat) < 0)
+ /* Store the stat info for the tarball's file, so
+ * can avoid including the tarball into itself.... */
+ if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
fatalError(io_error, tarName, strerror(errno));
- tarDev = tarballStat.st_dev;
- tarInode = tarballStat.st_ino;
/* Set the umask for this process so it doesn't
* screw up permission setting for us later. */
@@ -757,12 +809,17 @@
/* Read the directory/files and iterate over them one at a time */
while (argc-- > 0) {
if (recursiveAction(*argv++, TRUE, FALSE, FALSE,
- fileAction, fileAction, (void*) &tarFd) == FALSE) {
- exit(FALSE);
+ writeFileToTarball, writeFileToTarball,
+ (void*) &tbInfo) == FALSE) {
+ errorFlag = TRUE;
}
}
-
+ /* Hang up the tools, close up shop, head home */
close(tarFd);
+ if (errorFlag == TRUE) {
+ errorMsg("tar: Error exit delayed from previous errors\n");
+ return(FALSE);
+ }
return( TRUE);
}