diff options
author | Eric Andersen <andersen@codepoet.org> | 1999-10-13 02:26:06 +0400 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 1999-10-13 02:26:06 +0400 |
commit | 3cf52d19581b2077480e7d2e63010baa1f5399c1 (patch) | |
tree | d91b0cb332ebc976126e36a394655dde7a15d8b1 /tar.c | |
parent | 2ce1edcf544ac675e6762c9861a6b918401ea716 (diff) |
More stuff...
Diffstat (limited to 'tar.c')
-rw-r--r-- | tar.c | 1836 |
1 files changed, 881 insertions, 955 deletions
@@ -7,7 +7,7 @@ * 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> */ @@ -15,11 +15,11 @@ #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"; +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"; @@ -42,24 +42,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,168 +72,162 @@ typedef struct /* * Static data. */ -static int listFlag; -static int extractFlag; -static int createFlag; -static int verboseFlag; -static int tostdoutFlag; - -static int inHeader; -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 int listFlag; +static int extractFlag; +static int createFlag; +static int verboseFlag; +static int tostdoutFlag; + +static int inHeader; +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 void createPath (const char *name, int mode); +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, int 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 int 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 int putOctal(char * cp, int len, long value); +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(int argc, char ** argv) +extern int tar_main (int argc, char **argv) { - const char * options; - - 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; - } - - tarName = *argv++; - argc--; - - break; + const char *options; + + argc--; + argv++; + + if (argc < 1) { + fprintf (stderr, "%s", tar_usage); + exit (FALSE); + } + + + 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"); + + 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 '-': + 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", *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 != 1) { + 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) + writeTarFile (argc, argv); + else + readTarFile (argc, argv); + if (errorFlag) + fprintf (stderr, "\n"); + exit (errorFlag); } @@ -242,128 +235,119 @@ tar_main(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. + 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); + + 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) { + /* + * 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 ( (tarName==NULL) || !strcmp( tarName, "-") ) { - tarFd = STDIN; - } - else - tarFd = open(tarName, O_RDONLY); + if (inCc <= 0) { + cp = buf; + inCc = fullRead (tarFd, buf, blockSize); - if (tarFd < 0) - { - perror(tarName); + if (inCc < 0) { + perror (tarName); errorFlag = TRUE; - return; + goto done; + } + + if (inCc == 0) { + fprintf (stderr, + "Unexpected end of file from \"%s\"", tarName); + errorFlag = TRUE; + 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) { + 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. + /* + * 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. */ - if ((tarFd >= 0) && (close(tarFd) < 0)) - perror(tarName); + cc = inCc; + + if (cc > dataCc) + cc = dataCc; - /* - * Close the output file if needed. - * This is only done here on a previous error and so no - * message is required on errors. + 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 (tostdoutFlag==FALSE) { - if (outFd >= 0) - (void) close(outFd); - } + 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); + } } @@ -373,332 +357,307 @@ 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; - int hardLink; - int 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; + long size; + time_t mtime; + const char *name; + int cc; + int hardLink; + int 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; } - /* - * 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)); + eofFlag = TRUE; - if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) - { - if (!badHeader) - fprintf(stderr, "Bad tar header, skipping\n"); + return; + } - badHeader = TRUE; + /* + * 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)); - return; - } + if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) { + if (!badHeader) + fprintf (stderr, "Bad tar header, skipping\n"); - badHeader = FALSE; - skipFileFlag = FALSE; + badHeader = TRUE; - /* - * Check for the file modes. - */ - hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) || + return; + } + + badHeader = FALSE; + skipFileFlag = 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 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"); } - /* - * 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)) { + if (!hardLink && !softLink && S_ISREG (mode)) { + inHeader = (size == 0); + 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"); + skipFileFlag = TRUE; - return; - } + return; + } - /* - * We really want to extract the file. - */ - if (verboseFlag) - printf("x %s\n", name); + /* + * 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) - { - if (link(hp->linkName, name) < 0) - perror(name); - - return; - } - - if (softLink) - { -#ifdef S_ISLNK - if (symlink(hp->linkName, name) < 0) - perror(name); -#else - fprintf(stderr, "Cannot create symbolic links\n"); -#endif - return; + 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; } - /* - * 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) + printf ("x %s\n", name); - inHeader = (size == 0); - dataCc = size; + if (hardLink) { + if (link (hp->linkName, name) < 0) + perror (name); - /* - * 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; - } + return; + } - /* - * If the file is empty, then that's all we need to do. - */ - if (size == 0 && tostdoutFlag == FALSE) - { - (void) close(outFd); - outFd = -1; - } + 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); + + return; + } + + /* + * There is a file to write. + * First create the path to it if necessary with a default permission. + */ + createPath (name, 0777); + + inHeader = (size == 0); + dataCc = size; + + /* + * 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 the file is empty, then that's all we need to do. + */ + if (size == 0 && tostdoutFlag == 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 || skipFileFlag) + 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 = 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); } @@ -709,76 +668,70 @@ 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, int 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) + 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) + status = lstat (fileName, &statbuf); + else #endif - status = stat(fileName, &statbuf); + status = stat (fileName, &statbuf); - if (status < 0) - { - perror(fileName); + if (status < 0) { + perror (fileName); - return; - } + 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"); + /* + * 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; - } + return; + } - /* - * Check the type of file. - */ - mode = statbuf.st_mode; + /* + * Check the type of file. + */ + mode = statbuf.st_mode; - if (S_ISDIR(mode)) - { - saveDirectory(fileName, &statbuf); + if (S_ISDIR (mode)) { + saveDirectory (fileName, &statbuf); - return; - } + return; + } - if (S_ISREG(mode)) - { - saveRegularFile(fileName, &statbuf); + if (S_ISREG (mode)) { + saveRegularFile (fileName, &statbuf); - return; - } + return; + } - /* - * The file is a strange type of file, ignore it. - */ - fprintf(stderr, "%s: not a directory or regular file\n", fileName); + /* + * The file is a strange type of file, ignore it. + */ + fprintf (stderr, "%s: not a directory or regular file\n", fileName); } @@ -786,183 +739,173 @@ saveFile(const char * fileName, int 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) { - int sawEof; - int fileFd; - int cc; - int dataCount; - long fullDataCount; - char data[TAR_BLOCK_SIZE * 16]; - - /* - * Open the file for reading. + 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. */ - fileFd = open(fileName, O_RDONLY); - - if (fileFd < 0) - { - perror(fileName); + dataCount = sizeof (data); - return; - } + if (dataCount > fullDataCount) + dataCount = (int) fullDataCount; - /* - * Write out the header for the file. + /* + * Read the data from the file if we haven't seen the + * end of file yet. */ - writeHeader(fileName, statbuf); + cc = 0; - /* - * 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) - { - 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; - } - } + if (!sawEof) { + cc = fullRead (fileFd, data, dataCount); - /* - * Zero fill the rest of the data if necessary. - */ - if (cc < dataCount) - memset(data + cc, 0, dataCount - cc); + if (cc < 0) { + perror (fileName); - /* - * Write the buffer to the TAR file. - */ - writeTarBlock(data, dataCount); + (void) close (fileFd); + errorFlag = TRUE; - fullDataCount -= dataCount; + 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; + } } - /* - * Close the file. + /* + * 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. */ - if ( (tostdoutFlag==FALSE) && close(fileFd) < 0) - fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno)); + writeTarBlock (data, dataCount); + + fullDataCount -= dataCount; + } + + /* + * 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; - int 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[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; + } + + /* + * 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 && ((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); } @@ -970,55 +913,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)); } @@ -1027,59 +969,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; - } + 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; + } } @@ -1089,29 +1028,27 @@ writeTarBlock(const char * buf, int len) * 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) +static void createPath (const char *name, int mode) { - char * cp; - char * cpOld; - char buf[TAR_NAME_SIZE]; + char *cp; + char *cpOld; + char buf[TAR_NAME_SIZE]; - strcpy(buf, name); + strcpy (buf, name); - cp = strchr(buf, '/'); + cp = strchr (buf, '/'); - while (cp) - { - cpOld = cp; - cp = strchr(cp + 1, '/'); + while (cp) { + cpOld = cp; + cp = strchr (cp + 1, '/'); - *cpOld = '\0'; + *cpOld = '\0'; - if (mkdir(buf, cp ? 0777 : mode) == 0) - printf("Directory \"%s\" created\n", buf); + if (mkdir (buf, cp ? 0777 : mode) == 0) + printf ("Directory \"%s\" created\n", buf); - *cpOld = '/'; - } + *cpOld = '/'; + } } @@ -1120,38 +1057,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; } @@ -1160,50 +1093,48 @@ getOctal(const char * cp, int len) * The number is zero and space padded and possibly null padded. * Returns TRUE if successful. */ -static int -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--; + 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; - /* - * 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; } @@ -1213,48 +1144,43 @@ putOctal(char * cp, int len, long value) * Returns TRUE if the file is selected. */ static int -wantFileName(const char * fileName, int fileCount, char ** fileTable) +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; + 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); + fileLength = strlen (fileName); - /* - * Check each of the test paths. - */ - while (fileCount-- > 0) - { - pathName = *fileTable++; + /* + * Check each of the test paths. + */ + while (fileCount-- > 0) { + pathName = *fileTable++; - pathLength = strlen(pathName); + pathLength = strlen (pathName); - if (fileLength < pathLength) - continue; + if (fileLength < pathLength) + continue; - if (memcmp(fileName, pathName, pathLength) != 0) - continue; + if (memcmp (fileName, pathName, pathLength) != 0) + continue; - if ((fileLength == pathLength) || - (fileName[pathLength] == '/')) - { - return TRUE; - } + if ((fileLength == pathLength) || (fileName[pathLength] == '/')) { + return TRUE; } + } - return FALSE; + return FALSE; } #endif /* END CODE */ - - |