2 * Mini tar implementation for busybox based on code taken from sash.
4 * Copyright (c) 1999 by David I. Bell
5 * Permission is granted to use, distribute, or modify this source,
6 * provided that this copyright notice remains intact.
8 * Permission to distribute this code under the GPL has been granted.
10 * Modified for busybox by Erik Andersen <andersee@debian.org>
11 * Adjusted to grok stdin/stdout options.
13 * Modified to handle device special files by Matt Porter
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 #include <sys/types.h>
42 #include <sys/sysmacros.h>
45 static const char tar_usage[] =
46 "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n"
47 "Create, extract, or list files from a tar file\n\n"
49 "\tc=create, x=extract, t=list contents, v=verbose,\n"
50 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
57 #define TAR_BLOCK_SIZE 512
58 #define TAR_NAME_SIZE 100
62 * The POSIX (and basic GNU) tar header format.
63 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
64 * with zero padding. We only process this information minimally.
67 char name[TAR_NAME_SIZE];
75 char linkName[TAR_NAME_SIZE];
85 #define TAR_MAGIC "ustar"
86 #define TAR_VERSION "00"
88 #define TAR_TYPE_REGULAR '0'
89 #define TAR_TYPE_HARD_LINK '1'
90 #define TAR_TYPE_SOFT_LINK '2'
97 static int extractFlag;
98 static int createFlag;
99 static int verboseFlag;
100 static int tostdoutFlag;
102 static int inHeader; // <- check me
103 static int badHeader;
104 static int errorFlag;
105 static int skipFileFlag;
106 static int warnedRoot;
110 static const char *outName;
118 * Static data associated with the tar file.
120 static const char *tarName;
123 static ino_t tarInode;
127 * Local procedures to restore files from a tar file.
129 static void readTarFile (int fileCount, char **fileTable);
130 static void readData (const char *cp, int count);
131 static long getOctal (const char *cp, int len);
133 static void readHeader (const TarHeader * hp,
134 int fileCount, char **fileTable);
138 * Local procedures to save files into a tar file.
140 static void saveFile (const char *fileName, int seeLinks);
142 static void saveRegularFile (const char *fileName,
143 const struct stat *statbuf);
145 static void saveDirectory (const char *fileName,
146 const struct stat *statbuf);
148 static int wantFileName (const char *fileName,
149 int fileCount, char **fileTable);
151 static void writeHeader (const char *fileName, const struct stat *statbuf);
153 static void writeTarFile (int fileCount, char **fileTable);
154 static void writeTarBlock (const char *buf, int len);
155 static int putOctal (char *cp, int len, long value);
158 extern int tar_main (int argc, char **argv)
174 tostdoutFlag = FALSE;
184 options = (*argv++) + 1;
186 for (; *options; options++) {
189 if (tarName != NULL) {
190 fprintf (stderr, "Only one 'f' option allowed\n");
225 fprintf (stderr, "Unknown tar flag '%c'\n"
226 "Try `tar --help' for more information\n",
235 * Validate the options.
237 if (extractFlag + listFlag + createFlag != (TRUE+FALSE+FALSE)) {
239 "Exactly one of 'c', 'x' or 't' must be specified\n");
245 * Do the correct type of action supplying the rest of the
246 * command line arguments as the list of files to process.
248 if (createFlag==TRUE)
249 writeTarFile (argc, argv);
251 readTarFile (argc, argv);
253 fprintf (stderr, "\n");
259 * Read a tar file and extract or list the specified files within it.
260 * If the list is empty than all files are extracted or listed.
262 static void readTarFile (int fileCount, char **fileTable)
270 skipFileFlag = FALSE;
278 blockSize = sizeof (buf);
282 * Open the tar file for reading.
284 if ((tarName == NULL) || !strcmp (tarName, "-")) {
285 tarFd = fileno(stdin);
287 tarFd = open (tarName, O_RDONLY);
296 * Read blocks from the file until an end of file header block
297 * has been seen. (A real end of file from a read is an error.)
299 while (eofFlag==FALSE) {
301 * Read the next block of data if necessary.
302 * This will be a large block if possible, which we will
303 * then process in the small tar blocks.
307 inCc = fullRead (tarFd, buf, blockSize);
317 "Unexpected end of file from \"%s\"", tarName);
324 * If we are expecting a header block then examine it.
326 if (inHeader==TRUE) {
327 readHeader ((const TarHeader *) cp, fileCount, fileTable);
329 cp += TAR_BLOCK_SIZE;
330 inCc -= TAR_BLOCK_SIZE;
336 * We are currently handling the data for a file.
337 * Process the minimum of the amount of data we have available
338 * and the amount left to be processed for the file.
348 * If the amount left isn't an exact multiple of the tar block
349 * size then round it up to the next block boundary since there
350 * is padding at the end of the file.
352 if (cc % TAR_BLOCK_SIZE)
353 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
361 * Close the tar file if needed.
363 if ((tarFd >= 0) && (close (tarFd) < 0))
367 * Close the output file if needed.
368 * This is only done here on a previous error and so no
369 * message is required on errors.
371 if (tostdoutFlag == FALSE) {
380 * Examine the header block that was just read.
381 * This can specify the information for another file, or it can mark
382 * the end of the tar file.
385 readHeader (const TarHeader * hp, int fileCount, char **fileTable)
398 * If the block is completely empty, then this is the end of the
399 * archive file. If the name is null, then just skip this header.
403 if (*outName == '\0') {
404 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
415 * There is another file in the archive to examine.
416 * Extract the encoded information and check it.
418 mode = getOctal (hp->mode, sizeof (hp->mode));
419 uid = getOctal (hp->uid, sizeof (hp->uid));
420 gid = getOctal (hp->gid, sizeof (hp->gid));
421 size = getOctal (hp->size, sizeof (hp->size));
422 mtime = getOctal (hp->mtime, sizeof (hp->mtime));
423 checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
424 major = getOctal (hp->devMajor, sizeof (hp->devMajor));
425 minor = getOctal (hp->devMinor, sizeof (hp->devMinor));
427 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
428 if (badHeader==FALSE)
429 fprintf (stderr, "Bad tar header, skipping\n");
437 skipFileFlag = FALSE;
441 * Check for the file modes.
443 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
444 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
446 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
447 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
450 * Check for a directory.
452 if (outName[strlen (outName) - 1] == '/')
456 * Check for absolute paths in the file.
457 * If we find any, then warn the user and make them relative.
459 if (*outName == '/') {
460 while (*outName == '/')
463 if (warnedRoot==FALSE) {
465 "Absolute path detected, removing leading slashes\n");
472 * See if we want this file to be restored.
473 * If not, then set up to skip it.
475 if (wantFileName (outName, fileCount, fileTable) == FALSE) {
476 if ( !hardLink && !softLink && (S_ISREG (mode) || S_ISCHR (mode)
477 || S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) {
478 inHeader = (size == 0)? TRUE : FALSE;
488 * This file is to be handled.
489 * If we aren't extracting then just list information about the file.
491 if (extractFlag==FALSE) {
492 if (verboseFlag==TRUE) {
493 printf ("%s %3d/%-d ", modeString (mode), uid, gid);
494 if( S_ISCHR (mode) || S_ISBLK (mode) )
495 printf ("%4d,%4d %s ", major,minor, timeString (mtime));
497 printf ("%9ld %s ", size, timeString (mtime));
499 printf ("%s", outName);
502 printf (" (link to \"%s\")", hp->linkName);
504 printf (" (symlink to \"%s\")", hp->linkName);
505 else if (S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode) ||
506 S_ISSOCK(mode) || S_ISFIFO(mode) ) {
507 inHeader = (size == 0)? TRUE : FALSE;
517 * We really want to extract the file.
519 if (verboseFlag==TRUE)
520 printf ("x %s\n", outName);
523 if (link (hp->linkName, outName) < 0)
525 /* Set the file time */
528 utime (outName, &utb);
529 /* Set the file permissions */
530 chown(outName, uid, gid);
531 chmod(outName, mode);
537 if (symlink (hp->linkName, outName) < 0)
539 /* Try to change ownership of the symlink.
540 * If libs doesn't support that, don't bother.
541 * Changing the pointed-to file is the Wrong Thing(tm).
543 #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
544 lchown(outName, uid, gid);
547 /* Do not change permissions or date on symlink,
548 * since it changes the pointed to file instead. duh. */
550 fprintf (stderr, "Cannot create symbolic links\n");
555 /* Set the umask for this process so it doesn't
556 * screw things up. */
560 * If the file is a directory, then just create the path.
562 if (S_ISDIR (mode)) {
563 createPath (outName, mode);
564 /* Set the file time */
567 utime (outName, &utb);
568 /* Set the file permissions */
569 chown(outName, uid, gid);
570 chmod(outName, mode);
575 * There is a file to write.
576 * First create the path to it if necessary with default permissions.
578 createPath (outName, 0777);
580 inHeader = (size == 0)? TRUE : FALSE;
584 * Start the output file.
586 if (tostdoutFlag == TRUE)
587 outFd = fileno(stdout);
589 if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) {
591 outFd = mknod (outName, mode, makedev(major, minor) );
593 else if (S_ISFIFO(mode) ) {
595 outFd = mkfifo(outName, mode);
597 outFd = open (outName, O_WRONLY | O_CREAT | O_TRUNC, mode);
604 /* Set the file time */
607 utime (outName, &utb);
608 /* Set the file permissions */
609 chown(outName, uid, gid);
610 chmod(outName, mode);
615 * If the file is empty, then that's all we need to do.
617 if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
625 * Handle a data block of some specified size that was read.
627 static void readData (const char *cp, int count)
630 * Reduce the amount of data left in this file.
631 * If there is no more data left, then we need to read
640 * If we aren't extracting files or this file is being
641 * skipped then do nothing more.
643 if (extractFlag==FALSE || skipFileFlag==TRUE)
647 * Write the data to the output file.
649 if (fullWrite (outFd, cp, count) < 0) {
651 if (tostdoutFlag == FALSE) {
660 * Check if we are done writing to the file now.
662 if (dataCc <= 0 && tostdoutFlag == FALSE) {
667 /* Set the file time */
670 utime (outName, &utb);
671 /* Set the file permissions */
672 chown(outName, uid, gid);
673 chmod(outName, mode);
681 * Write a tar file containing the specified files.
683 static void writeTarFile (int fileCount, char **fileTable)
688 * Make sure there is at least one file specified.
690 if (fileCount <= 0) {
691 fprintf (stderr, "No files specified to be saved\n");
696 * Create the tar file for writing.
698 if ((tarName == NULL) || !strcmp (tarName, "-")) {
700 tarFd = fileno(stdout);
702 tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
711 * Get the device and inode of the tar file for checking later.
713 if (fstat (tarFd, &statbuf) < 0) {
719 tarDev = statbuf.st_dev;
720 tarInode = statbuf.st_ino;
723 * Append each file name into the archive file.
724 * Follow symbolic links for these top level file names.
726 while (errorFlag==FALSE && (fileCount-- > 0)) {
727 saveFile (*fileTable++, FALSE);
731 * Now write an empty block of zeroes to end the archive.
733 writeTarBlock ("", 1);
738 * Close the tar file and check for errors if it was opened.
740 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
746 * Save one file into the tar file.
747 * If the file is a directory, then this will recursively save all of
748 * the files and directories within the directory. The seeLinks
749 * flag indicates whether or not we want to see symbolic links as
750 * they really are, instead of blindly following them.
752 static void saveFile (const char *fileName, int seeLinks)
757 if (verboseFlag==TRUE)
758 printf ("a %s\n", fileName);
761 * Check that the file name will fit in the header.
763 if (strlen (fileName) >= TAR_NAME_SIZE) {
764 fprintf (stderr, "%s: File name is too long\n", fileName);
770 * Find out about the file.
774 status = lstat (fileName, &statbuf);
777 status = stat (fileName, &statbuf);
786 * Make sure we aren't trying to save our file into itself.
788 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
789 fprintf (stderr, "Skipping saving of archive file itself\n");
795 * Check the type of file.
797 mode = statbuf.st_mode;
799 if (S_ISDIR (mode)) {
800 saveDirectory (fileName, &statbuf);
804 if (S_ISREG (mode)) {
805 saveRegularFile (fileName, &statbuf);
810 /* Some day add support for tarring these up... but not today. :) */
811 // if (S_ISLNK(mode) || S_ISFIFO(mode) || S_ISBLK(mode) || S_ISCHR (mode) ) {
812 // fprintf (stderr, "%s: This version of tar can't store this type of file\n", fileName);
816 * The file is a strange type of file, ignore it.
818 fprintf (stderr, "%s: not a directory or regular file\n", fileName);
823 * Save a regular file to the tar file.
826 saveRegularFile (const char *fileName, const struct stat *statbuf)
833 char data[TAR_BLOCK_SIZE * 16];
836 * Open the file for reading.
838 fileFd = open (fileName, O_RDONLY);
847 * Write out the header for the file.
849 writeHeader (fileName, statbuf);
852 * Write the data blocks of the file.
853 * We must be careful to write the amount of data that the stat
854 * buffer indicated, even if the file has changed size. Otherwise
855 * the tar file will be incorrect.
857 fullDataCount = statbuf->st_size;
860 while (fullDataCount > 0) {
862 * Get the amount to write this iteration which is
863 * the minumum of the amount left to write and the
866 dataCount = sizeof (data);
868 if (dataCount > fullDataCount)
869 dataCount = (int) fullDataCount;
872 * Read the data from the file if we haven't seen the
878 cc = fullRead (fileFd, data, dataCount);
883 (void) close (fileFd);
890 * If the file ended too soon, complain and set
891 * a flag so we will zero fill the rest of it.
893 if (cc < dataCount) {
895 "%s: Short read - zero filling", fileName);
902 * Zero fill the rest of the data if necessary.
905 memset (data + cc, 0, dataCount - cc);
908 * Write the buffer to the TAR file.
910 writeTarBlock (data, dataCount);
912 fullDataCount -= dataCount;
918 if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
919 fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
924 * Save a directory and all of its files to the tar file.
926 static void saveDirectory (const char *dirName, const struct stat *statbuf)
929 struct dirent *entry;
931 char fullName[NAME_MAX];
934 * Construct the directory name as used in the tar file by appending
935 * a slash character to it.
937 strcpy (fullName, dirName);
938 strcat (fullName, "/");
941 * Write out the header for the directory entry.
943 writeHeader (fullName, statbuf);
946 * Open the directory.
948 dir = opendir (dirName);
951 fprintf (stderr, "Cannot read directory \"%s\": %s\n",
952 dirName, strerror (errno));
958 * See if a slash is needed.
960 needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
963 * Read all of the directory entries and check them,
964 * except for the current and parent directory entries.
966 while (errorFlag==FALSE && ((entry = readdir (dir)) != NULL)) {
967 if ((strcmp (entry->d_name, ".") == 0) ||
968 (strcmp (entry->d_name, "..") == 0)) {
973 * Build the full path name to the file.
975 strcpy (fullName, dirName);
978 strcat (fullName, "/");
980 strcat (fullName, entry->d_name);
983 * Write this file to the tar file, noticing whether or not
984 * the file is a symbolic link.
986 saveFile (fullName, TRUE);
990 * All done, close the directory.
997 * Write a tar header for the specified file name and status.
998 * It is assumed that the file name fits.
1000 static void writeHeader (const char *fileName, const struct stat *statbuf)
1003 const unsigned char *cp;
1008 * Zero the header block in preparation for filling it in.
1010 memset ((char *) &header, 0, sizeof (header));
1013 * Fill in the header.
1015 strcpy (header.name, fileName);
1017 strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
1018 strncpy (header.version, TAR_VERSION, sizeof (header.version));
1020 putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
1021 putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
1022 putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
1023 putOctal (header.size, sizeof (header.size), statbuf->st_size);
1024 putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
1026 header.typeFlag = TAR_TYPE_REGULAR;
1029 * Calculate and store the checksum.
1030 * This is the sum of all of the bytes of the header,
1031 * with the checksum field itself treated as blanks.
1033 memset (header.checkSum, ' ', sizeof (header.checkSum));
1035 cp = (const unsigned char *) &header;
1036 len = sizeof (header);
1042 putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
1045 * Write the tar header.
1047 writeTarBlock ((const char *) &header, sizeof (header));
1052 * Write data to one or more blocks of the tar file.
1053 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1054 * The errorFlag static variable is set on an error.
1056 static void writeTarBlock (const char *buf, int len)
1060 char fullBlock[TAR_BLOCK_SIZE];
1063 * If we had a write error before, then do nothing more.
1065 if (errorFlag==TRUE)
1069 * Get the amount of complete and partial blocks.
1071 partialLength = len % TAR_BLOCK_SIZE;
1072 completeLength = len - partialLength;
1075 * Write all of the complete blocks.
1077 if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
1086 * If there are no partial blocks left, we are done.
1088 if (partialLength == 0)
1092 * Copy the partial data into a complete block, and pad the rest
1093 * of it with zeroes.
1095 memcpy (fullBlock, buf + completeLength, partialLength);
1096 memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
1099 * Write the last complete block.
1101 if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1110 * Read an octal value in a field of the specified width, with optional
1111 * spaces on both sides of the number and with an optional null character
1112 * at the end. Returns -1 on an illegal format.
1114 static long getOctal (const char *cp, int len)
1118 while ((len > 0) && (*cp == ' ')) {
1123 if ((len == 0) || !isOctal (*cp))
1128 while ((len > 0) && isOctal (*cp)) {
1129 val = val * 8 + *cp++ - '0';
1133 while ((len > 0) && (*cp == ' ')) {
1138 if ((len > 0) && *cp)
1146 * Put an octal string into the specified buffer.
1147 * The number is zero and space padded and possibly null padded.
1148 * Returns TRUE if successful.
1150 static int putOctal (char *cp, int len, long value)
1154 char tempBuffer[32];
1157 * Create a string of the specified length with an initial space,
1158 * leading zeroes and the octal number, and a trailing null.
1160 tempString = tempBuffer;
1162 sprintf (tempString, " %0*lo", len - 2, value);
1164 tempLength = strlen (tempString) + 1;
1167 * If the string is too large, suppress the leading space.
1169 if (tempLength > len) {
1175 * If the string is still too large, suppress the trailing null.
1177 if (tempLength > len)
1181 * If the string is still too large, fail.
1183 if (tempLength > len)
1187 * Copy the string to the field.
1189 memcpy (cp, tempString, len);
1196 * See if the specified file name belongs to one of the specified list
1197 * of path prefixes. An empty list implies that all files are wanted.
1198 * Returns TRUE if the file is selected.
1201 wantFileName (const char *fileName, int fileCount, char **fileTable)
1203 const char *pathName;
1208 * If there are no files in the list, then the file is wanted.
1213 fileLength = strlen (fileName);
1216 * Check each of the test paths.
1218 while (fileCount-- > 0) {
1219 pathName = *fileTable++;
1221 pathLength = strlen (pathName);
1223 if (fileLength < pathLength)
1226 if (memcmp (fileName, pathName, pathLength) != 0)
1229 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {