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