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)
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,
37 #include <lbr$routines.h>
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
) ();
49 VMS_get_member_info (struct dsc$descriptor_s
*module
, unsigned long *rfa
)
56 static struct dsc$descriptor_s bufdesc
=
57 { 0, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, NULL
};
62 bufdesc
.dsc$a_pointer
= filename
;
63 bufdesc
.dsc$w_length
= sizeof (filename
);
65 status
= lbr$
set_module (&VMS_lib_idx
, rfa
, &bufdesc
,
66 &bufdesc
.dsc$w_length
, 0);
69 error (NILF
, _("lbr$set_module failed to extract module info, status = %d"),
72 lbr$
close (&VMS_lib_idx
);
77 mhd
= (struct mhddef
*) filename
;
80 /* John Fowler <jfowler@nyx.net> writes this is needed in his environment,
81 * but that decc$fix_time() isn't documented to work this way. Let me
82 * know if this causes problems in other VMS environments.
84 val
= decc$
fix_time (&mhd
->mhd$l_datim
) + timezone
- daylight
*3600;
87 for (i
= 0; i
< module
->dsc$w_length
; i
++)
88 filename
[i
] = _tolower ((unsigned char)module
->dsc$a_pointer
[i
]);
92 VMS_member_date
= (time_t) -1;
95 (*VMS_function
) (-1, filename
, 0, 0, 0, 0, val
, 0, 0, 0,
100 VMS_member_date
= fnval
;
107 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
109 Open the archive named ARCHIVE, find its members one by one,
110 and for each one call FUNCTION with the following arguments:
111 archive file descriptor for reading the data,
113 member name might be truncated flag,
114 member header position in file,
115 member data position in file,
120 member protection mode,
123 NOTE: on VMS systems, only name, date, and arg are meaningful!
125 The descriptor is poised to read the data of the member
126 when FUNCTION is called. It does not matter how much
129 If FUNCTION returns nonzero, we immediately return
130 what FUNCTION returned.
132 Returns -1 if archive does not exist,
133 Returns -2 if archive has invalid format.
134 Returns 0 if have scanned successfully. */
137 ar_scan (char *archive
, long int (*function
) PARAMS ((void)), long int arg
)
141 static struct dsc$descriptor_s libdesc
=
142 { 0, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, NULL
};
144 unsigned long func
= LBR$C_READ
;
145 unsigned long type
= LBR$C_TYP_UNK
;
146 unsigned long index
= 1;
150 status
= lbr$
ini_control (&VMS_lib_idx
, &func
, &type
, 0);
154 error (NILF
, _("lbr$ini_control failed with status = %d"),status
);
158 libdesc
.dsc$a_pointer
= archive
;
159 libdesc
.dsc$w_length
= strlen (archive
);
161 status
= lbr$
open (&VMS_lib_idx
, &libdesc
, 0, 0, 0, 0, 0);
165 error (NILF
, _("unable to open library `%s' to lookup member `%s'"),
166 archive
, (char *)arg
);
170 VMS_saved_memname
= (char *)arg
;
172 /* For comparison, delete .obj from arg name. */
174 p
= strrchr (VMS_saved_memname
, '.');
178 VMS_function
= function
;
180 VMS_member_date
= (time_t) -1;
181 lbr$
get_index (&VMS_lib_idx
, &index
, VMS_get_member_info
, 0);
183 /* Undo the damage. */
187 lbr$
close (&VMS_lib_idx
);
189 return VMS_member_date
> 0 ? VMS_member_date
: 0;
194 /* SCO Unix's compiler defines both of these. */
199 /* On the sun386i and in System V rel 3, ar.h defines two different archive
200 formats depending upon whether you have defined PORTAR (normal) or PORT5AR
201 (System V Release 1). There is no default, one or the other must be defined
202 to have a nonzero value. */
204 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
207 /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
208 PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
216 /* On AIX, define these symbols to be sure to get both archive formats.
217 AIX 4.3 introduced the "big" archive format to support 64-bit object
218 files, so on AIX 4.3 systems we need to support both the "normal" and
219 "big" archive formats. An archive's format is indicated in the
220 "fl_magic" field of the "FL_HDR" structure. For a normal archive,
221 this field will be the string defined by the AIAMAG symbol. For a
222 "big" archive, it will be the string defined by the AIAMAGBIG symbol
223 (at least on AIX it works this way).
225 Note: we'll define these symbols regardless of which AIX version
226 we're compiling on, but this is okay since we'll use the new symbols
227 only if they're present. */
229 # define __AR_SMALL__
237 /* BeOS 5 doesn't have <ar.h> but has archives in the same format
238 * as many other Unices. This was taken from GNU binutils for BeOS.
240 # define ARMAG "!<arch>\n" /* String that begins an archive file. */
241 # define SARMAG 8 /* Size of that string. */
242 # define ARFMAG "`\n" /* String in ar_fmag at end of each header. */
245 char ar_name
[16]; /* Member file name, sometimes / terminated. */
246 char ar_date
[12]; /* File date, decimal seconds since Epoch. */
247 char ar_uid
[6], ar_gid
[6]; /* User and group IDs, in ASCII decimal. */
248 char ar_mode
[8]; /* File mode, in ASCII octal. */
249 char ar_size
[10]; /* File size, in ASCII decimal. */
250 char ar_fmag
[2]; /* Always contains ARFMAG. */
254 /* These should allow us to read Windows (VC++) libraries (according to Frank
255 * Libbrecht <frankl@abzx.belgium.hp.com>)
257 # include <windows.h>
260 # define ARMAG IMAGE_ARCHIVE_START
261 # define SARMAG IMAGE_ARCHIVE_START_SIZE
262 # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER
263 # define ar_name Name
264 # define ar_mode Mode
265 # define ar_size Size
266 # define ar_date Date
267 # define ar_uid UserID
268 # define ar_gid GroupID
271 /* Cray's <ar.h> apparently defines this. */
273 # define AR_HDR_SIZE (sizeof (struct ar_hdr))
276 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
278 Open the archive named ARCHIVE, find its members one by one,
279 and for each one call FUNCTION with the following arguments:
280 archive file descriptor for reading the data,
282 member name might be truncated flag,
283 member header position in file,
284 member data position in file,
289 member protection mode,
292 The descriptor is poised to read the data of the member
293 when FUNCTION is called. It does not matter how much
296 If FUNCTION returns nonzero, we immediately return
297 what FUNCTION returned.
299 Returns -1 if archive does not exist,
300 Returns -2 if archive has invalid format.
301 Returns 0 if have scanned successfully. */
304 ar_scan (char *archive
, long int (*function
)(), long int arg
)
310 FL_HDR_BIG fl_header_big
;
316 register int desc
= open (archive
, O_RDONLY
, 0);
322 register int nread
= read (desc
, buf
, SARMAG
);
323 if (nread
!= SARMAG
|| bcmp (buf
, ARMAG
, SARMAG
))
332 register int nread
= read (desc
, (char *) &fl_header
, FL_HSZ
);
340 /* If this is a "big" archive, then set the flag and
341 re-read the header into the "big" structure. */
342 if (!bcmp (fl_header
.fl_magic
, AIAMAGBIG
, SAIAMAG
))
346 /* seek back to beginning of archive */
347 if (lseek (desc
, 0, 0) < 0)
353 /* re-read the header into the "big" structure */
354 nread
= read (desc
, (char *) &fl_header_big
, FL_HSZ_BIG
);
355 if (nread
!= FL_HSZ_BIG
)
363 /* Check to make sure this is a "normal" archive. */
364 if (bcmp (fl_header
.fl_magic
, AIAMAG
, SAIAMAG
))
375 unsigned short int buf
;
377 register int nread
= read(desc
, &buf
, sizeof (buf
));
378 if (nread
!= sizeof (buf
) || buf
!= ARMAG
)
387 /* Now find the members one by one. */
390 register long int member_offset
= SARMAG
;
393 long int member_offset
;
394 long int last_member_offset
;
399 sscanf (fl_header_big
.fl_fstmoff
, "%20ld", &member_offset
);
400 sscanf (fl_header_big
.fl_lstmoff
, "%20ld", &last_member_offset
);
405 sscanf (fl_header
.fl_fstmoff
, "%12ld", &member_offset
);
406 sscanf (fl_header
.fl_lstmoff
, "%12ld", &last_member_offset
);
409 if (member_offset
== 0)
417 register long int member_offset
= sizeof (int);
419 register long int member_offset
= sizeof (unsigned short int);
420 #endif /* Not Xenix. */
427 struct ar_hdr member_header
;
429 struct ar_hdr_big member_header_big
;
436 long int data_offset
;
438 char namebuf
[sizeof member_header
.ar_name
+ 1];
440 int is_namemap
; /* Nonzero if this entry maps long names. */
446 if (lseek (desc
, member_offset
, 0) < 0)
453 #define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
458 nread
= read (desc
, (char *) &member_header_big
,
459 AR_MEMHDR_SZ(member_header_big
) );
461 if (nread
!= AR_MEMHDR_SZ(member_header_big
))
467 sscanf (member_header_big
.ar_namlen
, "%4d", &name_len
);
468 nread
= read (desc
, name
, name_len
);
470 if (nread
!= name_len
)
478 sscanf (member_header_big
.ar_date
, "%12ld", &dateval
);
479 sscanf (member_header_big
.ar_uid
, "%12d", &uidval
);
480 sscanf (member_header_big
.ar_gid
, "%12d", &gidval
);
481 sscanf (member_header_big
.ar_mode
, "%12o", &eltmode
);
482 sscanf (member_header_big
.ar_size
, "%20ld", &eltsize
);
484 data_offset
= (member_offset
+ AR_MEMHDR_SZ(member_header_big
)
490 nread
= read (desc
, (char *) &member_header
,
491 AR_MEMHDR_SZ(member_header
) );
493 if (nread
!= AR_MEMHDR_SZ(member_header
))
499 sscanf (member_header
.ar_namlen
, "%4d", &name_len
);
500 nread
= read (desc
, name
, name_len
);
502 if (nread
!= name_len
)
510 sscanf (member_header
.ar_date
, "%12ld", &dateval
);
511 sscanf (member_header
.ar_uid
, "%12d", &uidval
);
512 sscanf (member_header
.ar_gid
, "%12d", &gidval
);
513 sscanf (member_header
.ar_mode
, "%12o", &eltmode
);
514 sscanf (member_header
.ar_size
, "%12ld", &eltsize
);
516 data_offset
= (member_offset
+ AR_MEMHDR_SZ(member_header
)
519 data_offset
+= data_offset
% 2;
522 (*function
) (desc
, name
, 0,
523 member_offset
, data_offset
, eltsize
,
524 dateval
, uidval
, gidval
,
527 #else /* Not AIAMAG. */
528 nread
= read (desc
, (char *) &member_header
, AR_HDR_SIZE
);
530 /* No data left means end of file; that is OK. */
533 if (nread
!= AR_HDR_SIZE
534 #if defined(ARFMAG) || defined(ARFZMAG)
537 bcmp (member_header
.ar_fmag
, ARFMAG
, 2)
543 bcmp (member_header
.ar_fmag
, ARFZMAG
, 2)
556 bcopy (member_header
.ar_name
, name
, sizeof member_header
.ar_name
);
558 register char *p
= name
+ sizeof member_header
.ar_name
;
561 while (p
> name
&& *--p
== ' ');
564 /* If the member name is "//" or "ARFILENAMES/" this may be
565 a list of file name mappings. The maximum file name
566 length supported by the standard archive format is 14
567 characters. This member will actually always be the
568 first or second entry in the archive, but we don't check
570 is_namemap
= (!strcmp (name
, "//")
571 || !strcmp (name
, "ARFILENAMES/"));
572 #endif /* Not AIAMAG. */
573 /* On some systems, there is a slash after each member name. */
578 /* If the member name starts with a space or a slash, this
579 is an index into the file name mappings (used by GNU ar).
580 Otherwise if the member name looks like #1/NUMBER the
581 real member name appears in the element data (used by
584 && (name
[0] == ' ' || name
[0] == '/')
587 name
= namemap
+ atoi (name
+ 1);
590 else if (name
[0] == '#'
594 int namesize
= atoi (name
+ 3);
596 name
= (char *) alloca (namesize
+ 1);
597 nread
= read (desc
, name
, namesize
);
598 if (nread
!= namesize
)
603 name
[namesize
] = '\0';
607 #endif /* Not AIAMAG. */
611 sscanf (member_header
.ar_mode
, "%o", &eltmode
);
612 eltsize
= atol (member_header
.ar_size
);
614 eltmode
= (unsigned short int) member_header
.ar_mode
;
615 eltsize
= member_header
.ar_size
;
616 #endif /* Not Xenix. */
619 (*function
) (desc
, name
, ! long_name
, member_offset
,
620 member_offset
+ AR_HDR_SIZE
, eltsize
,
622 atol (member_header
.ar_date
),
623 atoi (member_header
.ar_uid
),
624 atoi (member_header
.ar_gid
),
626 member_header
.ar_date
,
627 member_header
.ar_uid
,
628 member_header
.ar_gid
,
629 #endif /* Not Xenix. */
641 if (member_offset
== last_member_offset
)
642 /* End of the chain. */
647 sscanf (member_header_big
.ar_nxtmem
, "%20ld", &member_offset
);
650 sscanf (member_header
.ar_nxtmem
, "%12ld", &member_offset
);
652 if (lseek (desc
, member_offset
, 0) != member_offset
)
659 /* If this member maps archive names, we must read it in. The
660 name map will always precede any members whose names must
667 namemap
= (char *) alloca (eltsize
);
668 nread
= read (desc
, namemap
, eltsize
);
669 if (nread
!= eltsize
)
675 /* The names are separated by newlines. Some formats have
676 a trailing slash. Null terminate the strings for
678 limit
= namemap
+ eltsize
;
679 for (clear
= namemap
; clear
< limit
; clear
++)
684 if (clear
[-1] == '/')
692 member_offset
+= AR_HDR_SIZE
+ eltsize
;
693 if (member_offset
% 2 != 0)
704 /* Return nonzero iff NAME matches MEM.
705 If TRUNCATED is nonzero, MEM may be truncated to
706 sizeof (struct ar_hdr.ar_name) - 1. */
709 ar_name_equal (char *name
, char *mem
, int truncated
)
713 p
= strrchr (name
, '/');
721 /* TRUNCATED should never be set on this system. */
725 #if !defined (__hpux) && !defined (cray)
726 return strneq (name
, mem
, sizeof(hdr
.ar_name
) - 1);
728 return strneq (name
, mem
, sizeof(hdr
.ar_name
) - 2);
729 #endif /* !__hpux && !cray */
734 return !strcmp (name
, mem
);
740 ar_member_pos (int desc UNUSED
, char *mem
, int truncated
,
741 long int hdrpos
, long int datapos UNUSED
, long int size UNUSED
,
742 long int date UNUSED
, int uid UNUSED
, int gid UNUSED
,
743 int mode UNUSED
, char *name
)
745 if (!ar_name_equal (name
, mem
, truncated
))
750 /* Set date of member MEMNAME in archive ARNAME to current time.
751 Returns 0 if successful,
752 -1 if file ARNAME does not exist,
753 -2 if not a valid archive,
754 -3 if other random system call error (including file read-only),
755 1 if valid but member MEMNAME does not exist. */
758 ar_member_touch (char *arname
, char *memname
)
760 long int pos
= ar_scan (arname
, ar_member_pos
, (long int) memname
);
762 struct ar_hdr ar_hdr
;
772 fd
= open (arname
, O_RDWR
, 0666);
775 /* Read in this member's header */
776 if (lseek (fd
, pos
, 0) < 0)
778 if (AR_HDR_SIZE
!= read (fd
, (char *) &ar_hdr
, AR_HDR_SIZE
))
780 /* Write back the header, thus touching the archive file. */
781 if (lseek (fd
, pos
, 0) < 0)
783 if (AR_HDR_SIZE
!= write (fd
, (char *) &ar_hdr
, AR_HDR_SIZE
))
785 /* The file's mtime is the time we we want. */
786 EINTRLOOP (i
, fstat (fd
, &statbuf
));
789 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
790 /* Advance member's time to that time */
791 for (ui
= 0; ui
< sizeof ar_hdr
.ar_date
; ui
++)
792 ar_hdr
.ar_date
[ui
] = ' ';
793 sprintf (ar_hdr
.ar_date
, "%ld", (long int) statbuf
.st_mtime
);
795 ar_hdr
.ar_date
[strlen(ar_hdr
.ar_date
)] = ' ';
798 ar_hdr
.ar_date
= statbuf
.st_mtime
;
800 /* Write back this member's header */
801 if (lseek (fd
, pos
, 0) < 0)
803 if (AR_HDR_SIZE
!= write (fd
, (char *) &ar_hdr
, AR_HDR_SIZE
))
819 describe_member (int desc
, char *name
, int truncated
,
820 long int hdrpos
, long int datapos
, long int size
,
821 long int date
, int uid
, int gid
, int mode
)
823 extern char *ctime ();
825 printf (_("Member `%s'%s: %ld bytes at %ld (%ld).\n"),
826 name
, truncated
? _(" (name might be truncated)") : "",
827 size
, hdrpos
, datapos
);
828 printf (_(" Date %s"), ctime (&date
));
829 printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid
, gid
, mode
);
835 main (int argc
, char **argv
)
837 ar_scan (argv
[1], describe_member
);
842 #endif /* NO_ARCHIVES. */