diff options
-rw-r--r-- | Changelog | 7 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | TODO | 8 | ||||
-rw-r--r-- | archival/tar.c | 203 | ||||
-rw-r--r-- | busybox.def.h | 3 | ||||
-rw-r--r-- | tar.c | 203 |
6 files changed, 249 insertions, 179 deletions
@@ -11,16 +11,15 @@ | |||
11 | patch your kernel with the devps patch in the kernel-patches/ | 11 | patch your kernel with the devps patch in the kernel-patches/ |
12 | directory. | 12 | directory. |
13 | * Wrote basename, killall, and uptime. | 13 | * Wrote basename, killall, and uptime. |
14 | * tar has been completely rewritten by me. Both tar creation and | ||
15 | extraction are now well behaved. Costs 7.6k with all optional | ||
16 | tar features enabled, and 5k for just tar extraction support. | ||
14 | * Added freeramdisk, which will free up all memory associated | 17 | * Added freeramdisk, which will free up all memory associated |
15 | with a ram disk. Contributed by Emanuele Caratti <wiz@iol.it> | 18 | with a ram disk. Contributed by Emanuele Caratti <wiz@iol.it> |
16 | and then adjusted a bit by me. | 19 | and then adjusted a bit by me. |
17 | * Added tr and dirname from John Lombardo <john@deltanet.com> | 20 | * Added tr and dirname from John Lombardo <john@deltanet.com> |
18 | * Added echo and test (from me). | 21 | * Added echo and test (from me). |
19 | * Added usleep contributed by Nicolas Pitre <nico@cam.org> | 22 | * Added usleep contributed by Nicolas Pitre <nico@cam.org> |
20 | * tar wouldn't create directory entries that don't end in '/', | ||
21 | now it does (thanks to Avery Pennarun <apenwarr@worldvisions.ca>) | ||
22 | * tar has been completely rewritten, and tar creation and extraction | ||
23 | is now much better behaved. | ||
24 | * Several fixes from Pavel Roskin <pavel_roskin@geocities.com>: | 23 | * Several fixes from Pavel Roskin <pavel_roskin@geocities.com>: |
25 | - When `tail' fails to open a file it now exits. | 24 | - When `tail' fails to open a file it now exits. |
26 | - When `syslogd' is given the `-n' option it should still use | 25 | - When `syslogd' is given the `-n' option it should still use |
@@ -25,7 +25,7 @@ BUILDTIME := $(shell TZ=UTC date --utc "+%Y.%m.%d-%H:%M%z") | |||
25 | # Set the following to `true' to make a debuggable build. | 25 | # Set the following to `true' to make a debuggable build. |
26 | # Leave this set to `false' for production use. | 26 | # Leave this set to `false' for production use. |
27 | # eg: `make DODEBUG=true tests' | 27 | # eg: `make DODEBUG=true tests' |
28 | DODEBUG = true | 28 | DODEBUG = false |
29 | 29 | ||
30 | # If you want a static binary, turn this on. I can't think | 30 | # If you want a static binary, turn this on. I can't think |
31 | # of many situations where anybody would ever want it static, | 31 | # of many situations where anybody would ever want it static, |
@@ -72,7 +72,7 @@ endif | |||
72 | # -D_GNU_SOURCE is needed because environ is used in init.c | 72 | # -D_GNU_SOURCE is needed because environ is used in init.c |
73 | ifeq ($(DODEBUG),true) | 73 | ifeq ($(DODEBUG),true) |
74 | CFLAGS += -Wall -g -D_GNU_SOURCE | 74 | CFLAGS += -Wall -g -D_GNU_SOURCE |
75 | LDFLAGS = | 75 | LDFLAGS = |
76 | STRIP = | 76 | STRIP = |
77 | else | 77 | else |
78 | CFLAGS += -Wall $(OPTIMIZATION) -fomit-frame-pointer -fno-builtin -D_GNU_SOURCE | 78 | CFLAGS += -Wall $(OPTIMIZATION) -fomit-frame-pointer -fno-builtin -D_GNU_SOURCE |
@@ -22,7 +22,7 @@ around to it some time. If you have any good ideas, please let me know. | |||
22 | * hwclock | 22 | * hwclock |
23 | * stty | 23 | * stty |
24 | * cut | 24 | * cut |
25 | * expr (maybe?) (ash builtin?) | 25 | * expr |
26 | 26 | ||
27 | 27 | ||
28 | 28 | ||
@@ -42,12 +42,6 @@ Perhaps I need to add a better build system (like the Linux kernel?) | |||
42 | ----------------------- | 42 | ----------------------- |
43 | 43 | ||
44 | 44 | ||
45 | There is no exclude file(s) option to tar. LRP's packaging system can not | ||
46 | function without this. Will you have the time to add this soon? | ||
47 | |||
48 | |||
49 | ----------------------- | ||
50 | |||
51 | Feature request: | 45 | Feature request: |
52 | 46 | ||
53 | /bin/busybox --install -s which makes all links to commands that it | 47 | /bin/busybox --install -s which makes all links to commands that it |
diff --git a/archival/tar.c b/archival/tar.c index 02fde0a64..732f26ddc 100644 --- a/archival/tar.c +++ b/archival/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 | |||
57 | static const char tar_usage[] = | 55 | static 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] " | |
69 | static 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[] = | |||
91 | struct TarHeader | 91 | struct 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 | }; |
112 | typedef struct TarHeader TarHeader; | 112 | typedef 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, | |||
170 | extern int tar_main(int argc, char **argv) | 169 | extern 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) | |||
532 | static int readTarFile(const char* tarName, int extractFlag, int listFlag, | 532 | static 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) { |
diff --git a/busybox.def.h b/busybox.def.h index dd59a284a..b05f17a68 100644 --- a/busybox.def.h +++ b/busybox.def.h | |||
@@ -180,6 +180,9 @@ | |||
180 | // Enable support for creation of tar files. | 180 | // Enable support for creation of tar files. |
181 | #define BB_FEATURE_TAR_CREATE | 181 | #define BB_FEATURE_TAR_CREATE |
182 | // | 182 | // |
183 | // Enable support for "--exclude" for excluding files | ||
184 | //#define BB_FEATURE_TAR_EXCLUDE | ||
185 | // | ||
183 | //// Enable reverse sort | 186 | //// Enable reverse sort |
184 | //#define BB_FEATURE_SORT_REVERSE | 187 | //#define BB_FEATURE_SORT_REVERSE |
185 | // | 188 | // |
@@ -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 | |||
57 | static const char tar_usage[] = | 55 | static 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] " | |
69 | static 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[] = | |||
91 | struct TarHeader | 91 | struct 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 | }; |
112 | typedef struct TarHeader TarHeader; | 112 | typedef 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, | |||
170 | extern int tar_main(int argc, char **argv) | 169 | extern 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) | |||
532 | static int readTarFile(const char* tarName, int extractFlag, int listFlag, | 532 | static 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) { |