(root)/
make-4.4/
src/
arscan.c
       1  /* Library function for scanning an archive file.
       2  Copyright (C) 1987-2022 Free Software Foundation, Inc.
       3  This file is part of GNU Make.
       4  
       5  GNU Make is free software; you can redistribute it and/or modify it under the
       6  terms of the GNU General Public License as published by the Free Software
       7  Foundation; either version 3 of the License, or (at your option) any later
       8  version.
       9  
      10  GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
      11  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      12  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      13  
      14  You should have received a copy of the GNU General Public License along with
      15  this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include "makeint.h"
      18  
      19  #ifdef TEST
      20  /* Hack, the real error() routine eventually pulls in die from main.c */
      21  #define error(a, b, c, d)
      22  #endif
      23  
      24  #ifdef HAVE_FCNTL_H
      25  #include <fcntl.h>
      26  #else
      27  #include <sys/file.h>
      28  #endif
      29  
      30  #ifndef NO_ARCHIVES
      31  
      32  #ifdef VMS
      33  #include <lbrdef.h>
      34  #include <mhddef.h>
      35  #include <credef.h>
      36  #include <descrip.h>
      37  #include <ctype.h>
      38  #include <ssdef.h>
      39  #include <stsdef.h>
      40  #include <rmsdef.h>
      41  
      42  /* This symbol should be present in lbrdef.h. */
      43  #if !defined LBR$_HDRTRUNC
      44  #pragma extern_model save
      45  #pragma extern_model globalvalue
      46  extern unsigned int LBR$_HDRTRUNC;
      47  #pragma extern_model restore
      48  #endif
      49  
      50  #include <unixlib.h>
      51  #include <lbr$routines.h>
      52  
      53  const char *
      54  vmsify (const char *name, int type);
      55  
      56  /* Time conversion from VMS to Unix
      57     Conversion from local time (stored in library) to GMT (needed for gmake)
      58     Note: The tm_gmtoff element is a VMS extension to the ANSI standard. */
      59  static time_t
      60  vms_time_to_unix(void *vms_time)
      61  {
      62    struct tm *tmp;
      63    time_t unix_time;
      64  
      65    unix_time = decc$fix_time(vms_time);
      66    tmp = localtime(&unix_time);
      67    unix_time -= tmp->tm_gmtoff;
      68  
      69    return unix_time;
      70  }
      71  
      72  
      73  /* VMS library routines need static variables for callback */
      74  static void *VMS_lib_idx;
      75  
      76  static const void *VMS_saved_arg;
      77  
      78  static intmax_t (*VMS_function) ();
      79  
      80  static intmax_t VMS_function_ret;
      81  
      82  
      83  /* This is a callback procedure for lib$get_index */
      84  static int
      85  VMS_get_member_info(struct dsc$descriptor_s *module, unsigned long *rfa)
      86  {
      87    int status, i;
      88    const int truncated = 0; /* Member name may be truncated */
      89    time_t member_date; /* Member date */
      90    char *filename;
      91    unsigned int buffer_length; /* Actual buffer length */
      92  
      93    /* Unused constants - Make does not actually use most of these */
      94    const int file_desc = -1; /* archive file descriptor for reading the data */
      95    const int header_position = 0; /* Header position */
      96    const int data_position = 0; /* Data position in file */
      97    const int data_size = 0; /* Data size */
      98    const int uid = 0; /* member gid */
      99    const int gid = 0; /* member gid */
     100    const int mode = 0; /* member protection mode */
     101    /* End of unused constants */
     102  
     103    static struct dsc$descriptor_s bufdesc =
     104      { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
     105  
     106    /* Only need the module definition */
     107    struct mhddef *mhd;
     108  
     109    /* If a previous callback is non-zero, just return that status */
     110    if (VMS_function_ret)
     111      {
     112        return SS$_NORMAL;
     113      }
     114  
     115    /* lbr_set_module returns more than just the module header. So allocate
     116       a buffer which is big enough: the maximum LBR$C_MAXHDRSIZ. That's at
     117       least bigger than the size of struct mhddef.
     118       If the request is too small, a buffer truncated warning is issued so
     119       it can be reissued with a larger buffer.
     120       We do not care if the buffer is truncated, so that is still a success. */
     121    mhd = xmalloc(LBR$C_MAXHDRSIZ);
     122    bufdesc.dsc$a_pointer = (char *) mhd;
     123    bufdesc.dsc$w_length = LBR$C_MAXHDRSIZ;
     124  
     125    status = lbr$set_module(&VMS_lib_idx, rfa, &bufdesc, &buffer_length, 0);
     126  
     127    if ((status != LBR$_HDRTRUNC) && !$VMS_STATUS_SUCCESS(status))
     128      {
     129        ON(error, NILF,
     130            _("lbr$set_module() failed to extract module info, status = %d"),
     131            status);
     132  
     133        lbr$close(&VMS_lib_idx);
     134  
     135        return status;
     136      }
     137  
     138  #ifdef TEST
     139    /* When testing this code, it is useful to know the length returned */
     140    printf ("Input length = %d, actual = %u\n",
     141            bufdesc.dsc$w_length, buffer_length);
     142  #endif
     143  
     144    /* Conversion from VMS time to C time.
     145       VMS defectlet - mhddef is sub-optimal, for the time, it has a 32 bit
     146       longword, mhd$l_datim, and a 32 bit fill instead of two longwords, or
     147       equivalent. */
     148    member_date = vms_time_to_unix(&mhd->mhd$l_datim);
     149    free(mhd);
     150  
     151    /* Here we have a problem.  The module name on VMS does not have
     152       a file type, but the filename pattern in the "VMS_saved_arg"
     153       may have one.
     154       But only the method being called knows how to interpret the
     155       filename pattern.
     156       There are currently two different formats being used.
     157       This means that we need a VMS specific code in those methods
     158       to handle it. */
     159    filename = xmalloc(module->dsc$w_length + 1);
     160  
     161    /* TODO: We may need an option to preserve the case of the module
     162       For now force the module name to lower case */
     163    for (i = 0; i < module->dsc$w_length; i++)
     164      filename[i] = _tolower((unsigned char )module->dsc$a_pointer[i]);
     165  
     166    filename[i] = '\0';
     167  
     168    VMS_function_ret = (*VMS_function)(file_desc, filename, truncated,
     169        header_position, data_position, data_size, member_date, uid, gid, mode,
     170        VMS_saved_arg);
     171  
     172    free(filename);
     173    return SS$_NORMAL;
     174  }
     175  
     176  
     177  /* Takes three arguments ARCHIVE, FUNCTION and ARG.
     178  
     179     Open the archive named ARCHIVE, find its members one by one,
     180     and for each one call FUNCTION with the following arguments:
     181       archive file descriptor for reading the data,
     182       member name,
     183       member name might be truncated flag,
     184       member header position in file,
     185       member data position in file,
     186       member data size,
     187       member date,
     188       member uid,
     189       member gid,
     190       member protection mode,
     191       ARG.
     192  
     193     NOTE: on VMS systems, only name, date, and arg are meaningful!
     194  
     195     The descriptor is poised to read the data of the member
     196     when FUNCTION is called.  It does not matter how much
     197     data FUNCTION reads.
     198  
     199     If FUNCTION returns nonzero, we immediately return
     200     what FUNCTION returned.
     201  
     202     Returns -1 if archive does not exist,
     203     Returns -2 if archive has invalid format.
     204     Returns 0 if have scanned successfully.  */
     205  
     206  intmax_t
     207  ar_scan (const char *archive, ar_member_func_t function, const void *varg)
     208  {
     209    char *vms_archive;
     210  
     211    static struct dsc$descriptor_s libdesc =
     212      { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
     213  
     214    const unsigned long func = LBR$C_READ;
     215    const unsigned long type = LBR$C_TYP_UNK;
     216    const unsigned long index = 1;
     217    unsigned long lib_idx;
     218    int status;
     219  
     220    VMS_saved_arg = varg;
     221  
     222    /* Null archive string can show up in test and cause an access violation */
     223    if (archive == NULL)
     224      {
     225        /* Null filenames do not exist */
     226        return -1;
     227      }
     228  
     229    /* archive path name must be in VMS format */
     230    vms_archive = (char *) vmsify(archive, 0);
     231  
     232    status = lbr$ini_control(&VMS_lib_idx, &func, &type, 0);
     233  
     234    if (!$VMS_STATUS_SUCCESS(status))
     235      {
     236        ON(error, NILF, _("lbr$ini_control() failed with status = %d"), status);
     237        return -2;
     238      }
     239  
     240    libdesc.dsc$a_pointer = vms_archive;
     241    libdesc.dsc$w_length = strlen(vms_archive);
     242  
     243    status = lbr$open(&VMS_lib_idx, &libdesc, 0, NULL, 0, NULL, 0);
     244  
     245    if (!$VMS_STATUS_SUCCESS(status))
     246      {
     247  
     248        /* TODO: A library format failure could mean that this is a file
     249           generated by the GNU AR utility and in that case, we need to
     250           take the UNIX codepath.  This will also take a change to the
     251           GNV AR wrapper program. */
     252  
     253        switch (status)
     254          {
     255        case RMS$_FNF:
     256          /* Archive does not exist */
     257          return -1;
     258        default:
     259  #ifndef TEST
     260          OSN(error, NILF,
     261              _("unable to open library '%s' to lookup member status %d"),
     262              archive, status);
     263  #endif
     264          /* For library format errors, specification says to return -2 */
     265          return -2;
     266          }
     267      }
     268  
     269    VMS_function = function;
     270  
     271    /* Clear the return status, as we are supposed to stop calling the
     272       callback function if it becomes non-zero, and this is a static
     273       variable. */
     274    VMS_function_ret = 0;
     275  
     276    status = lbr$get_index(&VMS_lib_idx, &index, VMS_get_member_info, NULL, 0);
     277  
     278    lbr$close(&VMS_lib_idx);
     279  
     280    /* Unless a failure occurred in the lbr$ routines, return the
     281       the status from the 'function' routine. */
     282    if ($VMS_STATUS_SUCCESS(status))
     283      {
     284        return VMS_function_ret;
     285      }
     286  
     287    /* This must be something wrong with the library and an error
     288       message should already have been printed. */
     289    return -2;
     290  }
     291  
     292  #else /* !VMS */
     293  
     294  /* SCO Unix's compiler defines both of these.  */
     295  #ifdef  M_UNIX
     296  #undef  M_XENIX
     297  #endif
     298  
     299  /* On the sun386i and in System V rel 3, ar.h defines two different archive
     300     formats depending upon whether you have defined PORTAR (normal) or PORT5AR
     301     (System V Release 1).  There is no default, one or the other must be defined
     302     to have a nonzero value.  */
     303  
     304  #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
     305  #undef  PORTAR
     306  #ifdef M_XENIX
     307  /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
     308     PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
     309     right one.  */
     310  #define PORTAR 0
     311  #else
     312  #define PORTAR 1
     313  #endif
     314  #endif
     315  
     316  /* On AIX, define these symbols to be sure to get both archive formats.
     317     AIX 4.3 introduced the "big" archive format to support 64-bit object
     318     files, so on AIX 4.3 systems we need to support both the "normal" and
     319     "big" archive formats.  An archive's format is indicated in the
     320     "fl_magic" field of the "FL_HDR" structure.  For a normal archive,
     321     this field will be the string defined by the AIAMAG symbol.  For a
     322     "big" archive, it will be the string defined by the AIAMAGBIG symbol
     323     (at least on AIX it works this way).
     324  
     325     Note: we'll define these symbols regardless of which AIX version
     326     we're compiling on, but this is okay since we'll use the new symbols
     327     only if they're present.  */
     328  #ifdef _AIX
     329  # define __AR_SMALL__
     330  # define __AR_BIG__
     331  #endif
     332  
     333  #ifndef WINDOWS32
     334  # if !defined (__ANDROID__) && !defined (__BEOS__)
     335  #  include <ar.h>
     336  # else
     337     /* These platforms don't have <ar.h> but have archives in the same format
     338      * as many other Unices.  This was taken from GNU binutils for BeOS.
     339      */
     340  #  define ARMAG "!<arch>\n"     /* String that begins an archive file.  */
     341  #  define SARMAG 8              /* Size of that string.  */
     342  #  define ARFMAG "`\n"          /* String in ar_fmag at end of each header.  */
     343  struct ar_hdr
     344    {
     345      char ar_name[16];           /* Member file name, sometimes / terminated. */
     346      char ar_date[12];           /* File date, decimal seconds since Epoch.  */
     347      char ar_uid[6], ar_gid[6];  /* User and group IDs, in ASCII decimal.  */
     348      char ar_mode[8];            /* File mode, in ASCII octal.  */
     349      char ar_size[10];           /* File size, in ASCII decimal.  */
     350      char ar_fmag[2];            /* Always contains ARFMAG.  */
     351    };
     352  # endif
     353  # define TOCHAR(_m)     (_m)
     354  #else
     355  /* These should allow us to read Windows (VC++) libraries (according to Frank
     356   * Libbrecht <frankl@abzx.belgium.hp.com>)
     357   */
     358  # include <windows.h>
     359  # include <windef.h>
     360  # include <io.h>
     361  # define ARMAG      IMAGE_ARCHIVE_START
     362  # define SARMAG     IMAGE_ARCHIVE_START_SIZE
     363  # define ar_hdr     _IMAGE_ARCHIVE_MEMBER_HEADER
     364  # define ar_name    Name
     365  # define ar_mode    Mode
     366  # define ar_size    Size
     367  # define ar_date    Date
     368  # define ar_uid     UserID
     369  # define ar_gid     GroupID
     370  /* In Windows the member names have type BYTE so we must cast them.  */
     371  # define TOCHAR(_m)     ((char *)(_m))
     372  #endif
     373  
     374  /* Cray's <ar.h> apparently defines this.  */
     375  #ifndef AR_HDR_SIZE
     376  # define   AR_HDR_SIZE  (sizeof (struct ar_hdr))
     377  #endif
     378  
     379  #include "intprops.h"
     380  
     381  #include "output.h"
     382  
     383  
     384  static uintmax_t
     385  parse_int (const char *ptr, const size_t len, const int base, uintmax_t max,
     386             const char *type, const char *archive, const char *name)
     387  {
     388    const char *const ep = ptr + len;
     389    const int maxchar = '0' + base - 1;
     390    uintmax_t val = 0;
     391  
     392    /* In all the versions I know of the spaces come last, but be safe.  */
     393    while (ptr < ep && *ptr == ' ')
     394      ++ptr;
     395  
     396    while (ptr < ep && *ptr != ' ')
     397      {
     398        uintmax_t nv;
     399  
     400        if (*ptr < '0' || *ptr > maxchar)
     401          OSSS (fatal, NILF,
     402                _("Invalid %s for archive %s member %s"), type, archive, name);
     403        nv = (val * base) + (*ptr - '0');
     404        if (nv < val || nv > max)
     405          OSSS (fatal, NILF,
     406                _("Invalid %s for archive %s member %s"), type, archive, name);
     407        val = nv;
     408        ++ptr;
     409      }
     410  
     411    return val;
     412  }
     413  
     414  /* Takes three arguments ARCHIVE, FUNCTION and ARG.
     415  
     416     Open the archive named ARCHIVE, find its members one by one,
     417     and for each one call FUNCTION with the following arguments:
     418       archive file descriptor for reading the data,
     419       member name,
     420       member name might be truncated flag,
     421       member header position in file,
     422       member data position in file,
     423       member data size,
     424       member date,
     425       member uid,
     426       member gid,
     427       member protection mode,
     428       ARG.
     429  
     430     The descriptor is poised to read the data of the member
     431     when FUNCTION is called.  It does not matter how much
     432     data FUNCTION reads.
     433  
     434     If FUNCTION returns nonzero, we immediately return
     435     what FUNCTION returned.
     436  
     437     Returns -1 if archive does not exist,
     438     Returns -2 if archive has invalid format.
     439     Returns 0 if have scanned successfully.  */
     440  
     441  intmax_t
     442  ar_scan (const char *archive, ar_member_func_t function, const void *arg)
     443  {
     444  #ifdef AIAMAG
     445    FL_HDR fl_header;
     446  # ifdef AIAMAGBIG
     447    int big_archive = 0;
     448    FL_HDR_BIG fl_header_big;
     449  # endif
     450  #endif
     451    char *namemap = 0;
     452    unsigned int namemap_size = 0;
     453    int desc = open (archive, O_RDONLY, 0);
     454    if (desc < 0)
     455      return -1;
     456  
     457  #ifdef SARMAG
     458    {
     459      char buf[SARMAG];
     460      int nread;
     461      nread = readbuf (desc, buf, SARMAG);
     462      if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG))
     463        goto invalid;
     464    }
     465  #else
     466  #ifdef AIAMAG
     467    {
     468      int nread;
     469      nread = readbuf (desc, &fl_header, FL_HSZ);
     470      if (nread != FL_HSZ)
     471        goto invalid;
     472  
     473  #ifdef AIAMAGBIG
     474      /* If this is a "big" archive, then set the flag and
     475         re-read the header into the "big" structure. */
     476      if (!memcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
     477        {
     478          off_t o;
     479  
     480          big_archive = 1;
     481  
     482          /* seek back to beginning of archive */
     483          EINTRLOOP (o, lseek (desc, 0, 0));
     484          if (o < 0)
     485            goto invalid;
     486  
     487          /* re-read the header into the "big" structure */
     488          nread = readbuf (desc, &fl_header_big, FL_HSZ_BIG);
     489          if (nread != FL_HSZ_BIG)
     490            goto invalid;
     491        }
     492      else
     493  #endif
     494         /* Check to make sure this is a "normal" archive. */
     495        if (memcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
     496          goto invalid;
     497    }
     498  #else
     499    {
     500  #ifndef M_XENIX
     501      int buf;
     502  #else
     503      unsigned short int buf;
     504  #endif
     505      int nread;
     506      nread = readbuf (desc, &buf, sizeof (buf));
     507      if (nread != sizeof (buf) || buf != ARMAG)
     508        goto invalid;
     509    }
     510  #endif
     511  #endif
     512  
     513    /* Now find the members one by one.  */
     514    {
     515  #ifdef SARMAG
     516      long int member_offset = SARMAG;
     517  #else
     518  #ifdef AIAMAG
     519      long int member_offset;
     520      long int last_member_offset;
     521  
     522  #ifdef AIAMAGBIG
     523      if ( big_archive )
     524        {
     525          sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
     526          sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
     527        }
     528      else
     529  #endif
     530        {
     531          sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
     532          sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
     533        }
     534  
     535      if (member_offset == 0)
     536        {
     537          /* Empty archive.  */
     538          close (desc);
     539          return 0;
     540        }
     541  #else
     542  #ifndef M_XENIX
     543      long int member_offset = sizeof (int);
     544  #else   /* Xenix.  */
     545      long int member_offset = sizeof (unsigned short int);
     546  #endif  /* Not Xenix.  */
     547  #endif
     548  #endif
     549  
     550      while (1)
     551        {
     552          ssize_t nread;
     553          struct ar_hdr member_header;
     554  #ifdef AIAMAGBIG
     555          struct ar_hdr_big member_header_big;
     556  #endif
     557  #ifdef AIAMAG
     558  # define ARNAME_MAX 255
     559          char name[ARNAME_MAX + 1];
     560          int name_len;
     561          intmax_t dateval;
     562          int uidval, gidval;
     563          long int data_offset;
     564  #else
     565  # define ARNAME_MAX (int)sizeof(member_header.ar_name)
     566          char namebuf[ARNAME_MAX + 1];
     567          char *name;
     568          int is_namemap;         /* Nonzero if this entry maps long names.  */
     569          int long_name = 0;
     570  #endif
     571          long int eltsize;
     572          unsigned int eltmode;
     573          intmax_t eltdate;
     574          int eltuid, eltgid;
     575          intmax_t fnval;
     576          off_t o;
     577  
     578          memset(&member_header, '\0', sizeof (member_header));
     579  
     580          EINTRLOOP (o, lseek (desc, member_offset, 0));
     581          if (o < 0)
     582            goto invalid;
     583  
     584  #ifdef AIAMAG
     585  #define       AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
     586  
     587  #ifdef AIAMAGBIG
     588          if (big_archive)
     589            {
     590              nread = readbuf (desc, &member_header_big,
     591                               AR_MEMHDR_SZ(member_header_big));
     592  
     593              if (nread != AR_MEMHDR_SZ(member_header_big))
     594                goto invalid;
     595  
     596              sscanf (member_header_big.ar_namlen, "%4d", &name_len);
     597              if (name_len < 1 || name_len > ARNAME_MAX)
     598                goto invalid;
     599  
     600              nread = readbuf (desc, name, name_len);
     601              if (nread != name_len)
     602                goto invalid;
     603  
     604              name[name_len] = '\0';
     605  
     606              sscanf (member_header_big.ar_date, "%12" SCNdMAX, &dateval);
     607              sscanf (member_header_big.ar_uid, "%12d", &uidval);
     608              sscanf (member_header_big.ar_gid, "%12d", &gidval);
     609              sscanf (member_header_big.ar_mode, "%12o", &eltmode);
     610              sscanf (member_header_big.ar_size, "%20ld", &eltsize);
     611  
     612              data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
     613                             + name_len + 2);
     614            }
     615          else
     616  #endif
     617            {
     618              nread = readbuf (desc, &member_header,
     619                               AR_MEMHDR_SZ(member_header));
     620  
     621              if (nread != AR_MEMHDR_SZ(member_header))
     622                goto invalid;
     623  
     624              sscanf (member_header.ar_namlen, "%4d", &name_len);
     625              if (name_len < 1 || name_len > ARNAME_MAX)
     626                goto invalid;
     627  
     628              nread = readbuf (desc, name, name_len);
     629              if (nread != name_len)
     630                goto invalid;
     631  
     632              name[name_len] = '\0';
     633  
     634              sscanf (member_header.ar_date, "%12" SCNdMAX, &dateval);
     635              sscanf (member_header.ar_uid, "%12d", &uidval);
     636              sscanf (member_header.ar_gid, "%12d", &gidval);
     637              sscanf (member_header.ar_mode, "%12o", &eltmode);
     638              sscanf (member_header.ar_size, "%12ld", &eltsize);
     639  
     640              data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
     641                             + name_len + 2);
     642            }
     643          data_offset += data_offset % 2;
     644  
     645          fnval =
     646            (*function) (desc, name, 0,
     647                         member_offset, data_offset, eltsize,
     648                         dateval, uidval, gidval,
     649                         eltmode, arg);
     650  
     651  #else   /* Not AIAMAG.  */
     652          nread = readbuf (desc, &member_header, AR_HDR_SIZE);
     653          if (nread == 0)
     654            /* No data left means end of file; that is OK.  */
     655            break;
     656  
     657          if (nread != AR_HDR_SIZE
     658  #if defined(ARFMAG) || defined(ARFZMAG)
     659              || (
     660  # ifdef ARFMAG
     661                  memcmp (member_header.ar_fmag, ARFMAG, 2)
     662  # else
     663                  1
     664  # endif
     665                  &&
     666  # ifdef ARFZMAG
     667                  memcmp (member_header.ar_fmag, ARFZMAG, 2)
     668  # else
     669                  1
     670  # endif
     671                 )
     672  #endif
     673              )
     674            goto invalid;
     675  
     676          name = namebuf;
     677          memcpy (name, member_header.ar_name, sizeof member_header.ar_name);
     678          {
     679            char *p = name + sizeof member_header.ar_name;
     680            do
     681              *p = '\0';
     682            while (p > name && *--p == ' ');
     683  
     684  #ifndef AIAMAG
     685            /* If the member name is "//" or "ARFILENAMES/" this may be
     686               a list of file name mappings.  The maximum file name
     687               length supported by the standard archive format is 14
     688               characters.  This member will actually always be the
     689               first or second entry in the archive, but we don't check
     690               that.  */
     691            is_namemap = (!strcmp (name, "//")
     692                          || !strcmp (name, "ARFILENAMES/"));
     693  #endif  /* Not AIAMAG. */
     694  
     695            /* On some systems, there is a slash after each member name.  */
     696            if (*p == '/')
     697              *p = '\0';
     698  
     699  #ifndef AIAMAG
     700            /* If the member name starts with a space or a slash, this
     701               is an index into the file name mappings (used by GNU ar).
     702               Otherwise if the member name looks like #1/NUMBER the
     703               real member name appears in the element data (used by
     704               4.4BSD).  */
     705            if (! is_namemap
     706                && (name[0] == ' ' || name[0] == '/')
     707                && namemap != 0)
     708              {
     709                const char* err;
     710                unsigned int name_off = make_toui (name + 1, &err);
     711                size_t name_len;
     712  
     713                if (err|| name_off >= namemap_size)
     714                  goto invalid;
     715  
     716                name = namemap + name_off;
     717                name_len = strlen (name);
     718                if (name_len < 1)
     719                  goto invalid;
     720                long_name = 1;
     721              }
     722            else if (name[0] == '#'
     723                     && name[1] == '1'
     724                     && name[2] == '/')
     725              {
     726                const char* err;
     727                unsigned int name_len = make_toui (name + 3, &err);
     728  
     729                if (err || name_len == 0 || name_len >= MIN (PATH_MAX, INT_MAX))
     730                  goto invalid;
     731  
     732                name = alloca (name_len + 1);
     733                nread = readbuf (desc, name, name_len);
     734                if (nread < 0 || (unsigned int) nread != name_len)
     735                  goto invalid;
     736  
     737                name[name_len] = '\0';
     738  
     739                long_name = 1;
     740              }
     741  #endif /* Not AIAMAG. */
     742          }
     743  
     744  #ifndef M_XENIX
     745  #define PARSE_INT(_m, _t, _b, _n) \
     746          (_t) parse_int (TOCHAR (member_header._m), sizeof (member_header._m), \
     747                          _b, TYPE_MAXIMUM (_t), _n, archive, name)
     748  
     749          eltmode = PARSE_INT (ar_mode, unsigned int, 8, "mode");
     750          eltsize = PARSE_INT (ar_size, long, 10, "size");
     751          eltdate = PARSE_INT (ar_date, intmax_t, 10, "date");
     752          eltuid = PARSE_INT (ar_uid, int, 10, "uid");
     753          eltgid = PARSE_INT (ar_gid, int, 10, "gid");
     754  #undef PARSE_INT
     755  #else   /* Xenix.  */
     756          eltmode = (unsigned short int) member_header.ar_mode;
     757          eltsize = member_header.ar_size;
     758  #endif  /* Not Xenix.  */
     759  
     760          fnval =
     761            (*function) (desc, name, ! long_name, member_offset,
     762                         member_offset + AR_HDR_SIZE, eltsize,
     763  #ifndef M_XENIX
     764                         eltdate, eltuid, eltgid,
     765  #else   /* Xenix.  */
     766                         member_header.ar_date,
     767                         member_header.ar_uid,
     768                         member_header.ar_gid,
     769  #endif  /* Not Xenix.  */
     770                         eltmode, arg);
     771  
     772  #endif  /* AIAMAG.  */
     773  
     774          if (fnval)
     775            {
     776              (void) close (desc);
     777              return fnval;
     778            }
     779  
     780  #ifdef AIAMAG
     781          if (member_offset == last_member_offset)
     782            /* End of the chain.  */
     783            break;
     784  
     785  #ifdef AIAMAGBIG
     786          if (big_archive)
     787           sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
     788          else
     789  #endif
     790            sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
     791  
     792          if (lseek (desc, member_offset, 0) != member_offset)
     793            goto invalid;
     794  #else
     795  
     796          /* If this member maps archive names, we must read it in.  The
     797             name map will always precede any members whose names must
     798             be mapped.  */
     799          if (is_namemap)
     800            {
     801              char *clear;
     802              char *limit;
     803  
     804              if (eltsize > INT_MAX)
     805                goto invalid;
     806              namemap = alloca (eltsize + 1);
     807              nread = readbuf (desc, namemap, eltsize);
     808              if (nread != eltsize)
     809                goto invalid;
     810              namemap_size = eltsize;
     811  
     812              /* The names are separated by newlines.  Some formats have
     813                 a trailing slash.  Null terminate the strings for
     814                 convenience.  */
     815              limit = namemap + eltsize;
     816              for (clear = namemap; clear < limit; clear++)
     817                {
     818                  if (*clear == '\n')
     819                    {
     820                      *clear = '\0';
     821                      if (clear[-1] == '/')
     822                        clear[-1] = '\0';
     823                    }
     824                }
     825              *limit = '\0';
     826  
     827              is_namemap = 0;
     828            }
     829  
     830          member_offset += AR_HDR_SIZE + eltsize;
     831          if (member_offset % 2 != 0)
     832            member_offset++;
     833  #endif
     834        }
     835    }
     836  
     837    close (desc);
     838    return 0;
     839  
     840   invalid:
     841    close (desc);
     842    return -2;
     843  }
     844  #endif /* !VMS */
     845  
     846  /* Return nonzero iff NAME matches MEM.
     847     If TRUNCATED is nonzero, MEM may be truncated to
     848     sizeof (struct ar_hdr.ar_name) - 1.  */
     849  
     850  int
     851  ar_name_equal (const char *name, const char *mem, int truncated)
     852  {
     853    const char *p;
     854  
     855    p = strrchr (name, '/');
     856    if (p != 0)
     857      name = p + 1;
     858  
     859  #ifndef VMS
     860    if (truncated)
     861      {
     862  #ifdef AIAMAG
     863        /* TRUNCATED should never be set on this system.  */
     864        abort ();
     865  #else
     866        struct ar_hdr hdr;
     867  #if !defined (__hpux) && !defined (cray)
     868        return strneq (name, mem, sizeof (hdr.ar_name) - 1);
     869  #else
     870        return strneq (name, mem, sizeof (hdr.ar_name) - 2);
     871  #endif /* !__hpux && !cray */
     872  #endif /* !AIAMAG */
     873      }
     874  
     875    return !strcmp (name, mem);
     876  #else
     877    /* VMS members do not have suffixes, but the filenames usually
     878       have.
     879       Do we need to strip VMS disk/directory format paths?
     880  
     881       Most VMS compilers etc. by default are case insensitive
     882       but produce uppercase external names, incl. module names.
     883       However the VMS librarian (ar) and the linker by default
     884       are case sensitive: they take what they get, usually
     885       uppercase names. So for the non-default settings of the
     886       compilers etc. there is a need to have a case sensitive
     887       mode. */
     888    {
     889      int len;
     890      len = strlen(mem);
     891      int match;
     892      char *dot;
     893      if ((dot=strrchr(name,'.')))
     894        match = (len == dot - name) && !strncasecmp(name, mem, len);
     895      else
     896        match = !strcasecmp (name, mem);
     897      return match;
     898    }
     899  #endif /* !VMS */
     900  }
     901  
     902  #ifndef VMS
     903  /* ARGSUSED */
     904  static intmax_t
     905  ar_member_pos (int desc UNUSED, const char *mem, int truncated,
     906                 long int hdrpos, long int datapos UNUSED, long int size UNUSED,
     907                 intmax_t date UNUSED, int uid UNUSED, int gid UNUSED,
     908                 unsigned int mode UNUSED, const void *name)
     909  {
     910    if (!ar_name_equal (name, mem, truncated))
     911      return 0;
     912    return hdrpos;
     913  }
     914  
     915  /* Set date of member MEMNAME in archive ARNAME to current time.
     916     Returns 0 if successful,
     917     -1 if file ARNAME does not exist,
     918     -2 if not a valid archive,
     919     -3 if other random system call error (including file read-only),
     920     1 if valid but member MEMNAME does not exist.  */
     921  
     922  int
     923  ar_member_touch (const char *arname, const char *memname)
     924  {
     925    intmax_t pos = ar_scan (arname, ar_member_pos, memname);
     926    off_t opos;
     927    int fd;
     928    struct ar_hdr ar_hdr;
     929    off_t o;
     930    int r;
     931    int datelen;
     932    struct stat statbuf;
     933  
     934    if (pos < 0)
     935      return (int) pos;
     936    if (!pos)
     937      return 1;
     938  
     939    opos = (off_t) pos;
     940  
     941    EINTRLOOP (fd, open (arname, O_RDWR, 0666));
     942    if (fd < 0)
     943      return -3;
     944    /* Read in this member's header */
     945    EINTRLOOP (o, lseek (fd, opos, 0));
     946    if (o < 0)
     947      goto lose;
     948    r = readbuf (fd, &ar_hdr, AR_HDR_SIZE);
     949    if (r != AR_HDR_SIZE)
     950      goto lose;
     951    /* The file's mtime is the time we we want.  */
     952    EINTRLOOP (r, fstat (fd, &statbuf));
     953    if (r < 0)
     954      goto lose;
     955    /* Advance member's time to that time */
     956  #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
     957    datelen = snprintf (TOCHAR (ar_hdr.ar_date), sizeof ar_hdr.ar_date,
     958                        "%" PRIdMAX, (intmax_t) statbuf.st_mtime);
     959    if (! (0 <= datelen && datelen < (int) sizeof ar_hdr.ar_date))
     960      goto lose;
     961    memset (ar_hdr.ar_date + datelen, ' ', sizeof ar_hdr.ar_date - datelen);
     962  #else
     963    ar_hdr.ar_date = statbuf.st_mtime;
     964  #endif
     965    /* Write back this member's header */
     966    EINTRLOOP (o, lseek (fd, opos, 0));
     967    if (o < 0)
     968      goto lose;
     969    r = writebuf (fd, &ar_hdr, AR_HDR_SIZE);
     970    if (r != AR_HDR_SIZE)
     971      goto lose;
     972    close (fd);
     973    return 0;
     974  
     975   lose:
     976    r = errno;
     977    close (fd);
     978    errno = r;
     979    return -3;
     980  }
     981  #endif
     982  
     983  #ifdef TEST
     984  
     985  intmax_t
     986  describe_member (int desc, const char *name, int truncated,
     987                   long int hdrpos, long int datapos, long int size,
     988                   intmax_t date, int uid, int gid, unsigned int mode,
     989                   const void *arg)
     990  {
     991    extern char *ctime ();
     992    time_t d = date;
     993    char const *ds;
     994  
     995    printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"),
     996            name, truncated ? _(" (name might be truncated)") : "",
     997            size, hdrpos, datapos);
     998    ds = ctime (&d);
     999    printf (_("  Date %s"), ds ? ds : "?");
    1000    printf (_("  uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
    1001  
    1002    return 0;
    1003  }
    1004  
    1005  int
    1006  main (int argc, char **argv)
    1007  {
    1008    ar_scan (argv[1], describe_member, NULL);
    1009    return 0;
    1010  }
    1011  
    1012  #endif  /* TEST.  */
    1013  #endif  /* NO_ARCHIVES.  */