diff --git a/applets/usage.c b/applets/usage.c index 0dad1ba30..35f63db86 100644 --- a/applets/usage.c +++ b/applets/usage.c @@ -2,15 +2,15 @@ #if defined BB_AR const char ar_usage[] = - "ar [optxvV] archive [filenames] \n" + "ar [[-ov] -tpv archive] filenames \n" #ifndef BB_FEATURE_TRIVIAL_HELP "\nExtract or list files from an ar archive.\n\n" "Options:\n" - "\to\t\tpreserve original dates\n" - "\tp\t\textract to stdout\n" - "\tt\t\tlist\n" - "\tx\t\textract\n" - "\tv\t\tverbosely list files processed\n" + "\t-o\t\tpreserve original dates\n" + "\t-p\t\textract to stdout\n" + "\t-t\t\tlist\n" + "\t-x\t\textract\n" + "\t-v\t\tverbosely list files processed\n" #endif ; #endif diff --git a/ar.c b/ar.c index b1200b8ae..1c598fa16 100644 --- a/ar.c +++ b/ar.c @@ -4,6 +4,12 @@ * * Copyright (C) 2000 by Glenn McGrath * Written by Glenn McGrath 1 June 2000 + * + * Modified 8 August 2000 by Glenn McGrath + * - now uses getopt + * - moved copySubFile function to utilities.c + * - creates linked list of all headers + * - easily accessable to other busybox functions * * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. * @@ -21,10 +27,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Last modified 10 June 2000 + * Last modified 25 August 2000 */ - - #include #include #include @@ -34,287 +38,179 @@ #include #include "internal.h" -#define AR_BLOCK_SIZE 60 -#define AR_PRESERVE_DATE 1 /* preserve original dates */ -#define AR_VERBOSE 2 /* be verbose */ -#define AR_DISPLAY 4 /* display contents */ -#define AR_EXT_TO_FILE 8 /* extract contents of archive */ -#define AR_EXT_TO_STDOUT 16 /* extract to stdout */ +#define BLOCK_SIZE 60 +#define PRESERVE_DATE 1 /* preserve original dates */ +#define VERBOSE 2 /* be verbose */ +#define DISPLAY 4 /* display contents */ +#define EXT_TO_FILE 8 /* extract contents of archive */ +#define EXT_TO_STDOUT 16 /* extract to stdout */ #define BB_DECLARE_EXTERN #define bb_need_io_error #include "messages.c" -struct ArHeader { /* Byte Offset */ - char ar_name[16]; /* 0-15 */ - char ar_date[12]; /* 16-27 */ - char ar_uid[6], ar_gid[6]; /* 28-39 */ - char ar_mode[8]; /* 40-47 */ - char ar_size[10]; /* 48-57 */ - char ar_fmag[2]; /* 58-59 */ -}; -typedef struct ArHeader ArHeader; +typedef struct rawArHeader { /* Byte Offset */ + char name[16]; /* 0-15 */ + char date[12]; /* 16-27 */ + char uid[6], gid[6]; /* 28-39 */ + char mode[8]; /* 40-47 */ + char size[10]; /* 48-57 */ + char fmag[2]; /* 58-59 */ +} rawArHeader_t; -struct ArInfo { - char name[17]; /* File name */ - time_t date; /* long int, No of seconds since epoch */ - uid_t uid; /* unsigned int, Numeric UID */ - gid_t gid; /* unsigned int, Numeric GID */ - mode_t mode; /* unsigned int, Unix mode */ - size_t size; /* int, Size of the file */ -}; -typedef struct ArInfo ArInfo; +typedef struct headerL { + char name[16]; + size_t size; + uid_t uid; + gid_t gid; + mode_t mode; + time_t mtime; + off_t offset; + struct headerL *next; +} headerL_t; /* - * Display details of a file, verbosly if funct=2 + * populate linked list with all ar file entries and offset */ -static void displayEntry(struct ArInfo *entry, int funct) +static int parseArArchive(int srcFd, headerL_t *current) { - /* TODO convert mode to string */ - if ((funct & AR_VERBOSE) == AR_VERBOSE) - printf("%i %i/%i %8i %s ", entry->mode, entry->uid, entry->gid, - entry->size, timeString(entry->date)); - printf("%s\n", entry->name); -} - -/* this is from tar.c remove later*/ -static long getOctal(const char *cp, int size) -{ - long val = 0; - - for(;(size > 0) && (*cp == ' '); cp++, size--); - if ((size == 0) || !isOctal(*cp)) - return -1; - for(; (size > 0) && isOctal(*cp); size--) { - val = val * 8 + *cp++ - '0'; - } - for (;(size > 0) && (*cp == ' '); cp++, size--); - if ((size > 0) && *cp) - return -1; - return val; -} - -/* - * Converts from the char based struct to a new struct with stricter types - */ -static int processArHeader(struct ArHeader *rawHeader, struct ArInfo *header) -{ - int count2; - int count; - - /* check end of header marker is valid */ - if ((rawHeader->ar_fmag[0]!='`') || (rawHeader->ar_fmag[1]!='\n')) - return(FALSE); - - /* convert filename */ - for (count = 0; count < 16; count++) { - /* allow spaces in filename except at the end */ - if (rawHeader->ar_name[count] == ' ') { - for (count2 = count; count2 < 16; count2++) - if (!isspace(rawHeader->ar_name[count2])) - break; - if (count2 >= 16) - break; - } - /* GNU ar uses '/' as an end of filename marker */ - if (rawHeader->ar_name[count] == '/') - break; - header->name[count] = rawHeader->ar_name[count]; - } - header->name[count] = '\0'; - header->date = atoi(rawHeader->ar_date); - header->uid = atoi(rawHeader->ar_uid); - header->gid = atoi(rawHeader->ar_gid); - header->mode = getOctal(rawHeader->ar_mode, sizeof(rawHeader->ar_mode)); - header->size = atoi(rawHeader->ar_size); - return (TRUE); -} - -/* - * Copy size bytes from current position if srcFd to current position in dstFd - * taken from tarExtractRegularFile in tar.c, remove later - */ -static int copySubFile(int srcFd, int dstFd, int copySize) -{ - int readSize, writeSize, doneSize; - char buffer[BUFSIZ]; - - while (copySize > 0) { - if (copySize > BUFSIZ) - readSize = BUFSIZ; - else - readSize = copySize; - writeSize = fullRead(srcFd, buffer, readSize); - if (writeSize <= 0) { - errorMsg(io_error, "copySubFile", strerror(errno)); - return (FALSE); - } - doneSize = fullWrite(dstFd, buffer, writeSize); - if (doneSize <= 0) { - errorMsg(io_error, "copySubFile", strerror(errno)); - return (FALSE); - } - copySize -= doneSize; - } - return (TRUE); -} - -/* - * Extract the file described in ArInfo to the specified path - * set the new files uid, gid and mode - */ -static int extractToFile(struct ArInfo *file, int funct, int srcFd, const char *path) -{ - int dstFd, temp; - struct stat tmpStat; - char *pathname = NULL; - struct utimbuf newtime; - - if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) { - if (!createPath(path, 0777)) { - fatalError("Cannot extract to specified path"); - return (FALSE); - } - } - temp = (strlen(path) + 16); - pathname = (char *) xmalloc(temp); - pathname = strcpy(pathname, path); - pathname = strcat(pathname, file->name); - dstFd = device_open(pathname, O_WRONLY | O_CREAT); - temp = copySubFile(srcFd, dstFd, file->size); - fchown(dstFd, file->uid, file->gid); - fchmod(dstFd, file->mode); - close(dstFd); - if ((funct&AR_PRESERVE_DATE)==AR_PRESERVE_DATE) - newtime.modtime=file->date; - else - newtime.modtime=time(0); - newtime.actime=time(0); - temp = utime(pathname, &newtime); - return (TRUE); -} - -/* - * Return a file descriptor for the specified file and do error checks - */ -static int getArFd(char *filename) -{ - int arFd; + off_t lastOffset=0, thisOffset=0; char arVersion[8]; - - arFd = open(filename, O_RDONLY); - if (arFd < 0) { - errorMsg("Error opening '%s': %s\n", filename, strerror(errno)); - return (FALSE); - } - if (fullRead(arFd, arVersion, 8) <= 0) { - errorMsg( "Unexpected EOF in archive\n"); + rawArHeader_t rawArHeader; + + lseek(srcFd, 0, SEEK_SET); + if (fullRead(srcFd, arVersion, 8) <= 0) { + errorMsg("Invalid header magic\n"); return (FALSE); } if (strncmp(arVersion,"!",7) != 0) { - errorMsg("ar header fails check "); + errorMsg("This doesnt appear to be an ar archive\n"); return(FALSE); } - return arFd; + while (fullRead(srcFd, (char *) &rawArHeader, 60) == 60) { + if ( (rawArHeader.fmag[0] == '`') && + (rawArHeader.fmag[1] == '\n')) { + sscanf(rawArHeader.name, "%s", current->name); + parse_mode(rawArHeader.mode, ¤t->mode); + current->mtime = atoi(rawArHeader.date); + current->uid = atoi(rawArHeader.uid); + current->gid = atoi(rawArHeader.gid); + current->size = (size_t) atoi(rawArHeader.size); + current->offset = lseek(srcFd, 0 , SEEK_CUR); + current->next = (headerL_t *) xmalloc(sizeof(headerL_t)); + lastOffset = lseek(srcFd, (off_t) current->size, SEEK_CUR); + current = current->next; + } + else { /* GNU ar has an extra char after data */ + thisOffset=lseek(srcFd, 0, SEEK_CUR); + if ( (thisOffset - lastOffset) > ((off_t) 61) ) + return(FALSE); + lseek(srcFd, thisOffset - 59, SEEK_SET); + } + } + return(FALSE); } /* - * Step through the ar file and process it one entry at a time - * fileList[0] is the name of the ar archive - * fileList[1] and up are filenames to extract from the archive - * funct contains flags to specify the actions to be performed + * return the headerL_t struct for the specified filename */ -static int readArFile(char *fileList[16], int fileListSize, int funct) +static headerL_t *getSubFileHeader(int srcFd, const char filename[16]) { - int arFd, status, extFileFlag, i, lastOffset=0; - ArHeader rawArHeader; - ArInfo arEntry; + headerL_t *list; + list = xmalloc(sizeof(headerL_t)); - /* open the ar archive */ - arFd=getArFd(fileList[0]); + parseArArchive(srcFd, list); + while (list->next != NULL) { + if (strncmp(list->name, filename, strlen(filename))==0) + return(list); + list=list->next; + } + return(NULL); +} - /* read the first header, then loop until ono more headers */ - while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE)) - == AR_BLOCK_SIZE) { +/* + * populate linked list with all ar file entries and offset + */ +static int displayEntry(int srcFd, const char filename[16], int funct) +{ + headerL_t *file; - /* check the header is valid, if not try reading the header - agian with an offset of 1, needed as some ar archive end - with a '\n' which isnt counted in specified file size */ - if ((status=processArHeader(&rawArHeader, &arEntry))==FALSE ) { - if ((i=lseek(arFd, 0, SEEK_CUR))==(lastOffset+60)) - lseek(arFd, lastOffset+1, SEEK_SET); - else - return(FALSE); - } - else { - extFileFlag=0; - - if ((funct&AR_DISPLAY) || (funct&AR_VERBOSE)) - displayEntry(&arEntry, funct); + if ((file = getSubFileHeader(srcFd, filename)) == NULL) + return(FALSE); + if ((funct & VERBOSE) == VERBOSE) { + printf("%s %d/%d %8d %s ", modeString(file->mode), file->uid, file->gid, file->size, timeString(file->mtime)); + } + printf("%s\n", file->name); + return(TRUE); +} - /* check file was specified to be extracted only if - some file were specified */ - if ((funct&AR_EXT_TO_FILE) || (funct&AR_EXT_TO_STDOUT)){ - if (fileListSize==1) - extFileFlag=1; - else { - for( i=1; i<=fileListSize; i++) - if ((status=(strcmp(fileList[i],arEntry.name)))==0) - extFileFlag=1; - } - } - if (extFileFlag==1) { - if (funct&AR_EXT_TO_FILE) - extractToFile(&arEntry, funct, arFd, "./"); - else - copySubFile(arFd,fileno(stdout),arEntry.size); - } - else - lseek(arFd, arEntry.size, SEEK_CUR); - lastOffset=lseek(arFd, 0, SEEK_CUR); - } /* if processArHeader */ - } /* while */ - return (TRUE); +static int extractAr(int srcFd, int dstFd, const char filename[16]) +{ + headerL_t *file; + + if ( (file = getSubFileHeader(srcFd, filename)) == NULL) + return(FALSE); + 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, ret=0, i=0; - char *fileList[16], c, *opt_ptr; - - if (argc < 2) - usage(ar_usage); - - opt_ptr = argv[1]; - if (*opt_ptr == '-') - ++opt_ptr; - while ((c = *opt_ptr++) != '\0') { - switch (c) { + int funct = 0, opt=0; + int srcFd=0, dstFd=0; + + while ((opt = getopt(argc, argv, "ovt:p:x:")) != -1) { + switch (opt) { case 'o': - funct = funct | AR_PRESERVE_DATE; + funct = funct | PRESERVE_DATE; break; case 'v': - funct = funct | AR_VERBOSE; + funct = funct | VERBOSE; break; case 't': - funct = funct | AR_DISPLAY; - break; + funct = funct | DISPLAY; case 'x': - funct = funct | AR_EXT_TO_FILE; - break; + if (opt=='x') { + funct = funct | EXT_TO_FILE; + } case 'p': - funct = funct | AR_EXT_TO_STDOUT; + if (opt=='p') { + funct = funct | EXT_TO_STDOUT; + } + /* following is common to 't','x' and 'p' */ + if (optarg == NULL) { + printf("expected a filename\n"); + return(FALSE); + } + if ( (srcFd = open(optarg, O_RDONLY)) < 0) { + errorMsg("Cannot read %s\n", optarg); + return (FALSE); + } break; default: usage(ar_usage); } } - - for(i=0; i<(argc-2); i++) - fileList[i]=argv[i+2]; + + /* check options not just preserve_dates and/or verbose */ + if (funct < 4) { + usage(ar_usage); + return(FALSE); + } - if (funct > 3) - ret = readArFile(fileList, (argc-2), funct); - - return (ret); + /* find files to extract */ + if (optind 1 June 2000 + * + * Modified 8 August 2000 by Glenn McGrath + * - now uses getopt + * - moved copySubFile function to utilities.c + * - creates linked list of all headers + * - easily accessable to other busybox functions * * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. * @@ -21,10 +27,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Last modified 10 June 2000 + * Last modified 25 August 2000 */ - - #include #include #include @@ -34,287 +38,179 @@ #include #include "internal.h" -#define AR_BLOCK_SIZE 60 -#define AR_PRESERVE_DATE 1 /* preserve original dates */ -#define AR_VERBOSE 2 /* be verbose */ -#define AR_DISPLAY 4 /* display contents */ -#define AR_EXT_TO_FILE 8 /* extract contents of archive */ -#define AR_EXT_TO_STDOUT 16 /* extract to stdout */ +#define BLOCK_SIZE 60 +#define PRESERVE_DATE 1 /* preserve original dates */ +#define VERBOSE 2 /* be verbose */ +#define DISPLAY 4 /* display contents */ +#define EXT_TO_FILE 8 /* extract contents of archive */ +#define EXT_TO_STDOUT 16 /* extract to stdout */ #define BB_DECLARE_EXTERN #define bb_need_io_error #include "messages.c" -struct ArHeader { /* Byte Offset */ - char ar_name[16]; /* 0-15 */ - char ar_date[12]; /* 16-27 */ - char ar_uid[6], ar_gid[6]; /* 28-39 */ - char ar_mode[8]; /* 40-47 */ - char ar_size[10]; /* 48-57 */ - char ar_fmag[2]; /* 58-59 */ -}; -typedef struct ArHeader ArHeader; +typedef struct rawArHeader { /* Byte Offset */ + char name[16]; /* 0-15 */ + char date[12]; /* 16-27 */ + char uid[6], gid[6]; /* 28-39 */ + char mode[8]; /* 40-47 */ + char size[10]; /* 48-57 */ + char fmag[2]; /* 58-59 */ +} rawArHeader_t; -struct ArInfo { - char name[17]; /* File name */ - time_t date; /* long int, No of seconds since epoch */ - uid_t uid; /* unsigned int, Numeric UID */ - gid_t gid; /* unsigned int, Numeric GID */ - mode_t mode; /* unsigned int, Unix mode */ - size_t size; /* int, Size of the file */ -}; -typedef struct ArInfo ArInfo; +typedef struct headerL { + char name[16]; + size_t size; + uid_t uid; + gid_t gid; + mode_t mode; + time_t mtime; + off_t offset; + struct headerL *next; +} headerL_t; /* - * Display details of a file, verbosly if funct=2 + * populate linked list with all ar file entries and offset */ -static void displayEntry(struct ArInfo *entry, int funct) +static int parseArArchive(int srcFd, headerL_t *current) { - /* TODO convert mode to string */ - if ((funct & AR_VERBOSE) == AR_VERBOSE) - printf("%i %i/%i %8i %s ", entry->mode, entry->uid, entry->gid, - entry->size, timeString(entry->date)); - printf("%s\n", entry->name); -} - -/* this is from tar.c remove later*/ -static long getOctal(const char *cp, int size) -{ - long val = 0; - - for(;(size > 0) && (*cp == ' '); cp++, size--); - if ((size == 0) || !isOctal(*cp)) - return -1; - for(; (size > 0) && isOctal(*cp); size--) { - val = val * 8 + *cp++ - '0'; - } - for (;(size > 0) && (*cp == ' '); cp++, size--); - if ((size > 0) && *cp) - return -1; - return val; -} - -/* - * Converts from the char based struct to a new struct with stricter types - */ -static int processArHeader(struct ArHeader *rawHeader, struct ArInfo *header) -{ - int count2; - int count; - - /* check end of header marker is valid */ - if ((rawHeader->ar_fmag[0]!='`') || (rawHeader->ar_fmag[1]!='\n')) - return(FALSE); - - /* convert filename */ - for (count = 0; count < 16; count++) { - /* allow spaces in filename except at the end */ - if (rawHeader->ar_name[count] == ' ') { - for (count2 = count; count2 < 16; count2++) - if (!isspace(rawHeader->ar_name[count2])) - break; - if (count2 >= 16) - break; - } - /* GNU ar uses '/' as an end of filename marker */ - if (rawHeader->ar_name[count] == '/') - break; - header->name[count] = rawHeader->ar_name[count]; - } - header->name[count] = '\0'; - header->date = atoi(rawHeader->ar_date); - header->uid = atoi(rawHeader->ar_uid); - header->gid = atoi(rawHeader->ar_gid); - header->mode = getOctal(rawHeader->ar_mode, sizeof(rawHeader->ar_mode)); - header->size = atoi(rawHeader->ar_size); - return (TRUE); -} - -/* - * Copy size bytes from current position if srcFd to current position in dstFd - * taken from tarExtractRegularFile in tar.c, remove later - */ -static int copySubFile(int srcFd, int dstFd, int copySize) -{ - int readSize, writeSize, doneSize; - char buffer[BUFSIZ]; - - while (copySize > 0) { - if (copySize > BUFSIZ) - readSize = BUFSIZ; - else - readSize = copySize; - writeSize = fullRead(srcFd, buffer, readSize); - if (writeSize <= 0) { - errorMsg(io_error, "copySubFile", strerror(errno)); - return (FALSE); - } - doneSize = fullWrite(dstFd, buffer, writeSize); - if (doneSize <= 0) { - errorMsg(io_error, "copySubFile", strerror(errno)); - return (FALSE); - } - copySize -= doneSize; - } - return (TRUE); -} - -/* - * Extract the file described in ArInfo to the specified path - * set the new files uid, gid and mode - */ -static int extractToFile(struct ArInfo *file, int funct, int srcFd, const char *path) -{ - int dstFd, temp; - struct stat tmpStat; - char *pathname = NULL; - struct utimbuf newtime; - - if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) { - if (!createPath(path, 0777)) { - fatalError("Cannot extract to specified path"); - return (FALSE); - } - } - temp = (strlen(path) + 16); - pathname = (char *) xmalloc(temp); - pathname = strcpy(pathname, path); - pathname = strcat(pathname, file->name); - dstFd = device_open(pathname, O_WRONLY | O_CREAT); - temp = copySubFile(srcFd, dstFd, file->size); - fchown(dstFd, file->uid, file->gid); - fchmod(dstFd, file->mode); - close(dstFd); - if ((funct&AR_PRESERVE_DATE)==AR_PRESERVE_DATE) - newtime.modtime=file->date; - else - newtime.modtime=time(0); - newtime.actime=time(0); - temp = utime(pathname, &newtime); - return (TRUE); -} - -/* - * Return a file descriptor for the specified file and do error checks - */ -static int getArFd(char *filename) -{ - int arFd; + off_t lastOffset=0, thisOffset=0; char arVersion[8]; - - arFd = open(filename, O_RDONLY); - if (arFd < 0) { - errorMsg("Error opening '%s': %s\n", filename, strerror(errno)); - return (FALSE); - } - if (fullRead(arFd, arVersion, 8) <= 0) { - errorMsg( "Unexpected EOF in archive\n"); + rawArHeader_t rawArHeader; + + lseek(srcFd, 0, SEEK_SET); + if (fullRead(srcFd, arVersion, 8) <= 0) { + errorMsg("Invalid header magic\n"); return (FALSE); } if (strncmp(arVersion,"!",7) != 0) { - errorMsg("ar header fails check "); + errorMsg("This doesnt appear to be an ar archive\n"); return(FALSE); } - return arFd; + while (fullRead(srcFd, (char *) &rawArHeader, 60) == 60) { + if ( (rawArHeader.fmag[0] == '`') && + (rawArHeader.fmag[1] == '\n')) { + sscanf(rawArHeader.name, "%s", current->name); + parse_mode(rawArHeader.mode, ¤t->mode); + current->mtime = atoi(rawArHeader.date); + current->uid = atoi(rawArHeader.uid); + current->gid = atoi(rawArHeader.gid); + current->size = (size_t) atoi(rawArHeader.size); + current->offset = lseek(srcFd, 0 , SEEK_CUR); + current->next = (headerL_t *) xmalloc(sizeof(headerL_t)); + lastOffset = lseek(srcFd, (off_t) current->size, SEEK_CUR); + current = current->next; + } + else { /* GNU ar has an extra char after data */ + thisOffset=lseek(srcFd, 0, SEEK_CUR); + if ( (thisOffset - lastOffset) > ((off_t) 61) ) + return(FALSE); + lseek(srcFd, thisOffset - 59, SEEK_SET); + } + } + return(FALSE); } /* - * Step through the ar file and process it one entry at a time - * fileList[0] is the name of the ar archive - * fileList[1] and up are filenames to extract from the archive - * funct contains flags to specify the actions to be performed + * return the headerL_t struct for the specified filename */ -static int readArFile(char *fileList[16], int fileListSize, int funct) +static headerL_t *getSubFileHeader(int srcFd, const char filename[16]) { - int arFd, status, extFileFlag, i, lastOffset=0; - ArHeader rawArHeader; - ArInfo arEntry; + headerL_t *list; + list = xmalloc(sizeof(headerL_t)); - /* open the ar archive */ - arFd=getArFd(fileList[0]); + parseArArchive(srcFd, list); + while (list->next != NULL) { + if (strncmp(list->name, filename, strlen(filename))==0) + return(list); + list=list->next; + } + return(NULL); +} - /* read the first header, then loop until ono more headers */ - while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE)) - == AR_BLOCK_SIZE) { +/* + * populate linked list with all ar file entries and offset + */ +static int displayEntry(int srcFd, const char filename[16], int funct) +{ + headerL_t *file; - /* check the header is valid, if not try reading the header - agian with an offset of 1, needed as some ar archive end - with a '\n' which isnt counted in specified file size */ - if ((status=processArHeader(&rawArHeader, &arEntry))==FALSE ) { - if ((i=lseek(arFd, 0, SEEK_CUR))==(lastOffset+60)) - lseek(arFd, lastOffset+1, SEEK_SET); - else - return(FALSE); - } - else { - extFileFlag=0; - - if ((funct&AR_DISPLAY) || (funct&AR_VERBOSE)) - displayEntry(&arEntry, funct); + if ((file = getSubFileHeader(srcFd, filename)) == NULL) + return(FALSE); + if ((funct & VERBOSE) == VERBOSE) { + printf("%s %d/%d %8d %s ", modeString(file->mode), file->uid, file->gid, file->size, timeString(file->mtime)); + } + printf("%s\n", file->name); + return(TRUE); +} - /* check file was specified to be extracted only if - some file were specified */ - if ((funct&AR_EXT_TO_FILE) || (funct&AR_EXT_TO_STDOUT)){ - if (fileListSize==1) - extFileFlag=1; - else { - for( i=1; i<=fileListSize; i++) - if ((status=(strcmp(fileList[i],arEntry.name)))==0) - extFileFlag=1; - } - } - if (extFileFlag==1) { - if (funct&AR_EXT_TO_FILE) - extractToFile(&arEntry, funct, arFd, "./"); - else - copySubFile(arFd,fileno(stdout),arEntry.size); - } - else - lseek(arFd, arEntry.size, SEEK_CUR); - lastOffset=lseek(arFd, 0, SEEK_CUR); - } /* if processArHeader */ - } /* while */ - return (TRUE); +static int extractAr(int srcFd, int dstFd, const char filename[16]) +{ + headerL_t *file; + + if ( (file = getSubFileHeader(srcFd, filename)) == NULL) + return(FALSE); + 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, ret=0, i=0; - char *fileList[16], c, *opt_ptr; - - if (argc < 2) - usage(ar_usage); - - opt_ptr = argv[1]; - if (*opt_ptr == '-') - ++opt_ptr; - while ((c = *opt_ptr++) != '\0') { - switch (c) { + int funct = 0, opt=0; + int srcFd=0, dstFd=0; + + while ((opt = getopt(argc, argv, "ovt:p:x:")) != -1) { + switch (opt) { case 'o': - funct = funct | AR_PRESERVE_DATE; + funct = funct | PRESERVE_DATE; break; case 'v': - funct = funct | AR_VERBOSE; + funct = funct | VERBOSE; break; case 't': - funct = funct | AR_DISPLAY; - break; + funct = funct | DISPLAY; case 'x': - funct = funct | AR_EXT_TO_FILE; - break; + if (opt=='x') { + funct = funct | EXT_TO_FILE; + } case 'p': - funct = funct | AR_EXT_TO_STDOUT; + if (opt=='p') { + funct = funct | EXT_TO_STDOUT; + } + /* following is common to 't','x' and 'p' */ + if (optarg == NULL) { + printf("expected a filename\n"); + return(FALSE); + } + if ( (srcFd = open(optarg, O_RDONLY)) < 0) { + errorMsg("Cannot read %s\n", optarg); + return (FALSE); + } break; default: usage(ar_usage); } } - - for(i=0; i<(argc-2); i++) - fileList[i]=argv[i+2]; + + /* check options not just preserve_dates and/or verbose */ + if (funct < 4) { + usage(ar_usage); + return(FALSE); + } - if (funct > 3) - ret = readArFile(fileList, (argc-2), funct); - - return (ret); + /* find files to extract */ + if (optind outTotal) { - if (outTotal + inCc > count * blockSize) - inCc = count * blockSize - outTotal; - outCc = write(outFd, cp, inCc); - if (outCc < 0) { - perror(outFile); - goto cleanup; - } else if (outCc == 0) { - goto cleanup; - } + while ((inCc = read(inFd, buf, sizeof(buf))) > 0) { + intotal +=inCc; + if ((outCc = fullWrite(outFd, buf, inCc)) < 0) + break; + outTotal += outCc; + } - inCc -= outCc; - cp += outCc; - outTotal += outCc; - } - } - - if (inCc < 0) - perror(inFile); - - cleanup: /* Note that we are not freeing memory or closing * files here, to save a few bytes. */ #ifdef BB_FEATURE_CLEAN_UP diff --git a/dd.c b/dd.c index 6df2588ca..787e5da95 100644 --- a/dd.c +++ b/dd.c @@ -44,7 +44,6 @@ extern int dd_main(int argc, char **argv) { char *inFile = NULL; char *outFile = NULL; - char *cp; int inFd; int outFd; int inCc = 0; @@ -135,42 +134,14 @@ extern int dd_main(int argc, char **argv) lseek(inFd, skipBlocks * blockSize, SEEK_SET); lseek(outFd, seekBlocks * blockSize, SEEK_SET); - // - //TODO: Convert to using fullRead & fullWrite - // from utility.c - // -Erik - while (outTotal < count * blockSize) { - inCc = read(inFd, buf, blockSize); - if (inCc < 0) { - perror(inFile); - goto cleanup; - } else if (inCc == 0) { - goto cleanup; - } - intotal += inCc; - cp = buf; - while (intotal > outTotal) { - if (outTotal + inCc > count * blockSize) - inCc = count * blockSize - outTotal; - outCc = write(outFd, cp, inCc); - if (outCc < 0) { - perror(outFile); - goto cleanup; - } else if (outCc == 0) { - goto cleanup; - } + while ((inCc = read(inFd, buf, sizeof(buf))) > 0) { + intotal +=inCc; + if ((outCc = fullWrite(outFd, buf, inCc)) < 0) + break; + outTotal += outCc; + } - inCc -= outCc; - cp += outCc; - outTotal += outCc; - } - } - - if (inCc < 0) - perror(inFile); - - cleanup: /* Note that we are not freeing memory or closing * files here, to save a few bytes. */ #ifdef BB_FEATURE_CLEAN_UP diff --git a/internal.h b/internal.h index ab0d94fb8..f6edb1666 100644 --- a/internal.h +++ b/internal.h @@ -345,6 +345,7 @@ void reset_ino_dev_hashtable(void); int copyFile(const char *srcName, const char *destName, int setModes, int followLinks, int forceFlag); +int copySubFile(int srcFd, int dstFd, size_t remaining); char *buildName(const char *dirName, const char *fileName); int makeString(int argc, const char **argv, char *buf, int bufLen); char *getChunk(int size); diff --git a/usage.c b/usage.c index 0dad1ba30..35f63db86 100644 --- a/usage.c +++ b/usage.c @@ -2,15 +2,15 @@ #if defined BB_AR const char ar_usage[] = - "ar [optxvV] archive [filenames] \n" + "ar [[-ov] -tpv archive] filenames \n" #ifndef BB_FEATURE_TRIVIAL_HELP "\nExtract or list files from an ar archive.\n\n" "Options:\n" - "\to\t\tpreserve original dates\n" - "\tp\t\textract to stdout\n" - "\tt\t\tlist\n" - "\tx\t\textract\n" - "\tv\t\tverbosely list files processed\n" + "\t-o\t\tpreserve original dates\n" + "\t-p\t\textract to stdout\n" + "\t-t\t\tlist\n" + "\t-x\t\textract\n" + "\t-v\t\tverbosely list files processed\n" #endif ; #endif diff --git a/utility.c b/utility.c index de0311d17..2851dd20d 100644 --- a/utility.c +++ b/utility.c @@ -231,7 +231,7 @@ void reset_ino_dev_hashtable(void) #endif /* BB_CP_MV || BB_DU */ -#if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN) || defined (BB_AR) +#if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN) /* * Return TRUE if a fileName is a directory. * Nonexistant files return FALSE. @@ -264,6 +264,29 @@ int isDirectory(const char *fileName, const int followLinks, struct stat *statBu } #endif +#if defined (BB_AR) +/* + * Copy readSize bytes between two file descriptors + */ +int copySubFile(int srcFd, int dstFd, size_t remaining) +{ + size_t size; + char buffer[BUFSIZ]; + + while (remaining > 0) { + if (remaining > BUFSIZ) + size = BUFSIZ; + else + size = remaining; + if (fullWrite(dstFd, buffer, fullRead(srcFd, buffer, size)) < size) + return(FALSE); + remaining -= size; + } + return (TRUE); +} +#endif + + #if defined (BB_CP_MV) /* * Copy one file to another, while possibly preserving its modes, times, and @@ -277,9 +300,7 @@ copyFile(const char *srcName, const char *destName, { int rfd; int wfd; - int rcc; int status; - char buf[BUF_SIZE]; struct stat srcStatBuf; struct stat dstStatBuf; struct utimbuf times; @@ -364,8 +385,7 @@ copyFile(const char *srcName, const char *destName, return FALSE; } - wfd = - open(destName, O_WRONLY | O_CREAT | O_TRUNC, + wfd = open(destName, O_WRONLY | O_CREAT | O_TRUNC, srcStatBuf.st_mode); if (wfd < 0) { perror(destName); @@ -373,14 +393,9 @@ copyFile(const char *srcName, const char *destName, return FALSE; } - while ((rcc = read(rfd, buf, sizeof(buf))) > 0) { - if (fullWrite(wfd, buf, rcc) < 0) - goto error_exit; - } - if (rcc < 0) { - goto error_exit; - } - + if (copySubFile(rfd, wfd, srcStatBuf.st_size)==FALSE) + goto error_exit; + close(rfd); if (close(wfd) < 0) { return FALSE; @@ -677,7 +692,7 @@ int recursiveAction(const char *fileName, -#if defined (BB_TAR) || defined (BB_MKDIR) || defined (BB_AR) +#if defined (BB_TAR) || defined (BB_MKDIR) /* * Attempt to create the directories along the specified path, except for * the final component. The mode is given for the final directory only, @@ -1292,7 +1307,7 @@ extern long getNum(const char *cp) #endif /* BB_DD || BB_TAIL */ -#if defined BB_INIT || defined BB_SYSLOGD || defined BB_AR +#if defined BB_INIT || defined BB_SYSLOGD /* try to open up the specified device */ extern int device_open(char *device, int mode) {