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-fca8050f0fd224a22136b74fce23b700f1d07ccf.tar.gz
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 @@
//#define bb_need_io_error
//#include "messages.c"
+//#define BB_AR_EXPERIMENTAL_UNTAR
+
+#if defined BB_AR_EXPERIMENTAL_UNTAR
+typedef struct rawTarHeader {
+ char name[100]; /* 0-99 */
+ char mode[8]; /* 100-107 */
+ char uid[8]; /* 108-115 */
+ char gid[8]; /* 116-123 */
+ char size[12]; /* 124-135 */
+ char mtime[12]; /* 136-147 */
+ char chksum[8]; /* 148-155 */
+ char typeflag; /* 156-156 */
+ char linkname[100]; /* 157-256 */
+ char magic[6]; /* 257-262 */
+ char version[2]; /* 263-264 */
+ char uname[32]; /* 265-296 */
+ char gname[32]; /* 297-328 */
+ char devmajor[8]; /* 329-336 */
+ char devminor[8]; /* 337-344 */
+ char prefix[155]; /* 345-499 */
+ char padding[12]; /* 500-512 */
+} rawTarHeader_t;
+#endif
+
typedef struct rawArHeader { /* Byte Offset */
char name[16]; /* 0-15 */
char date[12]; /* 16-27 */
@@ -71,92 +95,136 @@ typedef struct headerL {
struct headerL *next;
} headerL_t;
+#if defined BB_AR_EXPERIMENTAL_UNTAR
/*
- * identify Ar header (magic) and set srcFd to first header entry
+ * identify Tar header (magic field) and reset srcFd to entry position
*/
-static int checkArMagic(int srcFd)
+static int checkTarMagic(int srcFd)
{
- char arMagic[8];
- if (fullRead(srcFd, arMagic, 8) != 8)
- return (FALSE);
-
- if (strncmp(arMagic,"!<arch>",7) != 0)
+ off_t headerStart;
+ char magic[6];
+
+ headerStart = lseek(srcFd, 0, SEEK_CUR);
+ lseek(srcFd, (off_t) 257, SEEK_CUR);
+ fullRead(srcFd, magic, 6);
+ lseek(srcFd, headerStart, SEEK_SET);
+ if (strncmp(magic, "ustar", 5)!=0)
+ return(FALSE);
+ return(TRUE);
+}
+
+
+static int readTarHeader(int srcFd, headerL_t *current)
+{
+ rawTarHeader_t rawTarHeader;
+ unsigned char *temp = (unsigned char *) &rawTarHeader;
+ long sum = 0;
+ int i;
+ off_t initialOffset;
+
+ initialOffset = lseek(srcFd, 0, SEEK_CUR);
+ if (fullRead(srcFd, (char *) &rawTarHeader, 512) != 512) {
+ lseek(srcFd, initialOffset, SEEK_SET);
return(FALSE);
- return(TRUE);
+ }
+ for (i = 0; i < 148 ; i++)
+ sum += temp[i];
+ sum += ' ' * 8;
+ for (i = 156; i < 512 ; i++)
+ sum += temp[i];
+ if (sum!= strtol(rawTarHeader.chksum, NULL, 8))
+ return(FALSE);
+ sscanf(rawTarHeader.name, "%s", current->name);
+ current->size = strtol(rawTarHeader.size, NULL, 8);
+ current->uid = strtol(rawTarHeader.uid, NULL, 8);
+ current->gid = strtol(rawTarHeader.gid, NULL, 8);
+ current->mode = strtol(rawTarHeader.mode, NULL, 8);
+ current->mtime = strtol(rawTarHeader.mtime, NULL, 8);
+ current->offset = lseek(srcFd, 0 , SEEK_CUR);
+
+ current->next = (headerL_t *) xmalloc(sizeof(headerL_t));
+ current = current->next;
+ return(TRUE);
}
+#endif
/*
- * read, convert and check the raw ar header
- * srcFd should be pointing to the start of header prior to entry
- * srcFd will be pointing at the start of data after successful exit
- * if returns FALSE srcFd is reset to initial position
+ * identify Ar header (magic) and reset srcFd to entry position
*/
-static int readRawArHeader(int srcFd, headerL_t *header)
+static int checkArMagic(int srcFd)
{
- rawArHeader_t rawArHeader;
- off_t initialOffset;
- size_t nameLength;
-
- initialOffset = lseek(srcFd, 0, SEEK_CUR);
- if (fullRead(srcFd, (char *) &rawArHeader, 60) != 60) {
- lseek(srcFd, initialOffset, SEEK_SET);
- return(FALSE);
- }
- if ((rawArHeader.fmag[0]!='`') || (rawArHeader.fmag[1]!='\n')) {
- lseek(srcFd, initialOffset, SEEK_SET);
- return(FALSE);
- }
+ off_t headerStart;
+ char arMagic[8];
- strncpy(header->name, rawArHeader.name, 16);
- nameLength=strcspn(header->name, " \\");
- header->name[nameLength]='\0';
- parse_mode(rawArHeader.mode, &header->mode);
- header->mtime = atoi(rawArHeader.date);
- header->uid = atoi(rawArHeader.uid);
- header->gid = atoi(rawArHeader.gid);
- header->size = (size_t) atoi(rawArHeader.size);
- header->offset = initialOffset + (off_t) 60;
- return(TRUE);
+ headerStart = lseek(srcFd, 0, SEEK_CUR);
+ if (fullRead(srcFd, arMagic, 8) != 8) {
+ printf("fatal error/n");
+ return (FALSE);
+ }
+ lseek(srcFd, headerStart, SEEK_SET);
+
+ if (strncmp(arMagic,"!<arch>",7) != 0)
+ return(FALSE);
+ return(TRUE);
}
/*
* get, check and correct the converted header
*/
-static int readArEntry(int srcFd, headerL_t *newEntry)
+static int readArEntry(int srcFd, headerL_t *entry)
{
size_t nameLength;
+ rawArHeader_t rawArHeader;
+ off_t initialOffset;
- if(readRawArHeader(srcFd, newEntry)==FALSE)
- return(FALSE);
-
- nameLength = strcspn(newEntry->name, "/");
+ initialOffset = lseek(srcFd, 0, SEEK_CUR);
+ if (fullRead(srcFd, (char *) &rawArHeader, 60) != 60) {
+ lseek(srcFd, initialOffset, SEEK_SET);
+ return(FALSE);
+ }
+ if ((rawArHeader.fmag[0]!='`') || (rawArHeader.fmag[1]!='\n')) {
+ lseek(srcFd, initialOffset, SEEK_SET);
+ return(FALSE);
+ }
+
+ strncpy(entry->name, rawArHeader.name, 16);
+ nameLength=strcspn(entry->name, " \\");
+ entry->name[nameLength]='\0';
+ parse_mode(rawArHeader.mode, &entry->mode);
+ entry->mtime = atoi(rawArHeader.date);
+ entry->uid = atoi(rawArHeader.uid);
+ entry->gid = atoi(rawArHeader.gid);
+ entry->size = (size_t) atoi(rawArHeader.size);
+ entry->offset = initialOffset + (off_t) 60;
+
+ nameLength = strcspn(entry->name, "/");
/* handle GNU style short filenames, strip trailing '/' */
if (nameLength > 0)
- newEntry->name[nameLength]='\0';
+ entry->name[nameLength]='\0';
/* handle GNU style long filenames */
if (nameLength == 0) {
/* escape from recursive call */
- if (newEntry->name[1]=='0')
+ if (entry->name[1]=='0')
return(TRUE);
/* the data section contains the real filename */
- if (newEntry->name[1]=='/') {
+ if (entry->name[1]=='/') {
char tempName[MAX_NAME_LENGTH];
- if (newEntry->size > MAX_NAME_LENGTH)
- newEntry->size = MAX_NAME_LENGTH;
- fullRead(srcFd, tempName, newEntry->size);
- tempName[newEntry->size-3]='\0';
+ if (entry->size > MAX_NAME_LENGTH)
+ entry->size = MAX_NAME_LENGTH;
+ fullRead(srcFd, tempName, entry->size);
+ tempName[entry->size-3]='\0';
/* read the second header for this entry */
/* be carefull, this is recursive */
- if (readArEntry(srcFd, newEntry)==FALSE)
+ if (readArEntry(srcFd, entry)==FALSE)
return(FALSE);
- if ((newEntry->name[0]='/') && (newEntry->name[1]='0'))
- strcpy(newEntry->name, tempName);
+ if ((entry->name[0]='/') && (entry->name[1]='0'))
+ strcpy(entry->name, tempName);
else {
errorMsg("Invalid long filename\n");
return(FALSE);
@@ -171,17 +239,54 @@ static int readArEntry(int srcFd, headerL_t *newEntry)
*/
static headerL_t *getHeaders(int srcFd, headerL_t *head, int funct)
{
+#if defined BB_AR_EXPERIMENTAL_UNTAR
+ int tar=FALSE;
+#endif
+ int ar=FALSE;
headerL_t *list;
+ off_t initialOffset;
+
list = (headerL_t *) malloc(sizeof(headerL_t));
+ initialOffset=lseek(srcFd, 0, SEEK_CUR);
+ if (checkArMagic(srcFd)==TRUE)
+ ar=TRUE;
+
+#if defined BB_AR_EXPERIMENTAL_UNTAR
+ if (checkTarMagic(srcFd)==TRUE)
+ tar=TRUE;
- if (checkArMagic(srcFd)==TRUE) {
- while(readArEntry(srcFd, list) == TRUE) {
+ if (tar==TRUE) {
+ while(readTarHeader(srcFd, list)==TRUE) {
+ off_t tarOffset;
+ list->next = (headerL_t *) malloc(sizeof(headerL_t));
+ *list->next = *head;
+ *head = *list;
+
+ /* recursive check for sub-archives */
+ if ((funct & RECURSIVE) == RECURSIVE)
+ head = getHeaders(srcFd, head, funct);
+ tarOffset = (off_t) head->size/512;
+ if ( head->size % 512 > 0)
+ tarOffset++;
+ tarOffset=tarOffset*512;
+ lseek(srcFd, head->offset + tarOffset, SEEK_SET);
+ }
+ }
+#endif
+
+ if (ar==TRUE) {
+ lseek(srcFd, 8, SEEK_CUR);
+ while(1) {
+ if (readArEntry(srcFd, list) == FALSE) {
+ lseek(srcFd, ++initialOffset, SEEK_CUR);
+ if (readArEntry(srcFd, list) == FALSE)
+ return(head);
+ }
list->next = (headerL_t *) malloc(sizeof(headerL_t));
*list->next = *head;
*head = *list;
-
/* recursive check for sub-archives */
- if ( funct & RECURSIVE )
+ if (funct & RECURSIVE)
head = getHeaders(srcFd, head, funct);
lseek(srcFd, head->offset + head->size, SEEK_SET);
}
@@ -202,27 +307,6 @@ static headerL_t *findEntry(headerL_t *head, const char *filename)
return(NULL);
}
-/*
- * populate linked list with all ar file entries and offset
- */
-static int displayEntry(headerL_t *head, int funct)
-{
- if ( funct & VERBOSE ) {
- printf("%s %d/%d %8d %s ", modeString(head->mode), head->uid, head->gid, head->size, timeString(head->mtime));
- }
- printf("%s\n", head->name);
- head = head->next;
- return(TRUE);
-}
-
-static int extractAr(int srcFd, int dstFd, headerL_t *file)
-{
- lseek(srcFd, file->offset, SEEK_SET);
- if (copySubFile(srcFd, dstFd, (size_t) file->size) == TRUE)
- return(TRUE);
- return(FALSE);
-}
-
extern int ar_main(int argc, char **argv)
{
int funct = 0, opt=0;
@@ -270,7 +354,6 @@ extern int ar_main(int argc, char **argv)
extractList = (headerL_t *) malloc(sizeof(headerL_t));
header = getHeaders(srcFd, header, funct);
-
/* find files to extract or display */
if (optind<argc) {
/* only handle specified files */
@@ -283,20 +366,28 @@ extern int ar_main(int argc, char **argv)
optind++;
}
}
- else
- /* extract everything */
+ else
extractList = header;
- while(extractList->next != NULL) {
- if ( funct & EXT_TO_FILE ) {
+ while(extractList->next != NULL) {
+ if (funct & EXT_TO_FILE) {
+ if (isDirectory(extractList->name, TRUE, NULL)==FALSE)
+ createPath(extractList->name, 0666);
dstFd = open(extractList->name, O_WRONLY | O_CREAT, extractList->mode);
-
- extractAr(srcFd, dstFd, extractList);
+ lseek(srcFd, extractList->offset, SEEK_SET);
+ copySubFile(srcFd, dstFd, (size_t) extractList->size);
+ }
+ if (funct & EXT_TO_STDOUT) {
+ lseek(srcFd, extractList->offset, SEEK_SET);
+ copySubFile(srcFd, fileno(stdout), (size_t) extractList->size);
+ }
+ if ( (funct & DISPLAY) || (funct & VERBOSE)) {
+ if (funct & VERBOSE)
+ printf("%s %d/%d %8d %s ", modeString(extractList->mode),
+ extractList->uid, extractList->gid,
+ extractList->size, timeString(extractList->mtime));
+ printf("%s\n", extractList->name);
}
- if ( funct & EXT_TO_STDOUT )
- extractAr(srcFd, fileno(stdout), extractList);
- if ( (funct & DISPLAY) || (funct & VERBOSE))
- displayEntry(extractList, funct);
extractList=extractList->next;
}
return (TRUE);