diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2000-12-15 06:50:09 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2000-12-15 06:50:09 +0000 |
commit | 4f1b0124c73ba30ba6cd97840b6fff0df90ad40c (patch) | |
tree | 30f251739028ad317cc6ded61bbe656425a1b832 | |
parent | 8abc78aa84a88c12fca41ae10e84898ad5089cae (diff) | |
download | busybox-w32-4f1b0124c73ba30ba6cd97840b6fff0df90ad40c.tar.gz busybox-w32-4f1b0124c73ba30ba6cd97840b6fff0df90ad40c.tar.bz2 busybox-w32-4f1b0124c73ba30ba6cd97840b6fff0df90ad40c.zip |
Rewrite, fix a bug with multiple long filenames, simplify structure, remove cruft, make code conform closer to style guide, saves 350 Bytes.
-rw-r--r-- | ar.c | 456 | ||||
-rw-r--r-- | archival/ar.c | 456 |
2 files changed, 284 insertions, 628 deletions
@@ -3,7 +3,7 @@ | |||
3 | * Mini ar implementation for busybox | 3 | * Mini ar implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 2000 by Glenn McGrath | 5 | * Copyright (C) 2000 by Glenn McGrath |
6 | * Written by Glenn McGrath <bug1@netconnect.com.au> 1 June 2000 | 6 | * Written by Glenn McGrath <bug1@optushome.com.au> 1 June 2000 |
7 | * | 7 | * |
8 | * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. | 8 | * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. |
9 | * | 9 | * |
@@ -21,317 +21,138 @@ | |||
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Last modified 20 September 2000 | ||
25 | */ | 24 | */ |
26 | #include <stdio.h> | ||
27 | #include <string.h> | ||
28 | #include <fcntl.h> | 25 | #include <fcntl.h> |
29 | #include <errno.h> | ||
30 | #include <ctype.h> | ||
31 | #include <time.h> | ||
32 | #include <utime.h> | ||
33 | #include <unistd.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <sys/types.h> | ||
36 | #include <sys/stat.h> | ||
37 | #include <malloc.h> | ||
38 | #include "busybox.h" | 26 | #include "busybox.h" |
39 | 27 | ||
40 | #define BLOCK_SIZE 60 | 28 | typedef struct ar_headers_s { |
41 | #define PRESERVE_DATE 1 /* preserve original dates */ | 29 | char *name; |
42 | #define VERBOSE 2 /* be verbose */ | 30 | size_t size; |
43 | #define DISPLAY 4 /* display contents */ | 31 | uid_t uid; |
44 | #define EXT_TO_FILE 8 /* extract contents of archive */ | 32 | gid_t gid; |
45 | #define EXT_TO_STDOUT 16 /* extract to stdout */ | 33 | mode_t mode; |
46 | #define RECURSIVE 32 | 34 | time_t mtime; |
35 | off_t offset; | ||
36 | struct ar_headers_s *next; | ||
37 | } ar_headers_t; | ||
47 | 38 | ||
48 | #define MAX_NAME_LENGTH 100 | ||
49 | |||
50 | //#define BB_DECLARE_EXTERN | ||
51 | //#define bb_need_io_error | ||
52 | //#include "messages.c" | ||
53 | |||
54 | //#define BB_AR_EXPERIMENTAL_UNTAR | ||
55 | |||
56 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
57 | typedef struct rawTarHeader { | ||
58 | char name[100]; /* 0-99 */ | ||
59 | char mode[8]; /* 100-107 */ | ||
60 | char uid[8]; /* 108-115 */ | ||
61 | char gid[8]; /* 116-123 */ | ||
62 | char size[12]; /* 124-135 */ | ||
63 | char mtime[12]; /* 136-147 */ | ||
64 | char chksum[8]; /* 148-155 */ | ||
65 | char typeflag; /* 156-156 */ | ||
66 | char linkname[100]; /* 157-256 */ | ||
67 | char magic[6]; /* 257-262 */ | ||
68 | char version[2]; /* 263-264 */ | ||
69 | char uname[32]; /* 265-296 */ | ||
70 | char gname[32]; /* 297-328 */ | ||
71 | char devmajor[8]; /* 329-336 */ | ||
72 | char devminor[8]; /* 337-344 */ | ||
73 | char prefix[155]; /* 345-499 */ | ||
74 | char padding[12]; /* 500-512 */ | ||
75 | } rawTarHeader_t; | ||
76 | #endif | ||
77 | |||
78 | typedef struct rawArHeader { /* Byte Offset */ | ||
79 | char name[16]; /* 0-15 */ | ||
80 | char date[12]; /* 16-27 */ | ||
81 | char uid[6], gid[6]; /* 28-39 */ | ||
82 | char mode[8]; /* 40-47 */ | ||
83 | char size[10]; /* 48-57 */ | ||
84 | char fmag[2]; /* 58-59 */ | ||
85 | } rawArHeader_t; | ||
86 | |||
87 | typedef struct headerL { | ||
88 | char name[MAX_NAME_LENGTH]; | ||
89 | size_t size; | ||
90 | uid_t uid; | ||
91 | gid_t gid; | ||
92 | mode_t mode; | ||
93 | time_t mtime; | ||
94 | off_t offset; | ||
95 | struct headerL *next; | ||
96 | } headerL_t; | ||
97 | |||
98 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
99 | /* | 39 | /* |
100 | * identify Tar header (magic field) and reset srcFd to entry position | 40 | * return the headerL_t struct for the filename descriptor |
101 | */ | 41 | */ |
102 | static int checkTarMagic(int srcFd) | 42 | static ar_headers_t get_headers(int srcFd) |
103 | { | ||
104 | off_t headerStart; | ||
105 | char magic[6]; | ||
106 | |||
107 | headerStart = lseek(srcFd, 0, SEEK_CUR); | ||
108 | lseek(srcFd, (off_t) 257, SEEK_CUR); | ||
109 | full_read(srcFd, magic, 6); | ||
110 | lseek(srcFd, headerStart, SEEK_SET); | ||
111 | if (strncmp(magic, "ustar", 5)!=0) | ||
112 | return(FALSE); | ||
113 | return(TRUE); | ||
114 | } | ||
115 | |||
116 | |||
117 | static int readTarHeader(int srcFd, headerL_t *current) | ||
118 | { | 43 | { |
119 | rawTarHeader_t rawTarHeader; | 44 | typedef struct raw_ar_header_s { /* Byte Offset */ |
120 | unsigned char *temp = (unsigned char *) &rawTarHeader; | 45 | char name[16]; /* 0-15 */ |
121 | long sum = 0; | 46 | char date[12]; /* 16-27 */ |
122 | int i; | 47 | char uid[6]; |
123 | off_t initialOffset; | 48 | char gid[6]; /* 28-39 */ |
124 | 49 | char mode[8]; /* 40-47 */ | |
125 | initialOffset = lseek(srcFd, 0, SEEK_CUR); | 50 | char size[10]; /* 48-57 */ |
126 | if (full_read(srcFd, (char *) &rawTarHeader, 512) != 512) { | 51 | char fmag[2]; /* 58-59 */ |
127 | lseek(srcFd, initialOffset, SEEK_SET); | 52 | } raw_ar_header_t; |
128 | return(FALSE); | 53 | raw_ar_header_t raw_ar_header; |
129 | } | 54 | |
130 | for (i = 0; i < 148 ; i++) | 55 | ar_headers_t *head, *entry; |
131 | sum += temp[i]; | 56 | char ar_magic[8]; |
132 | sum += ' ' * 8; | 57 | char *long_name=NULL; |
133 | for (i = 156; i < 512 ; i++) | ||
134 | sum += temp[i]; | ||
135 | if (sum!= strtol(rawTarHeader.chksum, NULL, 8)) | ||
136 | return(FALSE); | ||
137 | sscanf(rawTarHeader.name, "%s", current->name); | ||
138 | current->size = strtol(rawTarHeader.size, NULL, 8); | ||
139 | current->uid = strtol(rawTarHeader.uid, NULL, 8); | ||
140 | current->gid = strtol(rawTarHeader.gid, NULL, 8); | ||
141 | current->mode = strtol(rawTarHeader.mode, NULL, 8); | ||
142 | current->mtime = strtol(rawTarHeader.mtime, NULL, 8); | ||
143 | current->offset = lseek(srcFd, 0 , SEEK_CUR); | ||
144 | |||
145 | current->next = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
146 | current = current->next; | ||
147 | return(TRUE); | ||
148 | } | ||
149 | #endif | ||
150 | |||
151 | /* | ||
152 | * identify Ar header (magic) and reset srcFd to entry position | ||
153 | */ | ||
154 | static int checkArMagic(int srcFd) | ||
155 | { | ||
156 | off_t headerStart; | ||
157 | char arMagic[8]; | ||
158 | |||
159 | headerStart = lseek(srcFd, 0, SEEK_CUR); | ||
160 | if (full_read(srcFd, arMagic, 8) != 8) { | ||
161 | error_msg("fatal error\n"); | ||
162 | return (FALSE); | ||
163 | } | ||
164 | lseek(srcFd, headerStart, SEEK_SET); | ||
165 | |||
166 | if (strncmp(arMagic,"!<arch>",7) != 0) | ||
167 | return(FALSE); | ||
168 | return(TRUE); | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * get, check and correct the converted header | ||
173 | */ | ||
174 | static int readArEntry(int srcFd, headerL_t *entry) | ||
175 | { | ||
176 | size_t nameLength; | ||
177 | rawArHeader_t rawArHeader; | ||
178 | off_t initialOffset; | ||
179 | |||
180 | initialOffset = lseek(srcFd, 0, SEEK_CUR); | ||
181 | if (full_read(srcFd, (char *) &rawArHeader, 60) != 60) { | ||
182 | lseek(srcFd, initialOffset, SEEK_SET); | ||
183 | return(FALSE); | ||
184 | } | ||
185 | if ((rawArHeader.fmag[0]!='`') || (rawArHeader.fmag[1]!='\n')) { | ||
186 | lseek(srcFd, initialOffset, SEEK_SET); | ||
187 | return(FALSE); | ||
188 | } | ||
189 | |||
190 | strncpy(entry->name, rawArHeader.name, 16); | ||
191 | nameLength=strcspn(entry->name, " \\"); | ||
192 | entry->name[nameLength]='\0'; | ||
193 | parse_mode(rawArHeader.mode, &entry->mode); | ||
194 | entry->mtime = atoi(rawArHeader.date); | ||
195 | entry->uid = atoi(rawArHeader.uid); | ||
196 | entry->gid = atoi(rawArHeader.gid); | ||
197 | entry->size = (size_t) atoi(rawArHeader.size); | ||
198 | entry->offset = initialOffset + (off_t) 60; | ||
199 | |||
200 | nameLength = strcspn(entry->name, "/"); | ||
201 | 58 | ||
202 | /* handle GNU style short filenames, strip trailing '/' */ | 59 | head = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); |
203 | if (nameLength > 0) | 60 | entry = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); |
204 | entry->name[nameLength]='\0'; | ||
205 | 61 | ||
206 | /* handle GNU style long filenames */ | 62 | /* check ar magic */ |
207 | if (nameLength == 0) { | 63 | if (full_read(srcFd, ar_magic, 8) != 8) |
208 | /* escape from recursive call */ | 64 | error_msg_and_die("cannot read magic\n"); |
209 | if (entry->name[1]=='0') | 65 | if (strncmp(ar_magic,"!<arch>",7) != 0) |
210 | return(TRUE); | 66 | error_msg_and_die("invalid magic\n"); |
211 | 67 | ||
212 | /* the data section contains the real filename */ | 68 | while (full_read(srcFd, (char *) &raw_ar_header, 60)==60) { |
213 | if (entry->name[1]=='/') { | 69 | /* check the end of header markers are valid */ |
214 | char tempName[MAX_NAME_LENGTH]; | 70 | if ((raw_ar_header.fmag[0]!='`') || (raw_ar_header.fmag[1]!='\n')) { |
215 | 71 | char newline[1]; | |
216 | if (entry->size > MAX_NAME_LENGTH) | 72 | if (raw_ar_header.fmag[1]!='`') { |
217 | entry->size = MAX_NAME_LENGTH; | 73 | break; |
218 | full_read(srcFd, tempName, entry->size); | 74 | } |
219 | tempName[entry->size-3]='\0'; | 75 | /* some version of ar, have an extra '\n' after each entry */ |
220 | 76 | read(srcFd, newline, 1); | |
221 | /* read the second header for this entry */ | 77 | if (newline[0]!='\n') { |
222 | /* be carefull, this is recursive */ | 78 | break; |
223 | if (readArEntry(srcFd, entry)==FALSE) | 79 | } |
224 | return(FALSE); | 80 | /* fix up the header, we started reading 1 byte too early due to a '\n' */ |
81 | memmove((char *) &raw_ar_header, (char *)&raw_ar_header+1, 59); | ||
82 | /* dont worry about adding the last '\n', we dont need it now */ | ||
83 | } | ||
225 | 84 | ||
226 | if ((entry->name[0]='/') && (entry->name[1]='0')) | 85 | entry->size = (size_t) atoi(raw_ar_header.size); |
227 | strcpy(entry->name, tempName); | 86 | /* long filenames have '/' as the first character */ |
87 | if (raw_ar_header.name[0] == '/') { | ||
88 | if (raw_ar_header.name[1] == '/') { | ||
89 | /* multiple long filenames are stored as data in one entry */ | ||
90 | long_name = (char *) xrealloc(long_name, entry->size); | ||
91 | full_read(srcFd, long_name, entry->size); | ||
92 | continue; | ||
93 | } | ||
228 | else { | 94 | else { |
229 | error_msg("Invalid long filename\n"); | 95 | /* The number after the '/' indicates the offset in the ar data section |
230 | return(FALSE); | 96 | (saved in variable long_name) that conatains the real filename */ |
97 | const int long_name_offset = (int) atoi((char *) &raw_ar_header.name[1]); | ||
98 | entry->name = xmalloc(strlen(&long_name[long_name_offset])); | ||
99 | strcpy(entry->name, &long_name[long_name_offset]); | ||
231 | } | 100 | } |
232 | } | 101 | } |
233 | } | 102 | else { |
234 | return(TRUE); | 103 | /* short filenames */ |
235 | } | 104 | entry->name = xmalloc(16); |
236 | 105 | strncpy(entry->name, raw_ar_header.name, 16); | |
237 | /* | ||
238 | * return the headerL_t struct for the specified filename | ||
239 | */ | ||
240 | static headerL_t *getHeaders(int srcFd, headerL_t *head, int funct) | ||
241 | { | ||
242 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
243 | int tar=FALSE; | ||
244 | #endif | ||
245 | int ar=FALSE; | ||
246 | headerL_t *list; | ||
247 | off_t initialOffset; | ||
248 | |||
249 | list = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
250 | initialOffset=lseek(srcFd, 0, SEEK_CUR); | ||
251 | if (checkArMagic(srcFd)==TRUE) | ||
252 | ar=TRUE; | ||
253 | |||
254 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
255 | if (checkTarMagic(srcFd)==TRUE) | ||
256 | tar=TRUE; | ||
257 | |||
258 | if (tar==TRUE) { | ||
259 | while(readTarHeader(srcFd, list)==TRUE) { | ||
260 | off_t tarOffset; | ||
261 | list->next = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
262 | *list->next = *head; | ||
263 | *head = *list; | ||
264 | |||
265 | /* recursive check for sub-archives */ | ||
266 | if ((funct & RECURSIVE) == RECURSIVE) | ||
267 | head = getHeaders(srcFd, head, funct); | ||
268 | tarOffset = (off_t) head->size/512; | ||
269 | if ( head->size % 512 > 0) | ||
270 | tarOffset++; | ||
271 | tarOffset=tarOffset*512; | ||
272 | lseek(srcFd, head->offset + tarOffset, SEEK_SET); | ||
273 | } | ||
274 | } | ||
275 | #endif | ||
276 | |||
277 | if (ar==TRUE) { | ||
278 | lseek(srcFd, 8, SEEK_CUR); | ||
279 | while(1) { | ||
280 | if (readArEntry(srcFd, list) == FALSE) { | ||
281 | lseek(srcFd, ++initialOffset, SEEK_CUR); | ||
282 | if (readArEntry(srcFd, list) == FALSE) | ||
283 | return(head); | ||
284 | } | ||
285 | list->next = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
286 | *list->next = *head; | ||
287 | *head = *list; | ||
288 | /* recursive check for sub-archives */ | ||
289 | if (funct & RECURSIVE) | ||
290 | head = getHeaders(srcFd, head, funct); | ||
291 | lseek(srcFd, head->offset + head->size, SEEK_SET); | ||
292 | } | 106 | } |
107 | entry->name[strcspn(entry->name, " /")]='\0'; | ||
108 | |||
109 | /* convert the rest of the now valid char header to its typed struct */ | ||
110 | parse_mode(raw_ar_header.mode, &entry->mode); | ||
111 | entry->mtime = atoi(raw_ar_header.date); | ||
112 | entry->uid = atoi(raw_ar_header.uid); | ||
113 | entry->gid = atoi(raw_ar_header.gid); | ||
114 | entry->offset = lseek(srcFd, 0, SEEK_CUR); | ||
115 | |||
116 | /* add this entries header to our combined list */ | ||
117 | entry->next = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); | ||
118 | *entry->next = *head; | ||
119 | *head = *entry; | ||
120 | lseek(srcFd, (off_t) entry->size, SEEK_CUR); | ||
293 | } | 121 | } |
294 | return(head); | 122 | return(*head); |
295 | } | ||
296 | |||
297 | /* | ||
298 | * find an entry in the linked list matching the filename | ||
299 | */ | ||
300 | static headerL_t *findEntry(headerL_t *head, const char *filename) | ||
301 | { | ||
302 | while(head->next != NULL) { | ||
303 | if (strcmp(filename, head->name)==0) | ||
304 | return(head); | ||
305 | head=head->next; | ||
306 | } | ||
307 | return(NULL); | ||
308 | } | 123 | } |
309 | 124 | ||
310 | extern int ar_main(int argc, char **argv) | 125 | extern int ar_main(int argc, char **argv) |
311 | { | 126 | { |
312 | int funct = 0, opt=0; | 127 | const int preserve_date = 1; /* preserve original dates */ |
128 | const int verbose = 2; /* be verbose */ | ||
129 | const int display = 4; /* display contents */ | ||
130 | const int extract_to_file = 8; /* extract contents of archive */ | ||
131 | const int extract_to_stdout = 16; /* extract to stdout */ | ||
132 | |||
133 | int funct = 0, opt=0; | ||
313 | int srcFd=0, dstFd=0; | 134 | int srcFd=0, dstFd=0; |
314 | headerL_t *header, *entry, *extractList; | ||
315 | 135 | ||
316 | while ((opt = getopt(argc, argv, "ovtpxR")) != -1) { | 136 | ar_headers_t head, *extract_list=NULL; |
137 | |||
138 | extract_list = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); | ||
139 | |||
140 | while ((opt = getopt(argc, argv, "ovtpx")) != -1) { | ||
317 | switch (opt) { | 141 | switch (opt) { |
318 | case 'o': | 142 | case 'o': |
319 | funct |= PRESERVE_DATE; | 143 | funct |= preserve_date; |
320 | break; | 144 | break; |
321 | case 'v': | 145 | case 'v': |
322 | funct |= VERBOSE; | 146 | funct |= verbose; |
323 | break; | 147 | break; |
324 | case 't': | 148 | case 't': |
325 | funct |= DISPLAY; | 149 | funct |= display; |
326 | break; | ||
327 | case 'x': | ||
328 | funct |= EXT_TO_FILE; | ||
329 | break; | 150 | break; |
330 | case 'p': | 151 | case 'p': |
331 | funct |= EXT_TO_STDOUT; | 152 | funct |= extract_to_stdout; |
332 | break; | 153 | break; |
333 | case 'R': | 154 | case 'x': |
334 | funct |= RECURSIVE; | 155 | funct |= extract_to_file; |
335 | break; | 156 | break; |
336 | default: | 157 | default: |
337 | usage(ar_usage); | 158 | usage(ar_usage); |
@@ -345,47 +166,54 @@ extern int ar_main(int argc, char **argv) | |||
345 | if ( (srcFd = open(argv[optind], O_RDONLY)) < 0) | 166 | if ( (srcFd = open(argv[optind], O_RDONLY)) < 0) |
346 | error_msg_and_die("Cannot read %s\n", argv[optind]); | 167 | error_msg_and_die("Cannot read %s\n", argv[optind]); |
347 | 168 | ||
348 | optind++; | 169 | optind++; |
349 | entry = (headerL_t *) xmalloc(sizeof(headerL_t)); | 170 | head = get_headers(srcFd); |
350 | header = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
351 | extractList = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
352 | 171 | ||
353 | header = getHeaders(srcFd, header, funct); | ||
354 | /* find files to extract or display */ | 172 | /* find files to extract or display */ |
355 | if (optind<argc) { | 173 | /* search through argv and build extract list */ |
356 | /* only handle specified files */ | 174 | for (;optind<argc; optind++) { |
357 | while(optind < argc) { | 175 | ar_headers_t *ar_entry; |
358 | if ( (entry = findEntry(header, argv[optind])) != NULL) { | 176 | ar_entry = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); |
359 | entry->next = (headerL_t *) xmalloc(sizeof(headerL_t)); | 177 | ar_entry = &head; |
360 | *entry->next = *extractList; | 178 | while (ar_entry->next != NULL) { |
361 | *extractList = *entry; | 179 | if (strcmp(argv[optind], ar_entry->name) == 0) { |
180 | ar_headers_t *tmp; | ||
181 | tmp = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); | ||
182 | *tmp = *extract_list; | ||
183 | *extract_list = *ar_entry; | ||
184 | extract_list->next = tmp; | ||
185 | break; | ||
362 | } | 186 | } |
363 | optind++; | 187 | ar_entry=ar_entry->next; |
364 | } | 188 | } |
189 | } | ||
190 | |||
191 | /* if individual files not found extract all files */ | ||
192 | if (extract_list->next==NULL) { | ||
193 | extract_list = &head; | ||
365 | } | 194 | } |
366 | else | ||
367 | extractList = header; | ||
368 | 195 | ||
369 | while(extractList->next != NULL) { | 196 | /* find files to extract or display */ |
370 | if (funct & EXT_TO_FILE) { | 197 | while (extract_list->next != NULL) { |
371 | if (is_directory(extractList->name, TRUE, NULL)==FALSE) | 198 | if (funct & extract_to_file) { |
372 | create_path(extractList->name, 0666); | 199 | dstFd = open(extract_list->name, O_WRONLY | O_CREAT, extract_list->mode); |
373 | dstFd = open(extractList->name, O_WRONLY | O_CREAT, extractList->mode); | 200 | } |
374 | lseek(srcFd, extractList->offset, SEEK_SET); | 201 | else if (funct & extract_to_stdout) { |
375 | copy_file_chunk(srcFd, dstFd, (size_t) extractList->size); | 202 | dstFd = fileno(stdout); |
203 | } | ||
204 | if ((funct & extract_to_file) || (funct & extract_to_stdout)) { | ||
205 | lseek(srcFd, extract_list->offset, SEEK_SET); | ||
206 | copy_file_chunk(srcFd, dstFd, (size_t) extract_list->size); | ||
376 | } | 207 | } |
377 | if (funct & EXT_TO_STDOUT) { | 208 | if (funct & verbose) { |
378 | lseek(srcFd, extractList->offset, SEEK_SET); | 209 | printf("%s %d/%d %8d %s ", mode_string(extract_list->mode), |
379 | copy_file_chunk(srcFd, fileno(stdout), (size_t) extractList->size); | 210 | extract_list->uid, extract_list->gid, |
211 | extract_list->size, time_string(extract_list->mtime)); | ||
380 | } | 212 | } |
381 | if ( (funct & DISPLAY) || (funct & VERBOSE)) { | 213 | if ((funct & display) || (funct & verbose)){ |
382 | if (funct & VERBOSE) | 214 | printf("%s\n", extract_list->name); |
383 | printf("%s %d/%d %8d %s ", mode_string(extractList->mode), | ||
384 | extractList->uid, extractList->gid, | ||
385 | extractList->size, time_string(extractList->mtime)); | ||
386 | printf("%s\n", extractList->name); | ||
387 | } | 215 | } |
388 | extractList=extractList->next; | 216 | extract_list=extract_list->next; |
389 | } | 217 | } |
390 | return EXIT_SUCCESS; | 218 | return EXIT_SUCCESS; |
391 | } | 219 | } |
diff --git a/archival/ar.c b/archival/ar.c index 88cdd4f9f..bd54bb6b8 100644 --- a/archival/ar.c +++ b/archival/ar.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * Mini ar implementation for busybox | 3 | * Mini ar implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 2000 by Glenn McGrath | 5 | * Copyright (C) 2000 by Glenn McGrath |
6 | * Written by Glenn McGrath <bug1@netconnect.com.au> 1 June 2000 | 6 | * Written by Glenn McGrath <bug1@optushome.com.au> 1 June 2000 |
7 | * | 7 | * |
8 | * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. | 8 | * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. |
9 | * | 9 | * |
@@ -21,317 +21,138 @@ | |||
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Last modified 20 September 2000 | ||
25 | */ | 24 | */ |
26 | #include <stdio.h> | ||
27 | #include <string.h> | ||
28 | #include <fcntl.h> | 25 | #include <fcntl.h> |
29 | #include <errno.h> | ||
30 | #include <ctype.h> | ||
31 | #include <time.h> | ||
32 | #include <utime.h> | ||
33 | #include <unistd.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <sys/types.h> | ||
36 | #include <sys/stat.h> | ||
37 | #include <malloc.h> | ||
38 | #include "busybox.h" | 26 | #include "busybox.h" |
39 | 27 | ||
40 | #define BLOCK_SIZE 60 | 28 | typedef struct ar_headers_s { |
41 | #define PRESERVE_DATE 1 /* preserve original dates */ | 29 | char *name; |
42 | #define VERBOSE 2 /* be verbose */ | 30 | size_t size; |
43 | #define DISPLAY 4 /* display contents */ | 31 | uid_t uid; |
44 | #define EXT_TO_FILE 8 /* extract contents of archive */ | 32 | gid_t gid; |
45 | #define EXT_TO_STDOUT 16 /* extract to stdout */ | 33 | mode_t mode; |
46 | #define RECURSIVE 32 | 34 | time_t mtime; |
35 | off_t offset; | ||
36 | struct ar_headers_s *next; | ||
37 | } ar_headers_t; | ||
47 | 38 | ||
48 | #define MAX_NAME_LENGTH 100 | ||
49 | |||
50 | //#define BB_DECLARE_EXTERN | ||
51 | //#define bb_need_io_error | ||
52 | //#include "messages.c" | ||
53 | |||
54 | //#define BB_AR_EXPERIMENTAL_UNTAR | ||
55 | |||
56 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
57 | typedef struct rawTarHeader { | ||
58 | char name[100]; /* 0-99 */ | ||
59 | char mode[8]; /* 100-107 */ | ||
60 | char uid[8]; /* 108-115 */ | ||
61 | char gid[8]; /* 116-123 */ | ||
62 | char size[12]; /* 124-135 */ | ||
63 | char mtime[12]; /* 136-147 */ | ||
64 | char chksum[8]; /* 148-155 */ | ||
65 | char typeflag; /* 156-156 */ | ||
66 | char linkname[100]; /* 157-256 */ | ||
67 | char magic[6]; /* 257-262 */ | ||
68 | char version[2]; /* 263-264 */ | ||
69 | char uname[32]; /* 265-296 */ | ||
70 | char gname[32]; /* 297-328 */ | ||
71 | char devmajor[8]; /* 329-336 */ | ||
72 | char devminor[8]; /* 337-344 */ | ||
73 | char prefix[155]; /* 345-499 */ | ||
74 | char padding[12]; /* 500-512 */ | ||
75 | } rawTarHeader_t; | ||
76 | #endif | ||
77 | |||
78 | typedef struct rawArHeader { /* Byte Offset */ | ||
79 | char name[16]; /* 0-15 */ | ||
80 | char date[12]; /* 16-27 */ | ||
81 | char uid[6], gid[6]; /* 28-39 */ | ||
82 | char mode[8]; /* 40-47 */ | ||
83 | char size[10]; /* 48-57 */ | ||
84 | char fmag[2]; /* 58-59 */ | ||
85 | } rawArHeader_t; | ||
86 | |||
87 | typedef struct headerL { | ||
88 | char name[MAX_NAME_LENGTH]; | ||
89 | size_t size; | ||
90 | uid_t uid; | ||
91 | gid_t gid; | ||
92 | mode_t mode; | ||
93 | time_t mtime; | ||
94 | off_t offset; | ||
95 | struct headerL *next; | ||
96 | } headerL_t; | ||
97 | |||
98 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
99 | /* | 39 | /* |
100 | * identify Tar header (magic field) and reset srcFd to entry position | 40 | * return the headerL_t struct for the filename descriptor |
101 | */ | 41 | */ |
102 | static int checkTarMagic(int srcFd) | 42 | static ar_headers_t get_headers(int srcFd) |
103 | { | ||
104 | off_t headerStart; | ||
105 | char magic[6]; | ||
106 | |||
107 | headerStart = lseek(srcFd, 0, SEEK_CUR); | ||
108 | lseek(srcFd, (off_t) 257, SEEK_CUR); | ||
109 | full_read(srcFd, magic, 6); | ||
110 | lseek(srcFd, headerStart, SEEK_SET); | ||
111 | if (strncmp(magic, "ustar", 5)!=0) | ||
112 | return(FALSE); | ||
113 | return(TRUE); | ||
114 | } | ||
115 | |||
116 | |||
117 | static int readTarHeader(int srcFd, headerL_t *current) | ||
118 | { | 43 | { |
119 | rawTarHeader_t rawTarHeader; | 44 | typedef struct raw_ar_header_s { /* Byte Offset */ |
120 | unsigned char *temp = (unsigned char *) &rawTarHeader; | 45 | char name[16]; /* 0-15 */ |
121 | long sum = 0; | 46 | char date[12]; /* 16-27 */ |
122 | int i; | 47 | char uid[6]; |
123 | off_t initialOffset; | 48 | char gid[6]; /* 28-39 */ |
124 | 49 | char mode[8]; /* 40-47 */ | |
125 | initialOffset = lseek(srcFd, 0, SEEK_CUR); | 50 | char size[10]; /* 48-57 */ |
126 | if (full_read(srcFd, (char *) &rawTarHeader, 512) != 512) { | 51 | char fmag[2]; /* 58-59 */ |
127 | lseek(srcFd, initialOffset, SEEK_SET); | 52 | } raw_ar_header_t; |
128 | return(FALSE); | 53 | raw_ar_header_t raw_ar_header; |
129 | } | 54 | |
130 | for (i = 0; i < 148 ; i++) | 55 | ar_headers_t *head, *entry; |
131 | sum += temp[i]; | 56 | char ar_magic[8]; |
132 | sum += ' ' * 8; | 57 | char *long_name=NULL; |
133 | for (i = 156; i < 512 ; i++) | ||
134 | sum += temp[i]; | ||
135 | if (sum!= strtol(rawTarHeader.chksum, NULL, 8)) | ||
136 | return(FALSE); | ||
137 | sscanf(rawTarHeader.name, "%s", current->name); | ||
138 | current->size = strtol(rawTarHeader.size, NULL, 8); | ||
139 | current->uid = strtol(rawTarHeader.uid, NULL, 8); | ||
140 | current->gid = strtol(rawTarHeader.gid, NULL, 8); | ||
141 | current->mode = strtol(rawTarHeader.mode, NULL, 8); | ||
142 | current->mtime = strtol(rawTarHeader.mtime, NULL, 8); | ||
143 | current->offset = lseek(srcFd, 0 , SEEK_CUR); | ||
144 | |||
145 | current->next = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
146 | current = current->next; | ||
147 | return(TRUE); | ||
148 | } | ||
149 | #endif | ||
150 | |||
151 | /* | ||
152 | * identify Ar header (magic) and reset srcFd to entry position | ||
153 | */ | ||
154 | static int checkArMagic(int srcFd) | ||
155 | { | ||
156 | off_t headerStart; | ||
157 | char arMagic[8]; | ||
158 | |||
159 | headerStart = lseek(srcFd, 0, SEEK_CUR); | ||
160 | if (full_read(srcFd, arMagic, 8) != 8) { | ||
161 | error_msg("fatal error\n"); | ||
162 | return (FALSE); | ||
163 | } | ||
164 | lseek(srcFd, headerStart, SEEK_SET); | ||
165 | |||
166 | if (strncmp(arMagic,"!<arch>",7) != 0) | ||
167 | return(FALSE); | ||
168 | return(TRUE); | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * get, check and correct the converted header | ||
173 | */ | ||
174 | static int readArEntry(int srcFd, headerL_t *entry) | ||
175 | { | ||
176 | size_t nameLength; | ||
177 | rawArHeader_t rawArHeader; | ||
178 | off_t initialOffset; | ||
179 | |||
180 | initialOffset = lseek(srcFd, 0, SEEK_CUR); | ||
181 | if (full_read(srcFd, (char *) &rawArHeader, 60) != 60) { | ||
182 | lseek(srcFd, initialOffset, SEEK_SET); | ||
183 | return(FALSE); | ||
184 | } | ||
185 | if ((rawArHeader.fmag[0]!='`') || (rawArHeader.fmag[1]!='\n')) { | ||
186 | lseek(srcFd, initialOffset, SEEK_SET); | ||
187 | return(FALSE); | ||
188 | } | ||
189 | |||
190 | strncpy(entry->name, rawArHeader.name, 16); | ||
191 | nameLength=strcspn(entry->name, " \\"); | ||
192 | entry->name[nameLength]='\0'; | ||
193 | parse_mode(rawArHeader.mode, &entry->mode); | ||
194 | entry->mtime = atoi(rawArHeader.date); | ||
195 | entry->uid = atoi(rawArHeader.uid); | ||
196 | entry->gid = atoi(rawArHeader.gid); | ||
197 | entry->size = (size_t) atoi(rawArHeader.size); | ||
198 | entry->offset = initialOffset + (off_t) 60; | ||
199 | |||
200 | nameLength = strcspn(entry->name, "/"); | ||
201 | 58 | ||
202 | /* handle GNU style short filenames, strip trailing '/' */ | 59 | head = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); |
203 | if (nameLength > 0) | 60 | entry = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); |
204 | entry->name[nameLength]='\0'; | ||
205 | 61 | ||
206 | /* handle GNU style long filenames */ | 62 | /* check ar magic */ |
207 | if (nameLength == 0) { | 63 | if (full_read(srcFd, ar_magic, 8) != 8) |
208 | /* escape from recursive call */ | 64 | error_msg_and_die("cannot read magic\n"); |
209 | if (entry->name[1]=='0') | 65 | if (strncmp(ar_magic,"!<arch>",7) != 0) |
210 | return(TRUE); | 66 | error_msg_and_die("invalid magic\n"); |
211 | 67 | ||
212 | /* the data section contains the real filename */ | 68 | while (full_read(srcFd, (char *) &raw_ar_header, 60)==60) { |
213 | if (entry->name[1]=='/') { | 69 | /* check the end of header markers are valid */ |
214 | char tempName[MAX_NAME_LENGTH]; | 70 | if ((raw_ar_header.fmag[0]!='`') || (raw_ar_header.fmag[1]!='\n')) { |
215 | 71 | char newline[1]; | |
216 | if (entry->size > MAX_NAME_LENGTH) | 72 | if (raw_ar_header.fmag[1]!='`') { |
217 | entry->size = MAX_NAME_LENGTH; | 73 | break; |
218 | full_read(srcFd, tempName, entry->size); | 74 | } |
219 | tempName[entry->size-3]='\0'; | 75 | /* some version of ar, have an extra '\n' after each entry */ |
220 | 76 | read(srcFd, newline, 1); | |
221 | /* read the second header for this entry */ | 77 | if (newline[0]!='\n') { |
222 | /* be carefull, this is recursive */ | 78 | break; |
223 | if (readArEntry(srcFd, entry)==FALSE) | 79 | } |
224 | return(FALSE); | 80 | /* fix up the header, we started reading 1 byte too early due to a '\n' */ |
81 | memmove((char *) &raw_ar_header, (char *)&raw_ar_header+1, 59); | ||
82 | /* dont worry about adding the last '\n', we dont need it now */ | ||
83 | } | ||
225 | 84 | ||
226 | if ((entry->name[0]='/') && (entry->name[1]='0')) | 85 | entry->size = (size_t) atoi(raw_ar_header.size); |
227 | strcpy(entry->name, tempName); | 86 | /* long filenames have '/' as the first character */ |
87 | if (raw_ar_header.name[0] == '/') { | ||
88 | if (raw_ar_header.name[1] == '/') { | ||
89 | /* multiple long filenames are stored as data in one entry */ | ||
90 | long_name = (char *) xrealloc(long_name, entry->size); | ||
91 | full_read(srcFd, long_name, entry->size); | ||
92 | continue; | ||
93 | } | ||
228 | else { | 94 | else { |
229 | error_msg("Invalid long filename\n"); | 95 | /* The number after the '/' indicates the offset in the ar data section |
230 | return(FALSE); | 96 | (saved in variable long_name) that conatains the real filename */ |
97 | const int long_name_offset = (int) atoi((char *) &raw_ar_header.name[1]); | ||
98 | entry->name = xmalloc(strlen(&long_name[long_name_offset])); | ||
99 | strcpy(entry->name, &long_name[long_name_offset]); | ||
231 | } | 100 | } |
232 | } | 101 | } |
233 | } | 102 | else { |
234 | return(TRUE); | 103 | /* short filenames */ |
235 | } | 104 | entry->name = xmalloc(16); |
236 | 105 | strncpy(entry->name, raw_ar_header.name, 16); | |
237 | /* | ||
238 | * return the headerL_t struct for the specified filename | ||
239 | */ | ||
240 | static headerL_t *getHeaders(int srcFd, headerL_t *head, int funct) | ||
241 | { | ||
242 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
243 | int tar=FALSE; | ||
244 | #endif | ||
245 | int ar=FALSE; | ||
246 | headerL_t *list; | ||
247 | off_t initialOffset; | ||
248 | |||
249 | list = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
250 | initialOffset=lseek(srcFd, 0, SEEK_CUR); | ||
251 | if (checkArMagic(srcFd)==TRUE) | ||
252 | ar=TRUE; | ||
253 | |||
254 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
255 | if (checkTarMagic(srcFd)==TRUE) | ||
256 | tar=TRUE; | ||
257 | |||
258 | if (tar==TRUE) { | ||
259 | while(readTarHeader(srcFd, list)==TRUE) { | ||
260 | off_t tarOffset; | ||
261 | list->next = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
262 | *list->next = *head; | ||
263 | *head = *list; | ||
264 | |||
265 | /* recursive check for sub-archives */ | ||
266 | if ((funct & RECURSIVE) == RECURSIVE) | ||
267 | head = getHeaders(srcFd, head, funct); | ||
268 | tarOffset = (off_t) head->size/512; | ||
269 | if ( head->size % 512 > 0) | ||
270 | tarOffset++; | ||
271 | tarOffset=tarOffset*512; | ||
272 | lseek(srcFd, head->offset + tarOffset, SEEK_SET); | ||
273 | } | ||
274 | } | ||
275 | #endif | ||
276 | |||
277 | if (ar==TRUE) { | ||
278 | lseek(srcFd, 8, SEEK_CUR); | ||
279 | while(1) { | ||
280 | if (readArEntry(srcFd, list) == FALSE) { | ||
281 | lseek(srcFd, ++initialOffset, SEEK_CUR); | ||
282 | if (readArEntry(srcFd, list) == FALSE) | ||
283 | return(head); | ||
284 | } | ||
285 | list->next = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
286 | *list->next = *head; | ||
287 | *head = *list; | ||
288 | /* recursive check for sub-archives */ | ||
289 | if (funct & RECURSIVE) | ||
290 | head = getHeaders(srcFd, head, funct); | ||
291 | lseek(srcFd, head->offset + head->size, SEEK_SET); | ||
292 | } | 106 | } |
107 | entry->name[strcspn(entry->name, " /")]='\0'; | ||
108 | |||
109 | /* convert the rest of the now valid char header to its typed struct */ | ||
110 | parse_mode(raw_ar_header.mode, &entry->mode); | ||
111 | entry->mtime = atoi(raw_ar_header.date); | ||
112 | entry->uid = atoi(raw_ar_header.uid); | ||
113 | entry->gid = atoi(raw_ar_header.gid); | ||
114 | entry->offset = lseek(srcFd, 0, SEEK_CUR); | ||
115 | |||
116 | /* add this entries header to our combined list */ | ||
117 | entry->next = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); | ||
118 | *entry->next = *head; | ||
119 | *head = *entry; | ||
120 | lseek(srcFd, (off_t) entry->size, SEEK_CUR); | ||
293 | } | 121 | } |
294 | return(head); | 122 | return(*head); |
295 | } | ||
296 | |||
297 | /* | ||
298 | * find an entry in the linked list matching the filename | ||
299 | */ | ||
300 | static headerL_t *findEntry(headerL_t *head, const char *filename) | ||
301 | { | ||
302 | while(head->next != NULL) { | ||
303 | if (strcmp(filename, head->name)==0) | ||
304 | return(head); | ||
305 | head=head->next; | ||
306 | } | ||
307 | return(NULL); | ||
308 | } | 123 | } |
309 | 124 | ||
310 | extern int ar_main(int argc, char **argv) | 125 | extern int ar_main(int argc, char **argv) |
311 | { | 126 | { |
312 | int funct = 0, opt=0; | 127 | const int preserve_date = 1; /* preserve original dates */ |
128 | const int verbose = 2; /* be verbose */ | ||
129 | const int display = 4; /* display contents */ | ||
130 | const int extract_to_file = 8; /* extract contents of archive */ | ||
131 | const int extract_to_stdout = 16; /* extract to stdout */ | ||
132 | |||
133 | int funct = 0, opt=0; | ||
313 | int srcFd=0, dstFd=0; | 134 | int srcFd=0, dstFd=0; |
314 | headerL_t *header, *entry, *extractList; | ||
315 | 135 | ||
316 | while ((opt = getopt(argc, argv, "ovtpxR")) != -1) { | 136 | ar_headers_t head, *extract_list=NULL; |
137 | |||
138 | extract_list = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); | ||
139 | |||
140 | while ((opt = getopt(argc, argv, "ovtpx")) != -1) { | ||
317 | switch (opt) { | 141 | switch (opt) { |
318 | case 'o': | 142 | case 'o': |
319 | funct |= PRESERVE_DATE; | 143 | funct |= preserve_date; |
320 | break; | 144 | break; |
321 | case 'v': | 145 | case 'v': |
322 | funct |= VERBOSE; | 146 | funct |= verbose; |
323 | break; | 147 | break; |
324 | case 't': | 148 | case 't': |
325 | funct |= DISPLAY; | 149 | funct |= display; |
326 | break; | ||
327 | case 'x': | ||
328 | funct |= EXT_TO_FILE; | ||
329 | break; | 150 | break; |
330 | case 'p': | 151 | case 'p': |
331 | funct |= EXT_TO_STDOUT; | 152 | funct |= extract_to_stdout; |
332 | break; | 153 | break; |
333 | case 'R': | 154 | case 'x': |
334 | funct |= RECURSIVE; | 155 | funct |= extract_to_file; |
335 | break; | 156 | break; |
336 | default: | 157 | default: |
337 | usage(ar_usage); | 158 | usage(ar_usage); |
@@ -345,47 +166,54 @@ extern int ar_main(int argc, char **argv) | |||
345 | if ( (srcFd = open(argv[optind], O_RDONLY)) < 0) | 166 | if ( (srcFd = open(argv[optind], O_RDONLY)) < 0) |
346 | error_msg_and_die("Cannot read %s\n", argv[optind]); | 167 | error_msg_and_die("Cannot read %s\n", argv[optind]); |
347 | 168 | ||
348 | optind++; | 169 | optind++; |
349 | entry = (headerL_t *) xmalloc(sizeof(headerL_t)); | 170 | head = get_headers(srcFd); |
350 | header = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
351 | extractList = (headerL_t *) xmalloc(sizeof(headerL_t)); | ||
352 | 171 | ||
353 | header = getHeaders(srcFd, header, funct); | ||
354 | /* find files to extract or display */ | 172 | /* find files to extract or display */ |
355 | if (optind<argc) { | 173 | /* search through argv and build extract list */ |
356 | /* only handle specified files */ | 174 | for (;optind<argc; optind++) { |
357 | while(optind < argc) { | 175 | ar_headers_t *ar_entry; |
358 | if ( (entry = findEntry(header, argv[optind])) != NULL) { | 176 | ar_entry = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); |
359 | entry->next = (headerL_t *) xmalloc(sizeof(headerL_t)); | 177 | ar_entry = &head; |
360 | *entry->next = *extractList; | 178 | while (ar_entry->next != NULL) { |
361 | *extractList = *entry; | 179 | if (strcmp(argv[optind], ar_entry->name) == 0) { |
180 | ar_headers_t *tmp; | ||
181 | tmp = (ar_headers_t *) xmalloc(sizeof(ar_headers_t)); | ||
182 | *tmp = *extract_list; | ||
183 | *extract_list = *ar_entry; | ||
184 | extract_list->next = tmp; | ||
185 | break; | ||
362 | } | 186 | } |
363 | optind++; | 187 | ar_entry=ar_entry->next; |
364 | } | 188 | } |
189 | } | ||
190 | |||
191 | /* if individual files not found extract all files */ | ||
192 | if (extract_list->next==NULL) { | ||
193 | extract_list = &head; | ||
365 | } | 194 | } |
366 | else | ||
367 | extractList = header; | ||
368 | 195 | ||
369 | while(extractList->next != NULL) { | 196 | /* find files to extract or display */ |
370 | if (funct & EXT_TO_FILE) { | 197 | while (extract_list->next != NULL) { |
371 | if (is_directory(extractList->name, TRUE, NULL)==FALSE) | 198 | if (funct & extract_to_file) { |
372 | create_path(extractList->name, 0666); | 199 | dstFd = open(extract_list->name, O_WRONLY | O_CREAT, extract_list->mode); |
373 | dstFd = open(extractList->name, O_WRONLY | O_CREAT, extractList->mode); | 200 | } |
374 | lseek(srcFd, extractList->offset, SEEK_SET); | 201 | else if (funct & extract_to_stdout) { |
375 | copy_file_chunk(srcFd, dstFd, (size_t) extractList->size); | 202 | dstFd = fileno(stdout); |
203 | } | ||
204 | if ((funct & extract_to_file) || (funct & extract_to_stdout)) { | ||
205 | lseek(srcFd, extract_list->offset, SEEK_SET); | ||
206 | copy_file_chunk(srcFd, dstFd, (size_t) extract_list->size); | ||
376 | } | 207 | } |
377 | if (funct & EXT_TO_STDOUT) { | 208 | if (funct & verbose) { |
378 | lseek(srcFd, extractList->offset, SEEK_SET); | 209 | printf("%s %d/%d %8d %s ", mode_string(extract_list->mode), |
379 | copy_file_chunk(srcFd, fileno(stdout), (size_t) extractList->size); | 210 | extract_list->uid, extract_list->gid, |
211 | extract_list->size, time_string(extract_list->mtime)); | ||
380 | } | 212 | } |
381 | if ( (funct & DISPLAY) || (funct & VERBOSE)) { | 213 | if ((funct & display) || (funct & verbose)){ |
382 | if (funct & VERBOSE) | 214 | printf("%s\n", extract_list->name); |
383 | printf("%s %d/%d %8d %s ", mode_string(extractList->mode), | ||
384 | extractList->uid, extractList->gid, | ||
385 | extractList->size, time_string(extractList->mtime)); | ||
386 | printf("%s\n", extractList->name); | ||
387 | } | 215 | } |
388 | extractList=extractList->next; | 216 | extract_list=extract_list->next; |
389 | } | 217 | } |
390 | return EXIT_SUCCESS; | 218 | return EXIT_SUCCESS; |
391 | } | 219 | } |