Home | History | Annotate | Download | only in make-3.81
      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
     31 #include <lbrdef.h>
     32 #include <mhddef.h>
     33 #include <credef.h>
     34 #include <descrip.h>
     35 #include <ctype.h>
     36 #if __DECC
     37 #include <unixlib.h>
     38 #include <lbr$routines.h>
     39 #endif
     40 
     41 static void *VMS_lib_idx;
     42 
     43 static char *VMS_saved_memname;
     44 
     45 static time_t VMS_member_date;
     46 
     47 static long int (*VMS_function) ();
     48 
     49 static int
     50 VMS_get_member_info (struct dsc$descriptor_s *module, unsigned long *rfa)
     51 {
     52   int status, i;
     53   long int fnval;
     54 
     55   time_t val;
     56 
     57   static struct dsc$descriptor_s bufdesc =
     58     { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
     59 
     60   struct mhddef *mhd;
     61   char filename[128];
     62 
     63   bufdesc.dsc$a_pointer = filename;
     64   bufdesc.dsc$w_length = sizeof (filename);
     65 
     66   status = lbr$set_module (&VMS_lib_idx, rfa, &bufdesc,
     67 			   &bufdesc.dsc$w_length, 0);
     68   if (! (status & 1))
     69     {
     70       error (NILF, _("lbr$set_module failed to extract module info, status = %d"),
     71 	     status);
     72 
     73       lbr$close (&VMS_lib_idx);
     74 
     75       return 0;
     76     }
     77 
     78   mhd = (struct mhddef *) filename;
     79 
     80 #ifdef __DECC
     81   /* John Fowler <jfowler (at) nyx.net> writes this is needed in his environment,
     82    * but that decc$fix_time() isn't documented to work this way.  Let me
     83    * know if this causes problems in other VMS environments.
     84    */
     85   val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600;
     86 #endif
     87 
     88   for (i = 0; i < module->dsc$w_length; i++)
     89     filename[i] = _tolower ((unsigned char)module->dsc$a_pointer[i]);
     90 
     91   filename[i] = '\0';
     92 
     93   VMS_member_date = (time_t) -1;
     94 
     95   fnval =
     96     (*VMS_function) (-1, filename, 0, 0, 0, 0, val, 0, 0, 0,
     97 		     VMS_saved_memname);
     98 
     99   if (fnval)
    100     {
    101       VMS_member_date = fnval;
    102       return 0;
    103     }
    104   else
    105     return 1;
    106 }
    107 
    108 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
    109 
    110    Open the archive named ARCHIVE, find its members one by one,
    111    and for each one call FUNCTION with the following arguments:
    112      archive file descriptor for reading the data,
    113      member name,
    114      member name might be truncated flag,
    115      member header position in file,
    116      member data position in file,
    117      member data size,
    118      member date,
    119      member uid,
    120      member gid,
    121      member protection mode,
    122      ARG.
    123 
    124    NOTE: on VMS systems, only name, date, and arg are meaningful!
    125 
    126    The descriptor is poised to read the data of the member
    127    when FUNCTION is called.  It does not matter how much
    128    data FUNCTION reads.
    129 
    130    If FUNCTION returns nonzero, we immediately return
    131    what FUNCTION returned.
    132 
    133    Returns -1 if archive does not exist,
    134    Returns -2 if archive has invalid format.
    135    Returns 0 if have scanned successfully.  */
    136 
    137 long int
    138 ar_scan (char *archive, long int (*function) PARAMS ((void)), intptr_t arg)
    139 {
    140   char *p;
    141 
    142   static struct dsc$descriptor_s libdesc =
    143     { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
    144 
    145   unsigned long func = LBR$C_READ;
    146   unsigned long type = LBR$C_TYP_UNK;
    147   unsigned long index = 1;
    148 
    149   int status;
    150 
    151   status = lbr$ini_control (&VMS_lib_idx, &func, &type, 0);
    152 
    153   if (! (status & 1))
    154     {
    155       error (NILF, _("lbr$ini_control failed with status = %d"),status);
    156       return -2;
    157     }
    158 
    159   libdesc.dsc$a_pointer = archive;
    160   libdesc.dsc$w_length = strlen (archive);
    161 
    162   status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0);
    163 
    164   if (! (status & 1))
    165     {
    166       error (NILF, _("unable to open library `%s' to lookup member `%s'"),
    167 	     archive, (char *)arg);
    168       return -1;
    169     }
    170 
    171   VMS_saved_memname = (char *)arg;
    172 
    173   /* For comparison, delete .obj from arg name.  */
    174 
    175   p = strrchr (VMS_saved_memname, '.');
    176   if (p)
    177     *p = '\0';
    178 
    179   VMS_function = function;
    180 
    181   VMS_member_date = (time_t) -1;
    182   lbr$get_index (&VMS_lib_idx, &index, VMS_get_member_info, 0);
    183 
    184   /* Undo the damage.  */
    185   if (p)
    186     *p = '.';
    187 
    188   lbr$close (&VMS_lib_idx);
    189 
    190   return VMS_member_date > 0 ? VMS_member_date : 0;
    191 }
    192 
    193 #else /* !VMS */
    194 
    195 /* SCO Unix's compiler defines both of these.  */
    196 #ifdef	M_UNIX
    197 #undef	M_XENIX
    198 #endif
    199 
    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.  */
    204 
    205 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
    206 #undef	PORTAR
    207 #ifdef M_XENIX
    208 /* According to Jim Sievert <jas1 (at) 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
    216 
    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).
    225 
    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
    233 
    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.
    240     */
    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
    245   {
    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.  */
    252   };
    253 # endif
    254 #else
    255 /* These should allow us to read Windows (VC++) libraries (according to Frank
    256  * Libbrecht <frankl (at) abzx.belgium.hp.com>)
    257  */
    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
    271 
    272 /* Cray's <ar.h> apparently defines this.  */
    273 #ifndef	AR_HDR_SIZE
    274 # define   AR_HDR_SIZE	(sizeof (struct ar_hdr))
    275 #endif
    276 
    277 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
    279 
    280    Open the archive named ARCHIVE, find its members one by one,
    281    and for each one call FUNCTION with the following arguments:
    282      archive file descriptor for reading the data,
    283      member name,
    284      member name might be truncated flag,
    285      member header position in file,
    286      member data position in file,
    287      member data size,
    288      member date,
    289      member uid,
    290      member gid,
    291      member protection mode,
    292      ARG.
    293 
    294    The descriptor is poised to read the data of the member
    295    when FUNCTION is called.  It does not matter how much
    296    data FUNCTION reads.
    297 
    298    If FUNCTION returns nonzero, we immediately return
    299    what FUNCTION returned.
    300 
    301    Returns -1 if archive does not exist,
    302    Returns -2 if archive has invalid format.
    303    Returns 0 if have scanned successfully.  */
    304 
    305 long int
    306 ar_scan (char *archive, long int (*function)(), intptr_t arg)
    307 {
    308 #ifdef AIAMAG
    309   FL_HDR fl_header;
    310 #ifdef AIAMAGBIG
    311   int big_archive = 0;
    312   FL_HDR_BIG fl_header_big;
    313 #endif
    314 #else
    315   int long_name = 0;
    316 #endif
    317   char *namemap = 0;
    318   register int desc = open (archive, O_RDONLY, 0);
    319   if (desc < 0)
    320     return -1;
    321 #ifdef SARMAG
    322   {
    323     char buf[SARMAG];
    324     register int nread = read (desc, buf, SARMAG);
    325     if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
    326       {
    327 	(void) close (desc);
    328 	return -2;
    329       }
    330   }
    331 #else
    332 #ifdef AIAMAG
    333   {
    334     register int nread = read (desc, (char *) &fl_header, FL_HSZ);
    335 
    336     if (nread != FL_HSZ)
    337       {
    338 	(void) close (desc);
    339 	return -2;
    340       }
    341 #ifdef AIAMAGBIG
    342     /* If this is a "big" archive, then set the flag and
    343        re-read the header into the "big" structure. */
    344     if (!bcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
    345       {
    346 	big_archive = 1;
    347 
    348 	/* seek back to beginning of archive */
    349 	if (lseek (desc, 0, 0) < 0)
    350 	  {
    351 	    (void) close (desc);
    352 	    return -2;
    353 	  }
    354 
    355 	/* re-read the header into the "big" structure */
    356 	nread = read (desc, (char *) &fl_header_big, FL_HSZ_BIG);
    357 	if (nread != FL_HSZ_BIG)
    358 	  {
    359 	    (void) close (desc);
    360 	    return -2;
    361 	  }
    362       }
    363     else
    364 #endif
    365        /* Check to make sure this is a "normal" archive. */
    366       if (bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
    367 	{
    368           (void) close (desc);
    369           return -2;
    370 	}
    371   }
    372 #else
    373   {
    374 #ifndef M_XENIX
    375     int buf;
    376 #else
    377     unsigned short int buf;
    378 #endif
    379     register int nread = read(desc, &buf, sizeof (buf));
    380     if (nread != sizeof (buf) || buf != ARMAG)
    381       {
    382 	(void) close (desc);
    383 	return -2;
    384       }
    385   }
    386 #endif
    387 #endif
    388 
    389   /* Now find the members one by one.  */
    390   {
    391 #ifdef SARMAG
    392     register long int member_offset = SARMAG;
    393 #else
    394 #ifdef AIAMAG
    395     long int member_offset;
    396     long int last_member_offset;
    397 
    398 #ifdef AIAMAGBIG
    399     if ( big_archive )
    400       {
    401 	sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
    402 	sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
    403       }
    404     else
    405 #endif
    406       {
    407 	sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
    408 	sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
    409       }
    410 
    411     if (member_offset == 0)
    412       {
    413 	/* Empty archive.  */
    414 	close (desc);
    415 	return 0;
    416       }
    417 #else
    418 #ifndef	M_XENIX
    419     register long int member_offset = sizeof (int);
    420 #else	/* Xenix.  */
    421     register long int member_offset = sizeof (unsigned short int);
    422 #endif	/* Not Xenix.  */
    423 #endif
    424 #endif
    425 
    426     while (1)
    427       {
    428 	register int nread;
    429 	struct ar_hdr member_header;
    430 #ifdef AIAMAGBIG
    431 	struct ar_hdr_big member_header_big;
    432 #endif
    433 #ifdef AIAMAG
    434 	char name[256];
    435 	int name_len;
    436 	long int dateval;
    437 	int uidval, gidval;
    438 	long int data_offset;
    439 #else
    440 	char namebuf[sizeof member_header.ar_name + 1];
    441 	char *name;
    442 	int is_namemap;		/* Nonzero if this entry maps long names.  */
    443 #endif
    444 	long int eltsize;
    445 	int eltmode;
    446 	long int fnval;
    447 
    448 	if (lseek (desc, member_offset, 0) < 0)
    449 	  {
    450 	    (void) close (desc);
    451 	    return -2;
    452 	  }
    453 
    454 #ifdef AIAMAG
    455 #define       AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
    456 
    457 #ifdef AIAMAGBIG
    458 	if (big_archive)
    459 	  {
    460 	    nread = read (desc, (char *) &member_header_big,
    461 			  AR_MEMHDR_SZ(member_header_big) );
    462 
    463 	    if (nread != AR_MEMHDR_SZ(member_header_big))
    464 	      {
    465 		(void) close (desc);
    466 		return -2;
    467 	      }
    468 
    469 	    sscanf (member_header_big.ar_namlen, "%4d", &name_len);
    470 	    nread = read (desc, name, name_len);
    471 
    472 	    if (nread != name_len)
    473 	      {
    474 		(void) close (desc);
    475 		return -2;
    476 	      }
    477 
    478 	    name[name_len] = 0;
    479 
    480 	    sscanf (member_header_big.ar_date, "%12ld", &dateval);
    481 	    sscanf (member_header_big.ar_uid, "%12d", &uidval);
    482 	    sscanf (member_header_big.ar_gid, "%12d", &gidval);
    483 	    sscanf (member_header_big.ar_mode, "%12o", &eltmode);
    484 	    sscanf (member_header_big.ar_size, "%20ld", &eltsize);
    485 
    486 	    data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
    487 			   + name_len + 2);
    488 	  }
    489 	else
    490 #endif
    491 	  {
    492 	    nread = read (desc, (char *) &member_header,
    493 			  AR_MEMHDR_SZ(member_header) );
    494 
    495 	    if (nread != AR_MEMHDR_SZ(member_header))
    496 	      {
    497 		(void) close (desc);
    498 		return -2;
    499 	      }
    500 
    501 	    sscanf (member_header.ar_namlen, "%4d", &name_len);
    502 	    nread = read (desc, name, name_len);
    503 
    504 	    if (nread != name_len)
    505 	      {
    506 		(void) close (desc);
    507 		return -2;
    508 	      }
    509 
    510 	    name[name_len] = 0;
    511 
    512 	    sscanf (member_header.ar_date, "%12ld", &dateval);
    513 	    sscanf (member_header.ar_uid, "%12d", &uidval);
    514 	    sscanf (member_header.ar_gid, "%12d", &gidval);
    515 	    sscanf (member_header.ar_mode, "%12o", &eltmode);
    516 	    sscanf (member_header.ar_size, "%12ld", &eltsize);
    517 
    518 	    data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
    519 			   + name_len + 2);
    520 	  }
    521 	data_offset += data_offset % 2;
    522 
    523 	fnval =
    524 	  (*function) (desc, name, 0,
    525 		       member_offset, data_offset, eltsize,
    526 		       dateval, uidval, gidval,
    527 		       eltmode, arg);
    528 
    529 #else	/* Not AIAMAG.  */
    530 	nread = read (desc, (char *) &member_header, AR_HDR_SIZE);
    531 	if (nread == 0)
    532 	  /* No data left means end of file; that is OK.  */
    533 	  break;
    534 
    535 	if (nread != AR_HDR_SIZE
    536 #if defined(ARFMAG) || defined(ARFZMAG)
    537 	    || (
    538 # ifdef ARFMAG
    539                 bcmp (member_header.ar_fmag, ARFMAG, 2)
    540 # else
    541                 1
    542 # endif
    543                 &&
    544 # ifdef ARFZMAG
    545                 bcmp (member_header.ar_fmag, ARFZMAG, 2)
    546 # else
    547                 1
    548 # endif
    549                )
    550 #endif
    551 	    )
    552 	  {
    553 	    (void) close (desc);
    554 	    return -2;
    555 	  }
    556 
    557 	name = namebuf;
    558 	bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
    559 	{
    560 	  register char *p = name + sizeof member_header.ar_name;
    561 	  do
    562 	    *p = '\0';
    563 	  while (p > name && *--p == ' ');
    564 
    565 #ifndef AIAMAG
    566 	  /* If the member name is "//" or "ARFILENAMES/" this may be
    567 	     a list of file name mappings.  The maximum file name
    568  	     length supported by the standard archive format is 14
    569  	     characters.  This member will actually always be the
    570  	     first or second entry in the archive, but we don't check
    571  	     that.  */
    572  	  is_namemap = (!strcmp (name, "//")
    573 			|| !strcmp (name, "ARFILENAMES/"));
    574 #endif	/* Not AIAMAG. */
    575 	  /* On some systems, there is a slash after each member name.  */
    576 	  if (*p == '/')
    577 	    *p = '\0';
    578 
    579 #ifndef AIAMAG
    580  	  /* If the member name starts with a space or a slash, this
    581  	     is an index into the file name mappings (used by GNU ar).
    582  	     Otherwise if the member name looks like #1/NUMBER the
    583  	     real member name appears in the element data (used by
    584  	     4.4BSD).  */
    585  	  if (! is_namemap
    586  	      && (name[0] == ' ' || name[0] == '/')
    587  	      && namemap != 0)
    588 	    {
    589 	      name = namemap + atoi (name + 1);
    590 	      long_name = 1;
    591 	    }
    592  	  else if (name[0] == '#'
    593  		   && name[1] == '1'
    594  		   && name[2] == '/')
    595  	    {
    596  	      int namesize = atoi (name + 3);
    597 
    598  	      name = (char *) alloca (namesize + 1);
    599  	      nread = read (desc, name, namesize);
    600  	      if (nread != namesize)
    601  		{
    602  		  close (desc);
    603  		  return -2;
    604  		}
    605  	      name[namesize] = '\0';
    606 
    607 	      long_name = 1;
    608  	    }
    609 #endif /* Not AIAMAG. */
    610 	}
    611 
    612 #ifndef	M_XENIX
    613 	sscanf (member_header.ar_mode, "%o", &eltmode);
    614 	eltsize = atol (member_header.ar_size);
    615 #else	/* Xenix.  */
    616 	eltmode = (unsigned short int) member_header.ar_mode;
    617 	eltsize = member_header.ar_size;
    618 #endif	/* Not Xenix.  */
    619 
    620 	fnval =
    621 	  (*function) (desc, name, ! long_name, member_offset,
    622 		       member_offset + AR_HDR_SIZE, eltsize,
    623 #ifndef	M_XENIX
    624 		       atol (member_header.ar_date),
    625 		       atoi (member_header.ar_uid),
    626 		       atoi (member_header.ar_gid),
    627 #else	/* Xenix.  */
    628 		       member_header.ar_date,
    629 		       member_header.ar_uid,
    630 		       member_header.ar_gid,
    631 #endif	/* Not Xenix.  */
    632 		       eltmode, arg);
    633 
    634 #endif  /* AIAMAG.  */
    635 
    636 	if (fnval)
    637 	  {
    638 	    (void) close (desc);
    639 	    return fnval;
    640 	  }
    641 
    642 #ifdef AIAMAG
    643 	if (member_offset == last_member_offset)
    644 	  /* End of the chain.  */
    645 	  break;
    646 
    647 #ifdef AIAMAGBIG
    648 	if (big_archive)
    649           sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
    650 	else
    651 #endif
    652 	  sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
    653 
    654 	if (lseek (desc, member_offset, 0) != member_offset)
    655 	  {
    656 	    (void) close (desc);
    657 	    return -2;
    658 	  }
    659 #else
    660 
    661  	/* If this member maps archive names, we must read it in.  The
    662  	   name map will always precede any members whose names must
    663  	   be mapped.  */
    664 	if (is_namemap)
    665  	  {
    666  	    char *clear;
    667  	    char *limit;
    668 
    669  	    namemap = (char *) alloca (eltsize);
    670  	    nread = read (desc, namemap, eltsize);
    671  	    if (nread != eltsize)
    672  	      {
    673  		(void) close (desc);
    674  		return -2;
    675  	      }
    676 
    677  	    /* The names are separated by newlines.  Some formats have
    678  	       a trailing slash.  Null terminate the strings for
    679  	       convenience.  */
    680  	    limit = namemap + eltsize;
    681  	    for (clear = namemap; clear < limit; clear++)
    682  	      {
    683  		if (*clear == '\n')
    684  		  {
    685  		    *clear = '\0';
    686  		    if (clear[-1] == '/')
    687  		      clear[-1] = '\0';
    688  		  }
    689  	      }
    690 
    691 	    is_namemap = 0;
    692  	  }
    693 
    694 	member_offset += AR_HDR_SIZE + eltsize;
    695 	if (member_offset % 2 != 0)
    696 	  member_offset++;
    697 #endif
    698       }
    699   }
    700 
    701   close (desc);
    702   return 0;
    703 }
    704 #endif /* !VMS */
    705 
    706 /* Return nonzero iff NAME matches MEM.
    708    If TRUNCATED is nonzero, MEM may be truncated to
    709    sizeof (struct ar_hdr.ar_name) - 1.  */
    710 
    711 int
    712 ar_name_equal (char *name, char *mem, int truncated)
    713 {
    714   char *p;
    715 
    716   p = strrchr (name, '/');
    717   if (p != 0)
    718     name = p + 1;
    719 
    720 #ifndef VMS
    721   if (truncated)
    722     {
    723 #ifdef AIAMAG
    724       /* TRUNCATED should never be set on this system.  */
    725       abort ();
    726 #else
    727       struct ar_hdr hdr;
    728 #if !defined (__hpux) && !defined (cray)
    729       return strneq (name, mem, sizeof(hdr.ar_name) - 1);
    730 #else
    731       return strneq (name, mem, sizeof(hdr.ar_name) - 2);
    732 #endif /* !__hpux && !cray */
    733 #endif /* !AIAMAG */
    734     }
    735 #endif /* !VMS */
    736 
    737   return !strcmp (name, mem);
    738 }
    739 
    740 #ifndef VMS
    742 /* ARGSUSED */
    743 static long int
    744 ar_member_pos (int desc UNUSED, char *mem, int truncated,
    745 	       long int hdrpos, long int datapos UNUSED, long int size UNUSED,
    746                long int date UNUSED, int uid UNUSED, int gid UNUSED,
    747                int mode UNUSED, char *name)
    748 {
    749   if (!ar_name_equal (name, mem, truncated))
    750     return 0;
    751   return hdrpos;
    752 }
    753 
    754 /* Set date of member MEMNAME in archive ARNAME to current time.
    755    Returns 0 if successful,
    756    -1 if file ARNAME does not exist,
    757    -2 if not a valid archive,
    758    -3 if other random system call error (including file read-only),
    759    1 if valid but member MEMNAME does not exist.  */
    760 
    761 int
    762 ar_member_touch (char *arname, char *memname)
    763 {
    764   long int pos = ar_scan (arname, ar_member_pos, (intptr_t) memname);
    765   int fd;
    766   struct ar_hdr ar_hdr;
    767   int i;
    768   unsigned int ui;
    769   struct stat statbuf;
    770 
    771   if (pos < 0)
    772     return (int) pos;
    773   if (!pos)
    774     return 1;
    775 
    776   fd = open (arname, O_RDWR, 0666);
    777   if (fd < 0)
    778     return -3;
    779   /* Read in this member's header */
    780   if (lseek (fd, pos, 0) < 0)
    781     goto lose;
    782   if (AR_HDR_SIZE != read (fd, (char *) &ar_hdr, AR_HDR_SIZE))
    783     goto lose;
    784   /* Write back the header, thus touching the archive file.  */
    785   if (lseek (fd, pos, 0) < 0)
    786     goto lose;
    787   if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
    788     goto lose;
    789   /* The file's mtime is the time we we want.  */
    790   EINTRLOOP (i, fstat (fd, &statbuf));
    791   if (i < 0)
    792     goto lose;
    793 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
    794   /* Advance member's time to that time */
    795   for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++)
    796     ar_hdr.ar_date[ui] = ' ';
    797   sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime);
    798 #ifdef AIAMAG
    799   ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
    800 #endif
    801 #else
    802   ar_hdr.ar_date = statbuf.st_mtime;
    803 #endif
    804   /* Write back this member's header */
    805   if (lseek (fd, pos, 0) < 0)
    806     goto lose;
    807   if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
    808     goto lose;
    809   close (fd);
    810   return 0;
    811 
    812  lose:
    813   i = errno;
    814   close (fd);
    815   errno = i;
    816   return -3;
    817 }
    818 #endif
    819 
    820 #ifdef TEST
    822 
    823 intptr_t
    824 describe_member (int desc, char *name, int truncated,
    825 		 long int hdrpos, long int datapos, long int size,
    826                  long int date, int uid, int gid, int mode)
    827 {
    828   extern char *ctime ();
    829 
    830   printf (_("Member `%s'%s: %ld bytes at %ld (%ld).\n"),
    831 	  name, truncated ? _(" (name might be truncated)") : "",
    832 	  size, hdrpos, datapos);
    833   printf (_("  Date %s"), ctime (&date));
    834   printf (_("  uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
    835 
    836   return 0;
    837 }
    838 
    839 int
    840 main (int argc, char **argv)
    841 {
    842   ar_scan (argv[1], describe_member);
    843   return 0;
    844 }
    845 
    846 #endif	/* TEST.  */
    847 #endif	/* NO_ARCHIVES.  */
    848