diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-24 14:51:01 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-24 14:51:01 +0000 |
commit | 376ce1e775a97a01f1c454497fbe34d326043328 (patch) | |
tree | 94f9c05606bc4b38b47d408c7cf5e45be9ec29ec | |
parent | 14621929a194f9c8e618efdd8f58a031f7351231 (diff) | |
download | busybox-w32-376ce1e775a97a01f1c454497fbe34d326043328.tar.gz busybox-w32-376ce1e775a97a01f1c454497fbe34d326043328.tar.bz2 busybox-w32-376ce1e775a97a01f1c454497fbe34d326043328.zip |
tar:
* unpack: handle tar header fields which are not NUL terminated
* pack: handle 4+GB files correctly
* pack: refuse to store 101+ softlinks (was truncating link
target name)
* pack: mask mode with 07777
-rw-r--r-- | archival/libunarchive/get_header_tar.c | 167 | ||||
-rw-r--r-- | archival/tar.c | 232 | ||||
-rw-r--r-- | include/libbb.h | 1 | ||||
-rw-r--r-- | libbb/messages.c | 1 |
4 files changed, 220 insertions, 181 deletions
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c index f78377e28..b5cae9f12 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libunarchive/get_header_tar.c | |||
@@ -19,49 +19,69 @@ static char *longname = NULL; | |||
19 | static char *linkname = NULL; | 19 | static char *linkname = NULL; |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | /* NB: _DESTROYS_ str[len] character! */ | ||
23 | static unsigned long long getOctal(char *str, int len) | ||
24 | { | ||
25 | unsigned long long v; | ||
26 | /* Actually, tar header allows leading spaces also. | ||
27 | * Oh well, we will be liberal and skip this... | ||
28 | * The only downside probably is that we allow "-123" too :) | ||
29 | if (*str < '0' || *str > '7') | ||
30 | bb_error_msg_and_die("corrupted octal value in tar header"); | ||
31 | */ | ||
32 | str[len] = '\0'; | ||
33 | v = strtoull(str, &str, 8); | ||
34 | if (*str) | ||
35 | bb_error_msg_and_die("corrupted octal value in tar header"); | ||
36 | return v; | ||
37 | } | ||
38 | |||
39 | void BUG_tar_header_size(void); | ||
22 | char get_header_tar(archive_handle_t *archive_handle) | 40 | char get_header_tar(archive_handle_t *archive_handle) |
23 | { | 41 | { |
42 | static int end = 0; | ||
43 | |||
24 | file_header_t *file_header = archive_handle->file_header; | 44 | file_header_t *file_header = archive_handle->file_header; |
25 | union { | 45 | struct { |
26 | /* ustar header, Posix 1003.1 */ | 46 | /* ustar header, Posix 1003.1 */ |
27 | unsigned char raw[512]; | 47 | char name[100]; /* 0-99 */ |
28 | struct { | 48 | char mode[8]; /* 100-107 */ |
29 | char name[100]; /* 0-99 */ | 49 | char uid[8]; /* 108-115 */ |
30 | char mode[8]; /* 100-107 */ | 50 | char gid[8]; /* 116-123 */ |
31 | char uid[8]; /* 108-115 */ | 51 | char size[12]; /* 124-135 */ |
32 | char gid[8]; /* 116-123 */ | 52 | char mtime[12]; /* 136-147 */ |
33 | char size[12]; /* 124-135 */ | 53 | char chksum[8]; /* 148-155 */ |
34 | char mtime[12]; /* 136-147 */ | 54 | char typeflag; /* 156-156 */ |
35 | char chksum[8]; /* 148-155 */ | 55 | char linkname[100]; /* 157-256 */ |
36 | char typeflag; /* 156-156 */ | 56 | char magic[6]; /* 257-262 */ |
37 | char linkname[100]; /* 157-256 */ | 57 | char version[2]; /* 263-264 */ |
38 | char magic[6]; /* 257-262 */ | 58 | char uname[32]; /* 265-296 */ |
39 | char version[2]; /* 263-264 */ | 59 | char gname[32]; /* 297-328 */ |
40 | char uname[32]; /* 265-296 */ | 60 | char devmajor[8]; /* 329-336 */ |
41 | char gname[32]; /* 297-328 */ | 61 | char devminor[8]; /* 337-344 */ |
42 | char devmajor[8]; /* 329-336 */ | 62 | char prefix[155]; /* 345-499 */ |
43 | char devminor[8]; /* 337-344 */ | 63 | char padding[12]; /* 500-512 */ |
44 | char prefix[155]; /* 345-499 */ | ||
45 | char padding[12]; /* 500-512 */ | ||
46 | } formatted; | ||
47 | } tar; | 64 | } tar; |
48 | long sum = 0; | 65 | char *cp; |
49 | long i; | 66 | int sum, i; |
50 | static int end = 0; | 67 | |
68 | if (sizeof(tar) != 512) | ||
69 | BUG_tar_header_size(); | ||
51 | 70 | ||
52 | /* Align header */ | 71 | /* Align header */ |
53 | data_align(archive_handle, 512); | 72 | data_align(archive_handle, 512); |
54 | 73 | ||
55 | xread(archive_handle->src_fd, tar.raw, 512); | 74 | xread(archive_handle->src_fd, &tar, 512); |
56 | archive_handle->offset += 512; | 75 | archive_handle->offset += 512; |
57 | 76 | ||
58 | /* If there is no filename its an empty header */ | 77 | /* If there is no filename its an empty header */ |
59 | if (tar.formatted.name[0] == 0) { | 78 | if (tar.name[0] == 0) { |
60 | if (end) { | 79 | if (end) { |
61 | /* This is the second consecutive empty header! End of archive! | 80 | /* This is the second consecutive empty header! End of archive! |
62 | * Read until the end to empty the pipe from gz or bz2 | 81 | * Read until the end to empty the pipe from gz or bz2 |
63 | */ | 82 | */ |
64 | while (full_read(archive_handle->src_fd, tar.raw, 512) == 512); | 83 | while (full_read(archive_handle->src_fd, &tar, 512) == 512) |
84 | /* repeat */; | ||
65 | return EXIT_FAILURE; | 85 | return EXIT_FAILURE; |
66 | } | 86 | } |
67 | end = 1; | 87 | end = 1; |
@@ -72,21 +92,22 @@ char get_header_tar(archive_handle_t *archive_handle) | |||
72 | /* Check header has valid magic, "ustar" is for the proper tar | 92 | /* Check header has valid magic, "ustar" is for the proper tar |
73 | * 0's are for the old tar format | 93 | * 0's are for the old tar format |
74 | */ | 94 | */ |
75 | if (strncmp(tar.formatted.magic, "ustar", 5) != 0) { | 95 | if (strncmp(tar.magic, "ustar", 5) != 0) { |
76 | #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY | 96 | #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY |
77 | if (memcmp(tar.formatted.magic, "\0\0\0\0", 5) != 0) | 97 | if (memcmp(tar.magic, "\0\0\0\0", 5) != 0) |
78 | #endif | 98 | #endif |
79 | bb_error_msg_and_die("invalid tar magic"); | 99 | bb_error_msg_and_die("invalid tar magic"); |
80 | } | 100 | } |
81 | /* Do checksum on headers */ | 101 | /* Do checksum on headers */ |
102 | sum = ' ' * sizeof(tar.chksum); | ||
82 | for (i = 0; i < 148 ; i++) { | 103 | for (i = 0; i < 148 ; i++) { |
83 | sum += tar.raw[i]; | 104 | sum += ((char*)&tar)[i]; |
84 | } | 105 | } |
85 | sum += ' ' * 8; | ||
86 | for (i = 156; i < 512 ; i++) { | 106 | for (i = 156; i < 512 ; i++) { |
87 | sum += tar.raw[i]; | 107 | sum += ((char*)&tar)[i]; |
88 | } | 108 | } |
89 | if (sum != xstrtoul(tar.formatted.chksum, 8)) { | 109 | /* This field does not need special treatment (getOctal) */ |
110 | if (sum != xstrtoul(tar.chksum, 8)) { | ||
90 | bb_error_msg_and_die("invalid tar header checksum"); | 111 | bb_error_msg_and_die("invalid tar header checksum"); |
91 | } | 112 | } |
92 | 113 | ||
@@ -101,30 +122,34 @@ char get_header_tar(archive_handle_t *archive_handle) | |||
101 | } else | 122 | } else |
102 | #endif | 123 | #endif |
103 | { | 124 | { |
104 | file_header->name = xstrndup(tar.formatted.name, 100); | 125 | file_header->name = xstrndup(tar.name, sizeof(tar.name)); |
105 | if (tar.formatted.prefix[0]) { | 126 | if (tar.prefix[0]) { |
106 | char *temp = file_header->name; | 127 | char *temp = file_header->name; |
107 | file_header->name = concat_path_file(tar.formatted.prefix, temp); | 128 | file_header->name = concat_path_file(tar.prefix, temp); |
108 | free(temp); | 129 | free(temp); |
109 | } | 130 | } |
110 | } | 131 | } |
111 | 132 | ||
112 | file_header->uid = xstrtoul(tar.formatted.uid, 8); | 133 | /* getOctal trashes subsequent field, therefore we call it |
113 | file_header->gid = xstrtoul(tar.formatted.gid, 8); | 134 | * on fields in reverse order */ |
114 | file_header->size = XSTRTOUOFF(tar.formatted.size, 8); | 135 | #define GET_OCTAL(a) getOctal((a), sizeof(a)) |
115 | file_header->mtime = xstrtoul(tar.formatted.mtime, 8); | 136 | if (tar.devmajor[0]) { |
116 | file_header->link_name = tar.formatted.linkname[0] ? | 137 | unsigned minor = GET_OCTAL(tar.devminor); |
117 | xstrdup(tar.formatted.linkname) : NULL; | 138 | unsigned major = GET_OCTAL(tar.devmajor); |
118 | if (tar.formatted.devmajor[0]) { | 139 | file_header->device = makedev(major, minor); |
119 | file_header->device = makedev(xstrtoul(tar.formatted.devmajor, 8), | ||
120 | xstrtoul(tar.formatted.devminor, 8)); | ||
121 | } | 140 | } |
122 | 141 | file_header->mtime = GET_OCTAL(tar.mtime); | |
142 | file_header->size = GET_OCTAL(tar.size); | ||
143 | file_header->gid = GET_OCTAL(tar.gid); | ||
144 | file_header->uid = GET_OCTAL(tar.uid); | ||
145 | file_header->link_name = !tar.linkname[0] ? NULL : | ||
146 | xstrndup(tar.linkname, sizeof(tar.linkname)); | ||
123 | /* Set bits 0-11 of the files mode */ | 147 | /* Set bits 0-11 of the files mode */ |
124 | file_header->mode = 07777 & xstrtoul(tar.formatted.mode, 8); | 148 | file_header->mode = 07777 & GET_OCTAL(tar.mode); |
149 | #undef GET_OCTAL | ||
125 | 150 | ||
126 | /* Set bits 12-15 of the files mode */ | 151 | /* Set bits 12-15 of the files mode */ |
127 | switch (tar.formatted.typeflag) { | 152 | switch (tar.typeflag) { |
128 | /* busybox identifies hard links as being regular files with 0 size and a link name */ | 153 | /* busybox identifies hard links as being regular files with 0 size and a link name */ |
129 | case '1': | 154 | case '1': |
130 | file_header->mode |= S_IFREG; | 155 | file_header->mode |= S_IFREG; |
@@ -138,7 +163,7 @@ char get_header_tar(archive_handle_t *archive_handle) | |||
138 | file_header->mode |= S_IFDIR; | 163 | file_header->mode |= S_IFDIR; |
139 | } else | 164 | } else |
140 | #endif | 165 | #endif |
141 | file_header->mode |= S_IFREG; | 166 | file_header->mode |= S_IFREG; |
142 | break; | 167 | break; |
143 | case '2': | 168 | case '2': |
144 | file_header->mode |= S_IFLNK; | 169 | file_header->mode |= S_IFLNK; |
@@ -156,42 +181,36 @@ char get_header_tar(archive_handle_t *archive_handle) | |||
156 | file_header->mode |= S_IFIFO; | 181 | file_header->mode |= S_IFIFO; |
157 | break; | 182 | break; |
158 | #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS | 183 | #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS |
159 | case 'L': { | 184 | case 'L': |
160 | longname = xzalloc(file_header->size + 1); | 185 | longname = xzalloc(file_header->size + 1); |
161 | xread(archive_handle->src_fd, longname, file_header->size); | 186 | xread(archive_handle->src_fd, longname, file_header->size); |
162 | archive_handle->offset += file_header->size; | 187 | archive_handle->offset += file_header->size; |
163 | 188 | return get_header_tar(archive_handle); | |
164 | return get_header_tar(archive_handle); | 189 | case 'K': |
165 | } | 190 | linkname = xzalloc(file_header->size + 1); |
166 | case 'K': { | 191 | xread(archive_handle->src_fd, linkname, file_header->size); |
167 | linkname = xzalloc(file_header->size + 1); | 192 | archive_handle->offset += file_header->size; |
168 | xread(archive_handle->src_fd, linkname, file_header->size); | 193 | file_header->name = linkname; |
169 | archive_handle->offset += file_header->size; | 194 | return get_header_tar(archive_handle); |
170 | |||
171 | file_header->name = linkname; | ||
172 | return get_header_tar(archive_handle); | ||
173 | } | ||
174 | case 'D': /* GNU dump dir */ | 195 | case 'D': /* GNU dump dir */ |
175 | case 'M': /* Continuation of multi volume archive*/ | 196 | case 'M': /* Continuation of multi volume archive */ |
176 | case 'N': /* Old GNU for names > 100 characters */ | 197 | case 'N': /* Old GNU for names > 100 characters */ |
177 | case 'S': /* Sparse file */ | 198 | case 'S': /* Sparse file */ |
178 | case 'V': /* Volume header */ | 199 | case 'V': /* Volume header */ |
179 | #endif | 200 | #endif |
180 | case 'g': /* pax global header */ | 201 | case 'g': /* pax global header */ |
181 | case 'x': /* pax extended header */ | 202 | case 'x': /* pax extended header */ |
182 | bb_error_msg("ignoring extension type %c", tar.formatted.typeflag); | 203 | bb_error_msg("ignoring extension type %c", tar.typeflag); |
183 | break; | 204 | break; |
184 | default: | 205 | default: |
185 | bb_error_msg("unknown typeflag: 0x%x", tar.formatted.typeflag); | 206 | bb_error_msg("unknown typeflag: 0x%x", tar.typeflag); |
186 | } | ||
187 | { /* Strip trailing '/' in directories */ | ||
188 | /* Must be done after mode is set as '/' is used to check if its a directory */ | ||
189 | char *tmp = last_char_is(file_header->name, '/'); | ||
190 | if (tmp) { | ||
191 | *tmp = '\0'; | ||
192 | } | ||
193 | } | 207 | } |
194 | 208 | ||
209 | /* Strip trailing '/' in directories */ | ||
210 | /* Must be done after mode is set as '/' is used to check if its a directory */ | ||
211 | cp = last_char_is(file_header->name, '/'); | ||
212 | if (cp) *cp = '\0'; | ||
213 | |||
195 | if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { | 214 | if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { |
196 | archive_handle->action_header(archive_handle->file_header); | 215 | archive_handle->action_header(archive_handle->file_header); |
197 | archive_handle->flags |= ARCHIVE_EXTRACT_QUIET; | 216 | archive_handle->flags |= ARCHIVE_EXTRACT_QUIET; |
diff --git a/archival/tar.c b/archival/tar.c index db812e0f4..911c2d35e 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -35,25 +35,26 @@ | |||
35 | #define TAR_BLOCK_SIZE 512 | 35 | #define TAR_BLOCK_SIZE 512 |
36 | 36 | ||
37 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ | 37 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ |
38 | #define NAME_SIZE 100 | 38 | #define NAME_SIZE 100 |
39 | struct TarHeader { /* byte offset */ | 39 | #define NAME_SIZE_STR "100" |
40 | char name[NAME_SIZE]; /* 0-99 */ | 40 | struct TarHeader { /* byte offset */ |
41 | char mode[8]; /* 100-107 */ | 41 | char name[NAME_SIZE]; /* 0-99 */ |
42 | char uid[8]; /* 108-115 */ | 42 | char mode[8]; /* 100-107 */ |
43 | char gid[8]; /* 116-123 */ | 43 | char uid[8]; /* 108-115 */ |
44 | char size[12]; /* 124-135 */ | 44 | char gid[8]; /* 116-123 */ |
45 | char mtime[12]; /* 136-147 */ | 45 | char size[12]; /* 124-135 */ |
46 | char chksum[8]; /* 148-155 */ | 46 | char mtime[12]; /* 136-147 */ |
47 | char typeflag; /* 156-156 */ | 47 | char chksum[8]; /* 148-155 */ |
48 | char linkname[NAME_SIZE]; /* 157-256 */ | 48 | char typeflag; /* 156-156 */ |
49 | char magic[6]; /* 257-262 */ | 49 | char linkname[NAME_SIZE]; /* 157-256 */ |
50 | char version[2]; /* 263-264 */ | 50 | char magic[6]; /* 257-262 */ |
51 | char uname[32]; /* 265-296 */ | 51 | char version[2]; /* 263-264 */ |
52 | char gname[32]; /* 297-328 */ | 52 | char uname[32]; /* 265-296 */ |
53 | char devmajor[8]; /* 329-336 */ | 53 | char gname[32]; /* 297-328 */ |
54 | char devminor[8]; /* 337-344 */ | 54 | char devmajor[8]; /* 329-336 */ |
55 | char prefix[155]; /* 345-499 */ | 55 | char devminor[8]; /* 337-344 */ |
56 | char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */ | 56 | char prefix[155]; /* 345-499 */ |
57 | char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */ | ||
57 | }; | 58 | }; |
58 | typedef struct TarHeader TarHeader; | 59 | typedef struct TarHeader TarHeader; |
59 | 60 | ||
@@ -121,8 +122,8 @@ static void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr, | |||
121 | 122 | ||
122 | static void freeHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr) | 123 | static void freeHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr) |
123 | { | 124 | { |
124 | HardLinkInfo *hlInfo = NULL; | 125 | HardLinkInfo *hlInfo; |
125 | HardLinkInfo *hlInfoNext = NULL; | 126 | HardLinkInfo *hlInfoNext; |
126 | 127 | ||
127 | if (hlInfoHeadPtr) { | 128 | if (hlInfoHeadPtr) { |
128 | hlInfo = *hlInfoHeadPtr; | 129 | hlInfo = *hlInfoHeadPtr; |
@@ -148,60 +149,70 @@ static HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbu | |||
148 | } | 149 | } |
149 | 150 | ||
150 | /* Put an octal string into the specified buffer. | 151 | /* Put an octal string into the specified buffer. |
151 | * The number is zero and space padded and possibly null padded. | 152 | * The number is zero padded and possibly null terminated. |
152 | * Returns TRUE if successful. */ | 153 | * Returns TRUE if successful. - DISABLED (no caller ever checked) */ |
153 | static int putOctal(char *cp, int len, long value) | 154 | static void putOctal(char *cp, int len, long long value) |
154 | { | 155 | { |
155 | int tempLength; | 156 | int tempLength; |
156 | char tempBuffer[32]; | 157 | /* long long for the sake of storing lengths of 4Gb+ files */ |
158 | /* (we are bust anyway after 64Gb: it doesn't fit into the field) */ | ||
159 | char tempBuffer[sizeof(long long)*3+1]; | ||
157 | char *tempString = tempBuffer; | 160 | char *tempString = tempBuffer; |
158 | 161 | ||
159 | /* Create a string of the specified length with an initial space, | 162 | /* Create a string of the specified length with |
160 | * leading zeroes and the octal number, and a trailing null. */ | 163 | * leading zeroes and the octal number, and a trailing null. */ |
161 | sprintf(tempString, "%0*lo", len - 1, value); | 164 | tempLength = sprintf(tempBuffer, "%0*llo", len - 1, value); |
162 | 165 | ||
163 | /* If the string is too large, suppress the leading space. */ | 166 | /* If the string is too large, suppress leading 0's. */ |
164 | tempLength = strlen(tempString) + 1; | 167 | /* If that is not enough, drop trailing null. */ |
165 | if (tempLength > len) { | 168 | tempLength -= len; /* easier to do checks */ |
166 | tempLength--; | 169 | while (tempLength >= 0) { |
167 | tempString++; | 170 | if (tempString[0] != '0') { |
171 | if (!tempLength) { | ||
172 | /* 1234 barely fits in 4 chars (w/o EOL '\0') */ | ||
173 | break; | ||
174 | } | ||
175 | /* 12345 doesn't fit into 4 chars */ | ||
176 | return /*FALSE*/; | ||
177 | } | ||
178 | tempLength--; /* still have leading '0', */ | ||
179 | tempString++; /* can afford to drop it but retain EOL '\0' */ | ||
168 | } | 180 | } |
169 | 181 | ||
170 | /* If the string is still too large, suppress the trailing null. */ | ||
171 | if (tempLength > len) | ||
172 | tempLength--; | ||
173 | |||
174 | /* If the string is still too large, fail. */ | ||
175 | if (tempLength > len) | ||
176 | return FALSE; | ||
177 | |||
178 | /* Copy the string to the field. */ | 182 | /* Copy the string to the field. */ |
179 | memcpy(cp, tempString, len); | 183 | memcpy(cp, tempString, len); |
180 | 184 | /*return TRUE;*/ | |
181 | return TRUE; | ||
182 | } | 185 | } |
183 | 186 | ||
184 | /* Write out a tar header for the specified file/directory/whatever */ | 187 | /* Write out a tar header for the specified file/directory/whatever */ |
188 | void BUG_tar_header_size(void); | ||
185 | static int writeTarHeader(struct TarBallInfo *tbInfo, | 189 | static int writeTarHeader(struct TarBallInfo *tbInfo, |
186 | const char *header_name, const char *fileName, struct stat *statbuf) | 190 | const char *header_name, const char *fileName, struct stat *statbuf) |
187 | { | 191 | { |
188 | long chksum = 0; | ||
189 | struct TarHeader header; | 192 | struct TarHeader header; |
190 | const unsigned char *cp = (const unsigned char *) &header; | 193 | const unsigned char *cp; |
191 | ssize_t size = sizeof(struct TarHeader); | 194 | int chksum; |
195 | int size; | ||
192 | 196 | ||
193 | bzero(&header, size); | 197 | if (sizeof(header) != 512) |
198 | BUG_tar_header_size(); | ||
199 | |||
200 | bzero(&header, sizeof(struct TarHeader)); | ||
194 | 201 | ||
195 | safe_strncpy(header.name, header_name, sizeof(header.name)); | 202 | safe_strncpy(header.name, header_name, sizeof(header.name)); |
196 | 203 | ||
197 | putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); | 204 | /* POSIX says to mask mode with 07777. */ |
205 | putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 07777); | ||
198 | putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); | 206 | putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); |
199 | putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); | 207 | putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); |
200 | putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */ | 208 | if (sizeof(header.size) != sizeof("00000000000")) |
209 | BUG_tar_header_size(); | ||
210 | strcpy(header.size, "00000000000"); /* Regular file size is handled later */ | ||
201 | putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); | 211 | putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); |
202 | strcpy(header.magic, "ustar "); | 212 | strcpy(header.magic, "ustar "); |
203 | 213 | ||
204 | /* Enter the user and group names (default to root if it fails) */ | 214 | /* Enter the user and group names (default to root if it fails) */ |
215 | //cache!!! | ||
205 | if (bb_getpwuid(header.uname, statbuf->st_uid, sizeof(header.uname)) == NULL) | 216 | if (bb_getpwuid(header.uname, statbuf->st_uid, sizeof(header.uname)) == NULL) |
206 | strcpy(header.uname, "root"); | 217 | strcpy(header.uname, "root"); |
207 | if (bb_getgrgid(header.gname, statbuf->st_gid, sizeof(header.gname)) == NULL) | 218 | if (bb_getgrgid(header.gname, statbuf->st_gid, sizeof(header.gname)) == NULL) |
@@ -214,11 +225,18 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, | |||
214 | sizeof(header.linkname)); | 225 | sizeof(header.linkname)); |
215 | } else if (S_ISLNK(statbuf->st_mode)) { | 226 | } else if (S_ISLNK(statbuf->st_mode)) { |
216 | char *lpath = xreadlink(fileName); | 227 | char *lpath = xreadlink(fileName); |
217 | |||
218 | if (!lpath) /* Already printed err msg inside xreadlink() */ | 228 | if (!lpath) /* Already printed err msg inside xreadlink() */ |
219 | return FALSE; | 229 | return FALSE; |
220 | header.typeflag = SYMTYPE; | 230 | header.typeflag = SYMTYPE; |
221 | strncpy(header.linkname, lpath, sizeof(header.linkname)); | 231 | strncpy(header.linkname, lpath, sizeof(header.linkname)); |
232 | /* If it is larger than 100 bytes, bail out */ | ||
233 | if (header.linkname[sizeof(header.linkname)-1] /* at least 100? */ | ||
234 | && lpath[sizeof(header.linkname)] /* and 101th is also not zero */ | ||
235 | ) { | ||
236 | free(lpath); | ||
237 | bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported"); | ||
238 | return FALSE; | ||
239 | } | ||
222 | free(lpath); | 240 | free(lpath); |
223 | } else if (S_ISDIR(statbuf->st_mode)) { | 241 | } else if (S_ISDIR(statbuf->st_mode)) { |
224 | header.typeflag = DIRTYPE; | 242 | header.typeflag = DIRTYPE; |
@@ -252,9 +270,10 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, | |||
252 | * digits, followed by a null like the other fields... */ | 270 | * digits, followed by a null like the other fields... */ |
253 | memset(header.chksum, ' ', sizeof(header.chksum)); | 271 | memset(header.chksum, ' ', sizeof(header.chksum)); |
254 | cp = (const unsigned char *) &header; | 272 | cp = (const unsigned char *) &header; |
255 | while (size-- > 0) | 273 | chksum = 0; |
256 | chksum += *cp++; | 274 | size = sizeof(struct TarHeader); |
257 | putOctal(header.chksum, 7, chksum); | 275 | do { chksum += *cp++; } while (--size); |
276 | putOctal(header.chksum, sizeof(header.chksum)-1, chksum); | ||
258 | 277 | ||
259 | /* Now write the header out to disk */ | 278 | /* Now write the header out to disk */ |
260 | xwrite(tbInfo->tarFd, &header, sizeof(struct TarHeader)); | 279 | xwrite(tbInfo->tarFd, &header, sizeof(struct TarHeader)); |
@@ -348,22 +367,21 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, | |||
348 | } | 367 | } |
349 | 368 | ||
350 | if (strlen(fileName) >= NAME_SIZE) { | 369 | if (strlen(fileName) >= NAME_SIZE) { |
351 | bb_error_msg(bb_msg_name_longer_than_foo, NAME_SIZE); | 370 | bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported"); |
352 | return TRUE; | 371 | return TRUE; |
353 | } | 372 | } |
354 | 373 | ||
355 | if (header_name[0] == '\0') | 374 | if (header_name[0] == '\0') |
356 | return TRUE; | 375 | return TRUE; |
357 | 376 | ||
358 | if (ENABLE_FEATURE_TAR_FROM && | 377 | if (exclude_file(tbInfo->excludeList, header_name)) |
359 | exclude_file(tbInfo->excludeList, header_name)) { | ||
360 | return SKIP; | 378 | return SKIP; |
361 | } | ||
362 | 379 | ||
363 | /* Is this a regular file? */ | 380 | /* Is this a regular file? */ |
364 | if ((tbInfo->hlInfo == NULL) && (S_ISREG(statbuf->st_mode))) { | 381 | if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) { |
365 | /* open the file we want to archive, and make sure all is well */ | 382 | /* open the file we want to archive, and make sure all is well */ |
366 | if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { | 383 | inputFileFd = open(fileName, O_RDONLY); |
384 | if (inputFileFd < 0) { | ||
367 | bb_perror_msg("%s: cannot open", fileName); | 385 | bb_perror_msg("%s: cannot open", fileName); |
368 | return FALSE; | 386 | return FALSE; |
369 | } | 387 | } |
@@ -383,7 +401,8 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf, | |||
383 | close(inputFileFd); | 401 | close(inputFileFd); |
384 | 402 | ||
385 | /* Pad the file up to the tar block size */ | 403 | /* Pad the file up to the tar block size */ |
386 | readSize = (TAR_BLOCK_SIZE - readSize) & (TAR_BLOCK_SIZE-1); | 404 | /* (a few tricks here in the name of code size) */ |
405 | readSize = (-(int)readSize) & (TAR_BLOCK_SIZE-1); | ||
387 | bzero(bb_common_bufsiz1, readSize); | 406 | bzero(bb_common_bufsiz1, readSize); |
388 | xwrite(tbInfo->tarFd, bb_common_bufsiz1, readSize); | 407 | xwrite(tbInfo->tarFd, bb_common_bufsiz1, readSize); |
389 | } | 408 | } |
@@ -423,10 +442,10 @@ static int writeTarFile(const int tar_fd, const int verboseFlag, | |||
423 | signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ | 442 | signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ |
424 | 443 | ||
425 | # if __GNUC__ | 444 | # if __GNUC__ |
426 | /* Avoid vfork clobbering */ | 445 | /* Avoid vfork clobbering */ |
427 | (void) &include; | 446 | (void) &include; |
428 | (void) &errorFlag; | 447 | (void) &errorFlag; |
429 | (void) &zip_exec; | 448 | (void) &zip_exec; |
430 | # endif | 449 | # endif |
431 | 450 | ||
432 | gzipPid = vfork(); | 451 | gzipPid = vfork(); |
@@ -498,8 +517,8 @@ static int writeTarFile(const int tar_fd, const int verboseFlag, | |||
498 | if (errorFlag) | 517 | if (errorFlag) |
499 | bb_error_msg("error exit delayed from previous errors"); | 518 | bb_error_msg("error exit delayed from previous errors"); |
500 | 519 | ||
501 | if (gzipPid && waitpid(gzipPid, NULL, 0)==-1) | 520 | if (gzipPid && waitpid(gzipPid, NULL, 0) == -1) |
502 | bb_error_msg("cannot wait"); | 521 | bb_error_msg("waitpid failed"); |
503 | 522 | ||
504 | return !errorFlag; | 523 | return !errorFlag; |
505 | } | 524 | } |
@@ -634,7 +653,7 @@ static char get_header_tar_Z(archive_handle_t *archive_handle) | |||
634 | #define TAR_OPT_STR_NOPRESERVE "\203\213" | 653 | #define TAR_OPT_STR_NOPRESERVE "\203\213" |
635 | #define TAR_OPT_AFTER_NOPRESERVE TAR_OPT_AFTER_COMPRESS + 2 | 654 | #define TAR_OPT_AFTER_NOPRESERVE TAR_OPT_AFTER_COMPRESS + 2 |
636 | 655 | ||
637 | static const char tar_options[]="txC:f:Opvk" \ | 656 | static const char tar_options[] = "txC:f:Opvk" \ |
638 | TAR_OPT_STR_CREATE \ | 657 | TAR_OPT_STR_CREATE \ |
639 | TAR_OPT_STR_BZIP2 \ | 658 | TAR_OPT_STR_BZIP2 \ |
640 | TAR_OPT_STR_LZMA \ | 659 | TAR_OPT_STR_LZMA \ |
@@ -645,38 +664,38 @@ static const char tar_options[]="txC:f:Opvk" \ | |||
645 | 664 | ||
646 | #ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS | 665 | #ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS |
647 | static const struct option tar_long_options[] = { | 666 | static const struct option tar_long_options[] = { |
648 | { "list", 0, NULL, 't' }, | 667 | { "list", 0, NULL, 't' }, |
649 | { "extract", 0, NULL, 'x' }, | 668 | { "extract", 0, NULL, 'x' }, |
650 | { "directory", 1, NULL, 'C' }, | 669 | { "directory", 1, NULL, 'C' }, |
651 | { "file", 1, NULL, 'f' }, | 670 | { "file", 1, NULL, 'f' }, |
652 | { "to-stdout", 0, NULL, 'O' }, | 671 | { "to-stdout", 0, NULL, 'O' }, |
653 | { "same-permissions", 0, NULL, 'p' }, | 672 | { "same-permissions", 0, NULL, 'p' }, |
654 | { "verbose", 0, NULL, 'v' }, | 673 | { "verbose", 0, NULL, 'v' }, |
655 | { "keep-old", 0, NULL, 'k' }, | 674 | { "keep-old", 0, NULL, 'k' }, |
656 | { "no-same-owner", 0, NULL, '\203' }, | 675 | { "no-same-owner", 0, NULL, '\203' }, |
657 | { "no-same-permissions",0, NULL, '\213' }, | 676 | { "no-same-permissions",0, NULL, '\213' }, |
658 | # ifdef CONFIG_FEATURE_TAR_CREATE | 677 | # ifdef CONFIG_FEATURE_TAR_CREATE |
659 | { "create", 0, NULL, 'c' }, | 678 | { "create", 0, NULL, 'c' }, |
660 | { "dereference", 0, NULL, 'h' }, | 679 | { "dereference", 0, NULL, 'h' }, |
661 | # endif | 680 | # endif |
662 | # ifdef CONFIG_FEATURE_TAR_BZIP2 | 681 | # ifdef CONFIG_FEATURE_TAR_BZIP2 |
663 | { "bzip2", 0, NULL, 'j' }, | 682 | { "bzip2", 0, NULL, 'j' }, |
664 | # endif | 683 | # endif |
665 | # ifdef CONFIG_FEATURE_TAR_LZMA | 684 | # ifdef CONFIG_FEATURE_TAR_LZMA |
666 | { "lzma", 0, NULL, 'a' }, | 685 | { "lzma", 0, NULL, 'a' }, |
667 | # endif | 686 | # endif |
668 | # ifdef CONFIG_FEATURE_TAR_FROM | 687 | # ifdef CONFIG_FEATURE_TAR_FROM |
669 | { "files-from", 1, NULL, 'T' }, | 688 | { "files-from", 1, NULL, 'T' }, |
670 | { "exclude-from", 1, NULL, 'X' }, | 689 | { "exclude-from", 1, NULL, 'X' }, |
671 | { "exclude", 1, NULL, '\n' }, | 690 | { "exclude", 1, NULL, '\n' }, |
672 | # endif | 691 | # endif |
673 | # ifdef CONFIG_FEATURE_TAR_GZIP | 692 | # ifdef CONFIG_FEATURE_TAR_GZIP |
674 | { "gzip", 0, NULL, 'z' }, | 693 | { "gzip", 0, NULL, 'z' }, |
675 | # endif | 694 | # endif |
676 | # ifdef CONFIG_FEATURE_TAR_COMPRESS | 695 | # ifdef CONFIG_FEATURE_TAR_COMPRESS |
677 | { "compress", 0, NULL, 'Z' }, | 696 | { "compress", 0, NULL, 'Z' }, |
678 | # endif | 697 | # endif |
679 | { 0, 0, 0, 0 } | 698 | { 0, 0, 0, 0 } |
680 | }; | 699 | }; |
681 | #else | 700 | #else |
682 | #define tar_long_options 0 | 701 | #define tar_long_options 0 |
@@ -712,22 +731,23 @@ int tar_main(int argc, char **argv) | |||
712 | ); | 731 | ); |
713 | 732 | ||
714 | if (opt & CTX_TEST) { | 733 | if (opt & CTX_TEST) { |
715 | if ((tar_handle->action_header == header_list) || | 734 | if (tar_handle->action_header == header_list |
716 | (tar_handle->action_header == header_verbose_list)) | 735 | || tar_handle->action_header == header_verbose_list |
717 | { | 736 | ) { |
718 | tar_handle->action_header = header_verbose_list; | 737 | tar_handle->action_header = header_verbose_list; |
719 | } else tar_handle->action_header = header_list; | 738 | } else |
739 | tar_handle->action_header = header_list; | ||
720 | } | 740 | } |
721 | if((opt & CTX_EXTRACT) && tar_handle->action_data != data_extract_to_stdout) | 741 | if ((opt & CTX_EXTRACT) && tar_handle->action_data != data_extract_to_stdout) |
722 | tar_handle->action_data = data_extract_all; | 742 | tar_handle->action_data = data_extract_all; |
723 | 743 | ||
724 | if (opt & TAR_OPT_2STDOUT) | 744 | if (opt & TAR_OPT_2STDOUT) |
725 | tar_handle->action_data = data_extract_to_stdout; | 745 | tar_handle->action_data = data_extract_to_stdout; |
726 | 746 | ||
727 | if (opt & TAR_OPT_VERBOSE) { | 747 | if (opt & TAR_OPT_VERBOSE) { |
728 | if ((tar_handle->action_header == header_list) || | 748 | if (tar_handle->action_header == header_list |
729 | (tar_handle->action_header == header_verbose_list)) | 749 | || tar_handle->action_header == header_verbose_list |
730 | { | 750 | ) { |
731 | tar_handle->action_header = header_verbose_list; | 751 | tar_handle->action_header = header_verbose_list; |
732 | } else | 752 | } else |
733 | tar_handle->action_header = header_list; | 753 | tar_handle->action_header = header_list; |
@@ -782,7 +802,7 @@ int tar_main(int argc, char **argv) | |||
782 | optind++; | 802 | optind++; |
783 | } | 803 | } |
784 | 804 | ||
785 | if ((tar_handle->accept) || (tar_handle->reject)) | 805 | if (tar_handle->accept || tar_handle->reject) |
786 | tar_handle->filter = filter_accept_reject_list; | 806 | tar_handle->filter = filter_accept_reject_list; |
787 | 807 | ||
788 | /* Open the tar file */ | 808 | /* Open the tar file */ |
@@ -796,8 +816,9 @@ int tar_main(int argc, char **argv) | |||
796 | bb_error_msg_and_die("empty archive"); | 816 | bb_error_msg_and_die("empty archive"); |
797 | 817 | ||
798 | tar_stream = stdout; | 818 | tar_stream = stdout; |
799 | flags = O_WRONLY | O_CREAT | O_EXCL; | 819 | /* Mimicking GNU tar 1.15.1: */ |
800 | unlink(tar_filename); | 820 | flags = O_WRONLY|O_CREAT|O_TRUNC; |
821 | /* was doing unlink; open(O_WRONLY|O_CREAT|O_EXCL); why? */ | ||
801 | } else { | 822 | } else { |
802 | tar_stream = stdin; | 823 | tar_stream = stdin; |
803 | flags = O_RDONLY; | 824 | flags = O_RDONLY; |
@@ -824,9 +845,9 @@ int tar_main(int argc, char **argv) | |||
824 | if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2) | 845 | if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2) |
825 | zipMode = 2; | 846 | zipMode = 2; |
826 | 847 | ||
827 | if ((tar_handle->action_header == header_list) || | 848 | if (tar_handle->action_header == header_list |
828 | (tar_handle->action_header == header_verbose_list)) | 849 | || tar_handle->action_header == header_verbose_list |
829 | { | 850 | ) { |
830 | verboseFlag = TRUE; | 851 | verboseFlag = TRUE; |
831 | } | 852 | } |
832 | writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERENCE, | 853 | writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERENCE, |
@@ -839,9 +860,10 @@ int tar_main(int argc, char **argv) | |||
839 | /* Check that every file that should have been extracted was */ | 860 | /* Check that every file that should have been extracted was */ |
840 | while (tar_handle->accept) { | 861 | while (tar_handle->accept) { |
841 | if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) | 862 | if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) |
842 | && !find_list_entry(tar_handle->passed, tar_handle->accept->data)) | 863 | && !find_list_entry(tar_handle->passed, tar_handle->accept->data) |
843 | { | 864 | ) { |
844 | bb_error_msg_and_die("%s: not found in archive", tar_handle->accept->data); | 865 | bb_error_msg_and_die("%s: not found in archive", |
866 | tar_handle->accept->data); | ||
845 | } | 867 | } |
846 | tar_handle->accept = tar_handle->accept->link; | 868 | tar_handle->accept = tar_handle->accept->link; |
847 | } | 869 | } |
@@ -850,5 +872,5 @@ int tar_main(int argc, char **argv) | |||
850 | if (ENABLE_FEATURE_CLEAN_UP && tar_handle->src_fd != STDIN_FILENO) | 872 | if (ENABLE_FEATURE_CLEAN_UP && tar_handle->src_fd != STDIN_FILENO) |
851 | close(tar_handle->src_fd); | 873 | close(tar_handle->src_fd); |
852 | 874 | ||
853 | return(EXIT_SUCCESS); | 875 | return EXIT_SUCCESS; |
854 | } | 876 | } |
diff --git a/include/libbb.h b/include/libbb.h index c96ef6f94..2ccb6e7bb 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -610,7 +610,6 @@ extern const char bb_msg_memory_exhausted[]; | |||
610 | extern const char bb_msg_invalid_date[]; | 610 | extern const char bb_msg_invalid_date[]; |
611 | extern const char bb_msg_read_error[]; | 611 | extern const char bb_msg_read_error[]; |
612 | extern const char bb_msg_write_error[]; | 612 | extern const char bb_msg_write_error[]; |
613 | extern const char bb_msg_name_longer_than_foo[]; | ||
614 | extern const char bb_msg_unknown[]; | 613 | extern const char bb_msg_unknown[]; |
615 | extern const char bb_msg_can_not_create_raw_socket[]; | 614 | extern const char bb_msg_can_not_create_raw_socket[]; |
616 | extern const char bb_msg_perm_denied_are_you_root[]; | 615 | extern const char bb_msg_perm_denied_are_you_root[]; |
diff --git a/libbb/messages.c b/libbb/messages.c index e3c0faf95..c640faf5b 100644 --- a/libbb/messages.c +++ b/libbb/messages.c | |||
@@ -19,7 +19,6 @@ const char bb_msg_memory_exhausted[] = "memory exhausted"; | |||
19 | const char bb_msg_invalid_date[] = "invalid date '%s'"; | 19 | const char bb_msg_invalid_date[] = "invalid date '%s'"; |
20 | const char bb_msg_write_error[] = "write error"; | 20 | const char bb_msg_write_error[] = "write error"; |
21 | const char bb_msg_read_error[] = "read error"; | 21 | const char bb_msg_read_error[] = "read error"; |
22 | const char bb_msg_name_longer_than_foo[] = "names longer than %d chars not supported"; | ||
23 | const char bb_msg_unknown[] = "(unknown)"; | 22 | const char bb_msg_unknown[] = "(unknown)"; |
24 | const char bb_msg_can_not_create_raw_socket[] = "can't create raw socket"; | 23 | const char bb_msg_can_not_create_raw_socket[] = "can't create raw socket"; |
25 | const char bb_msg_perm_denied_are_you_root[] = "permission denied. (are you root?)"; | 24 | const char bb_msg_perm_denied_are_you_root[] = "permission denied. (are you root?)"; |