diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2000-09-11 05:25:39 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2000-09-11 05:25:39 +0000 |
commit | fca8050f0fd224a22136b74fce23b700f1d07ccf (patch) | |
tree | 11eeac7b1ceedd328e9af890a305c8618492f9c9 /archival/ar.c | |
parent | ac19b7e032c3d4449d08ea9ae438192b6a15170d (diff) | |
download | busybox-w32-fca8050f0fd224a22136b74fce23b700f1d07ccf.tar.gz busybox-w32-fca8050f0fd224a22136b74fce23b700f1d07ccf.tar.bz2 busybox-w32-fca8050f0fd224a22136b74fce23b700f1d07ccf.zip |
Fix .deb unpack and experimental TAR support
The previous ar.c fialed to recognise one record in .debs
Experimental tar support, this is currently *very* cheap because ar and
tar are functionally similar. It will need lots of testing so by
default tar support code is defined out.
To test uncomment the line "#define BB_AR_EXPERIMENTAL_UNTAR"
Diffstat (limited to 'archival/ar.c')
-rw-r--r-- | archival/ar.c | 265 |
1 files changed, 178 insertions, 87 deletions
diff --git a/archival/ar.c b/archival/ar.c index 61ce83029..d82763df1 100644 --- a/archival/ar.c +++ b/archival/ar.c | |||
@@ -51,6 +51,30 @@ | |||
51 | //#define bb_need_io_error | 51 | //#define bb_need_io_error |
52 | //#include "messages.c" | 52 | //#include "messages.c" |
53 | 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 | |||
54 | typedef struct rawArHeader { /* Byte Offset */ | 78 | typedef struct rawArHeader { /* Byte Offset */ |
55 | char name[16]; /* 0-15 */ | 79 | char name[16]; /* 0-15 */ |
56 | char date[12]; /* 16-27 */ | 80 | char date[12]; /* 16-27 */ |
@@ -71,92 +95,136 @@ typedef struct headerL { | |||
71 | struct headerL *next; | 95 | struct headerL *next; |
72 | } headerL_t; | 96 | } headerL_t; |
73 | 97 | ||
98 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
74 | /* | 99 | /* |
75 | * identify Ar header (magic) and set srcFd to first header entry | 100 | * identify Tar header (magic field) and reset srcFd to entry position |
76 | */ | 101 | */ |
77 | static int checkArMagic(int srcFd) | 102 | static int checkTarMagic(int srcFd) |
78 | { | 103 | { |
79 | char arMagic[8]; | 104 | off_t headerStart; |
80 | if (fullRead(srcFd, arMagic, 8) != 8) | 105 | char magic[6]; |
81 | return (FALSE); | 106 | |
82 | 107 | headerStart = lseek(srcFd, 0, SEEK_CUR); | |
83 | if (strncmp(arMagic,"!<arch>",7) != 0) | 108 | lseek(srcFd, (off_t) 257, SEEK_CUR); |
109 | fullRead(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 | { | ||
119 | rawTarHeader_t rawTarHeader; | ||
120 | unsigned char *temp = (unsigned char *) &rawTarHeader; | ||
121 | long sum = 0; | ||
122 | int i; | ||
123 | off_t initialOffset; | ||
124 | |||
125 | initialOffset = lseek(srcFd, 0, SEEK_CUR); | ||
126 | if (fullRead(srcFd, (char *) &rawTarHeader, 512) != 512) { | ||
127 | lseek(srcFd, initialOffset, SEEK_SET); | ||
84 | return(FALSE); | 128 | return(FALSE); |
85 | return(TRUE); | 129 | } |
130 | for (i = 0; i < 148 ; i++) | ||
131 | sum += temp[i]; | ||
132 | sum += ' ' * 8; | ||
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); | ||
86 | } | 148 | } |
149 | #endif | ||
87 | 150 | ||
88 | /* | 151 | /* |
89 | * read, convert and check the raw ar header | 152 | * identify Ar header (magic) and reset srcFd to entry position |
90 | * srcFd should be pointing to the start of header prior to entry | ||
91 | * srcFd will be pointing at the start of data after successful exit | ||
92 | * if returns FALSE srcFd is reset to initial position | ||
93 | */ | 153 | */ |
94 | static int readRawArHeader(int srcFd, headerL_t *header) | 154 | static int checkArMagic(int srcFd) |
95 | { | 155 | { |
96 | rawArHeader_t rawArHeader; | 156 | off_t headerStart; |
97 | off_t initialOffset; | 157 | char arMagic[8]; |
98 | size_t nameLength; | ||
99 | |||
100 | initialOffset = lseek(srcFd, 0, SEEK_CUR); | ||
101 | if (fullRead(srcFd, (char *) &rawArHeader, 60) != 60) { | ||
102 | lseek(srcFd, initialOffset, SEEK_SET); | ||
103 | return(FALSE); | ||
104 | } | ||
105 | if ((rawArHeader.fmag[0]!='`') || (rawArHeader.fmag[1]!='\n')) { | ||
106 | lseek(srcFd, initialOffset, SEEK_SET); | ||
107 | return(FALSE); | ||
108 | } | ||
109 | 158 | ||
110 | strncpy(header->name, rawArHeader.name, 16); | 159 | headerStart = lseek(srcFd, 0, SEEK_CUR); |
111 | nameLength=strcspn(header->name, " \\"); | 160 | if (fullRead(srcFd, arMagic, 8) != 8) { |
112 | header->name[nameLength]='\0'; | 161 | printf("fatal error/n"); |
113 | parse_mode(rawArHeader.mode, &header->mode); | 162 | return (FALSE); |
114 | header->mtime = atoi(rawArHeader.date); | 163 | } |
115 | header->uid = atoi(rawArHeader.uid); | 164 | lseek(srcFd, headerStart, SEEK_SET); |
116 | header->gid = atoi(rawArHeader.gid); | 165 | |
117 | header->size = (size_t) atoi(rawArHeader.size); | 166 | if (strncmp(arMagic,"!<arch>",7) != 0) |
118 | header->offset = initialOffset + (off_t) 60; | 167 | return(FALSE); |
119 | return(TRUE); | 168 | return(TRUE); |
120 | } | 169 | } |
121 | 170 | ||
122 | /* | 171 | /* |
123 | * get, check and correct the converted header | 172 | * get, check and correct the converted header |
124 | */ | 173 | */ |
125 | static int readArEntry(int srcFd, headerL_t *newEntry) | 174 | static int readArEntry(int srcFd, headerL_t *entry) |
126 | { | 175 | { |
127 | size_t nameLength; | 176 | size_t nameLength; |
177 | rawArHeader_t rawArHeader; | ||
178 | off_t initialOffset; | ||
128 | 179 | ||
129 | if(readRawArHeader(srcFd, newEntry)==FALSE) | 180 | initialOffset = lseek(srcFd, 0, SEEK_CUR); |
130 | return(FALSE); | 181 | if (fullRead(srcFd, (char *) &rawArHeader, 60) != 60) { |
131 | 182 | lseek(srcFd, initialOffset, SEEK_SET); | |
132 | nameLength = strcspn(newEntry->name, "/"); | 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, "/"); | ||
133 | 201 | ||
134 | /* handle GNU style short filenames, strip trailing '/' */ | 202 | /* handle GNU style short filenames, strip trailing '/' */ |
135 | if (nameLength > 0) | 203 | if (nameLength > 0) |
136 | newEntry->name[nameLength]='\0'; | 204 | entry->name[nameLength]='\0'; |
137 | 205 | ||
138 | /* handle GNU style long filenames */ | 206 | /* handle GNU style long filenames */ |
139 | if (nameLength == 0) { | 207 | if (nameLength == 0) { |
140 | /* escape from recursive call */ | 208 | /* escape from recursive call */ |
141 | if (newEntry->name[1]=='0') | 209 | if (entry->name[1]=='0') |
142 | return(TRUE); | 210 | return(TRUE); |
143 | 211 | ||
144 | /* the data section contains the real filename */ | 212 | /* the data section contains the real filename */ |
145 | if (newEntry->name[1]=='/') { | 213 | if (entry->name[1]=='/') { |
146 | char tempName[MAX_NAME_LENGTH]; | 214 | char tempName[MAX_NAME_LENGTH]; |
147 | 215 | ||
148 | if (newEntry->size > MAX_NAME_LENGTH) | 216 | if (entry->size > MAX_NAME_LENGTH) |
149 | newEntry->size = MAX_NAME_LENGTH; | 217 | entry->size = MAX_NAME_LENGTH; |
150 | fullRead(srcFd, tempName, newEntry->size); | 218 | fullRead(srcFd, tempName, entry->size); |
151 | tempName[newEntry->size-3]='\0'; | 219 | tempName[entry->size-3]='\0'; |
152 | 220 | ||
153 | /* read the second header for this entry */ | 221 | /* read the second header for this entry */ |
154 | /* be carefull, this is recursive */ | 222 | /* be carefull, this is recursive */ |
155 | if (readArEntry(srcFd, newEntry)==FALSE) | 223 | if (readArEntry(srcFd, entry)==FALSE) |
156 | return(FALSE); | 224 | return(FALSE); |
157 | 225 | ||
158 | if ((newEntry->name[0]='/') && (newEntry->name[1]='0')) | 226 | if ((entry->name[0]='/') && (entry->name[1]='0')) |
159 | strcpy(newEntry->name, tempName); | 227 | strcpy(entry->name, tempName); |
160 | else { | 228 | else { |
161 | errorMsg("Invalid long filename\n"); | 229 | errorMsg("Invalid long filename\n"); |
162 | return(FALSE); | 230 | return(FALSE); |
@@ -171,17 +239,54 @@ static int readArEntry(int srcFd, headerL_t *newEntry) | |||
171 | */ | 239 | */ |
172 | static headerL_t *getHeaders(int srcFd, headerL_t *head, int funct) | 240 | static headerL_t *getHeaders(int srcFd, headerL_t *head, int funct) |
173 | { | 241 | { |
242 | #if defined BB_AR_EXPERIMENTAL_UNTAR | ||
243 | int tar=FALSE; | ||
244 | #endif | ||
245 | int ar=FALSE; | ||
174 | headerL_t *list; | 246 | headerL_t *list; |
247 | off_t initialOffset; | ||
248 | |||
175 | list = (headerL_t *) malloc(sizeof(headerL_t)); | 249 | list = (headerL_t *) malloc(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; | ||
176 | 257 | ||
177 | if (checkArMagic(srcFd)==TRUE) { | 258 | if (tar==TRUE) { |
178 | while(readArEntry(srcFd, list) == TRUE) { | 259 | while(readTarHeader(srcFd, list)==TRUE) { |
260 | off_t tarOffset; | ||
261 | list->next = (headerL_t *) malloc(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 | } | ||
179 | list->next = (headerL_t *) malloc(sizeof(headerL_t)); | 285 | list->next = (headerL_t *) malloc(sizeof(headerL_t)); |
180 | *list->next = *head; | 286 | *list->next = *head; |
181 | *head = *list; | 287 | *head = *list; |
182 | |||
183 | /* recursive check for sub-archives */ | 288 | /* recursive check for sub-archives */ |
184 | if ( funct & RECURSIVE ) | 289 | if (funct & RECURSIVE) |
185 | head = getHeaders(srcFd, head, funct); | 290 | head = getHeaders(srcFd, head, funct); |
186 | lseek(srcFd, head->offset + head->size, SEEK_SET); | 291 | lseek(srcFd, head->offset + head->size, SEEK_SET); |
187 | } | 292 | } |
@@ -202,27 +307,6 @@ static headerL_t *findEntry(headerL_t *head, const char *filename) | |||
202 | return(NULL); | 307 | return(NULL); |
203 | } | 308 | } |
204 | 309 | ||
205 | /* | ||
206 | * populate linked list with all ar file entries and offset | ||
207 | */ | ||
208 | static int displayEntry(headerL_t *head, int funct) | ||
209 | { | ||
210 | if ( funct & VERBOSE ) { | ||
211 | printf("%s %d/%d %8d %s ", modeString(head->mode), head->uid, head->gid, head->size, timeString(head->mtime)); | ||
212 | } | ||
213 | printf("%s\n", head->name); | ||
214 | head = head->next; | ||
215 | return(TRUE); | ||
216 | } | ||
217 | |||
218 | static int extractAr(int srcFd, int dstFd, headerL_t *file) | ||
219 | { | ||
220 | lseek(srcFd, file->offset, SEEK_SET); | ||
221 | if (copySubFile(srcFd, dstFd, (size_t) file->size) == TRUE) | ||
222 | return(TRUE); | ||
223 | return(FALSE); | ||
224 | } | ||
225 | |||
226 | extern int ar_main(int argc, char **argv) | 310 | extern int ar_main(int argc, char **argv) |
227 | { | 311 | { |
228 | int funct = 0, opt=0; | 312 | int funct = 0, opt=0; |
@@ -270,7 +354,6 @@ extern int ar_main(int argc, char **argv) | |||
270 | extractList = (headerL_t *) malloc(sizeof(headerL_t)); | 354 | extractList = (headerL_t *) malloc(sizeof(headerL_t)); |
271 | 355 | ||
272 | header = getHeaders(srcFd, header, funct); | 356 | header = getHeaders(srcFd, header, funct); |
273 | |||
274 | /* find files to extract or display */ | 357 | /* find files to extract or display */ |
275 | if (optind<argc) { | 358 | if (optind<argc) { |
276 | /* only handle specified files */ | 359 | /* only handle specified files */ |
@@ -283,20 +366,28 @@ extern int ar_main(int argc, char **argv) | |||
283 | optind++; | 366 | optind++; |
284 | } | 367 | } |
285 | } | 368 | } |
286 | else | 369 | else |
287 | /* extract everything */ | ||
288 | extractList = header; | 370 | extractList = header; |
289 | 371 | ||
290 | while(extractList->next != NULL) { | 372 | while(extractList->next != NULL) { |
291 | if ( funct & EXT_TO_FILE ) { | 373 | if (funct & EXT_TO_FILE) { |
374 | if (isDirectory(extractList->name, TRUE, NULL)==FALSE) | ||
375 | createPath(extractList->name, 0666); | ||
292 | dstFd = open(extractList->name, O_WRONLY | O_CREAT, extractList->mode); | 376 | dstFd = open(extractList->name, O_WRONLY | O_CREAT, extractList->mode); |
293 | 377 | lseek(srcFd, extractList->offset, SEEK_SET); | |
294 | extractAr(srcFd, dstFd, extractList); | 378 | copySubFile(srcFd, dstFd, (size_t) extractList->size); |
379 | } | ||
380 | if (funct & EXT_TO_STDOUT) { | ||
381 | lseek(srcFd, extractList->offset, SEEK_SET); | ||
382 | copySubFile(srcFd, fileno(stdout), (size_t) extractList->size); | ||
383 | } | ||
384 | if ( (funct & DISPLAY) || (funct & VERBOSE)) { | ||
385 | if (funct & VERBOSE) | ||
386 | printf("%s %d/%d %8d %s ", modeString(extractList->mode), | ||
387 | extractList->uid, extractList->gid, | ||
388 | extractList->size, timeString(extractList->mtime)); | ||
389 | printf("%s\n", extractList->name); | ||
295 | } | 390 | } |
296 | if ( funct & EXT_TO_STDOUT ) | ||
297 | extractAr(srcFd, fileno(stdout), extractList); | ||
298 | if ( (funct & DISPLAY) || (funct & VERBOSE)) | ||
299 | displayEntry(extractList, funct); | ||
300 | extractList=extractList->next; | 391 | extractList=extractList->next; |
301 | } | 392 | } |
302 | return (TRUE); | 393 | return (TRUE); |