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