diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-12-12 02:14:35 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-12-12 02:14:35 +0000 |
commit | ab6b446e9567db741b463f74afb7d98cc583c4b9 (patch) | |
tree | 5a58620c525bf524451adec2ab2121fea04f04f8 | |
parent | 12abcb36c871f4c97d7aed3d9bd55e5477888bb7 (diff) | |
download | busybox-w32-ab6b446e9567db741b463f74afb7d98cc583c4b9.tar.gz busybox-w32-ab6b446e9567db741b463f74afb7d98cc583c4b9.tar.bz2 busybox-w32-ab6b446e9567db741b463f74afb7d98cc583c4b9.zip |
header_verbose_list: show off_t size, not cast to (unsigned)
get_header_tar: support GNU tar's "base256" encoding
function old new delta
get_header_tar 1536 1600 +64
header_verbose_list 242 257 +15
-rw-r--r-- | archival/libunarchive/get_header_tar.c | 73 | ||||
-rw-r--r-- | archival/libunarchive/header_verbose_list.c | 4 | ||||
-rw-r--r-- | archival/tar.c | 3 |
3 files changed, 76 insertions, 4 deletions
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c index bf0f92b25..48fc23d8b 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libunarchive/get_header_tar.c | |||
@@ -14,6 +14,74 @@ | |||
14 | #include "libbb.h" | 14 | #include "libbb.h" |
15 | #include "unarchive.h" | 15 | #include "unarchive.h" |
16 | 16 | ||
17 | /* | ||
18 | * GNU tar uses "base-256 encoding" for very large numbers (>8 billion). | ||
19 | * Encoding is binary, with highest bit always set as a marker | ||
20 | * and sign in next-highest bit: | ||
21 | * 80 00 .. 00 - zero | ||
22 | * bf ff .. ff - largest positive number | ||
23 | * ff ff .. ff - minus 1 | ||
24 | * c0 00 .. 00 - smallest negative number | ||
25 | * | ||
26 | * We expect it only in size field, where negative numbers don't make sense. | ||
27 | */ | ||
28 | static off_t getBase256_len12(const char *str) | ||
29 | { | ||
30 | off_t value; | ||
31 | int len; | ||
32 | |||
33 | /* if (*str & 0x40) error; - caller prevents this */ | ||
34 | |||
35 | if (sizeof(off_t) >= 12) { | ||
36 | /* Probably 128-bit (16 byte) off_t. Can be optimized. */ | ||
37 | len = 12; | ||
38 | value = *str++ & 0x3f; | ||
39 | while (--len) | ||
40 | value = (value << 8) + (unsigned char) *str++; | ||
41 | return value; | ||
42 | } | ||
43 | |||
44 | #ifdef CHECK_FOR_OVERFLOW | ||
45 | /* Can be optimized to eat 32-bit chunks */ | ||
46 | char c = *str++ & 0x3f; | ||
47 | len = 12; | ||
48 | while (1) { | ||
49 | if (c) | ||
50 | bb_error_msg_and_die("overflow in base-256 encoded file size"); | ||
51 | if (--len == sizeof(off_t)) | ||
52 | break; | ||
53 | c = *str++; | ||
54 | } | ||
55 | #else | ||
56 | str += (12 - sizeof(off_t)); | ||
57 | #endif | ||
58 | |||
59 | /* Now str points to sizeof(off_t) least significant bytes. | ||
60 | * | ||
61 | * Example of tar file with 8914993153 (0x213600001) byte file. | ||
62 | * Field starts at offset 7c: | ||
63 | * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....| | ||
64 | * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336| | ||
65 | * | ||
66 | * str is at offset 80 or 84 now (64-bit or 32-bit off_t). | ||
67 | * We (ab)use the fact that value happens to be aligned, | ||
68 | * and fetch it in one go: | ||
69 | */ | ||
70 | if (sizeof(off_t) == 8) { | ||
71 | value = *(off_t*)str; | ||
72 | value = SWAP_BE64(value); | ||
73 | } else if (sizeof(off_t) == 4) { | ||
74 | value = *(off_t*)str; | ||
75 | value = SWAP_BE32(value); | ||
76 | } else { | ||
77 | value = 0; | ||
78 | len = sizeof(off_t); | ||
79 | while (--len) | ||
80 | value = (value << 8) + (unsigned char) *str++; | ||
81 | } | ||
82 | return value; | ||
83 | } | ||
84 | |||
17 | /* NB: _DESTROYS_ str[len] character! */ | 85 | /* NB: _DESTROYS_ str[len] character! */ |
18 | static unsigned long long getOctal(char *str, int len) | 86 | static unsigned long long getOctal(char *str, int len) |
19 | { | 87 | { |
@@ -234,7 +302,10 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | |||
234 | file_header->gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL; | 302 | file_header->gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL; |
235 | #endif | 303 | #endif |
236 | file_header->mtime = GET_OCTAL(tar.mtime); | 304 | file_header->mtime = GET_OCTAL(tar.mtime); |
237 | file_header->size = GET_OCTAL(tar.size); | 305 | /* Size field: handle GNU tar's "base256 encoding" */ |
306 | file_header->size = (*tar.size & 0xc0) == 0x80 /* positive base256? */ | ||
307 | ? getBase256_len12(tar.size) | ||
308 | : GET_OCTAL(tar.size); | ||
238 | file_header->gid = GET_OCTAL(tar.gid); | 309 | file_header->gid = GET_OCTAL(tar.gid); |
239 | file_header->uid = GET_OCTAL(tar.uid); | 310 | file_header->uid = GET_OCTAL(tar.uid); |
240 | /* Set bits 0-11 of the files mode */ | 311 | /* Set bits 0-11 of the files mode */ |
diff --git a/archival/libunarchive/header_verbose_list.c b/archival/libunarchive/header_verbose_list.c index f059dd981..dc3100361 100644 --- a/archival/libunarchive/header_verbose_list.c +++ b/archival/libunarchive/header_verbose_list.c | |||
@@ -24,11 +24,11 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) | |||
24 | snprintf(gid, sizeof(gid), "%u", (unsigned)file_header->gid); | 24 | snprintf(gid, sizeof(gid), "%u", (unsigned)file_header->gid); |
25 | group = gid; | 25 | group = gid; |
26 | } | 26 | } |
27 | printf("%s %s/%s %9u %4u-%02u-%02u %02u:%02u:%02u %s", | 27 | printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", |
28 | bb_mode_string(file_header->mode), | 28 | bb_mode_string(file_header->mode), |
29 | user, | 29 | user, |
30 | group, | 30 | group, |
31 | (unsigned int) file_header->size, | 31 | file_header->size, |
32 | 1900 + mtime->tm_year, | 32 | 1900 + mtime->tm_year, |
33 | 1 + mtime->tm_mon, | 33 | 1 + mtime->tm_mon, |
34 | mtime->tm_mday, | 34 | mtime->tm_mday, |
diff --git a/archival/tar.c b/archival/tar.c index deb5c89b0..76f1a6240 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -357,7 +357,8 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, | |||
357 | if (tbInfo->verboseFlag) { | 357 | if (tbInfo->verboseFlag) { |
358 | FILE *vbFd = stdout; | 358 | FILE *vbFd = stdout; |
359 | 359 | ||
360 | if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */ | 360 | /* If archive goes to stdout, verbose goes to stderr */ |
361 | if (tbInfo->tarFd == STDOUT_FILENO) | ||
361 | vbFd = stderr; | 362 | vbFd = stderr; |
362 | /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */ | 363 | /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */ |
363 | /* We don't have such excesses here: for us "v" == "vv" */ | 364 | /* We don't have such excesses here: for us "v" == "vv" */ |