mirror of
https://github.com/sheumann/hush.git
synced 2024-12-22 14:30:31 +00:00
Update to ar.c from Glenn McGrath. His comments follow:
------------------------------ the attached diff applies to the ar.c i originally submitted Changes Preserve dates now works. Extracted files are set to the uid, gid and mode specified in the archive. Checks for valid end of header marker. Correctly unpacks newer debian files. (has a '\n' character between entries) Added more comments. Cleaned up code. Added a last modified date to help keep track of versions. TODO Common functionality in ar.c are in tar.c should be merged, in particular getOctal and extractSubFile. Should all functions that are used by multiple file go in utilities.c ?
This commit is contained in:
parent
b991395405
commit
852ff13fc4
195
ar.c
195
ar.c
@ -21,6 +21,7 @@
|
|||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
|
* Last modified 10 June 2000
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -28,9 +29,18 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
#define AR_BLOCK_SIZE 60
|
#define AR_BLOCK_SIZE 60
|
||||||
|
#define AR_PRESERVE_DATE 1
|
||||||
|
#define AR_VERBOSE 2
|
||||||
|
#define AR_DISPLAY 4
|
||||||
|
#define AR_EXT_TO_FILE 8
|
||||||
|
#define AR_EXT_TO_STDOUT 16
|
||||||
|
|
||||||
#define BB_DECLARE_EXTERN
|
#define BB_DECLARE_EXTERN
|
||||||
#define bb_need_io_error
|
#define bb_need_io_error
|
||||||
#include "messages.c"
|
#include "messages.c"
|
||||||
@ -67,22 +77,50 @@ static const char ar_usage[] = "ar [optxvV] archive [filenames] \n"
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
static void displayContents(struct ArInfo *entry, int funct)
|
/*
|
||||||
|
* Display details of a file, verbosly if funct=2
|
||||||
|
*/
|
||||||
|
static void displayEntry(struct ArInfo *entry, int funct)
|
||||||
{
|
{
|
||||||
/* TODO convert mode to string */
|
/* TODO convert mode to string */
|
||||||
if ((funct & 2) == 2)
|
if ((funct & AR_VERBOSE) == AR_VERBOSE)
|
||||||
printf("%i %i/%i %6i %s ", entry->mode, entry->uid, entry->gid,
|
printf("%i %i/%i %8i %s ", entry->mode, entry->uid, entry->gid,
|
||||||
entry->size, timeString(entry->date));
|
entry->size, timeString(entry->date));
|
||||||
printf("%s\n", entry->name);
|
printf("%s\n", entry->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts to new typed struct */
|
/* this is from tar.c remove later*/
|
||||||
static int readArHeader(struct ArHeader *rawHeader, struct ArInfo *header)
|
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 count2;
|
||||||
int count;
|
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++) {
|
for (count = 0; count < 16; count++) {
|
||||||
|
/* allow spaces in filename except at the end */
|
||||||
if (rawHeader->ar_name[count] == ' ') {
|
if (rawHeader->ar_name[count] == ' ') {
|
||||||
for (count2 = count; count2 < 16; count2++)
|
for (count2 = count; count2 < 16; count2++)
|
||||||
if (!isspace(rawHeader->ar_name[count2]))
|
if (!isspace(rawHeader->ar_name[count2]))
|
||||||
@ -90,6 +128,7 @@ static int readArHeader(struct ArHeader *rawHeader, struct ArInfo *header)
|
|||||||
if (count2 >= 16)
|
if (count2 >= 16)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* GNU ar uses '/' as an end of filename marker */
|
||||||
if (rawHeader->ar_name[count] == '/')
|
if (rawHeader->ar_name[count] == '/')
|
||||||
break;
|
break;
|
||||||
header->name[count] = rawHeader->ar_name[count];
|
header->name[count] = rawHeader->ar_name[count];
|
||||||
@ -98,15 +137,14 @@ static int readArHeader(struct ArHeader *rawHeader, struct ArInfo *header)
|
|||||||
header->date = atoi(rawHeader->ar_date);
|
header->date = atoi(rawHeader->ar_date);
|
||||||
header->uid = atoi(rawHeader->ar_uid);
|
header->uid = atoi(rawHeader->ar_uid);
|
||||||
header->gid = atoi(rawHeader->ar_gid);
|
header->gid = atoi(rawHeader->ar_gid);
|
||||||
header->mode = atoi(rawHeader->ar_mode);
|
header->mode = getOctal(rawHeader->ar_mode, sizeof(rawHeader->ar_mode));
|
||||||
header->size = atoi(rawHeader->ar_size);
|
header->size = atoi(rawHeader->ar_size);
|
||||||
return (TRUE);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy size bytes from current position if srcFd to current position in dstFd
|
* Copy size bytes from current position if srcFd to current position in dstFd
|
||||||
* taken from tarExtractRegularFile in tar.c
|
* taken from tarExtractRegularFile in tar.c, remove later
|
||||||
* could be used for ar, tar and copyFile .
|
|
||||||
*/
|
*/
|
||||||
static int copySubFile(int srcFd, int dstFd, int copySize)
|
static int copySubFile(int srcFd, int dstFd, int copySize)
|
||||||
{
|
{
|
||||||
@ -134,16 +172,15 @@ static int copySubFile(int srcFd, int dstFd, int copySize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to add checks, stat newfile before creation,change mode from 0777
|
* Extract the file described in ArInfo to the specified path
|
||||||
* extract to current dir
|
* set the new files uid, gid and mode
|
||||||
* dstStat.st_size copied from current position of file pointed to by srcFd
|
|
||||||
*/
|
*/
|
||||||
static int extractToFile(int srcFd, const char *path, const char *name,
|
static int extractToFile(struct ArInfo *file, int funct, int srcFd, const char *path)
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
int dstFd, temp;
|
int dstFd, temp;
|
||||||
struct stat tmpStat;
|
struct stat tmpStat;
|
||||||
char *pathname = NULL;
|
char *pathname = NULL;
|
||||||
|
struct utimbuf newtime;
|
||||||
|
|
||||||
if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) {
|
if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) {
|
||||||
if (!createPath(path, 0777)) {
|
if (!createPath(path, 0777)) {
|
||||||
@ -154,51 +191,32 @@ static int extractToFile(int srcFd, const char *path, const char *name,
|
|||||||
temp = (strlen(path) + 16);
|
temp = (strlen(path) + 16);
|
||||||
pathname = (char *) xmalloc(temp);
|
pathname = (char *) xmalloc(temp);
|
||||||
pathname = strcpy(pathname, path);
|
pathname = strcpy(pathname, path);
|
||||||
pathname = strcat(pathname, &name[0]);
|
pathname = strcat(pathname, file->name);
|
||||||
dstFd = device_open(pathname, O_WRONLY | O_CREAT);
|
dstFd = device_open(pathname, O_WRONLY | O_CREAT);
|
||||||
pathname = NULL;
|
temp = copySubFile(srcFd, dstFd, file->size);
|
||||||
temp = copySubFile(srcFd, dstFd, size);
|
fchown(dstFd, file->uid, file->gid);
|
||||||
|
fchmod(dstFd, file->mode);
|
||||||
close(dstFd);
|
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 (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step through the ar file entries */
|
/*
|
||||||
static int readArFile(char **fileNames, int argc, int funct)
|
* Return a file descriptor for the specified file and do error checks
|
||||||
|
*/
|
||||||
|
static int getArFd(char *filename)
|
||||||
{
|
{
|
||||||
int arFd = 0;
|
int arFd;
|
||||||
int pdates = 0;
|
|
||||||
int verbose = 0;
|
|
||||||
int display = 0;
|
|
||||||
int extract = 0;
|
|
||||||
int extToStdout = 0;
|
|
||||||
int status = 0;
|
|
||||||
int found = 0;
|
|
||||||
ArHeader rawArHeader;
|
|
||||||
ArInfo arEntry;
|
|
||||||
char arVersion[8];
|
char arVersion[8];
|
||||||
char *arName;
|
|
||||||
char *selName[argc - 2];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ((funct & 1) == 1)
|
arFd = open(filename, O_RDONLY);
|
||||||
pdates = 1;
|
|
||||||
if ((funct & 2) == 2)
|
|
||||||
verbose = 1;
|
|
||||||
if ((funct & 4) == 4)
|
|
||||||
display = 1;
|
|
||||||
if ((funct & 16) == 16) { /* extract to stdout */
|
|
||||||
extract = 1;
|
|
||||||
extToStdout = 1;
|
|
||||||
}
|
|
||||||
if ((funct & 8) == 8) { /* extract to file */
|
|
||||||
extract = 1;
|
|
||||||
}
|
|
||||||
arName = fileNames[2];
|
|
||||||
for (i = 0; i < (argc - 3); i++)
|
|
||||||
selName[i] = fileNames[i + 3];
|
|
||||||
arFd = open(arName, O_RDONLY);
|
|
||||||
if (arFd < 0) {
|
if (arFd < 0) {
|
||||||
errorMsg("Error opening '%s': %s\n", arName, strerror(errno));
|
errorMsg("Error opening '%s': %s\n", filename, strerror(errno));
|
||||||
return (FALSE);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
if (fullRead(arFd, arVersion, 8) <= 0) {
|
if (fullRead(arFd, arVersion, 8) <= 0) {
|
||||||
@ -209,40 +227,72 @@ static int readArFile(char **fileNames, int argc, int funct)
|
|||||||
errorMsg("ar header fails check ");
|
errorMsg("ar header fails check ");
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
return arFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
static int readArFile(char *fileList[16], int fileListSize, int funct)
|
||||||
|
{
|
||||||
|
int arFd, status, extFileFlag, i, lastOffset=0;
|
||||||
|
ArHeader rawArHeader;
|
||||||
|
ArInfo arEntry;
|
||||||
|
|
||||||
|
/* open the ar archive */
|
||||||
|
arFd=getArFd(fileList[0]);
|
||||||
|
|
||||||
|
/* read the first header, then loop until ono more headers */
|
||||||
while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE))
|
while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE))
|
||||||
== AR_BLOCK_SIZE) {
|
== AR_BLOCK_SIZE) {
|
||||||
readArHeader(&rawArHeader, &arEntry);
|
|
||||||
|
|
||||||
if (display == 1) {
|
/* check the header is valid, if not try reading the header
|
||||||
displayContents(&arEntry, funct);
|
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);
|
||||||
}
|
}
|
||||||
if (argc == 3)
|
|
||||||
found = 1;
|
|
||||||
else {
|
else {
|
||||||
found = 0;
|
extFileFlag=0;
|
||||||
for (i = 0; i < (argc - 3); i++) {
|
|
||||||
if ((status = (strcmp(selName[i], arEntry.name))) == 0)
|
if (funct&AR_DISPLAY)
|
||||||
found = 1;
|
displayEntry(&arEntry, funct);
|
||||||
|
|
||||||
|
/* 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 ((extract == 1) && (found == 1)) {
|
if (extFileFlag==1) {
|
||||||
if (extToStdout == 1) {
|
if (funct&AR_EXT_TO_FILE)
|
||||||
|
extractToFile(&arEntry, funct, arFd, "./");
|
||||||
|
else
|
||||||
copySubFile(arFd,fileno(stdout),arEntry.size);
|
copySubFile(arFd,fileno(stdout),arEntry.size);
|
||||||
} else {
|
|
||||||
extractToFile(arFd, "./", arEntry.name, arEntry.size);
|
|
||||||
}
|
}
|
||||||
} else
|
else
|
||||||
lseek(arFd, arEntry.size, SEEK_CUR);
|
lseek(arFd, arEntry.size, SEEK_CUR);
|
||||||
}
|
lastOffset=lseek(arFd, 0, SEEK_CUR);
|
||||||
return (0);
|
} /* if processArHeader */
|
||||||
|
} /* while */
|
||||||
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int ar_main(int argc, char **argv)
|
extern int ar_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int funct = 0, ret=0, i=0;
|
||||||
char *opt_ptr;
|
char *fileList[16], c, *opt_ptr;
|
||||||
char c;
|
|
||||||
int funct = 0;
|
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
usage(ar_usage);
|
usage(ar_usage);
|
||||||
@ -271,7 +321,12 @@ extern int ar_main(int argc, char **argv)
|
|||||||
usage(ar_usage);
|
usage(ar_usage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(i=0; i<(argc-2); i++)
|
||||||
|
fileList[i]=argv[i+2];
|
||||||
|
|
||||||
if (funct > 3)
|
if (funct > 3)
|
||||||
ret = readArFile(argv, argc, funct);
|
ret = readArFile(fileList, (argc-2), funct);
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
195
archival/ar.c
195
archival/ar.c
@ -21,6 +21,7 @@
|
|||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
|
* Last modified 10 June 2000
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -28,9 +29,18 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
#define AR_BLOCK_SIZE 60
|
#define AR_BLOCK_SIZE 60
|
||||||
|
#define AR_PRESERVE_DATE 1
|
||||||
|
#define AR_VERBOSE 2
|
||||||
|
#define AR_DISPLAY 4
|
||||||
|
#define AR_EXT_TO_FILE 8
|
||||||
|
#define AR_EXT_TO_STDOUT 16
|
||||||
|
|
||||||
#define BB_DECLARE_EXTERN
|
#define BB_DECLARE_EXTERN
|
||||||
#define bb_need_io_error
|
#define bb_need_io_error
|
||||||
#include "messages.c"
|
#include "messages.c"
|
||||||
@ -67,22 +77,50 @@ static const char ar_usage[] = "ar [optxvV] archive [filenames] \n"
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
static void displayContents(struct ArInfo *entry, int funct)
|
/*
|
||||||
|
* Display details of a file, verbosly if funct=2
|
||||||
|
*/
|
||||||
|
static void displayEntry(struct ArInfo *entry, int funct)
|
||||||
{
|
{
|
||||||
/* TODO convert mode to string */
|
/* TODO convert mode to string */
|
||||||
if ((funct & 2) == 2)
|
if ((funct & AR_VERBOSE) == AR_VERBOSE)
|
||||||
printf("%i %i/%i %6i %s ", entry->mode, entry->uid, entry->gid,
|
printf("%i %i/%i %8i %s ", entry->mode, entry->uid, entry->gid,
|
||||||
entry->size, timeString(entry->date));
|
entry->size, timeString(entry->date));
|
||||||
printf("%s\n", entry->name);
|
printf("%s\n", entry->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts to new typed struct */
|
/* this is from tar.c remove later*/
|
||||||
static int readArHeader(struct ArHeader *rawHeader, struct ArInfo *header)
|
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 count2;
|
||||||
int count;
|
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++) {
|
for (count = 0; count < 16; count++) {
|
||||||
|
/* allow spaces in filename except at the end */
|
||||||
if (rawHeader->ar_name[count] == ' ') {
|
if (rawHeader->ar_name[count] == ' ') {
|
||||||
for (count2 = count; count2 < 16; count2++)
|
for (count2 = count; count2 < 16; count2++)
|
||||||
if (!isspace(rawHeader->ar_name[count2]))
|
if (!isspace(rawHeader->ar_name[count2]))
|
||||||
@ -90,6 +128,7 @@ static int readArHeader(struct ArHeader *rawHeader, struct ArInfo *header)
|
|||||||
if (count2 >= 16)
|
if (count2 >= 16)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* GNU ar uses '/' as an end of filename marker */
|
||||||
if (rawHeader->ar_name[count] == '/')
|
if (rawHeader->ar_name[count] == '/')
|
||||||
break;
|
break;
|
||||||
header->name[count] = rawHeader->ar_name[count];
|
header->name[count] = rawHeader->ar_name[count];
|
||||||
@ -98,15 +137,14 @@ static int readArHeader(struct ArHeader *rawHeader, struct ArInfo *header)
|
|||||||
header->date = atoi(rawHeader->ar_date);
|
header->date = atoi(rawHeader->ar_date);
|
||||||
header->uid = atoi(rawHeader->ar_uid);
|
header->uid = atoi(rawHeader->ar_uid);
|
||||||
header->gid = atoi(rawHeader->ar_gid);
|
header->gid = atoi(rawHeader->ar_gid);
|
||||||
header->mode = atoi(rawHeader->ar_mode);
|
header->mode = getOctal(rawHeader->ar_mode, sizeof(rawHeader->ar_mode));
|
||||||
header->size = atoi(rawHeader->ar_size);
|
header->size = atoi(rawHeader->ar_size);
|
||||||
return (TRUE);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy size bytes from current position if srcFd to current position in dstFd
|
* Copy size bytes from current position if srcFd to current position in dstFd
|
||||||
* taken from tarExtractRegularFile in tar.c
|
* taken from tarExtractRegularFile in tar.c, remove later
|
||||||
* could be used for ar, tar and copyFile .
|
|
||||||
*/
|
*/
|
||||||
static int copySubFile(int srcFd, int dstFd, int copySize)
|
static int copySubFile(int srcFd, int dstFd, int copySize)
|
||||||
{
|
{
|
||||||
@ -134,16 +172,15 @@ static int copySubFile(int srcFd, int dstFd, int copySize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to add checks, stat newfile before creation,change mode from 0777
|
* Extract the file described in ArInfo to the specified path
|
||||||
* extract to current dir
|
* set the new files uid, gid and mode
|
||||||
* dstStat.st_size copied from current position of file pointed to by srcFd
|
|
||||||
*/
|
*/
|
||||||
static int extractToFile(int srcFd, const char *path, const char *name,
|
static int extractToFile(struct ArInfo *file, int funct, int srcFd, const char *path)
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
int dstFd, temp;
|
int dstFd, temp;
|
||||||
struct stat tmpStat;
|
struct stat tmpStat;
|
||||||
char *pathname = NULL;
|
char *pathname = NULL;
|
||||||
|
struct utimbuf newtime;
|
||||||
|
|
||||||
if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) {
|
if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) {
|
||||||
if (!createPath(path, 0777)) {
|
if (!createPath(path, 0777)) {
|
||||||
@ -154,51 +191,32 @@ static int extractToFile(int srcFd, const char *path, const char *name,
|
|||||||
temp = (strlen(path) + 16);
|
temp = (strlen(path) + 16);
|
||||||
pathname = (char *) xmalloc(temp);
|
pathname = (char *) xmalloc(temp);
|
||||||
pathname = strcpy(pathname, path);
|
pathname = strcpy(pathname, path);
|
||||||
pathname = strcat(pathname, &name[0]);
|
pathname = strcat(pathname, file->name);
|
||||||
dstFd = device_open(pathname, O_WRONLY | O_CREAT);
|
dstFd = device_open(pathname, O_WRONLY | O_CREAT);
|
||||||
pathname = NULL;
|
temp = copySubFile(srcFd, dstFd, file->size);
|
||||||
temp = copySubFile(srcFd, dstFd, size);
|
fchown(dstFd, file->uid, file->gid);
|
||||||
|
fchmod(dstFd, file->mode);
|
||||||
close(dstFd);
|
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 (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step through the ar file entries */
|
/*
|
||||||
static int readArFile(char **fileNames, int argc, int funct)
|
* Return a file descriptor for the specified file and do error checks
|
||||||
|
*/
|
||||||
|
static int getArFd(char *filename)
|
||||||
{
|
{
|
||||||
int arFd = 0;
|
int arFd;
|
||||||
int pdates = 0;
|
|
||||||
int verbose = 0;
|
|
||||||
int display = 0;
|
|
||||||
int extract = 0;
|
|
||||||
int extToStdout = 0;
|
|
||||||
int status = 0;
|
|
||||||
int found = 0;
|
|
||||||
ArHeader rawArHeader;
|
|
||||||
ArInfo arEntry;
|
|
||||||
char arVersion[8];
|
char arVersion[8];
|
||||||
char *arName;
|
|
||||||
char *selName[argc - 2];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ((funct & 1) == 1)
|
arFd = open(filename, O_RDONLY);
|
||||||
pdates = 1;
|
|
||||||
if ((funct & 2) == 2)
|
|
||||||
verbose = 1;
|
|
||||||
if ((funct & 4) == 4)
|
|
||||||
display = 1;
|
|
||||||
if ((funct & 16) == 16) { /* extract to stdout */
|
|
||||||
extract = 1;
|
|
||||||
extToStdout = 1;
|
|
||||||
}
|
|
||||||
if ((funct & 8) == 8) { /* extract to file */
|
|
||||||
extract = 1;
|
|
||||||
}
|
|
||||||
arName = fileNames[2];
|
|
||||||
for (i = 0; i < (argc - 3); i++)
|
|
||||||
selName[i] = fileNames[i + 3];
|
|
||||||
arFd = open(arName, O_RDONLY);
|
|
||||||
if (arFd < 0) {
|
if (arFd < 0) {
|
||||||
errorMsg("Error opening '%s': %s\n", arName, strerror(errno));
|
errorMsg("Error opening '%s': %s\n", filename, strerror(errno));
|
||||||
return (FALSE);
|
return (FALSE);
|
||||||
}
|
}
|
||||||
if (fullRead(arFd, arVersion, 8) <= 0) {
|
if (fullRead(arFd, arVersion, 8) <= 0) {
|
||||||
@ -209,40 +227,72 @@ static int readArFile(char **fileNames, int argc, int funct)
|
|||||||
errorMsg("ar header fails check ");
|
errorMsg("ar header fails check ");
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
return arFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
static int readArFile(char *fileList[16], int fileListSize, int funct)
|
||||||
|
{
|
||||||
|
int arFd, status, extFileFlag, i, lastOffset=0;
|
||||||
|
ArHeader rawArHeader;
|
||||||
|
ArInfo arEntry;
|
||||||
|
|
||||||
|
/* open the ar archive */
|
||||||
|
arFd=getArFd(fileList[0]);
|
||||||
|
|
||||||
|
/* read the first header, then loop until ono more headers */
|
||||||
while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE))
|
while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE))
|
||||||
== AR_BLOCK_SIZE) {
|
== AR_BLOCK_SIZE) {
|
||||||
readArHeader(&rawArHeader, &arEntry);
|
|
||||||
|
|
||||||
if (display == 1) {
|
/* check the header is valid, if not try reading the header
|
||||||
displayContents(&arEntry, funct);
|
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);
|
||||||
}
|
}
|
||||||
if (argc == 3)
|
|
||||||
found = 1;
|
|
||||||
else {
|
else {
|
||||||
found = 0;
|
extFileFlag=0;
|
||||||
for (i = 0; i < (argc - 3); i++) {
|
|
||||||
if ((status = (strcmp(selName[i], arEntry.name))) == 0)
|
if (funct&AR_DISPLAY)
|
||||||
found = 1;
|
displayEntry(&arEntry, funct);
|
||||||
|
|
||||||
|
/* 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 ((extract == 1) && (found == 1)) {
|
if (extFileFlag==1) {
|
||||||
if (extToStdout == 1) {
|
if (funct&AR_EXT_TO_FILE)
|
||||||
|
extractToFile(&arEntry, funct, arFd, "./");
|
||||||
|
else
|
||||||
copySubFile(arFd,fileno(stdout),arEntry.size);
|
copySubFile(arFd,fileno(stdout),arEntry.size);
|
||||||
} else {
|
|
||||||
extractToFile(arFd, "./", arEntry.name, arEntry.size);
|
|
||||||
}
|
}
|
||||||
} else
|
else
|
||||||
lseek(arFd, arEntry.size, SEEK_CUR);
|
lseek(arFd, arEntry.size, SEEK_CUR);
|
||||||
}
|
lastOffset=lseek(arFd, 0, SEEK_CUR);
|
||||||
return (0);
|
} /* if processArHeader */
|
||||||
|
} /* while */
|
||||||
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int ar_main(int argc, char **argv)
|
extern int ar_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int funct = 0, ret=0, i=0;
|
||||||
char *opt_ptr;
|
char *fileList[16], c, *opt_ptr;
|
||||||
char c;
|
|
||||||
int funct = 0;
|
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
usage(ar_usage);
|
usage(ar_usage);
|
||||||
@ -271,7 +321,12 @@ extern int ar_main(int argc, char **argv)
|
|||||||
usage(ar_usage);
|
usage(ar_usage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(i=0; i<(argc-2); i++)
|
||||||
|
fileList[i]=argv[i+2];
|
||||||
|
|
||||||
if (funct > 3)
|
if (funct > 3)
|
||||||
ret = readArFile(argv, argc, funct);
|
ret = readArFile(fileList, (argc-2), funct);
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user