aboutsummaryrefslogtreecommitdiff
path: root/tar.c
diff options
context:
space:
mode:
Diffstat (limited to 'tar.c')
-rw-r--r--tar.c203
1 files changed, 120 insertions, 83 deletions
diff --git a/tar.c b/tar.c
index 02fde0a64..732f26ddc 100644
--- a/tar.c
+++ b/tar.c
@@ -52,33 +52,33 @@
52#include <sys/param.h> /* for PATH_MAX */ 52#include <sys/param.h> /* for PATH_MAX */
53 53
54 54
55#ifdef BB_FEATURE_TAR_CREATE
56
57static const char tar_usage[] = 55static const char tar_usage[] =
58 "tar -[cxtvOf] [tarFile] [-X excludeFile] [FILE] ...\n\n" 56#ifdef BB_FEATURE_TAR_CREATE
59 "Create, extract, or list files from a tar file. Note that\n" 57 "tar -[cxtvO] "
60 "this version of tar packs hard links as separate files.\n\n"
61 "Options:\n"
62
63 "\tc=create, x=extract, t=list contents, v=verbose,\n"
64 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n"
65 "\tX=exclude file\n";
66
67#else 58#else
68 59 "tar -[xtvO] "
69static const char tar_usage[] =
70 "tar -[xtvO] [-f tarFile] [-X excludeFile] [FILE] ...\n\n"
71 "Extract, or list files stored in a tar file. This\n"
72 "version of tar does not support creation of tar files.\n\n"
73 "Options:\n"
74
75 "\tx=extract, t=list contents, v=verbose,\n"
76 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n"
77 "\tX=exclude file\n";
78
79
80#endif 60#endif
81 61#if defined BB_FEATURE_TAR_EXCLUDE
62 "[--exclude File] "
63#endif
64 "[-f tarFile] [FILE] ...\n\n"
65 "Create, extract, or list files from a tar file. Note that\n"
66 "this version of tar treats hard links as separate files.\n\n"
67 "Main operation mode:\n"
68#ifdef BB_FEATURE_TAR_CREATE
69 "\tc\t\tcreate\n"
70#endif
71 "\tx\t\textract\n"
72 "\tt\t\tlist\n"
73 "File selection:\n"
74 "\tf\t\tname of tarfile or \"-\" for stdin\n"
75 "\tO\t\textract to stdout\n"
76#if defined BB_FEATURE_TAR_EXCLUDE
77 "\t--exclude\tfile to exclude\n"
78#endif
79 "Informative output:\n"
80 "\tv\t\tverbosely list files processed\n"
81 ;
82 82
83/* Tar file constants */ 83/* Tar file constants */
84#ifndef MAJOR 84#ifndef MAJOR
@@ -91,31 +91,30 @@ static const char tar_usage[] =
91struct TarHeader 91struct TarHeader
92{ 92{
93 /* byte offset */ 93 /* byte offset */
94 char name[100]; /* 0 */ 94 char name[100]; /* 0-99 */
95 char mode[8]; /* 100 */ 95 char mode[8]; /* 100-107 */
96 char uid[8]; /* 108 */ 96 char uid[8]; /* 108-115 */
97 char gid[8]; /* 116 */ 97 char gid[8]; /* 116-123 */
98 char size[12]; /* 124 */ 98 char size[12]; /* 124-135 */
99 char mtime[12]; /* 136 */ 99 char mtime[12]; /* 136-147 */
100 char chksum[8]; /* 148 */ 100 char chksum[8]; /* 148-155 */
101 char typeflag; /* 156 */ 101 char typeflag; /* 156-156 */
102 char linkname[100]; /* 157 */ 102 char linkname[100]; /* 157-256 */
103 char magic[6]; /* 257 */ 103 char magic[6]; /* 257-262 */
104 char version[2]; /* 263 */ 104 char version[2]; /* 263-264 */
105 char uname[32]; /* 265 */ 105 char uname[32]; /* 265-296 */
106 char gname[32]; /* 297 */ 106 char gname[32]; /* 297-328 */
107 char devmajor[8]; /* 329 */ 107 char devmajor[8]; /* 329-336 */
108 char devminor[8]; /* 337 */ 108 char devminor[8]; /* 337-344 */
109 char prefix[155]; /* 345 */ 109 char prefix[155]; /* 345-499 */
110 /* padding 500 */ 110 char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
111}; 111};
112typedef struct TarHeader TarHeader; 112typedef struct TarHeader TarHeader;
113 113
114 114
115/* A few useful constants */ 115/* A few useful constants */
116#define TAR_MAGIC "ustar" /* ustar and a null */ 116#define TAR_MAGIC "ustar" /* ustar and a null */
117//#define TAR_VERSION "00" /* 00 and no null */ 117#define TAR_VERSION " " /* Be compatable with GNU tar format */
118#define TAR_VERSION " " /* Be compatable with old GNU format */
119#define TAR_MAGIC_LEN 6 118#define TAR_MAGIC_LEN 6
120#define TAR_VERSION_LEN 2 119#define TAR_VERSION_LEN 2
121#define TAR_BLOCK_SIZE 512 120#define TAR_BLOCK_SIZE 512
@@ -170,7 +169,9 @@ static int writeTarFile(const char* tarName, int tostdoutFlag,
170extern int tar_main(int argc, char **argv) 169extern int tar_main(int argc, char **argv)
171{ 170{
172 char** excludeList=NULL; 171 char** excludeList=NULL;
172#if defined BB_FEATURE_TAR_EXCLUDE
173 int excludeListSize=0; 173 int excludeListSize=0;
174#endif
174 const char *tarName=NULL; 175 const char *tarName=NULL;
175 int listFlag = FALSE; 176 int listFlag = FALSE;
176 int extractFlag = FALSE; 177 int extractFlag = FALSE;
@@ -224,22 +225,26 @@ extern int tar_main(int argc, char **argv)
224 tostdoutFlag = TRUE; 225 tostdoutFlag = TRUE;
225 tarName = "-"; 226 tarName = "-";
226 break; 227 break;
227 case 'X':
228 if (--argc == 0) {
229 fatalError( "Option requires an argument: No file specified\n");
230 }
231 excludeList=realloc( excludeList, sizeof(char**) * (excludeListSize+1));
232 excludeList[excludeListSize] = *(++argv);
233 /* Remove leading "/"s */
234 if (*excludeList[excludeListSize] =='/') {
235 excludeList[excludeListSize] = (excludeList[excludeListSize])+1;
236 }
237 if (excludeList[excludeListSize++] == NULL)
238 fatalError( "Option requires an argument: No file specified\n");
239 stopIt=TRUE;
240 break;
241
242 case '-': 228 case '-':
229#if defined BB_FEATURE_TAR_EXCLUDE
230 if (strcmp(*argv, "-exclude")==0) {
231 if (--argc == 0) {
232 fatalError( "Option requires an argument: No file specified\n");
233 }
234 excludeList=realloc( excludeList, sizeof(char**) * (excludeListSize+2));
235 excludeList[excludeListSize] = *(++argv);
236 /* Remove leading "/"s */
237 if (*excludeList[excludeListSize] =='/') {
238 excludeList[excludeListSize] = (excludeList[excludeListSize])+1;
239 }
240 if (excludeList[excludeListSize++] == NULL)
241 fatalError( "Option requires an argument: No file specified\n");
242 /* Tack a NULL onto the end of the list */
243 excludeList[excludeListSize] = NULL;
244 stopIt=TRUE;
245 break;
246 }
247#endif
243 usage(tar_usage); 248 usage(tar_usage);
244 break; 249 break;
245 250
@@ -249,13 +254,6 @@ extern int tar_main(int argc, char **argv)
249 } 254 }
250 } 255 }
251 } 256 }
252#if 0
253 for (i=0; i<excludeListSize; i++) {
254 printf( "%s\n", excludeList[i]);
255 fflush(stdout);
256 }
257#endif
258
259 257
260 /* 258 /*
261 * Do the correct type of action supplying the rest of the 259 * Do the correct type of action supplying the rest of the
@@ -336,6 +334,8 @@ tarExtractRegularFile(TarInfo *header, int extractFlag, int tostdoutFlag)
336 errorMsg(io_error, header->name, strerror(errno)); 334 errorMsg(io_error, header->name, strerror(errno));
337 return( FALSE); 335 return( FALSE);
338 } 336 }
337 } else {
338 actualWriteSz=writeSize;
339 } 339 }
340 340
341 size -= actualWriteSz; 341 size -= actualWriteSz;
@@ -532,11 +532,13 @@ readTarHeader(struct TarHeader *rawHeader, struct TarInfo *header)
532static int readTarFile(const char* tarName, int extractFlag, int listFlag, 532static int readTarFile(const char* tarName, int extractFlag, int listFlag,
533 int tostdoutFlag, int verboseFlag, char** excludeList) 533 int tostdoutFlag, int verboseFlag, char** excludeList)
534{ 534{
535 int status, tarFd=0; 535 int status, tarFd=-1;
536 int errorFlag=FALSE; 536 int errorFlag=FALSE;
537 TarHeader rawHeader; 537 TarHeader rawHeader;
538 TarInfo header; 538 TarInfo header;
539 //int skipFileFlag=FALSE; 539#if defined BB_FEATURE_TAR_EXCLUDE
540 char** tmpList;
541#endif
540 542
541 /* Open the tar file for reading. */ 543 /* Open the tar file for reading. */
542 if (!strcmp(tarName, "-")) 544 if (!strcmp(tarName, "-"))
@@ -557,7 +559,6 @@ static int readTarFile(const char* tarName, int extractFlag, int listFlag,
557 559
558 /* First, try to read the header */ 560 /* First, try to read the header */
559 if ( readTarHeader(&rawHeader, &header) == FALSE ) { 561 if ( readTarHeader(&rawHeader, &header) == FALSE ) {
560 close( tarFd);
561 if ( *(header.name) == '\0' ) { 562 if ( *(header.name) == '\0' ) {
562 goto endgame; 563 goto endgame;
563 } else { 564 } else {
@@ -568,7 +569,34 @@ static int readTarFile(const char* tarName, int extractFlag, int listFlag,
568 } 569 }
569 if ( *(header.name) == '\0' ) 570 if ( *(header.name) == '\0' )
570 goto endgame; 571 goto endgame;
571 572 header.tarFd = tarFd;
573
574#if defined BB_FEATURE_TAR_EXCLUDE
575 {
576 int skipFlag=FALSE;
577 /* Check for excluded files.... */
578 for (tmpList=excludeList; tmpList && *tmpList; tmpList++) {
579 /* Do some extra hoop jumping for when directory names
580 * end in '/' but the entry in tmpList doesn't */
581 if (strncmp( *tmpList, header.name, strlen(*tmpList))==0 || (
582 header.name[strlen(header.name)-1]=='/'
583 && strncmp( *tmpList, header.name,
584 MIN(strlen(header.name)-1, strlen(*tmpList)))==0)) {
585 /* If it is a regular file, pretend to extract it with
586 * the extractFlag set to FALSE, so the junk in the tarball
587 * is properly skipped over */
588 if ( header.type==REGTYPE || header.type==REGTYPE0 ) {
589 tarExtractRegularFile(&header, FALSE, FALSE);
590 }
591 skipFlag=TRUE;
592 break;
593 }
594 }
595 /* There are not the droids you're looking for, move along */
596 if (skipFlag==TRUE)
597 continue;
598 }
599#endif
572 /* Special treatment if the list (-t) flag is on */ 600 /* Special treatment if the list (-t) flag is on */
573 if (verboseFlag == TRUE && extractFlag == FALSE) { 601 if (verboseFlag == TRUE && extractFlag == FALSE) {
574 int len, len1; 602 int len, len1;
@@ -623,13 +651,6 @@ static int readTarFile(const char* tarName, int extractFlag, int listFlag,
623 printf("\n"); 651 printf("\n");
624 } 652 }
625 653
626#if 0
627 /* See if we want to restore this file or not */
628 skipFileFlag=FALSE;
629 if (wantFileName(outName) == FALSE) {
630 skipFileFlag = TRUE;
631 }
632#endif
633 /* Remove any clutter lying in our way */ 654 /* Remove any clutter lying in our way */
634 unlink( header.name); 655 unlink( header.name);
635 656
@@ -751,7 +772,9 @@ writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *st
751{ 772{
752 long chksum=0; 773 long chksum=0;
753 struct TarHeader header; 774 struct TarHeader header;
775#if defined BB_FEATURE_TAR_EXCLUDE
754 char** tmpList; 776 char** tmpList;
777#endif
755 const unsigned char *cp = (const unsigned char *) &header; 778 const unsigned char *cp = (const unsigned char *) &header;
756 ssize_t size = sizeof(struct TarHeader); 779 ssize_t size = sizeof(struct TarHeader);
757 780
@@ -769,15 +792,23 @@ writeTarHeader(struct TarBallInfo *tbInfo, const char *fileName, struct stat *st
769 strncpy(header.name, fileName, sizeof(header.name)); 792 strncpy(header.name, fileName, sizeof(header.name));
770 } 793 }
771 794
772 /* Now that leading '/''s have been removed, 795#if defined BB_FEATURE_TAR_EXCLUDE
773 * check for excluded files.... */ 796 /* Check for excluded files.... */
774 for (tmpList=tbInfo->excludeList; tmpList && *tmpList; tmpList++) { 797 for (tmpList=tbInfo->excludeList; tmpList && *tmpList; tmpList++) {
775 printf( "comparing '%s' and '%s'", *tmpList, header.name); 798 /* Do some extra hoop jumping for when directory names
776 if (strcmp( *tmpList, header.name)==0) 799 * end in '/' but the entry in tmpList doesn't */
777 printf( ": match\n"); 800 if (strncmp( *tmpList, header.name, strlen(*tmpList))==0 || (
778 else 801 header.name[strlen(header.name)-1]=='/'
779 printf( "\n"); 802 && strncmp( *tmpList, header.name,
803 MIN(strlen(header.name)-1, strlen(*tmpList)))==0)) {
804 /* Set the mode to something that is not a regular file, thereby
805 * faking out writeTarFile into thinking that nothing further need
806 * be done for this file. Yes, I know this is ugly, but it works. */
807 statbuf->st_mode = 0;
808 return( TRUE);
809 }
780 } 810 }
811#endif
781 812
782 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); 813 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
783 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); 814 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
@@ -965,6 +996,12 @@ static int writeTarFile(const char* tarName, int tostdoutFlag,
965 for (size=0; size<(2*TAR_BLOCK_SIZE); size++) { 996 for (size=0; size<(2*TAR_BLOCK_SIZE); size++) {
966 write(tbInfo.tarFd, "\0", 1); 997 write(tbInfo.tarFd, "\0", 1);
967 } 998 }
999
1000 /* To be pedantically correct, we would check if the tarball
1001 * is smaller then 20 tar blocks, and pad it if it was smaller,
1002 * but that isn't necessary for GNU tar interoperability, and
1003 * so is considered a waste of space */
1004
968 /* Hang up the tools, close up shop, head home */ 1005 /* Hang up the tools, close up shop, head home */
969 close(tarFd); 1006 close(tarFd);
970 if (errorFlag == TRUE) { 1007 if (errorFlag == TRUE) {