source: trunk/minix/commands/make/archive.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 6.3 KB
Line 
1/* archive.c - archive support Author: Kees J. Bot
2 * 13 Nov 1993
3 */
4#include "h.h"
5
6#ifdef unix
7
8#include <unistd.h>
9#include <fcntl.h>
10
11#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
12#define arraylimit(a) ((a) + arraysize(a))
13
14/* ASCII ar header. */
15
16#define ASCII_ARMAG "!<arch>\n"
17#define ASCII_SARMAG 8
18#define ASCII_ARFMAG "`\n"
19
20struct ascii_ar_hdr {
21 char ar_name[16];
22 char ar_date[12];
23 char ar_uid[6];
24 char ar_gid[6];
25 char ar_mode[8];
26 char ar_size[10];
27 char ar_fmag[2];
28};
29
30/* ACK ar header. */
31
32#define ACK_ARMAG 0177545
33#define ACK_AALMAG 0177454
34
35struct ack_ar_hdr {
36 char ar_name[14];
37 unsigned long ar_date;
38 unsigned char ar_uid;
39 unsigned char ar_gid;
40 unsigned short ar_mode;
41 unsigned long ar_size;
42};
43
44typedef struct archname {
45 struct archname *next; /* Next on the hash chain. */
46 char name[16]; /* One archive entry. */
47 time_t date; /* The timestamp. */
48 /* (no need for other attibutes) */
49} archname_t;
50
51static size_t namelen; /* Max name length, 14 or 16. */
52
53#define HASHSIZE (64 << sizeof(int))
54
55static archname_t *nametab[HASHSIZE];
56
57_PROTOTYPE( static int hash, (char *name) );
58_PROTOTYPE( static int searchtab, (char *name, time_t *date, int scan) );
59_PROTOTYPE( static void deltab, (void) );
60_PROTOTYPE( static long ar_atol, (char *s, size_t n) );
61_PROTOTYPE( static int read_ascii_archive, (int afd) );
62_PROTOTYPE( static int read_ack_archive, (int afd) );
63
64static char *lpar, *rpar; /* Leave these at '(' and ')'. */
65
66int is_archive_ref(name) char *name;
67/* True if name is of the form "archive(file)". */
68{
69 char *p = name;
70
71 while (*p != 0 && *p != '(' && *p != ')') p++;
72 lpar = p;
73 if (*p++ != '(') return 0;
74
75 while (*p != 0 && *p != '(' && *p != ')') p++;
76 rpar = p;
77 if (*p++ != ')') return 0;
78
79 return *p == 0;
80}
81
82static int hash(name) char *name;
83/* Compute a hash value out of a name. */
84{
85 unsigned h = 0;
86 unsigned char *p = (unsigned char *) name;
87 int n = namelen;
88
89 while (*p != 0) {
90 h = h * 0x1111 + *p++;
91 if (--n == 0) break;
92 }
93
94 return h % arraysize(nametab);
95}
96
97static int searchtab(name, date, scan) char *name; time_t *date; int scan;
98/* Enter a name to the table, or return the date of one already there. */
99{
100 archname_t **pnp, *np;
101 int cmp = 1;
102
103 pnp = &nametab[hash(name)];
104
105 while ((np = *pnp) != NULL
106 && (cmp = strncmp(name, np->name, namelen)) > 0) {
107 pnp= &np->next;
108 }
109
110 if (cmp != 0) {
111 if (scan) {
112 errno = ENOENT;
113 return -1;
114 }
115 if ((np = (archname_t *) malloc(sizeof(*np))) == NULL)
116 fatal("No memory for archive name cache",(char *)0,0);
117 strncpy(np->name, name, namelen);
118 np->date = *date;
119 np->next = *pnp;
120 *pnp = np;
121 }
122 if (scan) *date = np->date;
123 return 0;
124}
125
126static void deltab()
127/* Delete the name cache, a different library is to be read. */
128{
129 archname_t **pnp, *np, *junk;
130
131 for (pnp = nametab; pnp < arraylimit(nametab); pnp++) {
132 for (np = *pnp; np != NULL; ) {
133 junk = np;
134 np = np->next;
135 free(junk);
136 }
137 *pnp = NULL;
138 }
139}
140
141static long ar_atol(s, n) char *s; size_t n;
142/* Transform a string into a number. Ignore the space padding. */
143{
144 long l= 0;
145
146 while (n > 0) {
147 if (*s != ' ') l= l * 10 + (*s - '0');
148 s++;
149 n--;
150 }
151 return l;
152}
153
154static int read_ascii_archive(afd)
155int afd;
156/* Read a modern ASCII type archive. */
157{
158 struct ascii_ar_hdr hdr;
159 off_t pos= 8;
160 char *p;
161 time_t date;
162
163 namelen = 16;
164
165 for (;;) {
166 if (lseek(afd, pos, SEEK_SET) == -1) return -1;
167
168 switch (read(afd, &hdr, sizeof(hdr))) {
169 case sizeof(hdr):
170 break;
171 case -1:
172 return -1;
173 default:
174 return 0;
175 }
176
177 if (strncmp(hdr.ar_fmag, ASCII_ARFMAG, sizeof(hdr.ar_fmag)) != 0) {
178 errno= EINVAL;
179 return -1;
180 }
181
182 /* Strings are space padded! */
183 for (p= hdr.ar_name; p < hdr.ar_name + sizeof(hdr.ar_name); p++) {
184 if (*p == ' ') {
185 *p= 0;
186 break;
187 }
188 }
189
190 /* Add a file to the cache. */
191 date = ar_atol(hdr.ar_date, sizeof(hdr.ar_date));
192 searchtab(hdr.ar_name, &date, 0);
193
194 pos+= sizeof(hdr) + ar_atol(hdr.ar_size, sizeof(hdr.ar_size));
195 pos= (pos + 1) & (~ (off_t) 1);
196 }
197}
198
199static int read_ack_archive(afd)
200int afd;
201/* Read an ACK type archive. */
202{
203 unsigned char raw_hdr[14 + 4 + 1 + 1 + 2 + 4];
204 struct ack_ar_hdr hdr;
205 off_t pos= 2;
206 time_t date;
207
208 namelen = 14;
209
210 for (;;) {
211 if (lseek(afd, pos, SEEK_SET) == -1) return -1;
212
213 switch (read(afd, raw_hdr, sizeof(raw_hdr))) {
214 case sizeof(raw_hdr):
215 break;
216 case -1:
217 return -1;
218 default:
219 return 0;
220 }
221
222 /* Copy the useful fields from the raw bytes transforming PDP-11
223 * style numbers to native format.
224 */
225 memcpy(hdr.ar_name, raw_hdr + 0, 14);
226 hdr.ar_date= (long) raw_hdr[14 + 1] << 24
227 | (long) raw_hdr[14 + 0] << 16
228 | (long) raw_hdr[14 + 3] << 8
229 | (long) raw_hdr[14 + 2] << 0;
230 hdr.ar_size= (long) raw_hdr[22 + 1] << 24
231 | (long) raw_hdr[22 + 0] << 16
232 | (long) raw_hdr[22 + 3] << 8
233 | (long) raw_hdr[22 + 2] << 0;
234
235 /* Add a file to the cache. */
236 date = hdr.ar_date;
237 searchtab(hdr.ar_name, &date, 0);
238
239 pos= (pos + 26 + hdr.ar_size + 1) & (~ (off_t) 1);
240 }
241}
242
243int archive_stat(name, stp) char *name; struct stat *stp;
244/* Search an archive for a file and return that file's stat info. */
245{
246 int afd;
247 int r= -1;
248 char magic[8];
249 char *file;
250 static dev_t ardev;
251 static ino_t arino = 0;
252 static time_t armtime;
253
254 if (!is_archive_ref(name)) { errno = EINVAL; return -1; }
255 *lpar= 0;
256 *rpar= 0;
257 file= lpar + 1;
258
259 if (stat(name, stp) < 0) goto bail_out;
260
261 if (stp->st_ino != arino || stp->st_dev != ardev) {
262 /* Either the first (and probably only) library, or a different
263 * library.
264 */
265 arino = stp->st_ino;
266 ardev = stp->st_dev;
267 armtime = stp->st_mtime;
268 deltab();
269
270 if ((afd= open(name, O_RDONLY)) < 0) goto bail_out;
271
272 switch (read(afd, magic, sizeof(magic))) {
273 case 8:
274 if (strncmp(magic, ASCII_ARMAG, 8) == 0) {
275 r= read_ascii_archive(afd);
276 break;
277 }
278 if ((magic[0] & 0xFF) == ((ACK_AALMAG >> 0) & 0xFF)
279 && (magic[1] & 0xFF) == ((ACK_AALMAG >> 8) & 0xFF)
280 ) {
281 r= read_ack_archive(afd);
282 break;
283 }
284 /*FALL THROUGH*/
285 default:
286 errno = EINVAL;
287 /*FALL THROUGH*/
288 case -1:
289 /* r= -1 */;
290 }
291 { int e= errno; close(afd); errno= e; }
292 } else {
293 /* Library is cached. */
294 r = 0;
295 }
296
297 if (r == 0) {
298 /* Search the cache. */
299 r = searchtab(file, &stp->st_mtime, 1);
300 if (stp->st_mtime > armtime) stp->st_mtime = armtime;
301 }
302
303bail_out:
304 /* Repair the name(file) thing. */
305 *lpar= '(';
306 *rpar= ')';
307 return r;
308}
309#endif
Note: See TracBrowser for help on using the repository browser.