diff options
author | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2000-06-02 03:21:42 +0000 |
---|---|---|
committer | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2000-06-02 03:21:42 +0000 |
commit | 9e3d5ab99f2b9cb84b0ec52b24812b0081b0cc0a (patch) | |
tree | 10aa90962757d07724c78e4fc9baaa27ca7b4858 /ar.c | |
parent | be1caa3c14daabb874a1faab40ffdcf9ece9dd02 (diff) | |
download | busybox-w32-9e3d5ab99f2b9cb84b0ec52b24812b0081b0cc0a.tar.gz busybox-w32-9e3d5ab99f2b9cb84b0ec52b24812b0081b0cc0a.tar.bz2 busybox-w32-9e3d5ab99f2b9cb84b0ec52b24812b0081b0cc0a.zip |
A number of additional fixed from Pavel Roskin, note some more bugs in the
TODO list. Add Glenn to the Authors list for writing a mini ar for BusyBox,
which is now included.
-Erik
git-svn-id: svn://busybox.net/trunk/busybox@594 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'ar.c')
-rw-r--r-- | ar.c | 277 |
1 files changed, 277 insertions, 0 deletions
@@ -0,0 +1,277 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini ar implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 2000 by Glenn McGrath | ||
6 | * Written by Glenn McGrath <bug1@netconnect.com.au> 1 June 2000 | ||
7 | * | ||
8 | * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include <stdio.h> | ||
28 | #include <fcntl.h> | ||
29 | #include <errno.h> | ||
30 | #include <ctype.h> | ||
31 | #include "internal.h" | ||
32 | |||
33 | #define AR_BLOCK_SIZE 60 | ||
34 | #define BB_DECLARE_EXTERN | ||
35 | #define bb_need_io_error | ||
36 | #include "messages.c" | ||
37 | |||
38 | struct ArHeader { /* Byte Offset */ | ||
39 | char ar_name[16]; /* 0-15 */ | ||
40 | char ar_date[12]; /* 16-27 */ | ||
41 | char ar_uid[6], ar_gid[6]; /* 28-39 */ | ||
42 | char ar_mode[8]; /* 40-47 */ | ||
43 | char ar_size[10]; /* 48-57 */ | ||
44 | char ar_fmag[2]; /* 58-59 */ | ||
45 | }; | ||
46 | typedef struct ArHeader ArHeader; | ||
47 | |||
48 | struct ArInfo { | ||
49 | char name[17]; /* File name */ | ||
50 | time_t date; /* long int, No of seconds since epoch */ | ||
51 | uid_t uid; /* unsigned int, Numeric UID */ | ||
52 | gid_t gid; /* unsigned int, Numeric GID */ | ||
53 | mode_t mode; /* unsigned int, Unix mode */ | ||
54 | size_t size; /* int, Size of the file */ | ||
55 | }; | ||
56 | typedef struct ArInfo ArInfo; | ||
57 | |||
58 | static const char ar_usage[] = "ar [optxvV] archive [filenames] \n" | ||
59 | #ifndef BB_FEATURE_TRIVIAL_HELP | ||
60 | "\nExtract or list files from an ar archive.\n\n" | ||
61 | "Options:\n" | ||
62 | "\to\t\tpreserve original dates\n" | ||
63 | "\tp\t\textract to stdout\n" | ||
64 | "\tt\t\tlist\n" | ||
65 | "\tx\t\textract\n" | ||
66 | "\tv\t\tverbosely list files processed\n" | ||
67 | #endif | ||
68 | ; | ||
69 | |||
70 | static void displayContents(struct ArInfo *entry, int funct) | ||
71 | { | ||
72 | /* TODO convert mode to string */ | ||
73 | if ((funct & 2) == 2) | ||
74 | printf("%i %i/%i %6i %s ", entry->mode, entry->uid, entry->gid, | ||
75 | entry->size, timeString(entry->date)); | ||
76 | printf("%s\n", entry->name); | ||
77 | } | ||
78 | |||
79 | /* Converts to new typed struct */ | ||
80 | static int readArHeader(struct ArHeader *rawHeader, struct ArInfo *header) | ||
81 | { | ||
82 | int count2; | ||
83 | int count; | ||
84 | |||
85 | for (count = 0; count < 16; count++) { | ||
86 | if (rawHeader->ar_name[count] == ' ') { | ||
87 | for (count2 = count; count2 < 16; count2++) | ||
88 | if (!isspace(rawHeader->ar_name[count2])) | ||
89 | break; | ||
90 | if (count2 >= 16) | ||
91 | break; | ||
92 | } | ||
93 | if (rawHeader->ar_name[count] == '/') | ||
94 | break; | ||
95 | header->name[count] = rawHeader->ar_name[count]; | ||
96 | } | ||
97 | header->name[count] = '\0'; | ||
98 | header->date = atoi(rawHeader->ar_date); | ||
99 | header->uid = atoi(rawHeader->ar_uid); | ||
100 | header->gid = atoi(rawHeader->ar_gid); | ||
101 | header->mode = atoi(rawHeader->ar_mode); | ||
102 | header->size = atoi(rawHeader->ar_size); | ||
103 | return (TRUE); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * Copy size bytes from current position if srcFd to current position in dstFd | ||
108 | * taken from tarExtractRegularFile in tar.c | ||
109 | * could be used for ar, tar and copyFile . | ||
110 | */ | ||
111 | static int copySubFile(int srcFd, int dstFd, int copySize) | ||
112 | { | ||
113 | int readSize, writeSize, doneSize; | ||
114 | char buffer[BUFSIZ]; | ||
115 | |||
116 | while (copySize > 0) { | ||
117 | if (copySize > BUFSIZ) | ||
118 | readSize = BUFSIZ; | ||
119 | else | ||
120 | readSize = copySize; | ||
121 | writeSize = fullRead(srcFd, buffer, readSize); | ||
122 | if (writeSize <= 0) { | ||
123 | errorMsg(io_error, "copySubFile :", strerror(errno)); | ||
124 | return (FALSE); | ||
125 | } | ||
126 | doneSize = fullWrite(dstFd, buffer, writeSize); | ||
127 | if (doneSize <= 0) { | ||
128 | errorMsg(io_error, "copySubFile :", strerror(errno)); | ||
129 | return (FALSE); | ||
130 | } | ||
131 | copySize -= doneSize; | ||
132 | } | ||
133 | return (TRUE); | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * Need to add checks, stat newfile before creation,change mode from 0777 | ||
138 | * extract to current dir | ||
139 | * dstStat.st_size copied from current position of file pointed to by srcFd | ||
140 | */ | ||
141 | static int extractToFile(int srcFd, const char *path, const char *name, | ||
142 | int size) | ||
143 | { | ||
144 | int dstFd, temp; | ||
145 | struct stat tmpStat; | ||
146 | char *pathname = NULL; | ||
147 | |||
148 | if ((temp = isDirectory(path, TRUE, &tmpStat)) != TRUE) { | ||
149 | if (!createPath(path, 0777)) { | ||
150 | fatalError("Cannot extract to specified path"); | ||
151 | return (FALSE); | ||
152 | } | ||
153 | } | ||
154 | temp = (strlen(path) + 16); | ||
155 | pathname = (char *) xmalloc(temp); | ||
156 | pathname = strcpy(pathname, path); | ||
157 | pathname = strcat(pathname, &name[0]); | ||
158 | dstFd = device_open(pathname, O_WRONLY | O_CREAT); | ||
159 | pathname = NULL; | ||
160 | temp = copySubFile(srcFd, dstFd, size); | ||
161 | close(dstFd); | ||
162 | return (TRUE); | ||
163 | } | ||
164 | |||
165 | /* Step through the ar file entries */ | ||
166 | static int readArFile(char **fileNames, int argc, int funct) | ||
167 | { | ||
168 | int arFd = 0; | ||
169 | int pdates = 0; | ||
170 | int verbose = 0; | ||
171 | int display = 0; | ||
172 | int extract = 0; | ||
173 | int extToStdout = 0; | ||
174 | int status = 0; | ||
175 | int found = 0; | ||
176 | ArHeader rawArHeader; | ||
177 | ArInfo arEntry; | ||
178 | char arVersion[8]; | ||
179 | char *arName; | ||
180 | char *selName[argc - 2]; | ||
181 | int i; | ||
182 | |||
183 | if ((funct & 1) == 1) | ||
184 | pdates = 1; | ||
185 | if ((funct & 2) == 2) | ||
186 | verbose = 1; | ||
187 | if ((funct & 4) == 4) | ||
188 | display = 1; | ||
189 | if ((funct & 16) == 16) { /* extract to stdout */ | ||
190 | extract = 1; | ||
191 | extToStdout = 1; | ||
192 | } | ||
193 | if ((funct & 8) == 8) { /* extract to file */ | ||
194 | extract = 1; | ||
195 | } | ||
196 | arName = fileNames[2]; | ||
197 | for (i = 0; i < (argc - 3); i++) | ||
198 | selName[i] = fileNames[i + 3]; | ||
199 | arFd = open(arName, O_RDONLY); | ||
200 | if (arFd < 0) { | ||
201 | errorMsg("Error opening '%s': %s\n", arName, strerror(errno)); | ||
202 | return (FALSE); | ||
203 | } | ||
204 | if (fullRead(arFd, arVersion, 8) <= 0) { | ||
205 | errorMsg("ar: Unexpected EOF in archive\n"); | ||
206 | return (FALSE); | ||
207 | } | ||
208 | if (strncmp(arVersion, "!<arch>", 7) != 0) { | ||
209 | errorMsg("ar header fails check "); | ||
210 | return (FALSE); | ||
211 | } | ||
212 | while ((status = fullRead(arFd, (char *) &rawArHeader, AR_BLOCK_SIZE)) | ||
213 | == AR_BLOCK_SIZE) { | ||
214 | readArHeader(&rawArHeader, &arEntry); | ||
215 | |||
216 | if (display == 1) { | ||
217 | displayContents(&arEntry, funct); | ||
218 | } | ||
219 | if (argc == 3) | ||
220 | found = 1; | ||
221 | else { | ||
222 | found = 0; | ||
223 | for (i = 0; i < (argc - 3); i++) { | ||
224 | if ((status = (strcmp(selName[i], arEntry.name))) == 0) | ||
225 | found = 1; | ||
226 | } | ||
227 | } | ||
228 | if ((extract == 1) && (found == 1)) { | ||
229 | if (extToStdout == 1) { | ||
230 | copySubFile(arFd, fileno(stdout), arEntry.size); | ||
231 | } else { | ||
232 | extractToFile(arFd, "./", arEntry.name, arEntry.size); | ||
233 | } | ||
234 | } else | ||
235 | lseek(arFd, arEntry.size, SEEK_CUR); | ||
236 | } | ||
237 | return (0); | ||
238 | } | ||
239 | |||
240 | extern int ar_main(int argc, char **argv) | ||
241 | { | ||
242 | int ret = 0; | ||
243 | char *opt_ptr; | ||
244 | char c; | ||
245 | int funct = 0; | ||
246 | |||
247 | if (argc < 2) | ||
248 | usage(ar_usage); | ||
249 | |||
250 | opt_ptr = argv[1]; | ||
251 | if (*opt_ptr == '-') | ||
252 | ++opt_ptr; | ||
253 | while ((c = *opt_ptr++) != '\0') { | ||
254 | switch (c) { | ||
255 | case 'o': /* preserver original dates */ | ||
256 | funct = funct | 1; | ||
257 | break; | ||
258 | case 'p': /* extract to stdout */ | ||
259 | funct = funct | 16; | ||
260 | break; | ||
261 | case 't': /* display contents */ | ||
262 | funct = funct | 4; | ||
263 | break; | ||
264 | case 'x': /* extract contents of archive */ | ||
265 | funct = funct | 8; | ||
266 | break; | ||
267 | case 'v': /* be verbose */ | ||
268 | funct = funct | 2; | ||
269 | break; | ||
270 | default: | ||
271 | usage(ar_usage); | ||
272 | } | ||
273 | } | ||
274 | if (funct > 3) | ||
275 | ret = readArFile(argv, argc, funct); | ||
276 | return (ret); | ||
277 | } | ||