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