* Lots of bug fixes and cleanup; new i18n files, etc.
[make.git] / arscan.c
blob5cadbe64bada43abdc9c9844f9afb71c809dfb8f
1 /* Library function for scanning an archive file.
2 Copyright (C) 1987,89,91,92,93,94,95,97 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA. */
19 #include "make.h"
21 #ifdef HAVE_FCNTL_H
22 #include <fcntl.h>
23 #else
24 #include <sys/file.h>
25 #endif
27 #ifndef NO_ARCHIVES
29 #ifdef VMS
30 #include <lbrdef.h>
31 #include <mhddef.h>
32 #include <credef.h>
33 #include <descrip.h>
34 #include <ctype.h>
35 #if __DECC
36 #include <unixlib.h>
37 #include <lbr$routines.h>
38 #endif
40 static void *VMS_lib_idx;
42 static char *VMS_saved_memname;
44 static time_t VMS_member_date;
46 static long int (*VMS_function) ();
48 static int
49 VMS_get_member_info (module, rfa)
50 struct dsc$descriptor_s *module;
51 unsigned long *rfa;
53 int status, i;
54 long int fnval;
56 time_t val;
58 static struct dsc$descriptor_s bufdesc =
59 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
61 struct mhddef *mhd;
62 char filename[128];
64 bufdesc.dsc$a_pointer = filename;
65 bufdesc.dsc$w_length = sizeof (filename);
67 status = lbr$set_module (&VMS_lib_idx, rfa, &bufdesc,
68 &bufdesc.dsc$w_length, 0);
69 if (! status)
71 error (NILF, _("lbr$set_module failed to extract module info, status = %d"),
72 status);
74 lbr$close (&VMS_lib_idx);
76 return 0;
79 mhd = (struct mhddef *) filename;
81 #ifdef __DECC
82 val = decc$fix_time (&mhd->mhd$l_datim);
83 #endif
85 for (i = 0; i < module->dsc$w_length; i++)
86 filename[i] = _tolower ((unsigned char)module->dsc$a_pointer[i]);
88 filename[i] = '\0';
90 VMS_member_date = (time_t) -1;
92 fnval =
93 (*VMS_function) (-1, filename, 0, 0, 0, 0, val, 0, 0, 0,
94 VMS_saved_memname);
96 if (fnval)
98 VMS_member_date = fnval;
99 return 0;
101 else
102 return 1;
105 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
107 Open the archive named ARCHIVE, find its members one by one,
108 and for each one call FUNCTION with the following arguments:
109 archive file descriptor for reading the data,
110 member name,
111 member name might be truncated flag,
112 member header position in file,
113 member data position in file,
114 member data size,
115 member date,
116 member uid,
117 member gid,
118 member protection mode,
119 ARG.
121 NOTE: on VMS systems, only name, date, and arg are meaningful!
123 The descriptor is poised to read the data of the member
124 when FUNCTION is called. It does not matter how much
125 data FUNCTION reads.
127 If FUNCTION returns nonzero, we immediately return
128 what FUNCTION returned.
130 Returns -1 if archive does not exist,
131 Returns -2 if archive has invalid format.
132 Returns 0 if have scanned successfully. */
134 long int
135 ar_scan (archive, function, arg)
136 char *archive;
137 long int (*function) ();
138 long int arg;
140 char *p;
142 static struct dsc$descriptor_s libdesc =
143 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
145 unsigned long func = LBR$C_READ;
146 unsigned long type = LBR$C_TYP_UNK;
147 unsigned long index = 1;
149 int status;
151 status = lbr$ini_control (&VMS_lib_idx, &func, &type, 0);
153 if (! status)
155 error (NILF, _("lbr$ini_control failed with status = %d"),status);
156 return -2;
159 libdesc.dsc$a_pointer = archive;
160 libdesc.dsc$w_length = strlen (archive);
162 status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0);
164 if (! status)
166 error (NILF, _("unable to open library `%s' to lookup member `%s'"),
167 archive, (char *)arg);
168 return -1;
171 VMS_saved_memname = (char *)arg;
173 /* For comparison, delete .obj from arg name. */
175 p = strrchr (VMS_saved_memname, '.');
176 if (p)
177 *p = '\0';
179 VMS_function = function;
181 VMS_member_date = (time_t) -1;
182 lbr$get_index (&VMS_lib_idx, &index, VMS_get_member_info, 0);
184 /* Undo the damage. */
185 if (p)
186 *p = '.';
188 lbr$close (&VMS_lib_idx);
190 return VMS_member_date > 0 ? VMS_member_date : 0;
193 #else /* !VMS */
195 /* SCO Unix's compiler defines both of these. */
196 #ifdef M_UNIX
197 #undef M_XENIX
198 #endif
200 /* On the sun386i and in System V rel 3, ar.h defines two different archive
201 formats depending upon whether you have defined PORTAR (normal) or PORT5AR
202 (System V Release 1). There is no default, one or the other must be defined
203 to have a nonzero value. */
205 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
206 #undef PORTAR
207 #ifdef M_XENIX
208 /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
209 PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
210 right one. */
211 #define PORTAR 0
212 #else
213 #define PORTAR 1
214 #endif
215 #endif
217 /* On AIX, define these symbols to be sure to get both archive formats.
218 AIX 4.3 introduced the "big" archive format to support 64-bit object
219 files, so on AIX 4.3 systems we need to support both the "normal" and
220 "big" archive formats. An archive's format is indicated in the
221 "fl_magic" field of the "FL_HDR" structure. For a normal archive,
222 this field will be the string defined by the AIAMAG symbol. For a
223 "big" archive, it will be the string defined by the AIAMAGBIG symbol
224 (at least on AIX it works this way).
226 Note: we'll define these symbols regardless of which AIX version
227 we're compiling on, but this is okay since we'll use the new symbols
228 only if they're present. */
229 #ifdef _AIX
230 # define __AR_SMALL__
231 # define __AR_BIG__
232 #endif
234 #ifndef WINDOWS32
235 # ifndef __BEOS__
236 # include <ar.h>
237 # else
238 /* BeOS 5 doesn't have <ar.h> but has archives in the same format
239 * as many other Unices. This was taken from GNU binutils for BeOS.
241 # define ARMAG "!<arch>\n" /* String that begins an archive file. */
242 # define SARMAG 8 /* Size of that string. */
243 # define ARFMAG "`\n" /* String in ar_fmag at end of each header. */
244 struct ar_hdr
246 char ar_name[16]; /* Member file name, sometimes / terminated. */
247 char ar_date[12]; /* File date, decimal seconds since Epoch. */
248 char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */
249 char ar_mode[8]; /* File mode, in ASCII octal. */
250 char ar_size[10]; /* File size, in ASCII decimal. */
251 char ar_fmag[2]; /* Always contains ARFMAG. */
253 # endif
254 #else
255 /* These should allow us to read Windows (VC++) libraries (according to Frank
256 * Libbrecht <frankl@abzx.belgium.hp.com>)
258 # include <windows.h>
259 # include <windef.h>
260 # include <io.h>
261 # define ARMAG IMAGE_ARCHIVE_START
262 # define SARMAG IMAGE_ARCHIVE_START_SIZE
263 # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER
264 # define ar_name Name
265 # define ar_mode Mode
266 # define ar_size Size
267 # define ar_date Date
268 # define ar_uid UserID
269 # define ar_gid GroupID
270 #endif
272 /* Cray's <ar.h> apparently defines this. */
273 #ifndef AR_HDR_SIZE
274 # define AR_HDR_SIZE (sizeof (struct ar_hdr))
275 #endif
277 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
279 Open the archive named ARCHIVE, find its members one by one,
280 and for each one call FUNCTION with the following arguments:
281 archive file descriptor for reading the data,
282 member name,
283 member name might be truncated flag,
284 member header position in file,
285 member data position in file,
286 member data size,
287 member date,
288 member uid,
289 member gid,
290 member protection mode,
291 ARG.
293 The descriptor is poised to read the data of the member
294 when FUNCTION is called. It does not matter how much
295 data FUNCTION reads.
297 If FUNCTION returns nonzero, we immediately return
298 what FUNCTION returned.
300 Returns -1 if archive does not exist,
301 Returns -2 if archive has invalid format.
302 Returns 0 if have scanned successfully. */
304 long int
305 ar_scan (archive, function, arg)
306 char *archive;
307 long int (*function) ();
308 long int arg;
310 #ifdef AIAMAG
311 FL_HDR fl_header;
312 #ifdef AIAMAGBIG
313 int big_archive = 0;
314 FL_HDR_BIG fl_header_big;
315 #endif
316 #else
317 int long_name = 0;
318 #endif
319 char *namemap = 0;
320 register int desc = open (archive, O_RDONLY, 0);
321 if (desc < 0)
322 return -1;
323 #ifdef SARMAG
325 char buf[SARMAG];
326 register int nread = read (desc, buf, SARMAG);
327 if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
329 (void) close (desc);
330 return -2;
333 #else
334 #ifdef AIAMAG
336 register int nread = read (desc, (char *) &fl_header, FL_HSZ);
338 if (nread != FL_HSZ)
340 (void) close (desc);
341 return -2;
343 #ifdef AIAMAGBIG
344 /* If this is a "big" archive, then set the flag and
345 re-read the header into the "big" structure. */
346 if (!bcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
348 big_archive = 1;
350 /* seek back to beginning of archive */
351 if (lseek (desc, 0, 0) < 0)
353 (void) close (desc);
354 return -2;
357 /* re-read the header into the "big" structure */
358 nread = read (desc, (char *) &fl_header_big, FL_HSZ_BIG);
359 if (nread != FL_HSZ_BIG)
361 (void) close (desc);
362 return -2;
365 else
366 #endif
367 /* Check to make sure this is a "normal" archive. */
368 if (bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
370 (void) close (desc);
371 return -2;
374 #else
376 #ifndef M_XENIX
377 int buf;
378 #else
379 unsigned short int buf;
380 #endif
381 register int nread = read(desc, &buf, sizeof (buf));
382 if (nread != sizeof (buf) || buf != ARMAG)
384 (void) close (desc);
385 return -2;
388 #endif
389 #endif
391 /* Now find the members one by one. */
393 #ifdef SARMAG
394 register long int member_offset = SARMAG;
395 #else
396 #ifdef AIAMAG
397 long int member_offset;
398 long int last_member_offset;
400 #ifdef AIAMAGBIG
401 if ( big_archive )
403 sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
404 sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
406 else
407 #endif
409 sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
410 sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
413 if (member_offset == 0)
415 /* Empty archive. */
416 close (desc);
417 return 0;
419 #else
420 #ifndef M_XENIX
421 register long int member_offset = sizeof (int);
422 #else /* Xenix. */
423 register long int member_offset = sizeof (unsigned short int);
424 #endif /* Not Xenix. */
425 #endif
426 #endif
428 while (1)
430 register int nread;
431 struct ar_hdr member_header;
432 #ifdef AIAMAGBIG
433 struct ar_hdr_big member_header_big;
434 #endif
435 #ifdef AIAMAG
436 char name[256];
437 int name_len;
438 long int dateval;
439 int uidval, gidval;
440 long int data_offset;
441 #else
442 char namebuf[sizeof member_header.ar_name + 1];
443 char *name;
444 int is_namemap; /* Nonzero if this entry maps long names. */
445 #endif
446 long int eltsize;
447 int eltmode;
448 long int fnval;
450 if (lseek (desc, member_offset, 0) < 0)
452 (void) close (desc);
453 return -2;
456 #ifdef AIAMAG
457 #define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
459 #ifdef AIAMAGBIG
460 if (big_archive)
462 nread = read (desc, (char *) &member_header_big,
463 AR_MEMHDR_SZ(member_header_big) );
465 if (nread != AR_MEMHDR_SZ(member_header_big))
467 (void) close (desc);
468 return -2;
471 sscanf (member_header_big.ar_namlen, "%4d", &name_len);
472 nread = read (desc, name, name_len);
474 if (nread != name_len)
476 (void) close (desc);
477 return -2;
480 name[name_len] = 0;
482 sscanf (member_header_big.ar_date, "%12ld", &dateval);
483 sscanf (member_header_big.ar_uid, "%12d", &uidval);
484 sscanf (member_header_big.ar_gid, "%12d", &gidval);
485 sscanf (member_header_big.ar_mode, "%12o", &eltmode);
486 sscanf (member_header_big.ar_size, "%20ld", &eltsize);
488 data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
489 + name_len + 2);
491 else
492 #endif
494 nread = read (desc, (char *) &member_header,
495 AR_MEMHDR_SZ(member_header) );
497 if (nread != AR_MEMHDR_SZ(member_header))
499 (void) close (desc);
500 return -2;
503 sscanf (member_header.ar_namlen, "%4d", &name_len);
504 nread = read (desc, name, name_len);
506 if (nread != name_len)
508 (void) close (desc);
509 return -2;
512 name[name_len] = 0;
514 sscanf (member_header.ar_date, "%12ld", &dateval);
515 sscanf (member_header.ar_uid, "%12d", &uidval);
516 sscanf (member_header.ar_gid, "%12d", &gidval);
517 sscanf (member_header.ar_mode, "%12o", &eltmode);
518 sscanf (member_header.ar_size, "%12ld", &eltsize);
520 data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
521 + name_len + 2);
523 data_offset += data_offset % 2;
525 fnval =
526 (*function) (desc, name, 0,
527 member_offset, data_offset, eltsize,
528 dateval, uidval, gidval,
529 eltmode, arg);
531 #else /* Not AIAMAG. */
532 nread = read (desc, (char *) &member_header, AR_HDR_SIZE);
533 if (nread == 0)
534 /* No data left means end of file; that is OK. */
535 break;
537 if (nread != AR_HDR_SIZE
538 #if defined(ARFMAG) || defined(ARFZMAG)
539 || (
540 # ifdef ARFMAG
541 bcmp (member_header.ar_fmag, ARFMAG, 2)
542 # else
544 # endif
546 # ifdef ARFZMAG
547 bcmp (member_header.ar_fmag, ARFZMAG, 2)
548 # else
550 # endif
552 #endif
555 (void) close (desc);
556 return -2;
559 name = namebuf;
560 bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
562 register char *p = name + sizeof member_header.ar_name;
564 *p = '\0';
565 while (p > name && *--p == ' ');
567 #ifndef AIAMAG
568 /* If the member name is "//" or "ARFILENAMES/" this may be
569 a list of file name mappings. The maximum file name
570 length supported by the standard archive format is 14
571 characters. This member will actually always be the
572 first or second entry in the archive, but we don't check
573 that. */
574 is_namemap = (!strcmp (name, "//")
575 || !strcmp (name, "ARFILENAMES/"));
576 #endif /* Not AIAMAG. */
577 /* On some systems, there is a slash after each member name. */
578 if (*p == '/')
579 *p = '\0';
581 #ifndef AIAMAG
582 /* If the member name starts with a space or a slash, this
583 is an index into the file name mappings (used by GNU ar).
584 Otherwise if the member name looks like #1/NUMBER the
585 real member name appears in the element data (used by
586 4.4BSD). */
587 if (! is_namemap
588 && (name[0] == ' ' || name[0] == '/')
589 && namemap != 0)
591 name = namemap + atoi (name + 1);
592 long_name = 1;
594 else if (name[0] == '#'
595 && name[1] == '1'
596 && name[2] == '/')
598 int namesize = atoi (name + 3);
600 name = (char *) alloca (namesize + 1);
601 nread = read (desc, name, namesize);
602 if (nread != namesize)
604 close (desc);
605 return -2;
607 name[namesize] = '\0';
609 long_name = 1;
611 #endif /* Not AIAMAG. */
614 #ifndef M_XENIX
615 sscanf (member_header.ar_mode, "%o", &eltmode);
616 eltsize = atol (member_header.ar_size);
617 #else /* Xenix. */
618 eltmode = (unsigned short int) member_header.ar_mode;
619 eltsize = member_header.ar_size;
620 #endif /* Not Xenix. */
622 fnval =
623 (*function) (desc, name, ! long_name, member_offset,
624 member_offset + AR_HDR_SIZE, eltsize,
625 #ifndef M_XENIX
626 atol (member_header.ar_date),
627 atoi (member_header.ar_uid),
628 atoi (member_header.ar_gid),
629 #else /* Xenix. */
630 member_header.ar_date,
631 member_header.ar_uid,
632 member_header.ar_gid,
633 #endif /* Not Xenix. */
634 eltmode, arg);
636 #endif /* AIAMAG. */
638 if (fnval)
640 (void) close (desc);
641 return fnval;
644 #ifdef AIAMAG
645 if (member_offset == last_member_offset)
646 /* End of the chain. */
647 break;
649 #ifdef AIAMAGBIG
650 if (big_archive)
651 sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
652 else
653 #endif
654 sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
656 if (lseek (desc, member_offset, 0) != member_offset)
658 (void) close (desc);
659 return -2;
661 #else
663 /* If this member maps archive names, we must read it in. The
664 name map will always precede any members whose names must
665 be mapped. */
666 if (is_namemap)
668 char *clear;
669 char *limit;
671 namemap = (char *) alloca (eltsize);
672 nread = read (desc, namemap, eltsize);
673 if (nread != eltsize)
675 (void) close (desc);
676 return -2;
679 /* The names are separated by newlines. Some formats have
680 a trailing slash. Null terminate the strings for
681 convenience. */
682 limit = namemap + eltsize;
683 for (clear = namemap; clear < limit; clear++)
685 if (*clear == '\n')
687 *clear = '\0';
688 if (clear[-1] == '/')
689 clear[-1] = '\0';
693 is_namemap = 0;
696 member_offset += AR_HDR_SIZE + eltsize;
697 if (member_offset % 2 != 0)
698 member_offset++;
699 #endif
703 close (desc);
704 return 0;
706 #endif /* !VMS */
708 /* Return nonzero iff NAME matches MEM.
709 If TRUNCATED is nonzero, MEM may be truncated to
710 sizeof (struct ar_hdr.ar_name) - 1. */
713 ar_name_equal (name, mem, truncated)
714 char *name, *mem;
715 int truncated;
717 char *p;
719 p = strrchr (name, '/');
720 if (p != 0)
721 name = p + 1;
723 #ifndef VMS
724 if (truncated)
726 #ifdef AIAMAG
727 /* TRUNCATED should never be set on this system. */
728 abort ();
729 #else
730 struct ar_hdr hdr;
731 #if !defined (__hpux) && !defined (cray)
732 return strneq (name, mem, sizeof(hdr.ar_name) - 1);
733 #else
734 return strneq (name, mem, sizeof(hdr.ar_name) - 2);
735 #endif /* !__hpux && !cray */
736 #endif /* !AIAMAG */
738 #endif /* !VMS */
740 return !strcmp (name, mem);
743 #ifndef VMS
744 /* ARGSUSED */
745 static long int
746 ar_member_pos (desc, mem, truncated,
747 hdrpos, datapos, size, date, uid, gid, mode, name)
748 int desc;
749 char *mem;
750 int truncated;
751 long int hdrpos, datapos, size, date;
752 int uid, gid, mode;
753 char *name;
755 if (!ar_name_equal (name, mem, truncated))
756 return 0;
757 return hdrpos;
760 /* Set date of member MEMNAME in archive ARNAME to current time.
761 Returns 0 if successful,
762 -1 if file ARNAME does not exist,
763 -2 if not a valid archive,
764 -3 if other random system call error (including file read-only),
765 1 if valid but member MEMNAME does not exist. */
768 ar_member_touch (arname, memname)
769 char *arname, *memname;
771 register long int pos = ar_scan (arname, ar_member_pos, (long int) memname);
772 register int fd;
773 struct ar_hdr ar_hdr;
774 register int i;
775 struct stat statbuf;
777 if (pos < 0)
778 return (int) pos;
779 if (!pos)
780 return 1;
782 fd = open (arname, O_RDWR, 0666);
783 if (fd < 0)
784 return -3;
785 /* Read in this member's header */
786 if (lseek (fd, pos, 0) < 0)
787 goto lose;
788 if (AR_HDR_SIZE != read (fd, (char *) &ar_hdr, AR_HDR_SIZE))
789 goto lose;
790 /* Write back the header, thus touching the archive file. */
791 if (lseek (fd, pos, 0) < 0)
792 goto lose;
793 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
794 goto lose;
795 /* The file's mtime is the time we we want. */
796 while (fstat (fd, &statbuf) < 0 && EINTR_SET)
798 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
799 /* Advance member's time to that time */
800 for (i = 0; i < sizeof ar_hdr.ar_date; i++)
801 ar_hdr.ar_date[i] = ' ';
802 sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime);
803 #ifdef AIAMAG
804 ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
805 #endif
806 #else
807 ar_hdr.ar_date = statbuf.st_mtime;
808 #endif
809 /* Write back this member's header */
810 if (lseek (fd, pos, 0) < 0)
811 goto lose;
812 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
813 goto lose;
814 close (fd);
815 return 0;
817 lose:
818 i = errno;
819 close (fd);
820 errno = i;
821 return -3;
823 #endif
825 #ifdef TEST
827 long int
828 describe_member (desc, name, truncated,
829 hdrpos, datapos, size, date, uid, gid, mode)
830 int desc;
831 char *name;
832 int truncated;
833 long int hdrpos, datapos, size, date;
834 int uid, gid, mode;
836 extern char *ctime ();
838 printf (_("Member `%s'%s: %ld bytes at %ld (%ld).\n"),
839 name, truncated ? _(" (name might be truncated)") : "",
840 size, hdrpos, datapos);
841 printf (_(" Date %s"), ctime (&date));
842 printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
844 return 0;
847 main (argc, argv)
848 int argc;
849 char **argv;
851 ar_scan (argv[1], describe_member);
852 return 0;
855 #endif /* TEST. */
857 #endif /* NO_ARCHIVES. */