diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-09-20 01:28:27 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-09-20 01:28:27 +0200 |
commit | 2bf6634ef46b5360e6381e61b27415e52a1cd7c7 (patch) | |
tree | 90c15ef98f110afca8d93d33179a49145ef11518 | |
parent | b410d4ada73e9ebb30b2b50266a13c30479f5f21 (diff) | |
download | busybox-w32-2bf6634ef46b5360e6381e61b27415e52a1cd7c7.tar.gz busybox-w32-2bf6634ef46b5360e6381e61b27415e52a1cd7c7.tar.bz2 busybox-w32-2bf6634ef46b5360e6381e61b27415e52a1cd7c7.zip |
ar: fix long filenames handling (bug 611)
function old new delta
get_header_ar 493 528 +35
read_num - 25 +25
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | archival/libunarchive/get_header_ar.c | 87 |
1 files changed, 50 insertions, 37 deletions
diff --git a/archival/libunarchive/get_header_ar.c b/archival/libunarchive/get_header_ar.c index d476a9d24..e6d712d8d 100644 --- a/archival/libunarchive/get_header_ar.c +++ b/archival/libunarchive/get_header_ar.c | |||
@@ -7,10 +7,20 @@ | |||
7 | #include "libbb.h" | 7 | #include "libbb.h" |
8 | #include "unarchive.h" | 8 | #include "unarchive.h" |
9 | 9 | ||
10 | static unsigned read_num(const char *str, int base) | ||
11 | { | ||
12 | /* This code works because | ||
13 | * on misformatted numbers bb_strtou returns all-ones */ | ||
14 | int err = bb_strtou(str, NULL, base); | ||
15 | if (err == -1) | ||
16 | bb_error_msg_and_die("invalid ar header"); | ||
17 | return err; | ||
18 | } | ||
19 | |||
10 | char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) | 20 | char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) |
11 | { | 21 | { |
12 | int err; | ||
13 | file_header_t *typed = archive_handle->file_header; | 22 | file_header_t *typed = archive_handle->file_header; |
23 | unsigned size; | ||
14 | union { | 24 | union { |
15 | char raw[60]; | 25 | char raw[60]; |
16 | struct { | 26 | struct { |
@@ -49,57 +59,60 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) | |||
49 | if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') | 59 | if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') |
50 | bb_error_msg_and_die("invalid ar header"); | 60 | bb_error_msg_and_die("invalid ar header"); |
51 | 61 | ||
52 | /* FIXME: more thorough routine would be in order here */ | 62 | /* FIXME: more thorough routine would be in order here |
53 | /* (we have something like that in tar) */ | 63 | * (we have something like that in tar) |
54 | /* but for now we are lax. This code works because */ | 64 | * but for now we are lax. */ |
55 | /* on misformatted numbers bb_strtou returns all-ones */ | 65 | typed->size = size = read_num(ar.formatted.size, 10); |
56 | typed->mode = err = bb_strtou(ar.formatted.mode, NULL, 8); | ||
57 | if (err == -1) bb_error_msg_and_die("invalid ar header"); | ||
58 | typed->mtime = err = bb_strtou(ar.formatted.date, NULL, 10); | ||
59 | if (err == -1) bb_error_msg_and_die("invalid ar header"); | ||
60 | typed->uid = err = bb_strtou(ar.formatted.uid, NULL, 10); | ||
61 | if (err == -1) bb_error_msg_and_die("invalid ar header"); | ||
62 | typed->gid = err = bb_strtou(ar.formatted.gid, NULL, 10); | ||
63 | if (err == -1) bb_error_msg_and_die("invalid ar header"); | ||
64 | typed->size = err = bb_strtou(ar.formatted.size, NULL, 10); | ||
65 | if (err == -1) bb_error_msg_and_die("invalid ar header"); | ||
66 | 66 | ||
67 | /* long filenames have '/' as the first character */ | 67 | /* special filenames have '/' as the first character */ |
68 | if (ar.formatted.name[0] == '/') { | 68 | if (ar.formatted.name[0] == '/') { |
69 | if (ar.formatted.name[1] == ' ') { | ||
70 | /* This is the index of symbols in the file for compilers */ | ||
71 | data_skip(archive_handle); | ||
72 | archive_handle->offset += size; | ||
73 | return get_header_ar(archive_handle); /* Return next header */ | ||
74 | } | ||
69 | #if ENABLE_FEATURE_AR_LONG_FILENAMES | 75 | #if ENABLE_FEATURE_AR_LONG_FILENAMES |
70 | unsigned long_offset; | ||
71 | |||
72 | if (ar.formatted.name[1] == '/') { | 76 | if (ar.formatted.name[1] == '/') { |
73 | /* If the second char is a '/' then this entries data section | 77 | /* If the second char is a '/' then this entries data section |
74 | * stores long filename for multiple entries, they are stored | 78 | * stores long filename for multiple entries, they are stored |
75 | * in static variable long_names for use in future entries */ | 79 | * in static variable long_names for use in future entries |
76 | ar_long_name_size = typed->size; | 80 | */ |
77 | ar_long_names = xmalloc(ar_long_name_size); | 81 | ar_long_name_size = size; |
78 | xread(archive_handle->src_fd, ar_long_names, ar_long_name_size); | 82 | free(ar_long_names); |
79 | archive_handle->offset += ar_long_name_size; | 83 | ar_long_names = xmalloc(size); |
80 | /* This ar entries data section only contained filenames for other records | 84 | xread(archive_handle->src_fd, ar_long_names, size); |
81 | * they are stored in the static ar_long_names for future reference */ | 85 | archive_handle->offset += size; |
82 | return get_header_ar(archive_handle); /* Return next header */ | 86 | /* Return next header */ |
87 | return get_header_ar(archive_handle); | ||
83 | } | 88 | } |
89 | #else | ||
90 | bb_error_msg_and_die("long filenames not supported"); | ||
91 | #endif | ||
92 | } | ||
93 | /* Only size is always present, the rest may be missing in | ||
94 | * long filename pseudo file. Thus we decode the rest | ||
95 | * after dealing with long filename pseudo file. | ||
96 | */ | ||
97 | typed->mode = read_num(ar.formatted.mode, 8); | ||
98 | typed->mtime = read_num(ar.formatted.date, 10); | ||
99 | typed->uid = read_num(ar.formatted.uid, 10); | ||
100 | typed->gid = read_num(ar.formatted.gid, 10); | ||
84 | 101 | ||
85 | if (ar.formatted.name[1] == ' ') { | 102 | #if ENABLE_FEATURE_AR_LONG_FILENAMES |
86 | /* This is the index of symbols in the file for compilers */ | 103 | if (ar.formatted.name[0] == '/') { |
87 | data_skip(archive_handle); | 104 | unsigned long_offset; |
88 | archive_handle->offset += typed->size; | ||
89 | return get_header_ar(archive_handle); /* Return next header */ | ||
90 | } | ||
91 | 105 | ||
92 | /* The number after the '/' indicates the offset in the ar data section | 106 | /* The number after the '/' indicates the offset in the ar data section |
93 | * (saved in variable long_name) that conatains the real filename */ | 107 | * (saved in ar_long_names) that conatains the real filename */ |
94 | long_offset = atoi(&ar.formatted.name[1]); | 108 | long_offset = read_num(&ar.formatted.name[1], 10); |
95 | if (long_offset >= ar_long_name_size) { | 109 | if (long_offset >= ar_long_name_size) { |
96 | bb_error_msg_and_die("can't resolve long filename"); | 110 | bb_error_msg_and_die("can't resolve long filename"); |
97 | } | 111 | } |
98 | typed->name = xstrdup(ar_long_names + long_offset); | 112 | typed->name = xstrdup(ar_long_names + long_offset); |
99 | #else | 113 | } else |
100 | bb_error_msg_and_die("long filenames not supported"); | ||
101 | #endif | 114 | #endif |
102 | } else { | 115 | { |
103 | /* short filenames */ | 116 | /* short filenames */ |
104 | typed->name = xstrndup(ar.formatted.name, 16); | 117 | typed->name = xstrndup(ar.formatted.name, 16); |
105 | } | 118 | } |