(AC_MACRODIR): Define if undefined.
[make.git] / arscan.c
blobda9428de01817828cc69270ae721e00a20acfbcf
1 /* Library function for scanning an archive file.
2 Copyright (C) 1987, 89, 91, 92, 93, 94 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 /* SCO Unix's compiler defines both of these. */
29 #ifdef M_UNIX
30 #undef M_XENIX
31 #endif
33 /* On the sun386i and in System V rel 3, ar.h defines two different archive
34 formats depending upon whether you have defined PORTAR (normal) or PORT5AR
35 (System V Release 1). There is no default, one or the other must be defined
36 to have a nonzero value. */
38 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
39 #undef PORTAR
40 #ifdef M_XENIX
41 /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
42 PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
43 right one. */
44 #define PORTAR 0
45 #else
46 #define PORTAR 1
47 #endif
48 #endif
50 #include <ar.h>
52 /* Cray's <ar.h> apparently defines this. */
53 #ifndef AR_HDR_SIZE
54 #define AR_HDR_SIZE (sizeof (struct ar_hdr))
55 #endif
57 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
59 Open the archive named ARCHIVE, find its members one by one,
60 and for each one call FUNCTION with the following arguments:
61 archive file descriptor for reading the data,
62 member name,
63 member name might be truncated flag,
64 member header position in file,
65 member data position in file,
66 member data size,
67 member date,
68 member uid,
69 member gid,
70 member protection mode,
71 ARG.
73 The descriptor is poised to read the data of the member
74 when FUNCTION is called. It does not matter how much
75 data FUNCTION reads.
77 If FUNCTION returns nonzero, we immediately return
78 what FUNCTION returned.
80 Returns -1 if archive does not exist,
81 Returns -2 if archive has invalid format.
82 Returns 0 if have scanned successfully. */
84 long int
85 ar_scan (archive, function, arg)
86 char *archive;
87 long int (*function) ();
88 long int arg;
90 #ifdef AIAMAG
91 FL_HDR fl_header;
92 #else
93 int long_name = 0;
94 #endif
95 char *namemap = 0;
96 register int desc = open (archive, O_RDONLY, 0);
97 if (desc < 0)
98 return -1;
99 #ifdef SARMAG
101 char buf[SARMAG];
102 register int nread = read (desc, buf, SARMAG);
103 if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
105 (void) close (desc);
106 return -2;
109 #else
110 #ifdef AIAMAG
112 register int nread = read (desc, (char *) &fl_header, FL_HSZ);
113 if (nread != FL_HSZ || bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
115 (void) close (desc);
116 return -2;
119 #else
121 #ifndef M_XENIX
122 int buf;
123 #else
124 unsigned short int buf;
125 #endif
126 register int nread = read(desc, &buf, sizeof (buf));
127 if (nread != sizeof (buf) || buf != ARMAG)
129 (void) close (desc);
130 return -2;
133 #endif
134 #endif
136 /* Now find the members one by one. */
138 #ifdef SARMAG
139 register long int member_offset = SARMAG;
140 #else
141 #ifdef AIAMAG
142 long int member_offset;
143 long int last_member_offset;
145 sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
146 sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
147 #else
148 #ifndef M_XENIX
149 register long int member_offset = sizeof (int);
150 #else /* Xenix. */
151 register long int member_offset = sizeof (unsigned short int);
152 #endif /* Not Xenix. */
153 #endif
154 #endif
156 while (1)
158 register int nread;
159 struct ar_hdr member_header;
160 #ifdef AIAMAG
161 char name[256];
162 int name_len;
163 long int dateval;
164 int uidval, gidval;
165 long int data_offset;
166 #else
167 char namebuf[sizeof member_header.ar_name + 1];
168 char *name;
169 int is_namemap; /* Nonzero if this entry maps long names. */
170 #endif
171 long int eltsize;
172 int eltmode;
173 long int fnval;
175 if (lseek (desc, member_offset, 0) < 0)
177 (void) close (desc);
178 return -2;
181 #ifdef AIAMAG
182 #define AR_MEMHDR (AR_HDR_SIZE - sizeof (member_header._ar_name))
183 nread = read (desc, (char *) &member_header, AR_MEMHDR);
185 if (nread != AR_MEMHDR)
187 (void) close (desc);
188 return -2;
191 sscanf (member_header.ar_namlen, "%4d", &name_len);
192 nread = read (desc, name, name_len);
194 if (nread != name_len)
196 (void) close (desc);
197 return -2;
200 name[name_len] = 0;
202 sscanf (member_header.ar_date, "%12ld", &dateval);
203 sscanf (member_header.ar_uid, "%12d", &uidval);
204 sscanf (member_header.ar_gid, "%12d", &gidval);
205 sscanf (member_header.ar_mode, "%12o", &eltmode);
206 sscanf (member_header.ar_size, "%12ld", &eltsize);
208 if ((data_offset = member_offset + AR_MEMHDR + name_len + 2) % 2)
209 ++data_offset;
211 fnval =
212 (*function) (desc, name, 0,
213 member_offset, data_offset, eltsize,
214 dateval, uidval, gidval,
215 eltmode, arg);
217 #else /* Not AIAMAG. */
218 nread = read (desc, (char *) &member_header, AR_HDR_SIZE);
219 if (nread == 0)
220 /* No data left means end of file; that is OK. */
221 break;
223 if (nread != AR_HDR_SIZE
224 #ifdef ARFMAG
225 || bcmp (member_header.ar_fmag, ARFMAG, 2)
226 #endif
229 (void) close (desc);
230 return -2;
233 name = namebuf;
234 bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
236 register char *p = name + sizeof member_header.ar_name;
238 *p = '\0';
239 while (p > name && *--p == ' ');
241 #ifndef AIAMAG
242 /* If the member name is "//" or "ARFILENAMES/" this may be
243 a list of file name mappings. The maximum file name
244 length supported by the standard archive format is 14
245 characters. This member will actually always be the
246 first or second entry in the archive, but we don't check
247 that. */
248 is_namemap = (!strcmp (name, "//")
249 || !strcmp (name, "ARFILENAMES/"));
250 #endif /* Not AIAMAG. */
251 /* On some systems, there is a slash after each member name. */
252 if (*p == '/')
253 *p = '\0';
255 #ifndef AIAMAG
256 /* If the member name starts with a space or a slash, this
257 is an index into the file name mappings (used by GNU ar).
258 Otherwise if the member name looks like #1/NUMBER the
259 real member name appears in the element data (used by
260 4.4BSD). */
261 if (! is_namemap
262 && (name[0] == ' ' || name[0] == '/')
263 && namemap != 0)
265 name = namemap + atoi (name + 1);
266 long_name = 1;
268 else if (name[0] == '#'
269 && name[1] == '1'
270 && name[2] == '/')
272 int namesize = atoi (name + 3);
274 name = (char *) alloca (namesize + 1);
275 nread = read (desc, name, namesize);
276 if (nread != namesize)
278 close (desc);
279 return -2;
281 name[namesize] = '\0';
283 long_name = 1;
285 #endif /* Not AIAMAG. */
288 #ifndef M_XENIX
289 sscanf (member_header.ar_mode, "%o", &eltmode);
290 eltsize = atol (member_header.ar_size);
291 #else /* Xenix. */
292 eltmode = (unsigned short int) member_header.ar_mode;
293 eltsize = member_header.ar_size;
294 #endif /* Not Xenix. */
296 fnval =
297 (*function) (desc, name, ! long_name, member_offset,
298 member_offset + AR_HDR_SIZE, eltsize,
299 #ifndef M_XENIX
300 atol (member_header.ar_date),
301 atoi (member_header.ar_uid),
302 atoi (member_header.ar_gid),
303 #else /* Xenix. */
304 member_header.ar_date,
305 member_header.ar_uid,
306 member_header.ar_gid,
307 #endif /* Not Xenix. */
308 eltmode, arg);
310 #endif /* AIAMAG. */
312 if (fnval)
314 (void) close (desc);
315 return fnval;
318 #ifdef AIAMAG
319 if (member_offset == last_member_offset)
320 /* End of the chain. */
321 break;
323 sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
325 if (lseek (desc, member_offset, 0) != member_offset)
327 (void) close (desc);
328 return -2;
330 #else
332 /* If this member maps archive names, we must read it in. The
333 name map will always precede any members whose names must
334 be mapped. */
335 if (is_namemap)
337 char *clear;
338 char *limit;
340 namemap = (char *) alloca (eltsize);
341 nread = read (desc, namemap, eltsize);
342 if (nread != eltsize)
344 (void) close (desc);
345 return -2;
348 /* The names are separated by newlines. Some formats have
349 a trailing slash. Null terminate the strings for
350 convenience. */
351 limit = namemap + eltsize;
352 for (clear = namemap; clear < limit; clear++)
354 if (*clear == '\n')
356 *clear = '\0';
357 if (clear[-1] == '/')
358 clear[-1] = '\0';
362 is_namemap = 0;
365 member_offset += AR_HDR_SIZE + eltsize;
366 if (member_offset % 2 != 0)
367 member_offset++;
368 #endif
372 close (desc);
373 return 0;
376 /* Return nonzero iff NAME matches MEM.
377 If TRUNCATED is nonzero, MEM may be truncated to
378 sizeof (struct ar_hdr.ar_name) - 1. */
381 ar_name_equal (name, mem, truncated)
382 char *name, *mem;
383 int truncated;
385 char *p;
387 p = rindex (name, '/');
388 if (p != 0)
389 name = p + 1;
391 /* We no longer use this kludge, since we
392 now support long archive member names. */
394 #if 0 && !defined (AIAMAG) && !defined (APOLLO)
397 /* `reallylongname.o' matches `reallylongnam.o'.
398 If member names have a trailing slash, that's `reallylongna.o'. */
400 struct ar_hdr h;
401 unsigned int max = sizeof (h.ar_name);
402 unsigned int namelen, memlen;
404 if (strncmp (name, mem, max - 3))
405 return 0;
407 namelen = strlen (name);
408 memlen = strlen (mem);
410 if (namelen > memlen && memlen >= max - 1
411 && name[namelen - 2] == '.' && name[namelen - 1] == 'o'
412 && mem[memlen - 2] == '.' && mem[memlen - 1] == 'o')
413 return 1;
415 if (namelen != memlen)
416 return 0;
418 return (namelen < max - 3 || !strcmp (name + max - 3, mem + max - 3));
421 #else /* AIX or APOLLO. */
423 if (truncated)
425 #ifdef AIAMAG
426 /* TRUNCATED should never be set on this system. */
427 abort ();
428 #else
429 struct ar_hdr hdr;
430 return !strncmp (name, mem,
431 sizeof (hdr.ar_name) -
432 #ifndef __hpux
434 #else
436 #endif /* __hpux */
438 #endif
441 return !strcmp (name, mem);
443 #endif
446 /* ARGSUSED */
447 static long int
448 ar_member_pos (desc, mem, truncated,
449 hdrpos, datapos, size, date, uid, gid, mode, name)
450 int desc;
451 char *mem;
452 int truncated;
453 long int hdrpos, datapos, size, date;
454 int uid, gid, mode;
455 char *name;
457 if (!ar_name_equal (name, mem, truncated))
458 return 0;
459 return hdrpos;
462 /* Set date of member MEMNAME in archive ARNAME to current time.
463 Returns 0 if successful,
464 -1 if file ARNAME does not exist,
465 -2 if not a valid archive,
466 -3 if other random system call error (including file read-only),
467 1 if valid but member MEMNAME does not exist. */
470 ar_member_touch (arname, memname)
471 char *arname, *memname;
473 register long int pos = ar_scan (arname, ar_member_pos, (long int) memname);
474 register int fd;
475 struct ar_hdr ar_hdr;
476 register int i;
477 struct stat statbuf;
479 if (pos < 0)
480 return (int) pos;
481 if (!pos)
482 return 1;
484 fd = open (arname, O_RDWR, 0666);
485 if (fd < 0)
486 return -3;
487 /* Read in this member's header */
488 if (lseek (fd, pos, 0) < 0)
489 goto lose;
490 if (AR_HDR_SIZE != read (fd, (char *) &ar_hdr, AR_HDR_SIZE))
491 goto lose;
492 /* Write back the header, thus touching the archive file. */
493 if (lseek (fd, pos, 0) < 0)
494 goto lose;
495 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
496 goto lose;
497 /* The file's mtime is the time we we want. */
498 fstat (fd, &statbuf);
499 #if defined(ARFMAG) || defined(AIAMAG)
500 /* Advance member's time to that time */
501 for (i = 0; i < sizeof ar_hdr.ar_date; i++)
502 ar_hdr.ar_date[i] = ' ';
503 sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime);
504 #ifdef AIAMAG
505 ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
506 #endif
507 #else
508 ar_hdr.ar_date = statbuf.st_mtime;
509 #endif
510 /* Write back this member's header */
511 if (lseek (fd, pos, 0) < 0)
512 goto lose;
513 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
514 goto lose;
515 close (fd);
516 return 0;
518 lose:
519 i = errno;
520 close (fd);
521 errno = i;
522 return -3;
525 #ifdef TEST
527 long int
528 describe_member (desc, name, truncated,
529 hdrpos, datapos, size, date, uid, gid, mode)
530 int desc;
531 char *name;
532 int truncated;
533 long int hdrpos, datapos, size, date;
534 int uid, gid, mode;
536 extern char *ctime ();
538 printf ("Member `%s'%s: %ld bytes at %ld (%ld).\n",
539 name, truncated ? " (name might be truncated)" : "",
540 size, hdrpos, datapos);
541 printf (" Date %s", ctime (&date));
542 printf (" uid = %d, gid = %d, mode = 0%o.\n", uid, gid, mode);
544 return 0;
547 main (argc, argv)
548 int argc;
549 char **argv;
551 ar_scan (argv[1], describe_member);
552 return 0;
555 #endif /* TEST. */
557 #endif /* NO_ARCHIVES. */