1 /* Library function for scanning an archive file.
2 Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
3 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
4 2010 Free Software Foundation, Inc.
5 This file is part of GNU Make.
6 
7 GNU Make is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 3 of the License, or (at your option) any later
10 version.
11 
12 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License along with
17 this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 
19 #include "make.h"
20 
21 #ifdef HAVE_FCNTL_H
22 #include <fcntl.h>
23 #else
24 #include <sys/file.h>
25 #endif
26 
27 #ifndef	NO_ARCHIVES
28 
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
39 
40 static void *VMS_lib_idx;
41 
42 static char *VMS_saved_memname;
43 
44 static time_t VMS_member_date;
45 
46 static long int (*VMS_function) ();
47 
48 static int
VMS_get_member_info(struct dsc$descriptor_s * module,unsigned long * rfa)49 VMS_get_member_info (struct dsc$descriptor_s *module, unsigned long *rfa)
50 {
51   int status, i;
52   long int fnval;
53 
54   time_t val;
55 
56   static struct dsc$descriptor_s bufdesc =
57     { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
58 
59   struct mhddef *mhd;
60   char filename[128];
61 
62   bufdesc.dsc$a_pointer = filename;
63   bufdesc.dsc$w_length = sizeof (filename);
64 
65   status = lbr$set_module (&VMS_lib_idx, rfa, &bufdesc,
66 			   &bufdesc.dsc$w_length, 0);
67   if (! (status & 1))
68     {
69       error (NILF, _("lbr$set_module() failed to extract module info, status = %d"),
70 	     status);
71 
72       lbr$close (&VMS_lib_idx);
73 
74       return 0;
75     }
76 
77   mhd = (struct mhddef *) filename;
78 
79 #ifdef __DECC
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.
83    */
84   {
85     /* Modified by M. Gehre at 11-JAN-2008 because old formula is wrong:
86      * val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600;
87      * a) daylight specifies, if the timezone has daylight saving enabled, not
88      *    if it is active
89      * b) what we need is the information, if daylight saving was active, if
90      *    the library module was replaced. This information we get using the
91      *    localtime function
92      */
93 
94     struct tm *tmp;
95 
96     /* Conversion from VMS time to C time */
97     val = decc$fix_time (&mhd->mhd$l_datim);
98 
99     /*
100      * Conversion from local time (stored in library) to GMT (needed for gmake)
101      * Note: The tm_gmtoff element is a VMS extension to the ANSI standard.
102      */
103     tmp = localtime (&val);
104     val -= tmp->tm_gmtoff;
105   }
106 #endif
107 
108   for (i = 0; i < module->dsc$w_length; i++)
109     filename[i] = _tolower ((unsigned char)module->dsc$a_pointer[i]);
110 
111   filename[i] = '\0';
112 
113   VMS_member_date = (time_t) -1;
114 
115   fnval =
116     (*VMS_function) (-1, filename, 0, 0, 0, 0, val, 0, 0, 0,
117 		     VMS_saved_memname);
118 
119   if (fnval)
120     {
121       VMS_member_date = fnval;
122       return 0;
123     }
124   else
125     return 1;
126 }
127 
128 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
129 
130    Open the archive named ARCHIVE, find its members one by one,
131    and for each one call FUNCTION with the following arguments:
132      archive file descriptor for reading the data,
133      member name,
134      member name might be truncated flag,
135      member header position in file,
136      member data position in file,
137      member data size,
138      member date,
139      member uid,
140      member gid,
141      member protection mode,
142      ARG.
143 
144    NOTE: on VMS systems, only name, date, and arg are meaningful!
145 
146    The descriptor is poised to read the data of the member
147    when FUNCTION is called.  It does not matter how much
148    data FUNCTION reads.
149 
150    If FUNCTION returns nonzero, we immediately return
151    what FUNCTION returned.
152 
153    Returns -1 if archive does not exist,
154    Returns -2 if archive has invalid format.
155    Returns 0 if have scanned successfully.  */
156 
157 long int
ar_scan(const char * archive,ar_member_func_t function,const void * arg)158 ar_scan (const char *archive, ar_member_func_t function, const void *arg)
159 {
160   char *p;
161 
162   static struct dsc$descriptor_s libdesc =
163     { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
164 
165   unsigned long func = LBR$C_READ;
166   unsigned long type = LBR$C_TYP_UNK;
167   unsigned long index = 1;
168 
169   int status;
170 
171   status = lbr$ini_control (&VMS_lib_idx, &func, &type, 0);
172 
173   if (! (status & 1))
174     {
175       error (NILF, _("lbr$ini_control() failed with status = %d"), status);
176       return -2;
177     }
178 
179   /* there is no such descriptor with "const char *dsc$a_pointer" */
180   libdesc.dsc$a_pointer = (char *)archive;
181   libdesc.dsc$w_length = strlen (archive);
182 
183   status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0);
184 
185   if (! (status & 1))
186     {
187       error (NILF, _("unable to open library `%s' to lookup member `%s'"),
188 	     archive, (char *)arg);
189       return -1;
190     }
191 
192   VMS_saved_memname = (char *)arg;
193 
194   /* For comparison, delete .obj from arg name.  */
195 
196   p = strrchr (VMS_saved_memname, '.');
197   if (p)
198     *p = '\0';
199 
200   VMS_function = function;
201 
202   VMS_member_date = (time_t) -1;
203   lbr$get_index (&VMS_lib_idx, &index, VMS_get_member_info, 0);
204 
205   /* Undo the damage.  */
206   if (p)
207     *p = '.';
208 
209   lbr$close (&VMS_lib_idx);
210 
211   return VMS_member_date > 0 ? VMS_member_date : 0;
212 }
213 
214 #else /* !VMS */
215 
216 /* SCO Unix's compiler defines both of these.  */
217 #ifdef	M_UNIX
218 #undef	M_XENIX
219 #endif
220 
221 /* On the sun386i and in System V rel 3, ar.h defines two different archive
222    formats depending upon whether you have defined PORTAR (normal) or PORT5AR
223    (System V Release 1).  There is no default, one or the other must be defined
224    to have a nonzero value.  */
225 
226 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
227 #undef	PORTAR
228 #ifdef M_XENIX
229 /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
230    PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
231    right one.  */
232 #define PORTAR 0
233 #else
234 #define PORTAR 1
235 #endif
236 #endif
237 
238 /* On AIX, define these symbols to be sure to get both archive formats.
239    AIX 4.3 introduced the "big" archive format to support 64-bit object
240    files, so on AIX 4.3 systems we need to support both the "normal" and
241    "big" archive formats.  An archive's format is indicated in the
242    "fl_magic" field of the "FL_HDR" structure.  For a normal archive,
243    this field will be the string defined by the AIAMAG symbol.  For a
244    "big" archive, it will be the string defined by the AIAMAGBIG symbol
245    (at least on AIX it works this way).
246 
247    Note: we'll define these symbols regardless of which AIX version
248    we're compiling on, but this is okay since we'll use the new symbols
249    only if they're present.  */
250 #ifdef _AIX
251 # define __AR_SMALL__
252 # define __AR_BIG__
253 #endif
254 
255 #ifndef WINDOWS32
256 # if !defined(__BEOS__) && !defined(__HAIKU__)
257 #  include <ar.h>
258 # else
259    /* BeOS 5 doesn't have <ar.h> but has archives in the same format
260     * as many other Unices.  This was taken from GNU binutils for BeOS.
261     */
262 #  define ARMAG	"!<arch>\n"	/* String that begins an archive file.  */
263 #  define SARMAG 8		/* Size of that string.  */
264 #  define ARFMAG "`\n"		/* String in ar_fmag at end of each header.  */
265 struct ar_hdr
266   {
267     char ar_name[16];		/* Member file name, sometimes / terminated. */
268     char ar_date[12];		/* File date, decimal seconds since Epoch.  */
269     char ar_uid[6], ar_gid[6];	/* User and group IDs, in ASCII decimal.  */
270     char ar_mode[8];		/* File mode, in ASCII octal.  */
271     char ar_size[10];		/* File size, in ASCII decimal.  */
272     char ar_fmag[2];		/* Always contains ARFMAG.  */
273   };
274 # endif
275 # define TOCHAR(_m)     (_m)
276 #else
277 /* These should allow us to read Windows (VC++) libraries (according to Frank
278  * Libbrecht <frankl@abzx.belgium.hp.com>)
279  */
280 # include <windows.h>
281 # include <windef.h>
282 # include <io.h>
283 # define ARMAG      IMAGE_ARCHIVE_START
284 # define SARMAG     IMAGE_ARCHIVE_START_SIZE
285 # define ar_hdr     _IMAGE_ARCHIVE_MEMBER_HEADER
286 # define ar_name    Name
287 # define ar_mode    Mode
288 # define ar_size    Size
289 # define ar_date    Date
290 # define ar_uid     UserID
291 # define ar_gid     GroupID
292 /* In Windows the member names have type BYTE so we must cast them.  */
293 # define TOCHAR(_m)     ((char *)(_m))
294 #endif
295 
296 /* Cray's <ar.h> apparently defines this.  */
297 #ifndef	AR_HDR_SIZE
298 # define   AR_HDR_SIZE	(sizeof (struct ar_hdr))
299 #endif
300 
301 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
302 
303    Open the archive named ARCHIVE, find its members one by one,
304    and for each one call FUNCTION with the following arguments:
305      archive file descriptor for reading the data,
306      member name,
307      member name might be truncated flag,
308      member header position in file,
309      member data position in file,
310      member data size,
311      member date,
312      member uid,
313      member gid,
314      member protection mode,
315      ARG.
316 
317    The descriptor is poised to read the data of the member
318    when FUNCTION is called.  It does not matter how much
319    data FUNCTION reads.
320 
321    If FUNCTION returns nonzero, we immediately return
322    what FUNCTION returned.
323 
324    Returns -1 if archive does not exist,
325    Returns -2 if archive has invalid format.
326    Returns 0 if have scanned successfully.  */
327 
328 long int
ar_scan(const char * archive,ar_member_func_t function,const void * arg)329 ar_scan (const char *archive, ar_member_func_t function, const void *arg)
330 {
331 #ifdef AIAMAG
332   FL_HDR fl_header;
333 #ifdef AIAMAGBIG
334   int big_archive = 0;
335   FL_HDR_BIG fl_header_big;
336 #endif
337 #else
338   int long_name = 0;
339 #endif
340   char *namemap = 0;
341   int desc = open (archive, O_RDONLY, 0);
342   if (desc < 0)
343     return -1;
344 #ifdef SARMAG
345   {
346     char buf[SARMAG];
347     register int nread = read (desc, buf, SARMAG);
348     if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG))
349       {
350 	(void) close (desc);
351 	return -2;
352       }
353   }
354 #else
355 #ifdef AIAMAG
356   {
357     register int nread = read (desc, &fl_header, FL_HSZ);
358 
359     if (nread != FL_HSZ)
360       {
361 	(void) close (desc);
362 	return -2;
363       }
364 #ifdef AIAMAGBIG
365     /* If this is a "big" archive, then set the flag and
366        re-read the header into the "big" structure. */
367     if (!memcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
368       {
369 	big_archive = 1;
370 
371 	/* seek back to beginning of archive */
372 	if (lseek (desc, 0, 0) < 0)
373 	  {
374 	    (void) close (desc);
375 	    return -2;
376 	  }
377 
378 	/* re-read the header into the "big" structure */
379 	nread = read (desc, &fl_header_big, FL_HSZ_BIG);
380 	if (nread != FL_HSZ_BIG)
381 	  {
382 	    (void) close (desc);
383 	    return -2;
384 	  }
385       }
386     else
387 #endif
388        /* Check to make sure this is a "normal" archive. */
389       if (memcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
390 	{
391           (void) close (desc);
392           return -2;
393 	}
394   }
395 #else
396   {
397 #ifndef M_XENIX
398     int buf;
399 #else
400     unsigned short int buf;
401 #endif
402     register int nread = read(desc, &buf, sizeof (buf));
403     if (nread != sizeof (buf) || buf != ARMAG)
404       {
405 	(void) close (desc);
406 	return -2;
407       }
408   }
409 #endif
410 #endif
411 
412   /* Now find the members one by one.  */
413   {
414 #ifdef SARMAG
415     register long int member_offset = SARMAG;
416 #else
417 #ifdef AIAMAG
418     long int member_offset;
419     long int last_member_offset;
420 
421 #ifdef AIAMAGBIG
422     if ( big_archive )
423       {
424 	sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
425 	sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
426       }
427     else
428 #endif
429       {
430 	sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
431 	sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
432       }
433 
434     if (member_offset == 0)
435       {
436 	/* Empty archive.  */
437 	close (desc);
438 	return 0;
439       }
440 #else
441 #ifndef	M_XENIX
442     register long int member_offset = sizeof (int);
443 #else	/* Xenix.  */
444     register long int member_offset = sizeof (unsigned short int);
445 #endif	/* Not Xenix.  */
446 #endif
447 #endif
448 
449     while (1)
450       {
451 	register int nread;
452 	struct ar_hdr member_header;
453 #ifdef AIAMAGBIG
454 	struct ar_hdr_big member_header_big;
455 #endif
456 #ifdef AIAMAG
457 	char name[256];
458 	int name_len;
459 	long int dateval;
460 	int uidval, gidval;
461 	long int data_offset;
462 #else
463 	char namebuf[sizeof member_header.ar_name + 1];
464 	char *name;
465 	int is_namemap;		/* Nonzero if this entry maps long names.  */
466 #endif
467 	long int eltsize;
468 	int eltmode;
469 	long int fnval;
470 
471 	if (lseek (desc, member_offset, 0) < 0)
472 	  {
473 	    (void) close (desc);
474 	    return -2;
475 	  }
476 
477 #ifdef AIAMAG
478 #define       AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
479 
480 #ifdef AIAMAGBIG
481 	if (big_archive)
482 	  {
483 	    nread = read (desc, &member_header_big,
484 			  AR_MEMHDR_SZ(member_header_big) );
485 
486 	    if (nread != AR_MEMHDR_SZ(member_header_big))
487 	      {
488 		(void) close (desc);
489 		return -2;
490 	      }
491 
492 	    sscanf (member_header_big.ar_namlen, "%4d", &name_len);
493 	    nread = read (desc, name, name_len);
494 
495 	    if (nread != name_len)
496 	      {
497 		(void) close (desc);
498 		return -2;
499 	      }
500 
501 	    name[name_len] = 0;
502 
503 	    sscanf (member_header_big.ar_date, "%12ld", &dateval);
504 	    sscanf (member_header_big.ar_uid, "%12d", &uidval);
505 	    sscanf (member_header_big.ar_gid, "%12d", &gidval);
506 	    sscanf (member_header_big.ar_mode, "%12o", &eltmode);
507 	    sscanf (member_header_big.ar_size, "%20ld", &eltsize);
508 
509 	    data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
510 			   + name_len + 2);
511 	  }
512 	else
513 #endif
514 	  {
515 	    nread = read (desc, &member_header,
516 			  AR_MEMHDR_SZ(member_header) );
517 
518 	    if (nread != AR_MEMHDR_SZ(member_header))
519 	      {
520 		(void) close (desc);
521 		return -2;
522 	      }
523 
524 	    sscanf (member_header.ar_namlen, "%4d", &name_len);
525 	    nread = read (desc, name, name_len);
526 
527 	    if (nread != name_len)
528 	      {
529 		(void) close (desc);
530 		return -2;
531 	      }
532 
533 	    name[name_len] = 0;
534 
535 	    sscanf (member_header.ar_date, "%12ld", &dateval);
536 	    sscanf (member_header.ar_uid, "%12d", &uidval);
537 	    sscanf (member_header.ar_gid, "%12d", &gidval);
538 	    sscanf (member_header.ar_mode, "%12o", &eltmode);
539 	    sscanf (member_header.ar_size, "%12ld", &eltsize);
540 
541 	    data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
542 			   + name_len + 2);
543 	  }
544 	data_offset += data_offset % 2;
545 
546 	fnval =
547 	  (*function) (desc, name, 0,
548 		       member_offset, data_offset, eltsize,
549 		       dateval, uidval, gidval,
550 		       eltmode, arg);
551 
552 #else	/* Not AIAMAG.  */
553 	nread = read (desc, &member_header, AR_HDR_SIZE);
554 	if (nread == 0)
555 	  /* No data left means end of file; that is OK.  */
556 	  break;
557 
558 	if (nread != AR_HDR_SIZE
559 #if defined(ARFMAG) || defined(ARFZMAG)
560 	    || (
561 # ifdef ARFMAG
562                 memcmp (member_header.ar_fmag, ARFMAG, 2)
563 # else
564                 1
565 # endif
566                 &&
567 # ifdef ARFZMAG
568                 memcmp (member_header.ar_fmag, ARFZMAG, 2)
569 # else
570                 1
571 # endif
572                )
573 #endif
574 	    )
575 	  {
576 	    (void) close (desc);
577 	    return -2;
578 	  }
579 
580 	name = namebuf;
581 	memcpy (name, member_header.ar_name, sizeof member_header.ar_name);
582 	{
583 	  register char *p = name + sizeof member_header.ar_name;
584 	  do
585 	    *p = '\0';
586 	  while (p > name && *--p == ' ');
587 
588 #ifndef AIAMAG
589 	  /* If the member name is "//" or "ARFILENAMES/" this may be
590 	     a list of file name mappings.  The maximum file name
591 	     length supported by the standard archive format is 14
592 	     characters.  This member will actually always be the
593 	     first or second entry in the archive, but we don't check
594 	     that.  */
595 	  is_namemap = (!strcmp (name, "//")
596 			|| !strcmp (name, "ARFILENAMES/"));
597 #endif	/* Not AIAMAG. */
598 	  /* On some systems, there is a slash after each member name.  */
599 	  if (*p == '/')
600 	    *p = '\0';
601 
602 #ifndef AIAMAG
603 	  /* If the member name starts with a space or a slash, this
604 	     is an index into the file name mappings (used by GNU ar).
605 	     Otherwise if the member name looks like #1/NUMBER the
606 	     real member name appears in the element data (used by
607 	     4.4BSD).  */
608 	  if (! is_namemap
609 	      && (name[0] == ' ' || name[0] == '/')
610 	      && namemap != 0)
611 	    {
612 	      name = namemap + atoi (name + 1);
613 	      long_name = 1;
614 	    }
615 	  else if (name[0] == '#'
616 		   && name[1] == '1'
617 		   && name[2] == '/')
618 	    {
619 	      int namesize = atoi (name + 3);
620 
621 	      name = alloca (namesize + 1);
622 	      nread = read (desc, name, namesize);
623 	      if (nread != namesize)
624 		{
625 		  close (desc);
626 		  return -2;
627 		}
628 	      name[namesize] = '\0';
629 
630 	      long_name = 1;
631 	    }
632 #endif /* Not AIAMAG. */
633 	}
634 
635 #ifndef	M_XENIX
636 	sscanf (TOCHAR (member_header.ar_mode), "%o", &eltmode);
637 	eltsize = atol (TOCHAR (member_header.ar_size));
638 #else	/* Xenix.  */
639 	eltmode = (unsigned short int) member_header.ar_mode;
640 	eltsize = member_header.ar_size;
641 #endif	/* Not Xenix.  */
642 
643 	fnval =
644 	  (*function) (desc, name, ! long_name, member_offset,
645 		       member_offset + AR_HDR_SIZE, eltsize,
646 #ifndef	M_XENIX
647 		       atol (TOCHAR (member_header.ar_date)),
648 		       atoi (TOCHAR (member_header.ar_uid)),
649 		       atoi (TOCHAR (member_header.ar_gid)),
650 #else	/* Xenix.  */
651 		       member_header.ar_date,
652 		       member_header.ar_uid,
653 		       member_header.ar_gid,
654 #endif	/* Not Xenix.  */
655 		       eltmode, arg);
656 
657 #endif  /* AIAMAG.  */
658 
659 	if (fnval)
660 	  {
661 	    (void) close (desc);
662 	    return fnval;
663 	  }
664 
665 #ifdef AIAMAG
666 	if (member_offset == last_member_offset)
667 	  /* End of the chain.  */
668 	  break;
669 
670 #ifdef AIAMAGBIG
671 	if (big_archive)
672          sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
673 	else
674 #endif
675 	  sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
676 
677 	if (lseek (desc, member_offset, 0) != member_offset)
678 	  {
679 	    (void) close (desc);
680 	    return -2;
681 	  }
682 #else
683 
684 	/* If this member maps archive names, we must read it in.  The
685 	   name map will always precede any members whose names must
686 	   be mapped.  */
687 	if (is_namemap)
688 	  {
689 	    char *clear;
690 	    char *limit;
691 
692 	    namemap = alloca (eltsize);
693 	    nread = read (desc, namemap, eltsize);
694 	    if (nread != eltsize)
695 	      {
696 		(void) close (desc);
697 		return -2;
698 	      }
699 
700 	    /* The names are separated by newlines.  Some formats have
701 	       a trailing slash.  Null terminate the strings for
702 	       convenience.  */
703 	    limit = namemap + eltsize;
704 	    for (clear = namemap; clear < limit; clear++)
705 	      {
706 		if (*clear == '\n')
707 		  {
708 		    *clear = '\0';
709 		    if (clear[-1] == '/')
710 		      clear[-1] = '\0';
711 		  }
712 	      }
713 
714 	    is_namemap = 0;
715 	  }
716 
717 	member_offset += AR_HDR_SIZE + eltsize;
718 	if (member_offset % 2 != 0)
719 	  member_offset++;
720 #endif
721       }
722   }
723 
724   close (desc);
725   return 0;
726 }
727 #endif /* !VMS */
728 
729 /* Return nonzero iff NAME matches MEM.
730    If TRUNCATED is nonzero, MEM may be truncated to
731    sizeof (struct ar_hdr.ar_name) - 1.  */
732 
733 int
ar_name_equal(const char * name,const char * mem,int truncated)734 ar_name_equal (const char *name, const char *mem, int truncated)
735 {
736   const char *p;
737 
738   p = strrchr (name, '/');
739   if (p != 0)
740     name = p + 1;
741 
742 #ifndef VMS
743   if (truncated)
744     {
745 #ifdef AIAMAG
746       /* TRUNCATED should never be set on this system.  */
747       abort ();
748 #else
749       struct ar_hdr hdr;
750 #if !defined (__hpux) && !defined (cray)
751       return strneq (name, mem, sizeof(hdr.ar_name) - 1);
752 #else
753       return strneq (name, mem, sizeof(hdr.ar_name) - 2);
754 #endif /* !__hpux && !cray */
755 #endif /* !AIAMAG */
756     }
757 #endif /* !VMS */
758 
759   return !strcmp (name, mem);
760 }
761 
762 #ifndef VMS
763 /* ARGSUSED */
764 static long int
ar_member_pos(int desc UNUSED,const char * mem,int truncated,long int hdrpos,long int datapos UNUSED,long int size UNUSED,long int date UNUSED,int uid UNUSED,int gid UNUSED,int mode UNUSED,const void * name)765 ar_member_pos (int desc UNUSED, const char *mem, int truncated,
766 	       long int hdrpos, long int datapos UNUSED, long int size UNUSED,
767                long int date UNUSED, int uid UNUSED, int gid UNUSED,
768                int mode UNUSED, const void *name)
769 {
770   if (!ar_name_equal (name, mem, truncated))
771     return 0;
772   return hdrpos;
773 }
774 
775 /* Set date of member MEMNAME in archive ARNAME to current time.
776    Returns 0 if successful,
777    -1 if file ARNAME does not exist,
778    -2 if not a valid archive,
779    -3 if other random system call error (including file read-only),
780    1 if valid but member MEMNAME does not exist.  */
781 
782 int
ar_member_touch(const char * arname,const char * memname)783 ar_member_touch (const char *arname, const char *memname)
784 {
785   long int pos = ar_scan (arname, ar_member_pos, memname);
786   int fd;
787   struct ar_hdr ar_hdr;
788   int i;
789   unsigned int ui;
790   struct stat statbuf;
791 
792   if (pos < 0)
793     return (int) pos;
794   if (!pos)
795     return 1;
796 
797   fd = open (arname, O_RDWR, 0666);
798   if (fd < 0)
799     return -3;
800   /* Read in this member's header */
801   if (lseek (fd, pos, 0) < 0)
802     goto lose;
803   if (AR_HDR_SIZE != read (fd, &ar_hdr, AR_HDR_SIZE))
804     goto lose;
805   /* Write back the header, thus touching the archive file.  */
806   if (lseek (fd, pos, 0) < 0)
807     goto lose;
808   if (AR_HDR_SIZE != write (fd, &ar_hdr, AR_HDR_SIZE))
809     goto lose;
810   /* The file's mtime is the time we we want.  */
811   EINTRLOOP (i, fstat (fd, &statbuf));
812   if (i < 0)
813     goto lose;
814 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
815   /* Advance member's time to that time */
816   for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++)
817     ar_hdr.ar_date[ui] = ' ';
818   sprintf (TOCHAR (ar_hdr.ar_date), "%ld", (long int) statbuf.st_mtime);
819 #ifdef AIAMAG
820   ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
821 #endif
822 #else
823   ar_hdr.ar_date = statbuf.st_mtime;
824 #endif
825   /* Write back this member's header */
826   if (lseek (fd, pos, 0) < 0)
827     goto lose;
828   if (AR_HDR_SIZE != write (fd, &ar_hdr, AR_HDR_SIZE))
829     goto lose;
830   close (fd);
831   return 0;
832 
833  lose:
834   i = errno;
835   close (fd);
836   errno = i;
837   return -3;
838 }
839 #endif
840 
841 #ifdef TEST
842 
843 long int
describe_member(int desc,const char * name,int truncated,long int hdrpos,long int datapos,long int size,long int date,int uid,int gid,int mode,const void * arg)844 describe_member (int desc, const char *name, int truncated,
845 		 long int hdrpos, long int datapos, long int size,
846                  long int date, int uid, int gid, int mode, const void *arg)
847 {
848   extern char *ctime ();
849 
850   printf (_("Member `%s'%s: %ld bytes at %ld (%ld).\n"),
851 	  name, truncated ? _(" (name might be truncated)") : "",
852 	  size, hdrpos, datapos);
853   printf (_("  Date %s"), ctime (&date));
854   printf (_("  uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
855 
856   return 0;
857 }
858 
859 int
main(int argc,char ** argv)860 main (int argc, char **argv)
861 {
862   ar_scan (argv[1], describe_member, NULL);
863   return 0;
864 }
865 
866 #endif	/* TEST.  */
867 #endif	/* NO_ARCHIVES.  */
868