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 | |
| 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"
| -rw-r--r-- | ar.c | 265 | ||||
| -rw-r--r-- | archival/ar.c | 265 |
2 files changed, 356 insertions, 174 deletions
| @@ -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); |
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); |
