aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn L McGrath <bug1@ihug.co.nz>2000-08-25 03:50:10 +0000
committerGlenn L McGrath <bug1@ihug.co.nz>2000-08-25 03:50:10 +0000
commit06aeb6c417dd9d113949714486a6e6337ef70b97 (patch)
tree0f002c36314483775fa2a248ae1c8b5346c70030
parent4d5ac2f346d01e51cde9c44431067138bd586f36 (diff)
downloadbusybox-w32-06aeb6c417dd9d113949714486a6e6337ef70b97.tar.gz
busybox-w32-06aeb6c417dd9d113949714486a6e6337ef70b97.tar.bz2
busybox-w32-06aeb6c417dd9d113949714486a6e6337ef70b97.zip
ar.c now uses a linked list to process headers, uses getopt, new internal function extractAr(srcFD, dstFd, filename) to make it easily accessable to other busybox functions.
moved copySubFile from ar.c to utilities.c modified dd.c to use fullWrite modified copyFile in utilities.c to use copySubFile
-rw-r--r--applets/usage.c12
-rw-r--r--ar.c384
-rw-r--r--archival/ar.c384
-rw-r--r--coreutils/dd.c41
-rw-r--r--dd.c41
-rw-r--r--internal.h1
-rw-r--r--usage.c12
-rw-r--r--utility.c45
8 files changed, 335 insertions, 585 deletions
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 @@
2 2
3#if defined BB_AR 3#if defined BB_AR
4const char ar_usage[] = 4const char ar_usage[] =
5 "ar [optxvV] archive [filenames] \n" 5 "ar [[-ov] -tpv archive] filenames \n"
6#ifndef BB_FEATURE_TRIVIAL_HELP 6#ifndef BB_FEATURE_TRIVIAL_HELP
7 "\nExtract or list files from an ar archive.\n\n" 7 "\nExtract or list files from an ar archive.\n\n"
8 "Options:\n" 8 "Options:\n"
9 "\to\t\tpreserve original dates\n" 9 "\t-o\t\tpreserve original dates\n"
10 "\tp\t\textract to stdout\n" 10 "\t-p\t\textract to stdout\n"
11 "\tt\t\tlist\n" 11 "\t-t\t\tlist\n"
12 "\tx\t\textract\n" 12 "\t-x\t\textract\n"
13 "\tv\t\tverbosely list files processed\n" 13 "\t-v\t\tverbosely list files processed\n"
14#endif 14#endif
15 ; 15 ;
16#endif 16#endif
diff --git a/ar.c b/ar.c
index b1200b8ae..1c598fa16 100644
--- a/ar.c
+++ b/ar.c
@@ -4,6 +4,12 @@
4 * 4 *
5 * Copyright (C) 2000 by Glenn McGrath 5 * Copyright (C) 2000 by Glenn McGrath
6 * Written by Glenn McGrath <bug1@netconnect.com.au> 1 June 2000 6 * Written by Glenn McGrath <bug1@netconnect.com.au> 1 June 2000
7 *
8 * Modified 8 August 2000 by Glenn McGrath
9 * - now uses getopt
10 * - moved copySubFile function to utilities.c
11 * - creates linked list of all headers
12 * - easily accessable to other busybox functions
7 * 13 *
8 * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. 14 * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
9 * 15 *
@@ -21,10 +27,8 @@
21 * along with this program; if not, write to the Free Software 27 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * 29 *
24 * Last modified 10 June 2000 30 * Last modified 25 August 2000
25 */ 31 */
26
27
28#include <stdio.h> 32#include <stdio.h>
29#include <fcntl.h> 33#include <fcntl.h>
30#include <errno.h> 34#include <errno.h>
@@ -34,287 +38,179 @@
34#include <sys/types.h> 38#include <sys/types.h>
35#include "internal.h" 39#include "internal.h"
36 40
37#define AR_BLOCK_SIZE 60 41#define BLOCK_SIZE 60
38#define AR_PRESERVE_DATE 1 /* preserve original dates */ 42#define PRESERVE_DATE 1 /* preserve original dates */
39#define AR_VERBOSE 2 /* be verbose */ 43#define VERBOSE 2 /* be verbose */
40#define AR_DISPLAY 4 /* display contents */ 44#define DISPLAY 4 /* display contents */
41#define AR_EXT_TO_FILE 8 /* extract contents of archive */ 45#define EXT_TO_FILE 8 /* extract contents of archive */
42#define AR_EXT_TO_STDOUT 16 /* extract to stdout */ 46#define EXT_TO_STDOUT 16 /* extract to stdout */
43 47
44#define BB_DECLARE_EXTERN 48#define BB_DECLARE_EXTERN
45#define bb_need_io_error 49#define bb_need_io_error
46#include "messages.c" 50#include "messages.c"
47 51
48struct ArHeader { /* Byte Offset */ 52typedef struct rawArHeader { /* Byte Offset */
49 char ar_name[16]; /* 0-15 */ 53 char name[16]; /* 0-15 */
50 char ar_date[12]; /* 16-27 */ 54 char date[12]; /* 16-27 */
51 char ar_uid[6], ar_gid[6]; /* 28-39 */ 55 char uid[6], gid[6]; /* 28-39 */
52 char ar_mode[8]; /* 40-47 */ 56 char mode[8]; /* 40-47 */
53 char ar_size[10]; /* 48-57 */ 57 char size[10]; /* 48-57 */
54 char ar_fmag[2]; /* 58-59 */ 58 char fmag[2]; /* 58-59 */
55}; 59} rawArHeader_t;
56typedef struct ArHeader ArHeader; 60
57 61typedef struct headerL {
58struct ArInfo { 62 char name[16];
59 char name[17]; /* File name */ 63 size_t size;
60 time_t date; /* long int, No of seconds since epoch */ 64 uid_t uid;
61 uid_t uid; /* unsigned int, Numeric UID */ 65 gid_t gid;
62 gid_t gid; /* unsigned int, Numeric GID */ 66 mode_t mode;
63 mode_t mode; /* unsigned int, Unix mode */ 67 time_t mtime;
64 size_t size; /* int, Size of the file */ 68 off_t offset;
65}; 69 struct headerL *next;
66typedef struct ArInfo ArInfo; 70} headerL_t;
67 71
68/* 72/*
69 * Display details of a file, verbosly if funct=2 73 * populate linked list with all ar file entries and offset
70 */ 74 */
71static void displayEntry(struct ArInfo *entry, int funct) 75static int parseArArchive(int srcFd, headerL_t *current)
72{ 76{
73 /* TODO convert mode to string */ 77 off_t lastOffset=0, thisOffset=0;
74 if ((funct & AR_VERBOSE) == AR_VERBOSE) 78 char arVersion[8];
75 printf("%i %i/%i %8i %s ", entry->mode, entry->uid, entry->gid, 79 rawArHeader_t rawArHeader;
76 entry->size, timeString(entry->date)); 80
77 printf("%s\n", entry->name); 81 lseek(srcFd, 0, SEEK_SET);
78} 82 if (fullRead(srcFd, arVersion, 8) <= 0) {
79 83 errorMsg("Invalid header magic\n");
80/* this is from tar.c remove later*/ 84 return (FALSE);
81static long getOctal(const char *cp, int size)
82{
83 long val = 0;
84
85 for(;(size > 0) && (*cp == ' '); cp++, size--);
86 if ((size == 0) || !isOctal(*cp))
87 return -1;
88 for(; (size > 0) && isOctal(*cp); size--) {
89 val = val * 8 + *cp++ - '0';
90 } 85 }
91 for (;(size > 0) && (*cp == ' '); cp++, size--); 86 if (strncmp(arVersion,"!<arch>",7) != 0) {
92 if ((size > 0) && *cp) 87 errorMsg("This doesnt appear to be an ar archive\n");
93 return -1; 88 return(FALSE);
94 return val; 89 }
95} 90 while (fullRead(srcFd, (char *) &rawArHeader, 60) == 60) {
96 91 if ( (rawArHeader.fmag[0] == '`') &&
97/* 92 (rawArHeader.fmag[1] == '\n')) {
98 * Converts from the char based struct to a new struct with stricter types 93 sscanf(rawArHeader.name, "%s", current->name);
99 */ 94 parse_mode(rawArHeader.mode, &current->mode);
100static int processArHeader(struct ArHeader *rawHeader, struct ArInfo *header) 95 current->mtime = atoi(rawArHeader.date);
101{ 96 current->uid = atoi(rawArHeader.uid);
102 int count2; 97 current->gid = atoi(rawArHeader.gid);
103 int count; 98 current->size = (size_t) atoi(rawArHeader.size);
104 99 current->offset = lseek(srcFd, 0 , SEEK_CUR);
105 /* check end of header marker is valid */ 100 current->next = (headerL_t *) xmalloc(sizeof(headerL_t));
106 if ((rawHeader->ar_fmag[0]!='`') || (rawHeader->ar_fmag[1]!='\n')) 101 lastOffset = lseek(srcFd, (off_t) current->size, SEEK_CUR);
107 return(FALSE); 102 current = current->next;
108 103 }
109 /* convert filename */ 104 else { /* GNU ar has an extra char after data */
110 for (count = 0; count < 16; count++) { 105 thisOffset=lseek(srcFd, 0, SEEK_CUR);
111 /* allow spaces in filename except at the end */ 106 if ( (thisOffset - lastOffset) > ((off_t) 61) )
112 if (rawHeader->ar_name[count] == ' ') { 107 return(FALSE);
113 for (count2 = count; count2 < 16; count2++) 108 lseek(srcFd, thisOffset - 59, SEEK_SET);
114 if (!isspace(rawHeader->ar_name[count2])) 109 }
115 break; 110 }
116 if (count2 >= 16) 111 return(FALSE);
117 break;
118 }
119 /* GNU ar uses '/' as an end of filename marker */
120 if (rawHeader->ar_name[count] == '/')
121 break;
122 header->name[count] = rawHeader->ar_name[count];
123 }
124 header->name[count] = '\0';
125 header->date = atoi(rawHeader->ar_date);
126 header->uid = atoi(rawHeader->ar_uid);
127 header->gid = atoi(rawHeader->ar_gid);
128 header->mode = getOctal(rawHeader->ar_mode, sizeof(rawHeader->ar_mode));
129 header->size = atoi(rawHeader->ar_size);
130 return (TRUE);
131}
132
133/*
134 * Copy size bytes from current position if srcFd to current position in dstFd
135 * taken from tarExtractRegularFile in tar.c, remove later
136 */
137static int copySubFile(int srcFd, int dstFd, int copySize)
138{
139 int readSize, writeSize, doneSize;
140 char buffer[BUFSIZ];
141
142 while (copySize > 0) {
143 if (copySize > BUFSIZ)
144 readSize = BUFSIZ;
145 else
146 readSize = copySize;
147 writeSize = fullRead(srcFd, buffer, readSize);
148 if (writeSize <= 0) {
149 errorMsg(io_error, "copySubFile", strerror(errno));
150 return (FALSE);
151 }
152 doneSize = fullWrite(dstFd, buffer, writeSize);
153 if (doneSize <= 0) {
154 errorMsg(io_error, "copySubFile", strerror(errno));
155 return (FALSE);
156 }
157 copySize -= doneSize;
158 }
159 return (TRUE);
160} 112}
161 113
162/* 114/*
163 * Extract the file described in ArInfo to the specified path 115 * return the headerL_t struct for the specified filename
164 * set the new files uid, gid and mode
165 */ 116 */
166static int extractToFile(struct ArInfo *file, int funct, int srcFd, const char *path) 117static headerL_t *getSubFileHeader(int srcFd, const char filename[16])
167{ 118{
168 int dstFd, temp; 119 headerL_t *list;
169 struct stat tmpStat; 120 list = xmalloc(sizeof(headerL_t));
170 char *pathname = NULL; 121
171 struct utimbuf newtime; 122 parseArArchive(srcFd, list);
172 123 while (list->next != NULL) {
173 if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) { 124 if (strncmp(list->name, filename, strlen(filename))==0)
174 if (!createPath(path, 0777)) { 125 return(list);
175 fatalError("Cannot extract to specified path"); 126 list=list->next;
176 return (FALSE); 127 }
177 } 128 return(NULL);
178 }
179 temp = (strlen(path) + 16);
180 pathname = (char *) xmalloc(temp);
181 pathname = strcpy(pathname, path);
182 pathname = strcat(pathname, file->name);
183 dstFd = device_open(pathname, O_WRONLY | O_CREAT);
184 temp = copySubFile(srcFd, dstFd, file->size);
185 fchown(dstFd, file->uid, file->gid);
186 fchmod(dstFd, file->mode);
187 close(dstFd);
188 if ((funct&AR_PRESERVE_DATE)==AR_PRESERVE_DATE)
189 newtime.modtime=file->date;
190 else
191 newtime.modtime=time(0);
192 newtime.actime=time(0);
193 temp = utime(pathname, &newtime);
194 return (TRUE);
195} 129}
196 130
197/* 131/*
198 * Return a file descriptor for the specified file and do error checks 132 * populate linked list with all ar file entries and offset
199 */ 133 */
200static int getArFd(char *filename) 134static int displayEntry(int srcFd, const char filename[16], int funct)
201{ 135{
202 int arFd; 136 headerL_t *file;
203 char arVersion[8];
204 137
205 arFd = open(filename, O_RDONLY); 138 if ((file = getSubFileHeader(srcFd, filename)) == NULL)
206 if (arFd < 0) { 139 return(FALSE);
207 errorMsg("Error opening '%s': %s\n", filename, strerror(errno)); 140 if ((funct & VERBOSE) == VERBOSE) {
208 return (FALSE); 141 printf("%s %d/%d %8d %s ", modeString(file->mode), file->uid, file->gid, file->size, timeString(file->mtime));
209 } 142 }
210 if (fullRead(arFd, arVersion, 8) <= 0) { 143 printf("%s\n", file->name);
211 errorMsg( "Unexpected EOF in archive\n"); 144 return(TRUE);
212 return (FALSE);
213 }
214 if (strncmp(arVersion,"!<arch>",7) != 0) {
215 errorMsg("ar header fails check ");
216 return(FALSE);
217 }
218 return arFd;
219} 145}
220 146
221/* 147static int extractAr(int srcFd, int dstFd, const char filename[16])
222 * Step through the ar file and process it one entry at a time
223 * fileList[0] is the name of the ar archive
224 * fileList[1] and up are filenames to extract from the archive
225 * funct contains flags to specify the actions to be performed
226 */
227static int readArFile(char *fileList[16], int fileListSize, int funct)
228{ 148{
229 int arFd, status, extFileFlag, i, lastOffset=0; 149 headerL_t *file;
230 ArHeader rawArHeader; 150
231 ArInfo arEntry; 151 if ( (file = getSubFileHeader(srcFd, filename)) == NULL)
232 152 return(FALSE);
233 /* open the ar archive */ 153 lseek(srcFd, file->offset, SEEK_SET);
234 arFd=getArFd(fileList[0]); 154 if (copySubFile(srcFd, dstFd, (size_t) file->size) == TRUE)
235 155 return(TRUE);
236 /* read the first header, then loop until ono more headers */ 156 return(FALSE);
237 while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE))
238 == AR_BLOCK_SIZE) {
239
240 /* check the header is valid, if not try reading the header
241 agian with an offset of 1, needed as some ar archive end
242 with a '\n' which isnt counted in specified file size */
243 if ((status=processArHeader(&rawArHeader, &arEntry))==FALSE ) {
244 if ((i=lseek(arFd, 0, SEEK_CUR))==(lastOffset+60))
245 lseek(arFd, lastOffset+1, SEEK_SET);
246 else
247 return(FALSE);
248 }
249 else {
250 extFileFlag=0;
251
252 if ((funct&AR_DISPLAY) || (funct&AR_VERBOSE))
253 displayEntry(&arEntry, funct);
254
255 /* check file was specified to be extracted only if
256 some file were specified */
257 if ((funct&AR_EXT_TO_FILE) || (funct&AR_EXT_TO_STDOUT)){
258 if (fileListSize==1)
259 extFileFlag=1;
260 else {
261 for( i=1; i<=fileListSize; i++)
262 if ((status=(strcmp(fileList[i],arEntry.name)))==0)
263 extFileFlag=1;
264 }
265 }
266 if (extFileFlag==1) {
267 if (funct&AR_EXT_TO_FILE)
268 extractToFile(&arEntry, funct, arFd, "./");
269 else
270 copySubFile(arFd,fileno(stdout),arEntry.size);
271 }
272 else
273 lseek(arFd, arEntry.size, SEEK_CUR);
274 lastOffset=lseek(arFd, 0, SEEK_CUR);
275 } /* if processArHeader */
276 } /* while */
277 return (TRUE);
278} 157}
279 158
280extern int ar_main(int argc, char **argv) 159extern int ar_main(int argc, char **argv)
281{ 160{
282 int funct = 0, ret=0, i=0; 161 int funct = 0, opt=0;
283 char *fileList[16], c, *opt_ptr; 162 int srcFd=0, dstFd=0;
284 163
285 if (argc < 2) 164 while ((opt = getopt(argc, argv, "ovt:p:x:")) != -1) {
286 usage(ar_usage); 165 switch (opt) {
287
288 opt_ptr = argv[1];
289 if (*opt_ptr == '-')
290 ++opt_ptr;
291 while ((c = *opt_ptr++) != '\0') {
292 switch (c) {
293 case 'o': 166 case 'o':
294 funct = funct | AR_PRESERVE_DATE; 167 funct = funct | PRESERVE_DATE;
295 break; 168 break;
296 case 'v': 169 case 'v':
297 funct = funct | AR_VERBOSE; 170 funct = funct | VERBOSE;
298 break; 171 break;
299 case 't': 172 case 't':
300 funct = funct | AR_DISPLAY; 173 funct = funct | DISPLAY;
301 break;
302 case 'x': 174 case 'x':
303 funct = funct | AR_EXT_TO_FILE; 175 if (opt=='x') {
304 break; 176 funct = funct | EXT_TO_FILE;
177 }
305 case 'p': 178 case 'p':
306 funct = funct | AR_EXT_TO_STDOUT; 179 if (opt=='p') {
180 funct = funct | EXT_TO_STDOUT;
181 }
182 /* following is common to 't','x' and 'p' */
183 if (optarg == NULL) {
184 printf("expected a filename\n");
185 return(FALSE);
186 }
187 if ( (srcFd = open(optarg, O_RDONLY)) < 0) {
188 errorMsg("Cannot read %s\n", optarg);
189 return (FALSE);
190 }
307 break; 191 break;
308 default: 192 default:
309 usage(ar_usage); 193 usage(ar_usage);
310 } 194 }
311 } 195 }
312 196
313 for(i=0; i<(argc-2); i++) 197 /* check options not just preserve_dates and/or verbose */
314 fileList[i]=argv[i+2]; 198 if (funct < 4) {
315 199 usage(ar_usage);
316 if (funct > 3) 200 return(FALSE);
317 ret = readArFile(fileList, (argc-2), funct); 201 }
318 202
319 return (ret); 203 /* find files to extract */
204 if (optind<argc)
205 for(; optind < argc; optind++) {
206 if ( (funct & EXT_TO_FILE) == EXT_TO_FILE) {
207 dstFd = open(argv[optind], O_WRONLY | O_CREAT);
208 extractAr(srcFd, dstFd, argv[optind]);
209 }
210 if ( (funct & EXT_TO_STDOUT) == EXT_TO_STDOUT)
211 extractAr(srcFd, fileno(stdout), argv[optind]);
212 if ( (funct & DISPLAY) == DISPLAY)
213 displayEntry(srcFd, argv[optind], funct);
214 }
215 return (TRUE);
320} 216}
diff --git a/archival/ar.c b/archival/ar.c
index b1200b8ae..1c598fa16 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -4,6 +4,12 @@
4 * 4 *
5 * Copyright (C) 2000 by Glenn McGrath 5 * Copyright (C) 2000 by Glenn McGrath
6 * Written by Glenn McGrath <bug1@netconnect.com.au> 1 June 2000 6 * Written by Glenn McGrath <bug1@netconnect.com.au> 1 June 2000
7 *
8 * Modified 8 August 2000 by Glenn McGrath
9 * - now uses getopt
10 * - moved copySubFile function to utilities.c
11 * - creates linked list of all headers
12 * - easily accessable to other busybox functions
7 * 13 *
8 * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. 14 * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
9 * 15 *
@@ -21,10 +27,8 @@
21 * along with this program; if not, write to the Free Software 27 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * 29 *
24 * Last modified 10 June 2000 30 * Last modified 25 August 2000
25 */ 31 */
26
27
28#include <stdio.h> 32#include <stdio.h>
29#include <fcntl.h> 33#include <fcntl.h>
30#include <errno.h> 34#include <errno.h>
@@ -34,287 +38,179 @@
34#include <sys/types.h> 38#include <sys/types.h>
35#include "internal.h" 39#include "internal.h"
36 40
37#define AR_BLOCK_SIZE 60 41#define BLOCK_SIZE 60
38#define AR_PRESERVE_DATE 1 /* preserve original dates */ 42#define PRESERVE_DATE 1 /* preserve original dates */
39#define AR_VERBOSE 2 /* be verbose */ 43#define VERBOSE 2 /* be verbose */
40#define AR_DISPLAY 4 /* display contents */ 44#define DISPLAY 4 /* display contents */
41#define AR_EXT_TO_FILE 8 /* extract contents of archive */ 45#define EXT_TO_FILE 8 /* extract contents of archive */
42#define AR_EXT_TO_STDOUT 16 /* extract to stdout */ 46#define EXT_TO_STDOUT 16 /* extract to stdout */
43 47
44#define BB_DECLARE_EXTERN 48#define BB_DECLARE_EXTERN
45#define bb_need_io_error 49#define bb_need_io_error
46#include "messages.c" 50#include "messages.c"
47 51
48struct ArHeader { /* Byte Offset */ 52typedef struct rawArHeader { /* Byte Offset */
49 char ar_name[16]; /* 0-15 */ 53 char name[16]; /* 0-15 */
50 char ar_date[12]; /* 16-27 */ 54 char date[12]; /* 16-27 */
51 char ar_uid[6], ar_gid[6]; /* 28-39 */ 55 char uid[6], gid[6]; /* 28-39 */
52 char ar_mode[8]; /* 40-47 */ 56 char mode[8]; /* 40-47 */
53 char ar_size[10]; /* 48-57 */ 57 char size[10]; /* 48-57 */
54 char ar_fmag[2]; /* 58-59 */ 58 char fmag[2]; /* 58-59 */
55}; 59} rawArHeader_t;
56typedef struct ArHeader ArHeader; 60
57 61typedef struct headerL {
58struct ArInfo { 62 char name[16];
59 char name[17]; /* File name */ 63 size_t size;
60 time_t date; /* long int, No of seconds since epoch */ 64 uid_t uid;
61 uid_t uid; /* unsigned int, Numeric UID */ 65 gid_t gid;
62 gid_t gid; /* unsigned int, Numeric GID */ 66 mode_t mode;
63 mode_t mode; /* unsigned int, Unix mode */ 67 time_t mtime;
64 size_t size; /* int, Size of the file */ 68 off_t offset;
65}; 69 struct headerL *next;
66typedef struct ArInfo ArInfo; 70} headerL_t;
67 71
68/* 72/*
69 * Display details of a file, verbosly if funct=2 73 * populate linked list with all ar file entries and offset
70 */ 74 */
71static void displayEntry(struct ArInfo *entry, int funct) 75static int parseArArchive(int srcFd, headerL_t *current)
72{ 76{
73 /* TODO convert mode to string */ 77 off_t lastOffset=0, thisOffset=0;
74 if ((funct & AR_VERBOSE) == AR_VERBOSE) 78 char arVersion[8];
75 printf("%i %i/%i %8i %s ", entry->mode, entry->uid, entry->gid, 79 rawArHeader_t rawArHeader;
76 entry->size, timeString(entry->date)); 80
77 printf("%s\n", entry->name); 81 lseek(srcFd, 0, SEEK_SET);
78} 82 if (fullRead(srcFd, arVersion, 8) <= 0) {
79 83 errorMsg("Invalid header magic\n");
80/* this is from tar.c remove later*/ 84 return (FALSE);
81static long getOctal(const char *cp, int size)
82{
83 long val = 0;
84
85 for(;(size > 0) && (*cp == ' '); cp++, size--);
86 if ((size == 0) || !isOctal(*cp))
87 return -1;
88 for(; (size > 0) && isOctal(*cp); size--) {
89 val = val * 8 + *cp++ - '0';
90 } 85 }
91 for (;(size > 0) && (*cp == ' '); cp++, size--); 86 if (strncmp(arVersion,"!<arch>",7) != 0) {
92 if ((size > 0) && *cp) 87 errorMsg("This doesnt appear to be an ar archive\n");
93 return -1; 88 return(FALSE);
94 return val; 89 }
95} 90 while (fullRead(srcFd, (char *) &rawArHeader, 60) == 60) {
96 91 if ( (rawArHeader.fmag[0] == '`') &&
97/* 92 (rawArHeader.fmag[1] == '\n')) {
98 * Converts from the char based struct to a new struct with stricter types 93 sscanf(rawArHeader.name, "%s", current->name);
99 */ 94 parse_mode(rawArHeader.mode, &current->mode);
100static int processArHeader(struct ArHeader *rawHeader, struct ArInfo *header) 95 current->mtime = atoi(rawArHeader.date);
101{ 96 current->uid = atoi(rawArHeader.uid);
102 int count2; 97 current->gid = atoi(rawArHeader.gid);
103 int count; 98 current->size = (size_t) atoi(rawArHeader.size);
104 99 current->offset = lseek(srcFd, 0 , SEEK_CUR);
105 /* check end of header marker is valid */ 100 current->next = (headerL_t *) xmalloc(sizeof(headerL_t));
106 if ((rawHeader->ar_fmag[0]!='`') || (rawHeader->ar_fmag[1]!='\n')) 101 lastOffset = lseek(srcFd, (off_t) current->size, SEEK_CUR);
107 return(FALSE); 102 current = current->next;
108 103 }
109 /* convert filename */ 104 else { /* GNU ar has an extra char after data */
110 for (count = 0; count < 16; count++) { 105 thisOffset=lseek(srcFd, 0, SEEK_CUR);
111 /* allow spaces in filename except at the end */ 106 if ( (thisOffset - lastOffset) > ((off_t) 61) )
112 if (rawHeader->ar_name[count] == ' ') { 107 return(FALSE);
113 for (count2 = count; count2 < 16; count2++) 108 lseek(srcFd, thisOffset - 59, SEEK_SET);
114 if (!isspace(rawHeader->ar_name[count2])) 109 }
115 break; 110 }
116 if (count2 >= 16) 111 return(FALSE);
117 break;
118 }
119 /* GNU ar uses '/' as an end of filename marker */
120 if (rawHeader->ar_name[count] == '/')
121 break;
122 header->name[count] = rawHeader->ar_name[count];
123 }
124 header->name[count] = '\0';
125 header->date = atoi(rawHeader->ar_date);
126 header->uid = atoi(rawHeader->ar_uid);
127 header->gid = atoi(rawHeader->ar_gid);
128 header->mode = getOctal(rawHeader->ar_mode, sizeof(rawHeader->ar_mode));
129 header->size = atoi(rawHeader->ar_size);
130 return (TRUE);
131}
132
133/*
134 * Copy size bytes from current position if srcFd to current position in dstFd
135 * taken from tarExtractRegularFile in tar.c, remove later
136 */
137static int copySubFile(int srcFd, int dstFd, int copySize)
138{
139 int readSize, writeSize, doneSize;
140 char buffer[BUFSIZ];
141
142 while (copySize > 0) {
143 if (copySize > BUFSIZ)
144 readSize = BUFSIZ;
145 else
146 readSize = copySize;
147 writeSize = fullRead(srcFd, buffer, readSize);
148 if (writeSize <= 0) {
149 errorMsg(io_error, "copySubFile", strerror(errno));
150 return (FALSE);
151 }
152 doneSize = fullWrite(dstFd, buffer, writeSize);
153 if (doneSize <= 0) {
154 errorMsg(io_error, "copySubFile", strerror(errno));
155 return (FALSE);
156 }
157 copySize -= doneSize;
158 }
159 return (TRUE);
160} 112}
161 113
162/* 114/*
163 * Extract the file described in ArInfo to the specified path 115 * return the headerL_t struct for the specified filename
164 * set the new files uid, gid and mode
165 */ 116 */
166static int extractToFile(struct ArInfo *file, int funct, int srcFd, const char *path) 117static headerL_t *getSubFileHeader(int srcFd, const char filename[16])
167{ 118{
168 int dstFd, temp; 119 headerL_t *list;
169 struct stat tmpStat; 120 list = xmalloc(sizeof(headerL_t));
170 char *pathname = NULL; 121
171 struct utimbuf newtime; 122 parseArArchive(srcFd, list);
172 123 while (list->next != NULL) {
173 if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) { 124 if (strncmp(list->name, filename, strlen(filename))==0)
174 if (!createPath(path, 0777)) { 125 return(list);
175 fatalError("Cannot extract to specified path"); 126 list=list->next;
176 return (FALSE); 127 }
177 } 128 return(NULL);
178 }
179 temp = (strlen(path) + 16);
180 pathname = (char *) xmalloc(temp);
181 pathname = strcpy(pathname, path);
182 pathname = strcat(pathname, file->name);
183 dstFd = device_open(pathname, O_WRONLY | O_CREAT);
184 temp = copySubFile(srcFd, dstFd, file->size);
185 fchown(dstFd, file->uid, file->gid);
186 fchmod(dstFd, file->mode);
187 close(dstFd);
188 if ((funct&AR_PRESERVE_DATE)==AR_PRESERVE_DATE)
189 newtime.modtime=file->date;
190 else
191 newtime.modtime=time(0);
192 newtime.actime=time(0);
193 temp = utime(pathname, &newtime);
194 return (TRUE);
195} 129}
196 130
197/* 131/*
198 * Return a file descriptor for the specified file and do error checks 132 * populate linked list with all ar file entries and offset
199 */ 133 */
200static int getArFd(char *filename) 134static int displayEntry(int srcFd, const char filename[16], int funct)
201{ 135{
202 int arFd; 136 headerL_t *file;
203 char arVersion[8];
204 137
205 arFd = open(filename, O_RDONLY); 138 if ((file = getSubFileHeader(srcFd, filename)) == NULL)
206 if (arFd < 0) { 139 return(FALSE);
207 errorMsg("Error opening '%s': %s\n", filename, strerror(errno)); 140 if ((funct & VERBOSE) == VERBOSE) {
208 return (FALSE); 141 printf("%s %d/%d %8d %s ", modeString(file->mode), file->uid, file->gid, file->size, timeString(file->mtime));
209 } 142 }
210 if (fullRead(arFd, arVersion, 8) <= 0) { 143 printf("%s\n", file->name);
211 errorMsg( "Unexpected EOF in archive\n"); 144 return(TRUE);
212 return (FALSE);
213 }
214 if (strncmp(arVersion,"!<arch>",7) != 0) {
215 errorMsg("ar header fails check ");
216 return(FALSE);
217 }
218 return arFd;
219} 145}
220 146
221/* 147static int extractAr(int srcFd, int dstFd, const char filename[16])
222 * Step through the ar file and process it one entry at a time
223 * fileList[0] is the name of the ar archive
224 * fileList[1] and up are filenames to extract from the archive
225 * funct contains flags to specify the actions to be performed
226 */
227static int readArFile(char *fileList[16], int fileListSize, int funct)
228{ 148{
229 int arFd, status, extFileFlag, i, lastOffset=0; 149 headerL_t *file;
230 ArHeader rawArHeader; 150
231 ArInfo arEntry; 151 if ( (file = getSubFileHeader(srcFd, filename)) == NULL)
232 152 return(FALSE);
233 /* open the ar archive */ 153 lseek(srcFd, file->offset, SEEK_SET);
234 arFd=getArFd(fileList[0]); 154 if (copySubFile(srcFd, dstFd, (size_t) file->size) == TRUE)
235 155 return(TRUE);
236 /* read the first header, then loop until ono more headers */ 156 return(FALSE);
237 while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE))
238 == AR_BLOCK_SIZE) {
239
240 /* check the header is valid, if not try reading the header
241 agian with an offset of 1, needed as some ar archive end
242 with a '\n' which isnt counted in specified file size */
243 if ((status=processArHeader(&rawArHeader, &arEntry))==FALSE ) {
244 if ((i=lseek(arFd, 0, SEEK_CUR))==(lastOffset+60))
245 lseek(arFd, lastOffset+1, SEEK_SET);
246 else
247 return(FALSE);
248 }
249 else {
250 extFileFlag=0;
251
252 if ((funct&AR_DISPLAY) || (funct&AR_VERBOSE))
253 displayEntry(&arEntry, funct);
254
255 /* check file was specified to be extracted only if
256 some file were specified */
257 if ((funct&AR_EXT_TO_FILE) || (funct&AR_EXT_TO_STDOUT)){
258 if (fileListSize==1)
259 extFileFlag=1;
260 else {
261 for( i=1; i<=fileListSize; i++)
262 if ((status=(strcmp(fileList[i],arEntry.name)))==0)
263 extFileFlag=1;
264 }
265 }
266 if (extFileFlag==1) {
267 if (funct&AR_EXT_TO_FILE)
268 extractToFile(&arEntry, funct, arFd, "./");
269 else
270 copySubFile(arFd,fileno(stdout),arEntry.size);
271 }
272 else
273 lseek(arFd, arEntry.size, SEEK_CUR);
274 lastOffset=lseek(arFd, 0, SEEK_CUR);
275 } /* if processArHeader */
276 } /* while */
277 return (TRUE);
278} 157}
279 158
280extern int ar_main(int argc, char **argv) 159extern int ar_main(int argc, char **argv)
281{ 160{
282 int funct = 0, ret=0, i=0; 161 int funct = 0, opt=0;
283 char *fileList[16], c, *opt_ptr; 162 int srcFd=0, dstFd=0;
284 163
285 if (argc < 2) 164 while ((opt = getopt(argc, argv, "ovt:p:x:")) != -1) {
286 usage(ar_usage); 165 switch (opt) {
287
288 opt_ptr = argv[1];
289 if (*opt_ptr == '-')
290 ++opt_ptr;
291 while ((c = *opt_ptr++) != '\0') {
292 switch (c) {
293 case 'o': 166 case 'o':
294 funct = funct | AR_PRESERVE_DATE; 167 funct = funct | PRESERVE_DATE;
295 break; 168 break;
296 case 'v': 169 case 'v':
297 funct = funct | AR_VERBOSE; 170 funct = funct | VERBOSE;
298 break; 171 break;
299 case 't': 172 case 't':
300 funct = funct | AR_DISPLAY; 173 funct = funct | DISPLAY;
301 break;
302 case 'x': 174 case 'x':
303 funct = funct | AR_EXT_TO_FILE; 175 if (opt=='x') {
304 break; 176 funct = funct | EXT_TO_FILE;
177 }
305 case 'p': 178 case 'p':
306 funct = funct | AR_EXT_TO_STDOUT; 179 if (opt=='p') {
180 funct = funct | EXT_TO_STDOUT;
181 }
182 /* following is common to 't','x' and 'p' */
183 if (optarg == NULL) {
184 printf("expected a filename\n");
185 return(FALSE);
186 }
187 if ( (srcFd = open(optarg, O_RDONLY)) < 0) {
188 errorMsg("Cannot read %s\n", optarg);
189 return (FALSE);
190 }
307 break; 191 break;
308 default: 192 default:
309 usage(ar_usage); 193 usage(ar_usage);
310 } 194 }
311 } 195 }
312 196
313 for(i=0; i<(argc-2); i++) 197 /* check options not just preserve_dates and/or verbose */
314 fileList[i]=argv[i+2]; 198 if (funct < 4) {
315 199 usage(ar_usage);
316 if (funct > 3) 200 return(FALSE);
317 ret = readArFile(fileList, (argc-2), funct); 201 }
318 202
319 return (ret); 203 /* find files to extract */
204 if (optind<argc)
205 for(; optind < argc; optind++) {
206 if ( (funct & EXT_TO_FILE) == EXT_TO_FILE) {
207 dstFd = open(argv[optind], O_WRONLY | O_CREAT);
208 extractAr(srcFd, dstFd, argv[optind]);
209 }
210 if ( (funct & EXT_TO_STDOUT) == EXT_TO_STDOUT)
211 extractAr(srcFd, fileno(stdout), argv[optind]);
212 if ( (funct & DISPLAY) == DISPLAY)
213 displayEntry(srcFd, argv[optind], funct);
214 }
215 return (TRUE);
320} 216}
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 6df2588ca..787e5da95 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -44,7 +44,6 @@ extern int dd_main(int argc, char **argv)
44{ 44{
45 char *inFile = NULL; 45 char *inFile = NULL;
46 char *outFile = NULL; 46 char *outFile = NULL;
47 char *cp;
48 int inFd; 47 int inFd;
49 int outFd; 48 int outFd;
50 int inCc = 0; 49 int inCc = 0;
@@ -135,42 +134,14 @@ extern int dd_main(int argc, char **argv)
135 134
136 lseek(inFd, skipBlocks * blockSize, SEEK_SET); 135 lseek(inFd, skipBlocks * blockSize, SEEK_SET);
137 lseek(outFd, seekBlocks * blockSize, SEEK_SET); 136 lseek(outFd, seekBlocks * blockSize, SEEK_SET);
138 //
139 //TODO: Convert to using fullRead & fullWrite
140 // from utility.c
141 // -Erik
142 while (outTotal < count * blockSize) {
143 inCc = read(inFd, buf, blockSize);
144 if (inCc < 0) {
145 perror(inFile);
146 goto cleanup;
147 } else if (inCc == 0) {
148 goto cleanup;
149 }
150 intotal += inCc;
151 cp = buf;
152
153 while (intotal > outTotal) {
154 if (outTotal + inCc > count * blockSize)
155 inCc = count * blockSize - outTotal;
156 outCc = write(outFd, cp, inCc);
157 if (outCc < 0) {
158 perror(outFile);
159 goto cleanup;
160 } else if (outCc == 0) {
161 goto cleanup;
162 }
163
164 inCc -= outCc;
165 cp += outCc;
166 outTotal += outCc;
167 }
168 }
169 137
170 if (inCc < 0) 138 while ((inCc = read(inFd, buf, sizeof(buf))) > 0) {
171 perror(inFile); 139 intotal +=inCc;
140 if ((outCc = fullWrite(outFd, buf, inCc)) < 0)
141 break;
142 outTotal += outCc;
143 }
172 144
173 cleanup:
174 /* Note that we are not freeing memory or closing 145 /* Note that we are not freeing memory or closing
175 * files here, to save a few bytes. */ 146 * files here, to save a few bytes. */
176#ifdef BB_FEATURE_CLEAN_UP 147#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)
44{ 44{
45 char *inFile = NULL; 45 char *inFile = NULL;
46 char *outFile = NULL; 46 char *outFile = NULL;
47 char *cp;
48 int inFd; 47 int inFd;
49 int outFd; 48 int outFd;
50 int inCc = 0; 49 int inCc = 0;
@@ -135,42 +134,14 @@ extern int dd_main(int argc, char **argv)
135 134
136 lseek(inFd, skipBlocks * blockSize, SEEK_SET); 135 lseek(inFd, skipBlocks * blockSize, SEEK_SET);
137 lseek(outFd, seekBlocks * blockSize, SEEK_SET); 136 lseek(outFd, seekBlocks * blockSize, SEEK_SET);
138 //
139 //TODO: Convert to using fullRead & fullWrite
140 // from utility.c
141 // -Erik
142 while (outTotal < count * blockSize) {
143 inCc = read(inFd, buf, blockSize);
144 if (inCc < 0) {
145 perror(inFile);
146 goto cleanup;
147 } else if (inCc == 0) {
148 goto cleanup;
149 }
150 intotal += inCc;
151 cp = buf;
152
153 while (intotal > outTotal) {
154 if (outTotal + inCc > count * blockSize)
155 inCc = count * blockSize - outTotal;
156 outCc = write(outFd, cp, inCc);
157 if (outCc < 0) {
158 perror(outFile);
159 goto cleanup;
160 } else if (outCc == 0) {
161 goto cleanup;
162 }
163
164 inCc -= outCc;
165 cp += outCc;
166 outTotal += outCc;
167 }
168 }
169 137
170 if (inCc < 0) 138 while ((inCc = read(inFd, buf, sizeof(buf))) > 0) {
171 perror(inFile); 139 intotal +=inCc;
140 if ((outCc = fullWrite(outFd, buf, inCc)) < 0)
141 break;
142 outTotal += outCc;
143 }
172 144
173 cleanup:
174 /* Note that we are not freeing memory or closing 145 /* Note that we are not freeing memory or closing
175 * files here, to save a few bytes. */ 146 * files here, to save a few bytes. */
176#ifdef BB_FEATURE_CLEAN_UP 147#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);
345 345
346int copyFile(const char *srcName, const char *destName, 346int copyFile(const char *srcName, const char *destName,
347 int setModes, int followLinks, int forceFlag); 347 int setModes, int followLinks, int forceFlag);
348int copySubFile(int srcFd, int dstFd, size_t remaining);
348char *buildName(const char *dirName, const char *fileName); 349char *buildName(const char *dirName, const char *fileName);
349int makeString(int argc, const char **argv, char *buf, int bufLen); 350int makeString(int argc, const char **argv, char *buf, int bufLen);
350char *getChunk(int size); 351char *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 @@
2 2
3#if defined BB_AR 3#if defined BB_AR
4const char ar_usage[] = 4const char ar_usage[] =
5 "ar [optxvV] archive [filenames] \n" 5 "ar [[-ov] -tpv archive] filenames \n"
6#ifndef BB_FEATURE_TRIVIAL_HELP 6#ifndef BB_FEATURE_TRIVIAL_HELP
7 "\nExtract or list files from an ar archive.\n\n" 7 "\nExtract or list files from an ar archive.\n\n"
8 "Options:\n" 8 "Options:\n"
9 "\to\t\tpreserve original dates\n" 9 "\t-o\t\tpreserve original dates\n"
10 "\tp\t\textract to stdout\n" 10 "\t-p\t\textract to stdout\n"
11 "\tt\t\tlist\n" 11 "\t-t\t\tlist\n"
12 "\tx\t\textract\n" 12 "\t-x\t\textract\n"
13 "\tv\t\tverbosely list files processed\n" 13 "\t-v\t\tverbosely list files processed\n"
14#endif 14#endif
15 ; 15 ;
16#endif 16#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)
231 231
232#endif /* BB_CP_MV || BB_DU */ 232#endif /* BB_CP_MV || BB_DU */
233 233
234#if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN) || defined (BB_AR) 234#if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN)
235/* 235/*
236 * Return TRUE if a fileName is a directory. 236 * Return TRUE if a fileName is a directory.
237 * Nonexistant files return FALSE. 237 * Nonexistant files return FALSE.
@@ -264,6 +264,29 @@ int isDirectory(const char *fileName, const int followLinks, struct stat *statBu
264} 264}
265#endif 265#endif
266 266
267#if defined (BB_AR)
268/*
269 * Copy readSize bytes between two file descriptors
270 */
271int copySubFile(int srcFd, int dstFd, size_t remaining)
272{
273 size_t size;
274 char buffer[BUFSIZ];
275
276 while (remaining > 0) {
277 if (remaining > BUFSIZ)
278 size = BUFSIZ;
279 else
280 size = remaining;
281 if (fullWrite(dstFd, buffer, fullRead(srcFd, buffer, size)) < size)
282 return(FALSE);
283 remaining -= size;
284 }
285 return (TRUE);
286}
287#endif
288
289
267#if defined (BB_CP_MV) 290#if defined (BB_CP_MV)
268/* 291/*
269 * Copy one file to another, while possibly preserving its modes, times, and 292 * Copy one file to another, while possibly preserving its modes, times, and
@@ -277,9 +300,7 @@ copyFile(const char *srcName, const char *destName,
277{ 300{
278 int rfd; 301 int rfd;
279 int wfd; 302 int wfd;
280 int rcc;
281 int status; 303 int status;
282 char buf[BUF_SIZE];
283 struct stat srcStatBuf; 304 struct stat srcStatBuf;
284 struct stat dstStatBuf; 305 struct stat dstStatBuf;
285 struct utimbuf times; 306 struct utimbuf times;
@@ -364,8 +385,7 @@ copyFile(const char *srcName, const char *destName,
364 return FALSE; 385 return FALSE;
365 } 386 }
366 387
367 wfd = 388 wfd = open(destName, O_WRONLY | O_CREAT | O_TRUNC,
368 open(destName, O_WRONLY | O_CREAT | O_TRUNC,
369 srcStatBuf.st_mode); 389 srcStatBuf.st_mode);
370 if (wfd < 0) { 390 if (wfd < 0) {
371 perror(destName); 391 perror(destName);
@@ -373,14 +393,9 @@ copyFile(const char *srcName, const char *destName,
373 return FALSE; 393 return FALSE;
374 } 394 }
375 395
376 while ((rcc = read(rfd, buf, sizeof(buf))) > 0) { 396 if (copySubFile(rfd, wfd, srcStatBuf.st_size)==FALSE)
377 if (fullWrite(wfd, buf, rcc) < 0) 397 goto error_exit;
378 goto error_exit; 398
379 }
380 if (rcc < 0) {
381 goto error_exit;
382 }
383
384 close(rfd); 399 close(rfd);
385 if (close(wfd) < 0) { 400 if (close(wfd) < 0) {
386 return FALSE; 401 return FALSE;
@@ -677,7 +692,7 @@ int recursiveAction(const char *fileName,
677 692
678 693
679 694
680#if defined (BB_TAR) || defined (BB_MKDIR) || defined (BB_AR) 695#if defined (BB_TAR) || defined (BB_MKDIR)
681/* 696/*
682 * Attempt to create the directories along the specified path, except for 697 * Attempt to create the directories along the specified path, except for
683 * the final component. The mode is given for the final directory only, 698 * the final component. The mode is given for the final directory only,
@@ -1292,7 +1307,7 @@ extern long getNum(const char *cp)
1292#endif /* BB_DD || BB_TAIL */ 1307#endif /* BB_DD || BB_TAIL */
1293 1308
1294 1309
1295#if defined BB_INIT || defined BB_SYSLOGD || defined BB_AR 1310#if defined BB_INIT || defined BB_SYSLOGD
1296/* try to open up the specified device */ 1311/* try to open up the specified device */
1297extern int device_open(char *device, int mode) 1312extern int device_open(char *device, int mode)
1298{ 1313{