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 Free Software Foundation,
4 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 2, or (at your option) any later version.
10 
11 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along with
16 GNU Make; see the file COPYING.  If not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
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   val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600;
85 #endif
86 
87   for (i = 0; i < module->dsc$w_length; i++)
88     filename[i] = _tolower ((unsigned char)module->dsc$a_pointer[i]);
89 
90   filename[i] = '\0';
91 
92   VMS_member_date = (time_t) -1;
93 
94   fnval =
95     (*VMS_function) (-1, filename, 0, 0, 0, 0, val, 0, 0, 0,
96 		     VMS_saved_memname);
97 
98   if (fnval)
99     {
100       VMS_member_date = fnval;
101       return 0;
102     }
103   else
104     return 1;
105 }
106 
107 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
108 
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,
112      member name,
113      member name might be truncated flag,
114      member header position in file,
115      member data position in file,
116      member data size,
117      member date,
118      member uid,
119      member gid,
120      member protection mode,
121      ARG.
122 
123    NOTE: on VMS systems, only name, date, and arg are meaningful!
124 
125    The descriptor is poised to read the data of the member
126    when FUNCTION is called.  It does not matter how much
127    data FUNCTION reads.
128 
129    If FUNCTION returns nonzero, we immediately return
130    what FUNCTION returned.
131 
132    Returns -1 if archive does not exist,
133    Returns -2 if archive has invalid format.
134    Returns 0 if have scanned successfully.  */
135 
136 long int
ar_scan(char * archive,long int (* function)PARAMS ((void)),intptr_t arg)137 ar_scan (char *archive, long int (*function) PARAMS ((void)), intptr_t arg)
138 {
139   char *p;
140 
141   static struct dsc$descriptor_s libdesc =
142     { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
143 
144   unsigned long func = LBR$C_READ;
145   unsigned long type = LBR$C_TYP_UNK;
146   unsigned long index = 1;
147 
148   int status;
149 
150   status = lbr$ini_control (&VMS_lib_idx, &func, &type, 0);
151 
152   if (! (status & 1))
153     {
154       error (NILF, _("lbr$ini_control failed with status = %d"),status);
155       return -2;
156     }
157 
158   libdesc.dsc$a_pointer = archive;
159   libdesc.dsc$w_length = strlen (archive);
160 
161   status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0);
162 
163   if (! (status & 1))
164     {
165       error (NILF, _("unable to open library `%s' to lookup member `%s'"),
166 	     archive, (char *)arg);
167       return -1;
168     }
169 
170   VMS_saved_memname = (char *)arg;
171 
172   /* For comparison, delete .obj from arg name.  */
173 
174   p = strrchr (VMS_saved_memname, '.');
175   if (p)
176     *p = '\0';
177 
178   VMS_function = function;
179 
180   VMS_member_date = (time_t) -1;
181   lbr$get_index (&VMS_lib_idx, &index, VMS_get_member_info, 0);
182 
183   /* Undo the damage.  */
184   if (p)
185     *p = '.';
186 
187   lbr$close (&VMS_lib_idx);
188 
189   return VMS_member_date > 0 ? VMS_member_date : 0;
190 }
191 
192 #else /* !VMS */
193 
194 /* SCO Unix's compiler defines both of these.  */
195 #ifdef	M_UNIX
196 #undef	M_XENIX
197 #endif
198 
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.  */
203 
204 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
205 #undef	PORTAR
206 #ifdef M_XENIX
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
209    right one.  */
210 #define PORTAR 0
211 #else
212 #define PORTAR 1
213 #endif
214 #endif
215 
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).
224 
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.  */
228 #ifdef _AIX
229 # define __AR_SMALL__
230 # define __AR_BIG__
231 #endif
232 
233 #ifndef WINDOWS32
234 # ifndef __BEOS__
235 #  include <ar.h>
236 # else
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.
239     */
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.  */
243 struct ar_hdr
244   {
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.  */
251   };
252 # endif
253 #else
254 /* These should allow us to read Windows (VC++) libraries (according to Frank
255  * Libbrecht <frankl@abzx.belgium.hp.com>)
256  */
257 # include <windows.h>
258 # include <windef.h>
259 # include <io.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
269 #endif
270 
271 /* Cray's <ar.h> apparently defines this.  */
272 #ifndef	AR_HDR_SIZE
273 # define   AR_HDR_SIZE	(sizeof (struct ar_hdr))
274 #endif
275 
276 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
277 
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,
281      member name,
282      member name might be truncated flag,
283      member header position in file,
284      member data position in file,
285      member data size,
286      member date,
287      member uid,
288      member gid,
289      member protection mode,
290      ARG.
291 
292    The descriptor is poised to read the data of the member
293    when FUNCTION is called.  It does not matter how much
294    data FUNCTION reads.
295 
296    If FUNCTION returns nonzero, we immediately return
297    what FUNCTION returned.
298 
299    Returns -1 if archive does not exist,
300    Returns -2 if archive has invalid format.
301    Returns 0 if have scanned successfully.  */
302 
303 long int
ar_scan(char * archive,long int (* function)(),intptr_t arg)304 ar_scan (char *archive, long int (*function)(), intptr_t arg)
305 {
306 #ifdef AIAMAG
307   FL_HDR fl_header;
308 #ifdef AIAMAGBIG
309   int big_archive = 0;
310   FL_HDR_BIG fl_header_big;
311 #endif
312 #else
313   int long_name = 0;
314 #endif
315   char *namemap = 0;
316   register int desc = open (archive, O_RDONLY, 0);
317   if (desc < 0)
318     return -1;
319 #ifdef SARMAG
320   {
321     char buf[SARMAG];
322     register int nread = read (desc, buf, SARMAG);
323     if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
324       {
325 	(void) close (desc);
326 	return -2;
327       }
328   }
329 #else
330 #ifdef AIAMAG
331   {
332     register int nread = read (desc, (char *) &fl_header, FL_HSZ);
333 
334     if (nread != FL_HSZ)
335       {
336 	(void) close (desc);
337 	return -2;
338       }
339 #ifdef AIAMAGBIG
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))
343       {
344 	big_archive = 1;
345 
346 	/* seek back to beginning of archive */
347 	if (lseek (desc, 0, 0) < 0)
348 	  {
349 	    (void) close (desc);
350 	    return -2;
351 	  }
352 
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)
356 	  {
357 	    (void) close (desc);
358 	    return -2;
359 	  }
360       }
361     else
362 #endif
363        /* Check to make sure this is a "normal" archive. */
364       if (bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
365 	{
366           (void) close (desc);
367           return -2;
368 	}
369   }
370 #else
371   {
372 #ifndef M_XENIX
373     int buf;
374 #else
375     unsigned short int buf;
376 #endif
377     register int nread = read(desc, &buf, sizeof (buf));
378     if (nread != sizeof (buf) || buf != ARMAG)
379       {
380 	(void) close (desc);
381 	return -2;
382       }
383   }
384 #endif
385 #endif
386 
387   /* Now find the members one by one.  */
388   {
389 #ifdef SARMAG
390     register long int member_offset = SARMAG;
391 #else
392 #ifdef AIAMAG
393     long int member_offset;
394     long int last_member_offset;
395 
396 #ifdef AIAMAGBIG
397     if ( big_archive )
398       {
399 	sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
400 	sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
401       }
402     else
403 #endif
404       {
405 	sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
406 	sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
407       }
408 
409     if (member_offset == 0)
410       {
411 	/* Empty archive.  */
412 	close (desc);
413 	return 0;
414       }
415 #else
416 #ifndef	M_XENIX
417     register long int member_offset = sizeof (int);
418 #else	/* Xenix.  */
419     register long int member_offset = sizeof (unsigned short int);
420 #endif	/* Not Xenix.  */
421 #endif
422 #endif
423 
424     while (1)
425       {
426 	register int nread;
427 	struct ar_hdr member_header;
428 #ifdef AIAMAGBIG
429 	struct ar_hdr_big member_header_big;
430 #endif
431 #ifdef AIAMAG
432 	char name[256];
433 	int name_len;
434 	long int dateval;
435 	int uidval, gidval;
436 	long int data_offset;
437 #else
438 	char namebuf[sizeof member_header.ar_name + 1];
439 	char *name;
440 	int is_namemap;		/* Nonzero if this entry maps long names.  */
441 #endif
442 	long int eltsize;
443 	int eltmode;
444 	long int fnval;
445 
446 	if (lseek (desc, member_offset, 0) < 0)
447 	  {
448 	    (void) close (desc);
449 	    return -2;
450 	  }
451 
452 #ifdef AIAMAG
453 #define       AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
454 
455 #ifdef AIAMAGBIG
456 	if (big_archive)
457 	  {
458 	    nread = read (desc, (char *) &member_header_big,
459 			  AR_MEMHDR_SZ(member_header_big) );
460 
461 	    if (nread != AR_MEMHDR_SZ(member_header_big))
462 	      {
463 		(void) close (desc);
464 		return -2;
465 	      }
466 
467 	    sscanf (member_header_big.ar_namlen, "%4d", &name_len);
468 	    nread = read (desc, name, name_len);
469 
470 	    if (nread != name_len)
471 	      {
472 		(void) close (desc);
473 		return -2;
474 	      }
475 
476 	    name[name_len] = 0;
477 
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);
483 
484 	    data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
485 			   + name_len + 2);
486 	  }
487 	else
488 #endif
489 	  {
490 	    nread = read (desc, (char *) &member_header,
491 			  AR_MEMHDR_SZ(member_header) );
492 
493 	    if (nread != AR_MEMHDR_SZ(member_header))
494 	      {
495 		(void) close (desc);
496 		return -2;
497 	      }
498 
499 	    sscanf (member_header.ar_namlen, "%4d", &name_len);
500 	    nread = read (desc, name, name_len);
501 
502 	    if (nread != name_len)
503 	      {
504 		(void) close (desc);
505 		return -2;
506 	      }
507 
508 	    name[name_len] = 0;
509 
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);
515 
516 	    data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
517 			   + name_len + 2);
518 	  }
519 	data_offset += data_offset % 2;
520 
521 	fnval =
522 	  (*function) (desc, name, 0,
523 		       member_offset, data_offset, eltsize,
524 		       dateval, uidval, gidval,
525 		       eltmode, arg);
526 
527 #else	/* Not AIAMAG.  */
528 	nread = read (desc, (char *) &member_header, AR_HDR_SIZE);
529 	if (nread == 0)
530 	  /* No data left means end of file; that is OK.  */
531 	  break;
532 
533 	if (nread != AR_HDR_SIZE
534 #if defined(ARFMAG) || defined(ARFZMAG)
535 	    || (
536 # ifdef ARFMAG
537                 bcmp (member_header.ar_fmag, ARFMAG, 2)
538 # else
539                 1
540 # endif
541                 &&
542 # ifdef ARFZMAG
543                 bcmp (member_header.ar_fmag, ARFZMAG, 2)
544 # else
545                 1
546 # endif
547                )
548 #endif
549 	    )
550 	  {
551 	    (void) close (desc);
552 	    return -2;
553 	  }
554 
555 	name = namebuf;
556 	bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
557 	{
558 	  register char *p = name + sizeof member_header.ar_name;
559 	  do
560 	    *p = '\0';
561 	  while (p > name && *--p == ' ');
562 
563 #ifndef AIAMAG
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
569  	     that.  */
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.  */
574 	  if (*p == '/')
575 	    *p = '\0';
576 
577 #ifndef AIAMAG
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
582  	     4.4BSD).  */
583  	  if (! is_namemap
584  	      && (name[0] == ' ' || name[0] == '/')
585  	      && namemap != 0)
586 	    {
587 	      name = namemap + atoi (name + 1);
588 	      long_name = 1;
589 	    }
590  	  else if (name[0] == '#'
591  		   && name[1] == '1'
592  		   && name[2] == '/')
593  	    {
594  	      int namesize = atoi (name + 3);
595 
596  	      name = (char *) alloca (namesize + 1);
597  	      nread = read (desc, name, namesize);
598  	      if (nread != namesize)
599  		{
600  		  close (desc);
601  		  return -2;
602  		}
603  	      name[namesize] = '\0';
604 
605 	      long_name = 1;
606  	    }
607 #endif /* Not AIAMAG. */
608 	}
609 
610 #ifndef	M_XENIX
611 	sscanf (member_header.ar_mode, "%o", &eltmode);
612 	eltsize = atol (member_header.ar_size);
613 #else	/* Xenix.  */
614 	eltmode = (unsigned short int) member_header.ar_mode;
615 	eltsize = member_header.ar_size;
616 #endif	/* Not Xenix.  */
617 
618 	fnval =
619 	  (*function) (desc, name, ! long_name, member_offset,
620 		       member_offset + AR_HDR_SIZE, eltsize,
621 #ifndef	M_XENIX
622 		       atol (member_header.ar_date),
623 		       atoi (member_header.ar_uid),
624 		       atoi (member_header.ar_gid),
625 #else	/* Xenix.  */
626 		       member_header.ar_date,
627 		       member_header.ar_uid,
628 		       member_header.ar_gid,
629 #endif	/* Not Xenix.  */
630 		       eltmode, arg);
631 
632 #endif  /* AIAMAG.  */
633 
634 	if (fnval)
635 	  {
636 	    (void) close (desc);
637 	    return fnval;
638 	  }
639 
640 #ifdef AIAMAG
641 	if (member_offset == last_member_offset)
642 	  /* End of the chain.  */
643 	  break;
644 
645 #ifdef AIAMAGBIG
646 	if (big_archive)
647           sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
648 	else
649 #endif
650 	  sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
651 
652 	if (lseek (desc, member_offset, 0) != member_offset)
653 	  {
654 	    (void) close (desc);
655 	    return -2;
656 	  }
657 #else
658 
659  	/* If this member maps archive names, we must read it in.  The
660  	   name map will always precede any members whose names must
661  	   be mapped.  */
662 	if (is_namemap)
663  	  {
664  	    char *clear;
665  	    char *limit;
666 
667  	    namemap = (char *) alloca (eltsize);
668  	    nread = read (desc, namemap, eltsize);
669  	    if (nread != eltsize)
670  	      {
671  		(void) close (desc);
672  		return -2;
673  	      }
674 
675  	    /* The names are separated by newlines.  Some formats have
676  	       a trailing slash.  Null terminate the strings for
677  	       convenience.  */
678  	    limit = namemap + eltsize;
679  	    for (clear = namemap; clear < limit; clear++)
680  	      {
681  		if (*clear == '\n')
682  		  {
683  		    *clear = '\0';
684  		    if (clear[-1] == '/')
685  		      clear[-1] = '\0';
686  		  }
687  	      }
688 
689 	    is_namemap = 0;
690  	  }
691 
692 	member_offset += AR_HDR_SIZE + eltsize;
693 	if (member_offset % 2 != 0)
694 	  member_offset++;
695 #endif
696       }
697   }
698 
699   close (desc);
700   return 0;
701 }
702 #endif /* !VMS */
703 
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.  */
707 
708 int
ar_name_equal(char * name,char * mem,int truncated)709 ar_name_equal (char *name, char *mem, int truncated)
710 {
711   char *p;
712 
713   p = strrchr (name, '/');
714   if (p != 0)
715     name = p + 1;
716 
717 #ifndef VMS
718   if (truncated)
719     {
720 #ifdef AIAMAG
721       /* TRUNCATED should never be set on this system.  */
722       abort ();
723 #else
724       struct ar_hdr hdr;
725 #if !defined (__hpux) && !defined (cray)
726       return strneq (name, mem, sizeof(hdr.ar_name) - 1);
727 #else
728       return strneq (name, mem, sizeof(hdr.ar_name) - 2);
729 #endif /* !__hpux && !cray */
730 #endif /* !AIAMAG */
731     }
732 #endif /* !VMS */
733 
734   return !strcmp (name, mem);
735 }
736 
737 #ifndef VMS
738 /* ARGSUSED */
739 static long int
ar_member_pos(int desc UNUSED,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,char * name)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)
744 {
745   if (!ar_name_equal (name, mem, truncated))
746     return 0;
747   return hdrpos;
748 }
749 
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.  */
756 
757 int
ar_member_touch(char * arname,char * memname)758 ar_member_touch (char *arname, char *memname)
759 {
760   long int pos = ar_scan (arname, ar_member_pos, (intptr_t) memname);
761   int fd;
762   struct ar_hdr ar_hdr;
763   int i;
764   unsigned int ui;
765   struct stat statbuf;
766 
767   if (pos < 0)
768     return (int) pos;
769   if (!pos)
770     return 1;
771 
772   fd = open (arname, O_RDWR, 0666);
773   if (fd < 0)
774     return -3;
775   /* Read in this member's header */
776   if (lseek (fd, pos, 0) < 0)
777     goto lose;
778   if (AR_HDR_SIZE != read (fd, (char *) &ar_hdr, AR_HDR_SIZE))
779     goto lose;
780   /* Write back the header, thus touching the archive file.  */
781   if (lseek (fd, pos, 0) < 0)
782     goto lose;
783   if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
784     goto lose;
785   /* The file's mtime is the time we we want.  */
786   EINTRLOOP (i, fstat (fd, &statbuf));
787   if (i < 0)
788     goto lose;
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);
794 #ifdef AIAMAG
795   ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
796 #endif
797 #else
798   ar_hdr.ar_date = statbuf.st_mtime;
799 #endif
800   /* Write back this member's header */
801   if (lseek (fd, pos, 0) < 0)
802     goto lose;
803   if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
804     goto lose;
805   close (fd);
806   return 0;
807 
808  lose:
809   i = errno;
810   close (fd);
811   errno = i;
812   return -3;
813 }
814 #endif
815 
816 #ifdef TEST
817 
818 intptr_t
describe_member(int desc,char * name,int truncated,long int hdrpos,long int datapos,long int size,long int date,int uid,int gid,int mode)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)
822 {
823   extern char *ctime ();
824 
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);
830 
831   return 0;
832 }
833 
834 int
main(int argc,char ** argv)835 main (int argc, char **argv)
836 {
837   ar_scan (argv[1], describe_member);
838   return 0;
839 }
840 
841 #endif	/* TEST.  */
842 #endif	/* NO_ARCHIVES.  */
843