*** empty log message ***
[make.git] / arscan.c
blob7352785e286ff039481ca5a680c794b3f06264e5
1 /* Library function for scanning an archive file.
2 Copyright (C) 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #include "make.h"
20 #ifdef HAVE_FCNTL_H
21 #include <fcntl.h>
22 #else
23 #include <sys/file.h>
24 #endif
26 #ifndef NO_ARCHIVES
28 /* On the sun386i and in System V rel 3, ar.h defines two different archive
29 formats depending upon whether you have defined PORTAR (normal) or PORT5AR
30 (System V Release 1). There is no default, one or the other must be defined
31 to have a nonzero value. */
33 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
34 #undef PORTAR
35 #define PORTAR 1
36 #endif
38 #include <ar.h>
40 /* Cray's <ar.h> apparently defines this. */
41 #ifndef AR_HDR_SIZE
42 #define AR_HDR_SIZE (sizeof (struct ar_hdr))
43 #endif
45 /* SCO Unix's compiler defines both of these. */
46 #ifdef M_UNIX
47 #undef M_XENIX
48 #endif
50 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
52 Open the archive named ARCHIVE, find its members one by one,
53 and for each one call FUNCTION with the following arguments:
54 archive file descriptor for reading the data,
55 member name,
56 member name might be truncated flag,
57 member header position in file,
58 member data position in file,
59 member data size,
60 member date,
61 member uid,
62 member gid,
63 member protection mode,
64 ARG.
66 The descriptor is poised to read the data of the member
67 when FUNCTION is called. It does not matter how much
68 data FUNCTION reads.
70 If FUNCTION returns nonzero, we immediately return
71 what FUNCTION returned.
73 Returns -1 if archive does not exist,
74 Returns -2 if archive has invalid format.
75 Returns 0 if have scanned successfully. */
77 long int
78 ar_scan (archive, function, arg)
79 char *archive;
80 long int (*function) ();
81 long int arg;
83 #ifdef AIAMAG
84 FL_HDR fl_header;
85 #else
86 int long_name = 0;
87 #endif
88 char *namemap = 0;
89 register int desc = open (archive, O_RDONLY, 0);
90 if (desc < 0)
91 return -1;
92 #ifdef SARMAG
94 char buf[SARMAG];
95 register int nread = read (desc, buf, SARMAG);
96 if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
98 (void) close (desc);
99 return -2;
102 #else
103 #ifdef AIAMAG
105 register int nread = read (desc, (char *) &fl_header, FL_HSZ);
106 if (nread != FL_HSZ || bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
108 (void) close (desc);
109 return -2;
112 #else
114 #ifndef M_XENIX
115 int buf;
116 #else
117 unsigned short int buf;
118 #endif
119 register int nread = read(desc, &buf, sizeof (buf));
120 if (nread != sizeof (buf) || buf != ARMAG)
122 (void) close (desc);
123 return -2;
126 #endif
127 #endif
129 /* Now find the members one by one. */
131 #ifdef SARMAG
132 register long int member_offset = SARMAG;
133 #else
134 #ifdef AIAMAG
135 long int member_offset;
136 long int last_member_offset;
138 sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
139 sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
140 #else
141 #ifndef M_XENIX
142 register long int member_offset = sizeof (int);
143 #else /* Xenix. */
144 register long int member_offset = sizeof (unsigned short int);
145 #endif /* Not Xenix. */
146 #endif
147 #endif
149 while (1)
151 register int nread;
152 struct ar_hdr member_header;
153 #ifdef AIAMAG
154 char name[256];
155 int name_len;
156 long int dateval;
157 int uidval, gidval;
158 long int data_offset;
159 #else
160 char namebuf[sizeof member_header.ar_name + 1];
161 char *name;
162 int is_namemap; /* Nonzero if this entry maps long names. */
163 #endif
164 long int eltsize;
165 int eltmode;
166 long int fnval;
168 if (lseek (desc, member_offset, 0) < 0)
170 (void) close (desc);
171 return -2;
174 #ifdef AIAMAG
175 #define AR_MEMHDR (AR_HDR_SIZE - sizeof (member_header._ar_name))
176 nread = read (desc, (char *) &member_header, AR_MEMHDR);
178 if (nread != AR_MEMHDR)
180 (void) close (desc);
181 return -2;
184 sscanf (member_header.ar_namlen, "%4d", &name_len);
185 nread = read (desc, name, name_len);
187 if (nread != name_len)
189 (void) close (desc);
190 return -2;
193 name[name_len] = 0;
195 sscanf (member_header.ar_date, "%12ld", &dateval);
196 sscanf (member_header.ar_uid, "%12d", &uidval);
197 sscanf (member_header.ar_gid, "%12d", &gidval);
198 sscanf (member_header.ar_mode, "%12o", &eltmode);
199 sscanf (member_header.ar_size, "%12ld", &eltsize);
201 if ((data_offset = member_offset + AR_MEMHDR + name_len + 2) % 2)
202 ++data_offset;
204 fnval =
205 (*function) (desc, name, 0,
206 member_offset, data_offset, eltsize,
207 dateval, uidval, gidval,
208 eltmode, arg);
210 #else /* Not AIAMAG. */
211 nread = read (desc, (char *) &member_header, AR_HDR_SIZE);
212 if (nread == 0)
213 /* No data left means end of file; that is OK. */
214 break;
216 if (nread != AR_HDR_SIZE
217 #ifdef ARFMAG
218 || bcmp (member_header.ar_fmag, ARFMAG, 2)
219 #endif
222 (void) close (desc);
223 return -2;
226 name = namebuf;
227 bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
229 register char *p = name + sizeof member_header.ar_name;
231 *p = '\0';
232 while (p > name && *--p == ' ');
234 #ifndef AIAMAG
235 /* If the member name is "//" or "ARFILENAMES/" this may be
236 a list of file name mappings. The maximum file name
237 length supported by the standard archive format is 14
238 characters. This member will actually always be the
239 first or second entry in the archive, but we don't check
240 that. */
241 is_namemap = (!strcmp (name, "//")
242 || !strcmp (name, "ARFILENAMES/"));
243 #endif /* Not AIAMAG. */
244 /* On some systems, there is a slash after each member name. */
245 if (*p == '/')
246 *p = '\0';
248 #ifndef AIAMAG
249 /* If the member name starts with a space or a slash, this
250 is an index into the file name mappings (used by GNU ar).
251 Otherwise if the member name looks like #1/NUMBER the
252 real member name appears in the element data (used by
253 4.4BSD). */
254 if (! is_namemap
255 && (name[0] == ' ' || name[0] == '/')
256 && namemap != 0)
258 name = namemap + atoi (name + 1);
259 long_name = 1;
261 else if (name[0] == '#'
262 && name[1] == '1'
263 && name[2] == '/')
265 int namesize = atoi (name + 3);
267 name = (char *) alloca (namesize + 1);
268 nread = read (desc, name, namesize);
269 if (nread != namesize)
271 close (desc);
272 return -2;
274 name[namesize] = '\0';
276 long_name = 1;
278 #endif /* Not AIAMAG. */
281 #ifndef M_XENIX
282 sscanf (member_header.ar_mode, "%o", &eltmode);
283 eltsize = atol (member_header.ar_size);
284 #else /* Xenix. */
285 eltmode = (unsigned short int) member_header.ar_mode;
286 eltsize = member_header.ar_size;
287 #endif /* Not Xenix. */
289 fnval =
290 (*function) (desc, name, ! long_name, member_offset,
291 member_offset + AR_HDR_SIZE, eltsize,
292 #ifndef M_XENIX
293 atol (member_header.ar_date),
294 atoi (member_header.ar_uid),
295 atoi (member_header.ar_gid),
296 #else /* Xenix. */
297 member_header.ar_date,
298 member_header.ar_uid,
299 member_header.ar_gid,
300 #endif /* Not Xenix. */
301 eltmode, arg);
303 #endif /* AIAMAG. */
305 if (fnval)
307 (void) close (desc);
308 return fnval;
311 #ifdef AIAMAG
312 if (member_offset == last_member_offset)
313 /* End of the chain. */
314 break;
316 sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
318 if (lseek (desc, member_offset, 0) != member_offset)
320 (void) close (desc);
321 return -2;
323 #else
325 /* If this member maps archive names, we must read it in. The
326 name map will always precede any members whose names must
327 be mapped. */
328 if (is_namemap)
330 char *clear;
331 char *limit;
333 namemap = (char *) alloca (eltsize);
334 nread = read (desc, namemap, eltsize);
335 if (nread != eltsize)
337 (void) close (desc);
338 return -2;
341 /* The names are separated by newlines. Some formats have
342 a trailing slash. Null terminate the strings for
343 convenience. */
344 limit = namemap + eltsize;
345 for (clear = namemap; clear < limit; clear++)
347 if (*clear == '\n')
349 *clear = '\0';
350 if (clear[-1] == '/')
351 clear[-1] = '\0';
355 is_namemap = 0;
358 member_offset += AR_HDR_SIZE + eltsize;
359 if (member_offset % 2 != 0)
360 member_offset++;
361 #endif
365 close (desc);
366 return 0;
369 /* Return nonzero iff NAME matches MEM.
370 If TRUNCATED is nonzero, MEM may be truncated to
371 sizeof (struct ar_hdr.ar_name) - 1. */
374 ar_name_equal (name, mem, truncated)
375 char *name, *mem;
376 int truncated;
378 char *p;
380 p = rindex (name, '/');
381 if (p != 0)
382 name = p + 1;
384 /* We no longer use this kludge, since we
385 now support long archive member names. */
387 #if 0 && !defined (AIAMAG) && !defined (APOLLO)
390 /* `reallylongname.o' matches `reallylongnam.o'.
391 If member names have a trailing slash, that's `reallylongna.o'. */
393 struct ar_hdr h;
394 unsigned int max = sizeof (h.ar_name);
395 unsigned int namelen, memlen;
397 if (strncmp (name, mem, max - 3))
398 return 0;
400 namelen = strlen (name);
401 memlen = strlen (mem);
403 if (namelen > memlen && memlen >= max - 1
404 && name[namelen - 2] == '.' && name[namelen - 1] == 'o'
405 && mem[memlen - 2] == '.' && mem[memlen - 1] == 'o')
406 return 1;
408 if (namelen != memlen)
409 return 0;
411 return (namelen < max - 3 || !strcmp (name + max - 3, mem + max - 3));
414 #else /* AIX or APOLLO. */
416 if (truncated)
418 #ifdef AIAMAG
419 /* TRUNCATED should never be set on this system. */
420 abort ();
421 #else
422 struct ar_hdr hdr;
423 return !strncmp (name, mem,
424 sizeof (hdr.ar_name) - 1);
425 #endif
428 return !strcmp (name, mem);
430 #endif
433 /* ARGSUSED */
434 static long int
435 ar_member_pos (desc, mem, truncated,
436 hdrpos, datapos, size, date, uid, gid, mode, name)
437 int desc;
438 char *mem;
439 int truncated;
440 long int hdrpos, datapos, size, date;
441 int uid, gid, mode;
442 char *name;
444 if (!ar_name_equal (name, mem, truncated))
445 return 0;
446 return hdrpos;
449 /* Set date of member MEMNAME in archive ARNAME to current time.
450 Returns 0 if successful,
451 -1 if file ARNAME does not exist,
452 -2 if not a valid archive,
453 -3 if other random system call error (including file read-only),
454 1 if valid but member MEMNAME does not exist. */
457 ar_member_touch (arname, memname)
458 char *arname, *memname;
460 register long int pos = ar_scan (arname, ar_member_pos, (long int) memname);
461 register int fd;
462 struct ar_hdr ar_hdr;
463 register int i;
464 struct stat statbuf;
466 if (pos < 0)
467 return (int) pos;
468 if (!pos)
469 return 1;
471 fd = open (arname, O_RDWR, 0666);
472 if (fd < 0)
473 return -3;
474 /* Read in this member's header */
475 if (lseek (fd, pos, 0) < 0)
476 goto lose;
477 if (AR_HDR_SIZE != read (fd, (char *) &ar_hdr, AR_HDR_SIZE))
478 goto lose;
479 /* Write back the header, thus touching the archive file. */
480 if (lseek (fd, pos, 0) < 0)
481 goto lose;
482 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
483 goto lose;
484 /* The file's mtime is the time we we want. */
485 fstat (fd, &statbuf);
486 #if defined(ARFMAG) || defined(AIAMAG)
487 /* Advance member's time to that time */
488 for (i = 0; i < sizeof ar_hdr.ar_date; i++)
489 ar_hdr.ar_date[i] = ' ';
490 sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime);
491 #ifdef AIAMAG
492 ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
493 #endif
494 #else
495 ar_hdr.ar_date = statbuf.st_mtime;
496 #endif
497 /* Write back this member's header */
498 if (lseek (fd, pos, 0) < 0)
499 goto lose;
500 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
501 goto lose;
502 close (fd);
503 return 0;
505 lose:
506 i = errno;
507 close (fd);
508 errno = i;
509 return -3;
512 #ifdef TEST
514 long int
515 describe_member (desc, name, truncated,
516 hdrpos, datapos, size, date, uid, gid, mode)
517 int desc;
518 char *name;
519 int truncated;
520 long int hdrpos, datapos, size, date;
521 int uid, gid, mode;
523 extern char *ctime ();
525 printf ("Member `%s'%s: %ld bytes at %ld (%ld).\n",
526 name, truncated ? " (name might be truncated)" : "",
527 size, hdrpos, datapos);
528 printf (" Date %s", ctime (&date));
529 printf (" uid = %d, gid = %d, mode = 0%o.\n", uid, gid, mode);
531 return 0;
534 main (argc, argv)
535 int argc;
536 char **argv;
538 ar_scan (argv[1], describe_member);
539 return 0;
542 #endif /* TEST. */
544 #endif /* NO_ARCHIVES. */