2 * Copyright (c) 2014 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
6 * The "tar" built-in command.
7 * This allows creation, extraction, and listing of tar files.
12 #include <sys/types.h>
21 #define TAR_BLOCK_SIZE 512
22 #define TAR_NAME_SIZE 100
26 * The POSIX (and basic GNU) tar header format.
27 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
28 * with zero padding. We only process this information minimally.
32 char name[TAR_NAME_SIZE];
40 char linkName[TAR_NAME_SIZE];
51 #define TAR_MAGIC "ustar"
52 #define TAR_VERSION "00"
54 #define TAR_TYPE_REGULAR '0'
55 #define TAR_TYPE_HARD_LINK '1'
56 #define TAR_TYPE_SOFT_LINK '2'
63 static BOOL extractFlag;
64 static BOOL createFlag;
65 static BOOL verboseFlag;
68 static BOOL badHeader;
69 static BOOL errorFlag;
70 static BOOL skipFileFlag;
71 static BOOL warnedRoot;
75 static char outName[TAR_NAME_SIZE];
79 * Static data associated with the tar file.
81 static const char * tarName;
84 static ino_t tarInode;
88 * Local procedures to restore files from a tar file.
90 static BOOL readTarFile(int fileCount, const char ** fileTable);
91 static BOOL readData(const char * cp, int count);
92 static BOOL createPath(const char * name, int mode);
93 static long getOctal(const char * cp, int len);
95 static BOOL readHeader(const TarHeader * hp,
96 int fileCount, const char ** fileTable);
100 * Local procedures to save files into a tar file.
102 static void saveFile(const char * fileName, BOOL seeLinks);
104 static void saveRegularFile(const char * fileName,
105 const struct stat * statbuf);
107 static void saveDirectory(const char * fileName,
108 const struct stat * statbuf);
110 static BOOL wantFileName(const char * fileName,
111 int fileCount, const char ** fileTable);
113 static void writeHeader(const char * fileName,
114 const struct stat * statbuf);
116 static BOOL writeTarFile(int fileCount, const char ** fileTable);
117 static void writeTarBlock(const char * buf, int len);
118 static BOOL putOctal(char * cp, int len, long value);
123 do_tar(int argc, const char ** argv)
125 const char * options;
133 fprintf(stderr, "Too few arguments for tar\n");
153 for (; *options; options++)
160 fprintf(stderr, "Only one 'f' option allowed\n");
187 fprintf(stderr, "Unknown tar flag '%c'\n", *options);
194 * Validate the options.
196 if (extractFlag + listFlag + createFlag != 1)
198 fprintf(stderr, "Exactly one of 'c', 'x' or 't' must be specified\n");
205 fprintf(stderr, "The 'f' flag must be specified\n");
211 * Do the correct type of action supplying the rest of the
212 * command line arguments as the list of files to process.
215 successFlag = writeTarFile(argc, argv);
217 successFlag = readTarFile(argc, argv);
224 * Read a tar file and extract or list the specified files within it.
225 * If the list is empty than all files are extracted or listed.
226 * Returns TRUE on success.
229 readTarFile(int fileCount, const char ** fileTable)
238 skipFileFlag = FALSE;
248 blockSize = sizeof(buf);
252 * Open the tar file for reading.
254 tarFd = open(tarName, O_RDONLY);
264 * Read blocks from the file until an end of file header block
265 * has been seen. (A real end of file from a read is an error.)
267 while (!intFlag && !eofFlag)
270 * Read the next block of data if necessary.
271 * This will be a large block if possible, which we will
272 * then process in the small tar blocks.
277 inCc = fullRead(tarFd, buf, blockSize);
290 "Unexpected end of file from \"%s\"",
299 * If we are expecting a header block then examine it.
303 if (!readHeader((const TarHeader *) cp, fileCount, fileTable))
306 cp += TAR_BLOCK_SIZE;
307 inCc -= TAR_BLOCK_SIZE;
313 * We are currently handling the data for a file.
314 * Process the minimum of the amount of data we have available
315 * and the amount left to be processed for the file.
322 if (!readData(cp, cc))
326 * If the amount left isn't an exact multiple of the tar block
327 * size then round it up to the next block boundary since there
328 * is padding at the end of the file.
330 if (cc % TAR_BLOCK_SIZE)
331 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
338 * Check for an interrupt.
342 fprintf(stderr, "Interrupted - aborting\n");
348 * Close the tar file if needed.
350 if ((tarFd >= 0) && (close(tarFd) < 0))
357 * Close the output file if needed.
358 * This is only done here on a previous error and so no
359 * message is required on errors.
369 * Examine the header block that was just read.
370 * This can specify the information for another file, or it can mark
371 * the end of the tar file. Returns TRUE on success.
374 readHeader(const TarHeader * hp, int fileCount, const char ** fileTable)
387 * If the block is completely empty, then this is the end of the
388 * archive file. If the name is null, then just skip this header.
394 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--)
406 * There is another file in the archive to examine.
407 * Extract the encoded information and check it.
409 mode = getOctal(hp->mode, sizeof(hp->mode));
410 uid = getOctal(hp->uid, sizeof(hp->uid));
411 gid = getOctal(hp->gid, sizeof(hp->gid));
412 size = getOctal(hp->size, sizeof(hp->size));
413 mtime = getOctal(hp->mtime, sizeof(hp->mtime));
415 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0))
418 fprintf(stderr, "Bad tar header, skipping\n");
426 skipFileFlag = FALSE;
429 * Check for the file modes.
431 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
432 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
434 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
435 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
438 * Check for a directory or a regular file.
440 if (name[strlen(name) - 1] == '/')
442 else if ((mode & S_IFMT) == 0)
446 * Check for absolute paths in the file.
447 * If we find any, then warn the user and make them relative.
457 "Absolute path detected, removing leading slashes\n");
464 * See if we want this file to be restored.
465 * If not, then set up to skip it.
467 if (!wantFileName(name, fileCount, fileTable))
469 if (!hardLink && !softLink && S_ISREG(mode))
471 inHeader = (size == 0);
481 * This file is to be handled.
482 * If we aren't extracting then just list information about the file.
488 printf("%s %3d/%-d %9ld %s %s", modeString(mode),
489 uid, gid, size, timeString(mtime), name);
495 printf(" (link to \"%s\")", hp->linkName);
497 printf(" (symlink to \"%s\")", hp->linkName);
498 else if (S_ISREG(mode))
500 inHeader = (size == 0);
510 * We really want to extract the file.
513 printf("x %s\n", name);
517 if (link(hp->linkName, name) < 0)
529 if (symlink(hp->linkName, name) < 0)
538 fprintf(stderr, "Cannot create symbolic links\n");
544 * If the file is a directory, then just create the path.
547 return createPath(name, mode);
550 * There is a file to write.
551 * First create the path to it if necessary with a default permission.
553 if (!createPath(name, 0777))
556 inHeader = (size == 0);
560 * Start the output file.
562 outFd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
573 * If the file is empty, then that's all we need to do.
586 * Handle a data block of some specified size that was read.
587 * Returns TRUE on success.
590 readData(const char * cp, int count)
593 * Reduce the amount of data left in this file.
594 * If there is no more data left, then we need to read
603 * If we aren't extracting files or this file is being
604 * skipped then do nothing more.
606 if (!extractFlag || skipFileFlag)
610 * Write the data to the output file.
612 if (fullWrite(outFd, cp, count) < 0)
623 * If the write failed, close the file and disable further
624 * writes to this file.
641 * Write a tar file containing the specified files.
642 * Returns TRUE on success.
645 writeTarFile(int fileCount, const char ** fileTable)
654 * Make sure there is at least one file specified.
658 fprintf(stderr, "No files specified to be saved\n");
664 * Create the tar file for writing.
666 tarFd = open(tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
676 * Get the device and inode of the tar file for checking later.
678 if (fstat(tarFd, &statbuf) < 0)
686 tarDev = statbuf.st_dev;
687 tarInode = statbuf.st_ino;
690 * Append each file name into the archive file.
691 * Follow symbolic links for these top level file names.
693 while (!intFlag && !errorFlag && (fileCount-- > 0))
695 saveFile(*fileTable++, FALSE);
700 fprintf(stderr, "Interrupted - aborting archiving\n");
705 * Now write an empty block of zeroes to end the archive.
707 writeTarBlock("", 1);
712 * Close the tar file and check for errors if it was opened.
714 if ((tarFd >= 0) && (close(tarFd) < 0))
725 * Save one file into the tar file.
726 * If the file is a directory, then this will recursively save all of
727 * the files and directories within the directory. The seeLinks
728 * flag indicates whether or not we want to see symbolic links as
729 * they really are, instead of blindly following them.
732 saveFile(const char * fileName, BOOL seeLinks)
739 printf("a %s\n", fileName);
742 * Check that the file name will fit in the header.
744 if (strlen(fileName) >= TAR_NAME_SIZE)
746 fprintf(stderr, "%s: File name is too long\n", fileName);
752 * Find out about the file.
756 status = lstat(fileName, &statbuf);
759 status = stat(fileName, &statbuf);
769 * Make sure we aren't trying to save our file into itself.
771 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode))
773 fprintf(stderr, "Skipping saving of archive file itself\n");
779 * Check the type of file.
781 mode = statbuf.st_mode;
785 saveDirectory(fileName, &statbuf);
792 saveRegularFile(fileName, &statbuf);
798 * The file is a strange type of file, ignore it.
800 fprintf(stderr, "%s: not a directory or regular file\n", fileName);
805 * Save a regular file to the tar file.
808 saveRegularFile(const char * fileName, const struct stat * statbuf)
815 char data[TAR_BLOCK_SIZE * 16];
818 * Open the file for reading.
820 fileFd = open(fileName, O_RDONLY);
830 * Write out the header for the file.
832 writeHeader(fileName, statbuf);
835 * Write the data blocks of the file.
836 * We must be careful to write the amount of data that the stat
837 * buffer indicated, even if the file has changed size. Otherwise
838 * the tar file will be incorrect.
840 fullDataCount = statbuf->st_size;
843 while (!intFlag && (fullDataCount > 0))
846 * Get the amount to write this iteration which is
847 * the minumum of the amount left to write and the
850 dataCount = sizeof(data);
852 if (dataCount > fullDataCount)
853 dataCount = (int) fullDataCount;
856 * Read the data from the file if we haven't seen the
863 cc = fullRead(fileFd, data, dataCount);
869 (void) close(fileFd);
876 * If the file ended too soon, complain and set
877 * a flag so we will zero fill the rest of it.
882 "%s: Short read - zero filling",
890 * Zero fill the rest of the data if necessary.
893 memset(data + cc, 0, dataCount - cc);
896 * Write the buffer to the TAR file.
898 writeTarBlock(data, dataCount);
900 fullDataCount -= dataCount;
906 if (close(fileFd) < 0)
907 fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno));
912 * Save a directory and all of its files to the tar file.
915 saveDirectory(const char * dirName, const struct stat * statbuf)
918 struct dirent * entry;
920 char fullName[PATH_LEN];
923 * Construct the directory name as used in the tar file by appending
924 * a slash character to it.
926 strcpy(fullName, dirName);
927 strcat(fullName, "/");
930 * Write out the header for the directory entry.
932 writeHeader(fullName, statbuf);
935 * Open the directory.
937 dir = opendir(dirName);
941 fprintf(stderr, "Cannot read directory \"%s\": %s\n",
942 dirName, strerror(errno));
948 * See if a slash is needed.
950 needSlash = (*dirName && (dirName[strlen(dirName) - 1] != '/'));
953 * Read all of the directory entries and check them,
954 * except for the current and parent directory entries.
956 while (!intFlag && !errorFlag && ((entry = readdir(dir)) != NULL))
958 if ((strcmp(entry->d_name, ".") == 0) ||
959 (strcmp(entry->d_name, "..") == 0))
965 * Build the full path name to the file.
967 strcpy(fullName, dirName);
970 strcat(fullName, "/");
972 strcat(fullName, entry->d_name);
975 * Write this file to the tar file, noticing whether or not
976 * the file is a symbolic link.
978 saveFile(fullName, TRUE);
982 * All done, close the directory.
989 * Write a tar header for the specified file name and status.
990 * It is assumed that the file name fits.
993 writeHeader(const char * fileName, const struct stat * statbuf)
996 const unsigned char * cp;
1001 * Zero the header block in preparation for filling it in.
1003 memset((char *) &header, 0, sizeof(header));
1006 * Fill in the header.
1008 strcpy(header.name, fileName);
1010 strncpy(header.magic, TAR_MAGIC, sizeof(header.magic));
1011 strncpy(header.version, TAR_VERSION, sizeof(header.version));
1013 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777);
1014 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
1015 putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
1016 putOctal(header.size, sizeof(header.size), statbuf->st_size);
1017 putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
1019 header.typeFlag = TAR_TYPE_REGULAR;
1022 * Calculate and store the checksum.
1023 * This is the sum of all of the bytes of the header,
1024 * with the checksum field itself treated as blanks.
1026 memset(header.checkSum, ' ', sizeof(header.checkSum));
1028 cp = (const unsigned char *) &header;
1029 len = sizeof(header);
1035 putOctal(header.checkSum, sizeof(header.checkSum), checkSum);
1038 * Write the tar header.
1040 writeTarBlock((const char *) &header, sizeof(header));
1045 * Write data to one or more blocks of the tar file.
1046 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1047 * The errorFlag static variable is set on an error.
1050 writeTarBlock(const char * buf, int len)
1054 char fullBlock[TAR_BLOCK_SIZE];
1057 * If we had a write error before, then do nothing more.
1063 * Get the amount of complete and partial blocks.
1065 partialLength = len % TAR_BLOCK_SIZE;
1066 completeLength = len - partialLength;
1069 * Write all of the complete blocks.
1071 if ((completeLength > 0) && !fullWrite(tarFd, buf, completeLength))
1081 * If there are no partial blocks left, we are done.
1083 if (partialLength == 0)
1087 * Copy the partial data into a complete block, and pad the rest
1088 * of it with zeroes.
1090 memcpy(fullBlock, buf + completeLength, partialLength);
1091 memset(fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
1094 * Write the last complete block.
1096 if (!fullWrite(tarFd, fullBlock, TAR_BLOCK_SIZE))
1106 * Attempt to create the directories along the specified path, except for
1107 * the final component. The mode is given for the final directory only,
1108 * while all previous ones get default protections. Errors are not reported
1109 * here, as failures to restore files can be reported later.
1110 * Returns TRUE on success.
1113 createPath(const char * name, int mode)
1117 char buf[TAR_NAME_SIZE];
1121 cp = strchr(buf, '/');
1126 cp = strchr(cp + 1, '/');
1130 if (mkdir(buf, cp ? 0777 : mode) == 0)
1131 printf("Directory \"%s\" created\n", buf);
1141 * Read an octal value in a field of the specified width, with optional
1142 * spaces on both sides of the number and with an optional null character
1143 * at the end. Returns -1 on an illegal format.
1146 getOctal(const char * cp, int len)
1150 while ((len > 0) && (*cp == ' '))
1156 if ((len == 0) || !isOctal(*cp))
1161 while ((len > 0) && isOctal(*cp))
1163 val = val * 8 + *cp++ - '0';
1167 while ((len > 0) && (*cp == ' '))
1173 if ((len > 0) && *cp)
1181 * Put an octal string into the specified buffer.
1182 * The number is zero and space padded and possibly null padded.
1183 * Returns TRUE if successful.
1186 putOctal(char * cp, int len, long value)
1190 char tempBuffer[32];
1193 * Create a string of the specified length with an initial space,
1194 * leading zeroes and the octal number, and a trailing null.
1196 tempString = tempBuffer;
1198 sprintf(tempString, " %0*lo", len - 2, value);
1200 tempLength = strlen(tempString) + 1;
1203 * If the string is too large, suppress the leading space.
1205 if (tempLength > len)
1212 * If the string is still too large, suppress the trailing null.
1214 if (tempLength > len)
1218 * If the string is still too large, fail.
1220 if (tempLength > len)
1224 * Copy the string to the field.
1226 memcpy(cp, tempString, len);
1233 * See if the specified file name belongs to one of the specified list
1234 * of path prefixes. An empty list implies that all files are wanted.
1235 * Returns TRUE if the file is selected.
1238 wantFileName(const char * fileName, int fileCount, const char ** fileTable)
1240 const char * pathName;
1245 * If there are no files in the list, then the file is wanted.
1250 fileLength = strlen(fileName);
1253 * Check each of the test paths.
1255 while (fileCount-- > 0)
1257 pathName = *fileTable++;
1259 pathLength = strlen(pathName);
1261 if (fileLength < pathLength)
1264 if (memcmp(fileName, pathName, pathLength) != 0)
1267 if ((fileLength == pathLength) ||
1268 (fileName[pathLength] == '/'))