Imported Upstream version 4.2.1
[platform/upstream/make.git] / arscan.c
1 /* Library function for scanning an archive file.
2 Copyright (C) 1987-2016 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 <http://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 #ifndef 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 long int (*VMS_function) ();
79
80 static long int 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 = %d\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 long int
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 \f
379 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
380
381    Open the archive named ARCHIVE, find its members one by one,
382    and for each one call FUNCTION with the following arguments:
383      archive file descriptor for reading the data,
384      member name,
385      member name might be truncated flag,
386      member header position in file,
387      member data position in file,
388      member data size,
389      member date,
390      member uid,
391      member gid,
392      member protection mode,
393      ARG.
394
395    The descriptor is poised to read the data of the member
396    when FUNCTION is called.  It does not matter how much
397    data FUNCTION reads.
398
399    If FUNCTION returns nonzero, we immediately return
400    what FUNCTION returned.
401
402    Returns -1 if archive does not exist,
403    Returns -2 if archive has invalid format.
404    Returns 0 if have scanned successfully.  */
405
406 long int
407 ar_scan (const char *archive, ar_member_func_t function, const void *arg)
408 {
409 #ifdef AIAMAG
410   FL_HDR fl_header;
411 # ifdef AIAMAGBIG
412   int big_archive = 0;
413   FL_HDR_BIG fl_header_big;
414 # endif
415 #endif
416   char *namemap = 0;
417   int desc = open (archive, O_RDONLY, 0);
418   if (desc < 0)
419     return -1;
420 #ifdef SARMAG
421   {
422     char buf[SARMAG];
423     int nread;
424     EINTRLOOP (nread, read (desc, buf, SARMAG));
425     if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG))
426       {
427         (void) close (desc);
428         return -2;
429       }
430   }
431 #else
432 #ifdef AIAMAG
433   {
434     int nread;
435     EINTRLOOP (nread, read (desc, &fl_header, FL_HSZ));
436     if (nread != FL_HSZ)
437       {
438         (void) close (desc);
439         return -2;
440       }
441 #ifdef AIAMAGBIG
442     /* If this is a "big" archive, then set the flag and
443        re-read the header into the "big" structure. */
444     if (!memcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
445       {
446         off_t o;
447
448         big_archive = 1;
449
450         /* seek back to beginning of archive */
451         EINTRLOOP (o, lseek (desc, 0, 0));
452         if (o < 0)
453           {
454             (void) close (desc);
455             return -2;
456           }
457
458         /* re-read the header into the "big" structure */
459         EINTRLOOP (nread, read (desc, &fl_header_big, FL_HSZ_BIG));
460         if (nread != FL_HSZ_BIG)
461           {
462             (void) close (desc);
463             return -2;
464           }
465       }
466     else
467 #endif
468        /* Check to make sure this is a "normal" archive. */
469       if (memcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
470         {
471           (void) close (desc);
472           return -2;
473         }
474   }
475 #else
476   {
477 #ifndef M_XENIX
478     int buf;
479 #else
480     unsigned short int buf;
481 #endif
482     int nread;
483     EINTRLOOP (nread, read (desc, &buf, sizeof (buf)));
484     if (nread != sizeof (buf) || buf != ARMAG)
485       {
486         (void) close (desc);
487         return -2;
488       }
489   }
490 #endif
491 #endif
492
493   /* Now find the members one by one.  */
494   {
495 #ifdef SARMAG
496     register long int member_offset = SARMAG;
497 #else
498 #ifdef AIAMAG
499     long int member_offset;
500     long int last_member_offset;
501
502 #ifdef AIAMAGBIG
503     if ( big_archive )
504       {
505         sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
506         sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
507       }
508     else
509 #endif
510       {
511         sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
512         sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
513       }
514
515     if (member_offset == 0)
516       {
517         /* Empty archive.  */
518         close (desc);
519         return 0;
520       }
521 #else
522 #ifndef M_XENIX
523     register long int member_offset = sizeof (int);
524 #else   /* Xenix.  */
525     register long int member_offset = sizeof (unsigned short int);
526 #endif  /* Not Xenix.  */
527 #endif
528 #endif
529
530     while (1)
531       {
532         register int nread;
533         struct ar_hdr member_header;
534 #ifdef AIAMAGBIG
535         struct ar_hdr_big member_header_big;
536 #endif
537 #ifdef AIAMAG
538         char name[256];
539         int name_len;
540         long int dateval;
541         int uidval, gidval;
542         long int data_offset;
543 #else
544         char namebuf[sizeof member_header.ar_name + 1];
545         char *name;
546         int is_namemap;         /* Nonzero if this entry maps long names.  */
547         int long_name = 0;
548 #endif
549         long int eltsize;
550         unsigned int eltmode;
551         long int fnval;
552         off_t o;
553
554         EINTRLOOP (o, lseek (desc, member_offset, 0));
555         if (o < 0)
556           {
557             (void) close (desc);
558             return -2;
559           }
560
561 #ifdef AIAMAG
562 #define       AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
563
564 #ifdef AIAMAGBIG
565         if (big_archive)
566           {
567             EINTRLOOP (nread, read (desc, &member_header_big,
568                                     AR_MEMHDR_SZ(member_header_big)));
569
570             if (nread != AR_MEMHDR_SZ(member_header_big))
571               {
572                 (void) close (desc);
573                 return -2;
574               }
575
576             sscanf (member_header_big.ar_namlen, "%4d", &name_len);
577             EINTRLOOP (nread, read (desc, name, name_len));
578
579             if (nread != name_len)
580               {
581                 (void) close (desc);
582                 return -2;
583               }
584
585             name[name_len] = 0;
586
587             sscanf (member_header_big.ar_date, "%12ld", &dateval);
588             sscanf (member_header_big.ar_uid, "%12d", &uidval);
589             sscanf (member_header_big.ar_gid, "%12d", &gidval);
590             sscanf (member_header_big.ar_mode, "%12o", &eltmode);
591             sscanf (member_header_big.ar_size, "%20ld", &eltsize);
592
593             data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
594                            + name_len + 2);
595           }
596         else
597 #endif
598           {
599             EINTRLOOP (nread, read (desc, &member_header,
600                                     AR_MEMHDR_SZ(member_header)));
601
602             if (nread != AR_MEMHDR_SZ(member_header))
603               {
604                 (void) close (desc);
605                 return -2;
606               }
607
608             sscanf (member_header.ar_namlen, "%4d", &name_len);
609             EINTRLOOP (nread, read (desc, name, name_len));
610
611             if (nread != name_len)
612               {
613                 (void) close (desc);
614                 return -2;
615               }
616
617             name[name_len] = 0;
618
619             sscanf (member_header.ar_date, "%12ld", &dateval);
620             sscanf (member_header.ar_uid, "%12d", &uidval);
621             sscanf (member_header.ar_gid, "%12d", &gidval);
622             sscanf (member_header.ar_mode, "%12o", &eltmode);
623             sscanf (member_header.ar_size, "%12ld", &eltsize);
624
625             data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
626                            + name_len + 2);
627           }
628         data_offset += data_offset % 2;
629
630         fnval =
631           (*function) (desc, name, 0,
632                        member_offset, data_offset, eltsize,
633                        dateval, uidval, gidval,
634                        eltmode, arg);
635
636 #else   /* Not AIAMAG.  */
637         EINTRLOOP (nread, read (desc, &member_header, AR_HDR_SIZE));
638         if (nread == 0)
639           /* No data left means end of file; that is OK.  */
640           break;
641
642         if (nread != AR_HDR_SIZE
643 #if defined(ARFMAG) || defined(ARFZMAG)
644             || (
645 # ifdef ARFMAG
646                 memcmp (member_header.ar_fmag, ARFMAG, 2)
647 # else
648                 1
649 # endif
650                 &&
651 # ifdef ARFZMAG
652                 memcmp (member_header.ar_fmag, ARFZMAG, 2)
653 # else
654                 1
655 # endif
656                )
657 #endif
658             )
659           {
660             (void) close (desc);
661             return -2;
662           }
663
664         name = namebuf;
665         memcpy (name, member_header.ar_name, sizeof member_header.ar_name);
666         {
667           register char *p = name + sizeof member_header.ar_name;
668           do
669             *p = '\0';
670           while (p > name && *--p == ' ');
671
672 #ifndef AIAMAG
673           /* If the member name is "//" or "ARFILENAMES/" this may be
674              a list of file name mappings.  The maximum file name
675              length supported by the standard archive format is 14
676              characters.  This member will actually always be the
677              first or second entry in the archive, but we don't check
678              that.  */
679           is_namemap = (!strcmp (name, "//")
680                         || !strcmp (name, "ARFILENAMES/"));
681 #endif  /* Not AIAMAG. */
682           /* On some systems, there is a slash after each member name.  */
683           if (*p == '/')
684             *p = '\0';
685
686 #ifndef AIAMAG
687           /* If the member name starts with a space or a slash, this
688              is an index into the file name mappings (used by GNU ar).
689              Otherwise if the member name looks like #1/NUMBER the
690              real member name appears in the element data (used by
691              4.4BSD).  */
692           if (! is_namemap
693               && (name[0] == ' ' || name[0] == '/')
694               && namemap != 0)
695             {
696               name = namemap + atoi (name + 1);
697               long_name = 1;
698             }
699           else if (name[0] == '#'
700                    && name[1] == '1'
701                    && name[2] == '/')
702             {
703               int namesize = atoi (name + 3);
704
705               name = alloca (namesize + 1);
706               EINTRLOOP (nread, read (desc, name, namesize));
707               if (nread != namesize)
708                 {
709                   close (desc);
710                   return -2;
711                 }
712               name[namesize] = '\0';
713
714               long_name = 1;
715             }
716 #endif /* Not AIAMAG. */
717         }
718
719 #ifndef M_XENIX
720         sscanf (TOCHAR (member_header.ar_mode), "%o", &eltmode);
721         eltsize = atol (TOCHAR (member_header.ar_size));
722 #else   /* Xenix.  */
723         eltmode = (unsigned short int) member_header.ar_mode;
724         eltsize = member_header.ar_size;
725 #endif  /* Not Xenix.  */
726
727         fnval =
728           (*function) (desc, name, ! long_name, member_offset,
729                        member_offset + AR_HDR_SIZE, eltsize,
730 #ifndef M_XENIX
731                        atol (TOCHAR (member_header.ar_date)),
732                        atoi (TOCHAR (member_header.ar_uid)),
733                        atoi (TOCHAR (member_header.ar_gid)),
734 #else   /* Xenix.  */
735                        member_header.ar_date,
736                        member_header.ar_uid,
737                        member_header.ar_gid,
738 #endif  /* Not Xenix.  */
739                        eltmode, arg);
740
741 #endif  /* AIAMAG.  */
742
743         if (fnval)
744           {
745             (void) close (desc);
746             return fnval;
747           }
748
749 #ifdef AIAMAG
750         if (member_offset == last_member_offset)
751           /* End of the chain.  */
752           break;
753
754 #ifdef AIAMAGBIG
755         if (big_archive)
756          sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
757         else
758 #endif
759           sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
760
761         if (lseek (desc, member_offset, 0) != member_offset)
762           {
763             (void) close (desc);
764             return -2;
765           }
766 #else
767
768         /* If this member maps archive names, we must read it in.  The
769            name map will always precede any members whose names must
770            be mapped.  */
771         if (is_namemap)
772           {
773             char *clear;
774             char *limit;
775
776             namemap = alloca (eltsize);
777             EINTRLOOP (nread, read (desc, namemap, eltsize));
778             if (nread != eltsize)
779               {
780                 (void) close (desc);
781                 return -2;
782               }
783
784             /* The names are separated by newlines.  Some formats have
785                a trailing slash.  Null terminate the strings for
786                convenience.  */
787             limit = namemap + eltsize;
788             for (clear = namemap; clear < limit; clear++)
789               {
790                 if (*clear == '\n')
791                   {
792                     *clear = '\0';
793                     if (clear[-1] == '/')
794                       clear[-1] = '\0';
795                   }
796               }
797
798             is_namemap = 0;
799           }
800
801         member_offset += AR_HDR_SIZE + eltsize;
802         if (member_offset % 2 != 0)
803           member_offset++;
804 #endif
805       }
806   }
807
808   close (desc);
809   return 0;
810 }
811 #endif /* !VMS */
812 \f
813 /* Return nonzero iff NAME matches MEM.
814    If TRUNCATED is nonzero, MEM may be truncated to
815    sizeof (struct ar_hdr.ar_name) - 1.  */
816
817 int
818 ar_name_equal (const char *name, const char *mem, int truncated)
819 {
820   const char *p;
821
822   p = strrchr (name, '/');
823   if (p != 0)
824     name = p + 1;
825
826 #ifndef VMS
827   if (truncated)
828     {
829 #ifdef AIAMAG
830       /* TRUNCATED should never be set on this system.  */
831       abort ();
832 #else
833       struct ar_hdr hdr;
834 #if !defined (__hpux) && !defined (cray)
835       return strneq (name, mem, sizeof (hdr.ar_name) - 1);
836 #else
837       return strneq (name, mem, sizeof (hdr.ar_name) - 2);
838 #endif /* !__hpux && !cray */
839 #endif /* !AIAMAG */
840     }
841
842   return !strcmp (name, mem);
843 #else
844   /* VMS members do not have suffixes, but the filenames usually
845      have.
846      Do we need to strip VMS disk/directory format paths?
847
848      Most VMS compilers etc. by default are case insensitive
849      but produce uppercase external names, incl. module names.
850      However the VMS librarian (ar) and the linker by default
851      are case sensitive: they take what they get, usually
852      uppercase names. So for the non-default settings of the
853      compilers etc. there is a need to have a case sensitive
854      mode. */
855   {
856     int len;
857     len = strlen(mem);
858     int match;
859     char *dot;
860     if ((dot=strrchr(name,'.')))
861       match = (len == dot - name) && !strncasecmp(name, mem, len);
862     else
863       match = !strcasecmp (name, mem);
864     return match;
865   }
866 #endif /* !VMS */
867 }
868 \f
869 #ifndef VMS
870 /* ARGSUSED */
871 static long int
872 ar_member_pos (int desc UNUSED, const char *mem, int truncated,
873                long int hdrpos, long int datapos UNUSED, long int size UNUSED,
874                long int date UNUSED, int uid UNUSED, int gid UNUSED,
875                unsigned int mode UNUSED, const void *name)
876 {
877   if (!ar_name_equal (name, mem, truncated))
878     return 0;
879   return hdrpos;
880 }
881
882 /* Set date of member MEMNAME in archive ARNAME to current time.
883    Returns 0 if successful,
884    -1 if file ARNAME does not exist,
885    -2 if not a valid archive,
886    -3 if other random system call error (including file read-only),
887    1 if valid but member MEMNAME does not exist.  */
888
889 int
890 ar_member_touch (const char *arname, const char *memname)
891 {
892   long int pos = ar_scan (arname, ar_member_pos, memname);
893   int fd;
894   struct ar_hdr ar_hdr;
895   off_t o;
896   int r;
897   unsigned int ui;
898   struct stat statbuf;
899
900   if (pos < 0)
901     return (int) pos;
902   if (!pos)
903     return 1;
904
905   EINTRLOOP (fd, open (arname, O_RDWR, 0666));
906   if (fd < 0)
907     return -3;
908   /* Read in this member's header */
909   EINTRLOOP (o, lseek (fd, pos, 0));
910   if (o < 0)
911     goto lose;
912   EINTRLOOP (r, read (fd, &ar_hdr, AR_HDR_SIZE));
913   if (r != AR_HDR_SIZE)
914     goto lose;
915   /* Write back the header, thus touching the archive file.  */
916   EINTRLOOP (o, lseek (fd, pos, 0));
917   if (o < 0)
918     goto lose;
919   EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE));
920   if (r != AR_HDR_SIZE)
921     goto lose;
922   /* The file's mtime is the time we we want.  */
923   EINTRLOOP (r, fstat (fd, &statbuf));
924   if (r < 0)
925     goto lose;
926 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
927   /* Advance member's time to that time */
928   for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++)
929     ar_hdr.ar_date[ui] = ' ';
930   sprintf (TOCHAR (ar_hdr.ar_date), "%lu", (long unsigned) statbuf.st_mtime);
931 #ifdef AIAMAG
932   ar_hdr.ar_date[strlen (ar_hdr.ar_date)] = ' ';
933 #endif
934 #else
935   ar_hdr.ar_date = statbuf.st_mtime;
936 #endif
937   /* Write back this member's header */
938   EINTRLOOP (o, lseek (fd, pos, 0));
939   if (o < 0)
940     goto lose;
941   EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE));
942   if (r != AR_HDR_SIZE)
943     goto lose;
944   close (fd);
945   return 0;
946
947  lose:
948   r = errno;
949   close (fd);
950   errno = r;
951   return -3;
952 }
953 #endif
954 \f
955 #ifdef TEST
956
957 long int
958 describe_member (int desc, const char *name, int truncated,
959                  long int hdrpos, long int datapos, long int size,
960                  long int date, int uid, int gid, unsigned int mode,
961                  const void *arg)
962 {
963   extern char *ctime ();
964
965   printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"),
966           name, truncated ? _(" (name might be truncated)") : "",
967           size, hdrpos, datapos);
968   printf (_("  Date %s"), ctime (&date));
969   printf (_("  uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
970
971   return 0;
972 }
973
974 int
975 main (int argc, char **argv)
976 {
977   ar_scan (argv[1], describe_member, NULL);
978   return 0;
979 }
980
981 #endif  /* TEST.  */
982 #endif  /* NO_ARCHIVES.  */