aboutsummaryrefslogtreecommitdiff
path: root/archival/ar.c
diff options
context:
space:
mode:
authorGlenn L McGrath <bug1@ihug.co.nz>2000-09-11 05:25:39 +0000
committerGlenn L McGrath <bug1@ihug.co.nz>2000-09-11 05:25:39 +0000
commitfca8050f0fd224a22136b74fce23b700f1d07ccf (patch)
tree11eeac7b1ceedd328e9af890a305c8618492f9c9 /archival/ar.c
parentac19b7e032c3d4449d08ea9ae438192b6a15170d (diff)
downloadbusybox-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.c265
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
57typedef 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
54typedef struct rawArHeader { /* Byte Offset */ 78typedef 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 */
77static int checkArMagic(int srcFd) 102static 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
117static 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 */
94static int readRawArHeader(int srcFd, headerL_t *header) 154static 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 */
125static int readArEntry(int srcFd, headerL_t *newEntry) 174static 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 */
172static headerL_t *getHeaders(int srcFd, headerL_t *head, int funct) 240static 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 */
208static 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
218static 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
226extern int ar_main(int argc, char **argv) 310extern 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);