aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog7
-rw-r--r--Makefile4
-rw-r--r--TODO8
-rw-r--r--archival/tar.c203
-rw-r--r--busybox.def.h3
-rw-r--r--tar.c203
6 files changed, 249 insertions, 179 deletions
diff --git a/Changelog b/Changelog
index f506e095e..4a9fb6fc0 100644
--- a/Changelog
+++ b/Changelog
@@ -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
diff --git a/Makefile b/Makefile
index d647a5139..38d518eed 100644
--- a/Makefile
+++ b/Makefile
@@ -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'
28DODEBUG = true 28DODEBUG = 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
73ifeq ($(DODEBUG),true) 73ifeq ($(DODEBUG),true)
74 CFLAGS += -Wall -g -D_GNU_SOURCE 74 CFLAGS += -Wall -g -D_GNU_SOURCE
75 LDFLAGS = 75 LDFLAGS =
76 STRIP = 76 STRIP =
77else 77else
78 CFLAGS += -Wall $(OPTIMIZATION) -fomit-frame-pointer -fno-builtin -D_GNU_SOURCE 78 CFLAGS += -Wall $(OPTIMIZATION) -fomit-frame-pointer -fno-builtin -D_GNU_SOURCE
diff --git a/TODO b/TODO
index 421c402e3..48c8fefea 100644
--- a/TODO
+++ b/TODO
@@ -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
45There is no exclude file(s) option to tar. LRP's packaging system can not
46function without this. Will you have the time to add this soon?
47
48
49-----------------------
50
51Feature request: 45Feature 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
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) {
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//
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) {