diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2000-08-25 03:50:10 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2000-08-25 03:50:10 +0000 |
commit | 06aeb6c417dd9d113949714486a6e6337ef70b97 (patch) | |
tree | 0f002c36314483775fa2a248ae1c8b5346c70030 | |
parent | 4d5ac2f346d01e51cde9c44431067138bd586f36 (diff) | |
download | busybox-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.c | 12 | ||||
-rw-r--r-- | ar.c | 384 | ||||
-rw-r--r-- | archival/ar.c | 384 | ||||
-rw-r--r-- | coreutils/dd.c | 41 | ||||
-rw-r--r-- | dd.c | 41 | ||||
-rw-r--r-- | internal.h | 1 | ||||
-rw-r--r-- | usage.c | 12 | ||||
-rw-r--r-- | utility.c | 45 |
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 |
4 | const char ar_usage[] = | 4 | const 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 |
@@ -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 | ||
48 | struct ArHeader { /* Byte Offset */ | 52 | typedef 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; |
56 | typedef struct ArHeader ArHeader; | 60 | |
57 | 61 | typedef struct headerL { | |
58 | struct 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; |
66 | typedef 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 | */ |
71 | static void displayEntry(struct ArInfo *entry, int funct) | 75 | static 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); |
81 | static 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, ¤t->mode); |
100 | static 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 | */ | ||
137 | static 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 | */ |
166 | static int extractToFile(struct ArInfo *file, int funct, int srcFd, const char *path) | 117 | static 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 | */ |
200 | static int getArFd(char *filename) | 134 | static 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 | /* | 147 | static 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 | */ | ||
227 | static 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 | ||
280 | extern int ar_main(int argc, char **argv) | 159 | extern 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 | ||
48 | struct ArHeader { /* Byte Offset */ | 52 | typedef 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; |
56 | typedef struct ArHeader ArHeader; | 60 | |
57 | 61 | typedef struct headerL { | |
58 | struct 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; |
66 | typedef 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 | */ |
71 | static void displayEntry(struct ArInfo *entry, int funct) | 75 | static 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); |
81 | static 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, ¤t->mode); |
100 | static 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 | */ | ||
137 | static 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 | */ |
166 | static int extractToFile(struct ArInfo *file, int funct, int srcFd, const char *path) | 117 | static 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 | */ |
200 | static int getArFd(char *filename) | 134 | static 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 | /* | 147 | static 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 | */ | ||
227 | static 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 | ||
280 | extern int ar_main(int argc, char **argv) | 159 | extern 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 |
@@ -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 | ||
346 | int copyFile(const char *srcName, const char *destName, | 346 | int copyFile(const char *srcName, const char *destName, |
347 | int setModes, int followLinks, int forceFlag); | 347 | int setModes, int followLinks, int forceFlag); |
348 | int copySubFile(int srcFd, int dstFd, size_t remaining); | ||
348 | char *buildName(const char *dirName, const char *fileName); | 349 | char *buildName(const char *dirName, const char *fileName); |
349 | int makeString(int argc, const char **argv, char *buf, int bufLen); | 350 | int makeString(int argc, const char **argv, char *buf, int bufLen); |
350 | char *getChunk(int size); | 351 | char *getChunk(int size); |
@@ -2,15 +2,15 @@ | |||
2 | 2 | ||
3 | #if defined BB_AR | 3 | #if defined BB_AR |
4 | const char ar_usage[] = | 4 | const 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 |
@@ -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 | */ | ||
271 | int 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 */ |
1297 | extern int device_open(char *device, int mode) | 1312 | extern int device_open(char *device, int mode) |
1298 | { | 1313 | { |