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