1 /* Library function for scanning an archive file.
2 Copyright (C) 1987-2013 Free Software Foundation, Inc.
3 This file is part of GNU Make.
5 GNU Make is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3 of the License, or (at your option) any later
10 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along with
15 this program. If not, see <http://www.gnu.org/licenses/>. */
35 #include <lbr$routines.h>
38 static void *VMS_lib_idx;
40 static char *VMS_saved_memname;
42 static time_t VMS_member_date;
44 static long int (*VMS_function) ();
47 VMS_get_member_info (struct dsc$descriptor_s *module, unsigned long *rfa)
54 static struct dsc$descriptor_s bufdesc =
55 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
60 bufdesc.dsc$a_pointer = filename;
61 bufdesc.dsc$w_length = sizeof (filename);
63 status = lbr$set_module (&VMS_lib_idx, rfa, &bufdesc,
64 &bufdesc.dsc$w_length, 0);
67 error (NILF, _("lbr$set_module() failed to extract module info, status = %d"),
70 lbr$close (&VMS_lib_idx);
75 mhd = (struct mhddef *) filename;
78 /* John Fowler <jfowler@nyx.net> writes this is needed in his environment,
79 * but that decc$fix_time() isn't documented to work this way. Let me
80 * know if this causes problems in other VMS environments.
83 /* Modified by M. Gehre at 11-JAN-2008 because old formula is wrong:
84 * val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600;
85 * a) daylight specifies, if the timezone has daylight saving enabled, not
87 * b) what we need is the information, if daylight saving was active, if
88 * the library module was replaced. This information we get using the
94 /* Conversion from VMS time to C time */
95 val = decc$fix_time (&mhd->mhd$l_datim);
98 * Conversion from local time (stored in library) to GMT (needed for gmake)
99 * Note: The tm_gmtoff element is a VMS extension to the ANSI standard.
101 tmp = localtime (&val);
102 val -= tmp->tm_gmtoff;
106 for (i = 0; i < module->dsc$w_length; i++)
107 filename[i] = _tolower ((unsigned char)module->dsc$a_pointer[i]);
111 VMS_member_date = (time_t) -1;
114 (*VMS_function) (-1, filename, 0, 0, 0, 0, val, 0, 0, 0,
119 VMS_member_date = fnval;
126 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
128 Open the archive named ARCHIVE, find its members one by one,
129 and for each one call FUNCTION with the following arguments:
130 archive file descriptor for reading the data,
132 member name might be truncated flag,
133 member header position in file,
134 member data position in file,
139 member protection mode,
142 NOTE: on VMS systems, only name, date, and arg are meaningful!
144 The descriptor is poised to read the data of the member
145 when FUNCTION is called. It does not matter how much
148 If FUNCTION returns nonzero, we immediately return
149 what FUNCTION returned.
151 Returns -1 if archive does not exist,
152 Returns -2 if archive has invalid format.
153 Returns 0 if have scanned successfully. */
156 ar_scan (const char *archive, ar_member_func_t function, const void *arg)
160 static struct dsc$descriptor_s libdesc =
161 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
163 unsigned long func = LBR$C_READ;
164 unsigned long type = LBR$C_TYP_UNK;
165 unsigned long index = 1;
169 status = lbr$ini_control (&VMS_lib_idx, &func, &type, 0);
173 error (NILF, _("lbr$ini_control() failed with status = %d"), status);
177 /* there is no such descriptor with "const char *dsc$a_pointer" */
178 libdesc.dsc$a_pointer = (char *)archive;
179 libdesc.dsc$w_length = strlen (archive);
181 status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0);
185 error (NILF, _("unable to open library '%s' to lookup member '%s'"),
186 archive, (char *)arg);
190 VMS_saved_memname = (char *)arg;
192 /* For comparison, delete .obj from arg name. */
194 p = strrchr (VMS_saved_memname, '.');
198 VMS_function = function;
200 VMS_member_date = (time_t) -1;
201 lbr$get_index (&VMS_lib_idx, &index, VMS_get_member_info, 0);
203 /* Undo the damage. */
207 lbr$close (&VMS_lib_idx);
209 return VMS_member_date > 0 ? VMS_member_date : 0;
214 /* SCO Unix's compiler defines both of these. */
219 /* On the sun386i and in System V rel 3, ar.h defines two different archive
220 formats depending upon whether you have defined PORTAR (normal) or PORT5AR
221 (System V Release 1). There is no default, one or the other must be defined
222 to have a nonzero value. */
224 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
227 /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
228 PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
236 /* On AIX, define these symbols to be sure to get both archive formats.
237 AIX 4.3 introduced the "big" archive format to support 64-bit object
238 files, so on AIX 4.3 systems we need to support both the "normal" and
239 "big" archive formats. An archive's format is indicated in the
240 "fl_magic" field of the "FL_HDR" structure. For a normal archive,
241 this field will be the string defined by the AIAMAG symbol. For a
242 "big" archive, it will be the string defined by the AIAMAGBIG symbol
243 (at least on AIX it works this way).
245 Note: we'll define these symbols regardless of which AIX version
246 we're compiling on, but this is okay since we'll use the new symbols
247 only if they're present. */
249 # define __AR_SMALL__
257 /* BeOS 5 doesn't have <ar.h> but has archives in the same format
258 * as many other Unices. This was taken from GNU binutils for BeOS.
260 # define ARMAG "!<arch>\n" /* String that begins an archive file. */
261 # define SARMAG 8 /* Size of that string. */
262 # define ARFMAG "`\n" /* String in ar_fmag at end of each header. */
265 char ar_name[16]; /* Member file name, sometimes / terminated. */
266 char ar_date[12]; /* File date, decimal seconds since Epoch. */
267 char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */
268 char ar_mode[8]; /* File mode, in ASCII octal. */
269 char ar_size[10]; /* File size, in ASCII decimal. */
270 char ar_fmag[2]; /* Always contains ARFMAG. */
273 # define TOCHAR(_m) (_m)
275 /* These should allow us to read Windows (VC++) libraries (according to Frank
276 * Libbrecht <frankl@abzx.belgium.hp.com>)
278 # include <windows.h>
281 # define ARMAG IMAGE_ARCHIVE_START
282 # define SARMAG IMAGE_ARCHIVE_START_SIZE
283 # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER
284 # define ar_name Name
285 # define ar_mode Mode
286 # define ar_size Size
287 # define ar_date Date
288 # define ar_uid UserID
289 # define ar_gid GroupID
290 /* In Windows the member names have type BYTE so we must cast them. */
291 # define TOCHAR(_m) ((char *)(_m))
294 /* Cray's <ar.h> apparently defines this. */
296 # define AR_HDR_SIZE (sizeof (struct ar_hdr))
299 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
301 Open the archive named ARCHIVE, find its members one by one,
302 and for each one call FUNCTION with the following arguments:
303 archive file descriptor for reading the data,
305 member name might be truncated flag,
306 member header position in file,
307 member data position in file,
312 member protection mode,
315 The descriptor is poised to read the data of the member
316 when FUNCTION is called. It does not matter how much
319 If FUNCTION returns nonzero, we immediately return
320 what FUNCTION returned.
322 Returns -1 if archive does not exist,
323 Returns -2 if archive has invalid format.
324 Returns 0 if have scanned successfully. */
327 ar_scan (const char *archive, ar_member_func_t function, const void *arg)
333 FL_HDR_BIG fl_header_big;
337 int desc = open (archive, O_RDONLY, 0);
343 register int nread = read (desc, buf, SARMAG);
344 if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG))
353 register int nread = read (desc, &fl_header, FL_HSZ);
361 /* If this is a "big" archive, then set the flag and
362 re-read the header into the "big" structure. */
363 if (!memcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
367 /* seek back to beginning of archive */
368 if (lseek (desc, 0, 0) < 0)
374 /* re-read the header into the "big" structure */
375 nread = read (desc, &fl_header_big, FL_HSZ_BIG);
376 if (nread != FL_HSZ_BIG)
384 /* Check to make sure this is a "normal" archive. */
385 if (memcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
396 unsigned short int buf;
398 register int nread = read (desc, &buf, sizeof (buf));
399 if (nread != sizeof (buf) || buf != ARMAG)
408 /* Now find the members one by one. */
411 register long int member_offset = SARMAG;
414 long int member_offset;
415 long int last_member_offset;
420 sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
421 sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
426 sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
427 sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
430 if (member_offset == 0)
438 register long int member_offset = sizeof (int);
440 register long int member_offset = sizeof (unsigned short int);
441 #endif /* Not Xenix. */
448 struct ar_hdr member_header;
450 struct ar_hdr_big member_header_big;
457 long int data_offset;
459 char namebuf[sizeof member_header.ar_name + 1];
461 int is_namemap; /* Nonzero if this entry maps long names. */
468 if (lseek (desc, member_offset, 0) < 0)
475 #define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
480 nread = read (desc, &member_header_big,
481 AR_MEMHDR_SZ(member_header_big) );
483 if (nread != AR_MEMHDR_SZ(member_header_big))
489 sscanf (member_header_big.ar_namlen, "%4d", &name_len);
490 nread = read (desc, name, name_len);
492 if (nread != name_len)
500 sscanf (member_header_big.ar_date, "%12ld", &dateval);
501 sscanf (member_header_big.ar_uid, "%12d", &uidval);
502 sscanf (member_header_big.ar_gid, "%12d", &gidval);
503 sscanf (member_header_big.ar_mode, "%12o", &eltmode);
504 sscanf (member_header_big.ar_size, "%20ld", &eltsize);
506 data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
512 nread = read (desc, &member_header,
513 AR_MEMHDR_SZ(member_header) );
515 if (nread != AR_MEMHDR_SZ(member_header))
521 sscanf (member_header.ar_namlen, "%4d", &name_len);
522 nread = read (desc, name, name_len);
524 if (nread != name_len)
532 sscanf (member_header.ar_date, "%12ld", &dateval);
533 sscanf (member_header.ar_uid, "%12d", &uidval);
534 sscanf (member_header.ar_gid, "%12d", &gidval);
535 sscanf (member_header.ar_mode, "%12o", &eltmode);
536 sscanf (member_header.ar_size, "%12ld", &eltsize);
538 data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
541 data_offset += data_offset % 2;
544 (*function) (desc, name, 0,
545 member_offset, data_offset, eltsize,
546 dateval, uidval, gidval,
549 #else /* Not AIAMAG. */
550 nread = read (desc, &member_header, AR_HDR_SIZE);
552 /* No data left means end of file; that is OK. */
555 if (nread != AR_HDR_SIZE
556 #if defined(ARFMAG) || defined(ARFZMAG)
559 memcmp (member_header.ar_fmag, ARFMAG, 2)
565 memcmp (member_header.ar_fmag, ARFZMAG, 2)
578 memcpy (name, member_header.ar_name, sizeof member_header.ar_name);
580 register char *p = name + sizeof member_header.ar_name;
583 while (p > name && *--p == ' ');
586 /* If the member name is "//" or "ARFILENAMES/" this may be
587 a list of file name mappings. The maximum file name
588 length supported by the standard archive format is 14
589 characters. This member will actually always be the
590 first or second entry in the archive, but we don't check
592 is_namemap = (!strcmp (name, "//")
593 || !strcmp (name, "ARFILENAMES/"));
594 #endif /* Not AIAMAG. */
595 /* On some systems, there is a slash after each member name. */
600 /* If the member name starts with a space or a slash, this
601 is an index into the file name mappings (used by GNU ar).
602 Otherwise if the member name looks like #1/NUMBER the
603 real member name appears in the element data (used by
606 && (name[0] == ' ' || name[0] == '/')
609 name = namemap + atoi (name + 1);
612 else if (name[0] == '#'
616 int namesize = atoi (name + 3);
618 name = alloca (namesize + 1);
619 nread = read (desc, name, namesize);
620 if (nread != namesize)
625 name[namesize] = '\0';
629 #endif /* Not AIAMAG. */
633 sscanf (TOCHAR (member_header.ar_mode), "%o", &eltmode);
634 eltsize = atol (TOCHAR (member_header.ar_size));
636 eltmode = (unsigned short int) member_header.ar_mode;
637 eltsize = member_header.ar_size;
638 #endif /* Not Xenix. */
641 (*function) (desc, name, ! long_name, member_offset,
642 member_offset + AR_HDR_SIZE, eltsize,
644 atol (TOCHAR (member_header.ar_date)),
645 atoi (TOCHAR (member_header.ar_uid)),
646 atoi (TOCHAR (member_header.ar_gid)),
648 member_header.ar_date,
649 member_header.ar_uid,
650 member_header.ar_gid,
651 #endif /* Not Xenix. */
663 if (member_offset == last_member_offset)
664 /* End of the chain. */
669 sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
672 sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
674 if (lseek (desc, member_offset, 0) != member_offset)
681 /* If this member maps archive names, we must read it in. The
682 name map will always precede any members whose names must
689 namemap = alloca (eltsize);
690 nread = read (desc, namemap, eltsize);
691 if (nread != eltsize)
697 /* The names are separated by newlines. Some formats have
698 a trailing slash. Null terminate the strings for
700 limit = namemap + eltsize;
701 for (clear = namemap; clear < limit; clear++)
706 if (clear[-1] == '/')
714 member_offset += AR_HDR_SIZE + eltsize;
715 if (member_offset % 2 != 0)
726 /* Return nonzero iff NAME matches MEM.
727 If TRUNCATED is nonzero, MEM may be truncated to
728 sizeof (struct ar_hdr.ar_name) - 1. */
731 ar_name_equal (const char *name, const char *mem, int truncated)
735 p = strrchr (name, '/');
743 /* TRUNCATED should never be set on this system. */
747 #if !defined (__hpux) && !defined (cray)
748 return strneq (name, mem, sizeof (hdr.ar_name) - 1);
750 return strneq (name, mem, sizeof (hdr.ar_name) - 2);
751 #endif /* !__hpux && !cray */
756 return !strcmp (name, mem);
762 ar_member_pos (int desc UNUSED, const char *mem, int truncated,
763 long int hdrpos, long int datapos UNUSED, long int size UNUSED,
764 long int date UNUSED, int uid UNUSED, int gid UNUSED,
765 int mode UNUSED, const void *name)
767 if (!ar_name_equal (name, mem, truncated))
772 /* Set date of member MEMNAME in archive ARNAME to current time.
773 Returns 0 if successful,
774 -1 if file ARNAME does not exist,
775 -2 if not a valid archive,
776 -3 if other random system call error (including file read-only),
777 1 if valid but member MEMNAME does not exist. */
780 ar_member_touch (const char *arname, const char *memname)
782 long int pos = ar_scan (arname, ar_member_pos, memname);
784 struct ar_hdr ar_hdr;
794 fd = open (arname, O_RDWR, 0666);
797 /* Read in this member's header */
798 if (lseek (fd, pos, 0) < 0)
800 if (AR_HDR_SIZE != read (fd, &ar_hdr, AR_HDR_SIZE))
802 /* Write back the header, thus touching the archive file. */
803 if (lseek (fd, pos, 0) < 0)
805 if (AR_HDR_SIZE != write (fd, &ar_hdr, AR_HDR_SIZE))
807 /* The file's mtime is the time we we want. */
808 EINTRLOOP (i, fstat (fd, &statbuf));
811 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
812 /* Advance member's time to that time */
813 for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++)
814 ar_hdr.ar_date[ui] = ' ';
815 sprintf (TOCHAR (ar_hdr.ar_date), "%ld", (long int) statbuf.st_mtime);
817 ar_hdr.ar_date[strlen (ar_hdr.ar_date)] = ' ';
820 ar_hdr.ar_date = statbuf.st_mtime;
822 /* Write back this member's header */
823 if (lseek (fd, pos, 0) < 0)
825 if (AR_HDR_SIZE != write (fd, &ar_hdr, AR_HDR_SIZE))
841 describe_member (int desc, const char *name, int truncated,
842 long int hdrpos, long int datapos, long int size,
843 long int date, int uid, int gid, int mode, const void *arg)
845 extern char *ctime ();
847 printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"),
848 name, truncated ? _(" (name might be truncated)") : "",
849 size, hdrpos, datapos);
850 printf (_(" Date %s"), ctime (&date));
851 printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
857 main (int argc, char **argv)
859 ar_scan (argv[1], describe_member, NULL);
864 #endif /* NO_ARCHIVES. */