Update tar so creation of tarballs is much closer to working...

-Erik
This commit is contained in:
Erik Andersen 2000-04-04 18:39:50 +00:00
parent 183da4ade1
commit 68a9ea4208
2 changed files with 250 additions and 136 deletions

View File

@ -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 @@ static int readTarFile(const char* tarName, int extractFlag, int listFlag,
#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 @@ extern int tar_main(int argc, char **argv)
#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 @@ tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag)
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 @@ endgame:
#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 @@ static int putOctal (char *cp, int len, long value)
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 @@ writeTarHeader(struct TarHeader *rawHeader, struct TarInfo *header)
/* 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 @@ static int writeTarFile(const char* tarName, int extractFlag, int listFlag,
/* 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 @@ static int writeTarFile(const char* tarName, int extractFlag, int listFlag,
/* 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);
}

193
tar.c
View File

@ -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 @@ static int readTarFile(const char* tarName, int extractFlag, int listFlag,
#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 @@ extern int tar_main(int argc, char **argv)
#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 @@ tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag)
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 @@ endgame:
#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 @@ static int putOctal (char *cp, int len, long value)
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 @@ writeTarHeader(struct TarHeader *rawHeader, struct TarInfo *header)
/* 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 @@ static int writeTarFile(const char* tarName, int extractFlag, int listFlag,
/* 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 @@ static int writeTarFile(const char* tarName, int extractFlag, int listFlag,
/* 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);
}