1 /* Library function for scanning an archive file.
2 Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
3 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
4 2010 Free Software Foundation, Inc.
5 This file is part of GNU Make.
6
7 GNU Make is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 3 of the License, or (at your option) any later
10 version.
11
12 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along with
17 this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 #include "make.h"
20
21 #ifdef HAVE_FCNTL_H
22 #include <fcntl.h>
23 #else
24 #include <sys/file.h>
25 #endif
26
27 #ifndef NO_ARCHIVES
28
29 #ifdef VMS
30 #include <lbrdef.h>
31 #include <mhddef.h>
32 #include <credef.h>
33 #include <descrip.h>
34 #include <ctype.h>
35 #if __DECC
36 #include <unixlib.h>
37 #include <lbr$routines.h>
38 #endif
39
40 static void *VMS_lib_idx;
41
42 static char *VMS_saved_memname;
43
44 static time_t VMS_member_date;
45
46 static long int (*VMS_function) ();
47
48 static int
VMS_get_member_info(struct dsc$descriptor_s * module,unsigned long * rfa)49 VMS_get_member_info (struct dsc$descriptor_s *module, unsigned long *rfa)
50 {
51 int status, i;
52 long int fnval;
53
54 time_t val;
55
56 static struct dsc$descriptor_s bufdesc =
57 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
58
59 struct mhddef *mhd;
60 char filename[128];
61
62 bufdesc.dsc$a_pointer = filename;
63 bufdesc.dsc$w_length = sizeof (filename);
64
65 status = lbr$set_module (&VMS_lib_idx, rfa, &bufdesc,
66 &bufdesc.dsc$w_length, 0);
67 if (! (status & 1))
68 {
69 error (NILF, _("lbr$set_module() failed to extract module info, status = %d"),
70 status);
71
72 lbr$close (&VMS_lib_idx);
73
74 return 0;
75 }
76
77 mhd = (struct mhddef *) filename;
78
79 #ifdef __DECC
80 /* John Fowler <jfowler@nyx.net> writes this is needed in his environment,
81 * but that decc$fix_time() isn't documented to work this way. Let me
82 * know if this causes problems in other VMS environments.
83 */
84 {
85 /* Modified by M. Gehre at 11-JAN-2008 because old formula is wrong:
86 * val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600;
87 * a) daylight specifies, if the timezone has daylight saving enabled, not
88 * if it is active
89 * b) what we need is the information, if daylight saving was active, if
90 * the library module was replaced. This information we get using the
91 * localtime function
92 */
93
94 struct tm *tmp;
95
96 /* Conversion from VMS time to C time */
97 val = decc$fix_time (&mhd->mhd$l_datim);
98
99 /*
100 * Conversion from local time (stored in library) to GMT (needed for gmake)
101 * Note: The tm_gmtoff element is a VMS extension to the ANSI standard.
102 */
103 tmp = localtime (&val);
104 val -= tmp->tm_gmtoff;
105 }
106 #endif
107
108 for (i = 0; i < module->dsc$w_length; i++)
109 filename[i] = _tolower ((unsigned char)module->dsc$a_pointer[i]);
110
111 filename[i] = '\0';
112
113 VMS_member_date = (time_t) -1;
114
115 fnval =
116 (*VMS_function) (-1, filename, 0, 0, 0, 0, val, 0, 0, 0,
117 VMS_saved_memname);
118
119 if (fnval)
120 {
121 VMS_member_date = fnval;
122 return 0;
123 }
124 else
125 return 1;
126 }
127
128 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
129
130 Open the archive named ARCHIVE, find its members one by one,
131 and for each one call FUNCTION with the following arguments:
132 archive file descriptor for reading the data,
133 member name,
134 member name might be truncated flag,
135 member header position in file,
136 member data position in file,
137 member data size,
138 member date,
139 member uid,
140 member gid,
141 member protection mode,
142 ARG.
143
144 NOTE: on VMS systems, only name, date, and arg are meaningful!
145
146 The descriptor is poised to read the data of the member
147 when FUNCTION is called. It does not matter how much
148 data FUNCTION reads.
149
150 If FUNCTION returns nonzero, we immediately return
151 what FUNCTION returned.
152
153 Returns -1 if archive does not exist,
154 Returns -2 if archive has invalid format.
155 Returns 0 if have scanned successfully. */
156
157 long int
ar_scan(const char * archive,ar_member_func_t function,const void * arg)158 ar_scan (const char *archive, ar_member_func_t function, const void *arg)
159 {
160 char *p;
161
162 static struct dsc$descriptor_s libdesc =
163 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
164
165 unsigned long func = LBR$C_READ;
166 unsigned long type = LBR$C_TYP_UNK;
167 unsigned long index = 1;
168
169 int status;
170
171 status = lbr$ini_control (&VMS_lib_idx, &func, &type, 0);
172
173 if (! (status & 1))
174 {
175 error (NILF, _("lbr$ini_control() failed with status = %d"), status);
176 return -2;
177 }
178
179 /* there is no such descriptor with "const char *dsc$a_pointer" */
180 libdesc.dsc$a_pointer = (char *)archive;
181 libdesc.dsc$w_length = strlen (archive);
182
183 status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0);
184
185 if (! (status & 1))
186 {
187 error (NILF, _("unable to open library `%s' to lookup member `%s'"),
188 archive, (char *)arg);
189 return -1;
190 }
191
192 VMS_saved_memname = (char *)arg;
193
194 /* For comparison, delete .obj from arg name. */
195
196 p = strrchr (VMS_saved_memname, '.');
197 if (p)
198 *p = '\0';
199
200 VMS_function = function;
201
202 VMS_member_date = (time_t) -1;
203 lbr$get_index (&VMS_lib_idx, &index, VMS_get_member_info, 0);
204
205 /* Undo the damage. */
206 if (p)
207 *p = '.';
208
209 lbr$close (&VMS_lib_idx);
210
211 return VMS_member_date > 0 ? VMS_member_date : 0;
212 }
213
214 #else /* !VMS */
215
216 /* SCO Unix's compiler defines both of these. */
217 #ifdef M_UNIX
218 #undef M_XENIX
219 #endif
220
221 /* On the sun386i and in System V rel 3, ar.h defines two different archive
222 formats depending upon whether you have defined PORTAR (normal) or PORT5AR
223 (System V Release 1). There is no default, one or the other must be defined
224 to have a nonzero value. */
225
226 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
227 #undef PORTAR
228 #ifdef M_XENIX
229 /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
230 PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
231 right one. */
232 #define PORTAR 0
233 #else
234 #define PORTAR 1
235 #endif
236 #endif
237
238 /* On AIX, define these symbols to be sure to get both archive formats.
239 AIX 4.3 introduced the "big" archive format to support 64-bit object
240 files, so on AIX 4.3 systems we need to support both the "normal" and
241 "big" archive formats. An archive's format is indicated in the
242 "fl_magic" field of the "FL_HDR" structure. For a normal archive,
243 this field will be the string defined by the AIAMAG symbol. For a
244 "big" archive, it will be the string defined by the AIAMAGBIG symbol
245 (at least on AIX it works this way).
246
247 Note: we'll define these symbols regardless of which AIX version
248 we're compiling on, but this is okay since we'll use the new symbols
249 only if they're present. */
250 #ifdef _AIX
251 # define __AR_SMALL__
252 # define __AR_BIG__
253 #endif
254
255 #ifndef WINDOWS32
256 # if !defined(__BEOS__) && !defined(__HAIKU__)
257 # include <ar.h>
258 # else
259 /* BeOS 5 doesn't have <ar.h> but has archives in the same format
260 * as many other Unices. This was taken from GNU binutils for BeOS.
261 */
262 # define ARMAG "!<arch>\n" /* String that begins an archive file. */
263 # define SARMAG 8 /* Size of that string. */
264 # define ARFMAG "`\n" /* String in ar_fmag at end of each header. */
265 struct ar_hdr
266 {
267 char ar_name[16]; /* Member file name, sometimes / terminated. */
268 char ar_date[12]; /* File date, decimal seconds since Epoch. */
269 char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */
270 char ar_mode[8]; /* File mode, in ASCII octal. */
271 char ar_size[10]; /* File size, in ASCII decimal. */
272 char ar_fmag[2]; /* Always contains ARFMAG. */
273 };
274 # endif
275 # define TOCHAR(_m) (_m)
276 #else
277 /* These should allow us to read Windows (VC++) libraries (according to Frank
278 * Libbrecht <frankl@abzx.belgium.hp.com>)
279 */
280 # include <windows.h>
281 # include <windef.h>
282 # include <io.h>
283 # define ARMAG IMAGE_ARCHIVE_START
284 # define SARMAG IMAGE_ARCHIVE_START_SIZE
285 # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER
286 # define ar_name Name
287 # define ar_mode Mode
288 # define ar_size Size
289 # define ar_date Date
290 # define ar_uid UserID
291 # define ar_gid GroupID
292 /* In Windows the member names have type BYTE so we must cast them. */
293 # define TOCHAR(_m) ((char *)(_m))
294 #endif
295
296 /* Cray's <ar.h> apparently defines this. */
297 #ifndef AR_HDR_SIZE
298 # define AR_HDR_SIZE (sizeof (struct ar_hdr))
299 #endif
300
301 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
302
303 Open the archive named ARCHIVE, find its members one by one,
304 and for each one call FUNCTION with the following arguments:
305 archive file descriptor for reading the data,
306 member name,
307 member name might be truncated flag,
308 member header position in file,
309 member data position in file,
310 member data size,
311 member date,
312 member uid,
313 member gid,
314 member protection mode,
315 ARG.
316
317 The descriptor is poised to read the data of the member
318 when FUNCTION is called. It does not matter how much
319 data FUNCTION reads.
320
321 If FUNCTION returns nonzero, we immediately return
322 what FUNCTION returned.
323
324 Returns -1 if archive does not exist,
325 Returns -2 if archive has invalid format.
326 Returns 0 if have scanned successfully. */
327
328 long int
ar_scan(const char * archive,ar_member_func_t function,const void * arg)329 ar_scan (const char *archive, ar_member_func_t function, const void *arg)
330 {
331 #ifdef AIAMAG
332 FL_HDR fl_header;
333 #ifdef AIAMAGBIG
334 int big_archive = 0;
335 FL_HDR_BIG fl_header_big;
336 #endif
337 #else
338 int long_name = 0;
339 #endif
340 char *namemap = 0;
341 int desc = open (archive, O_RDONLY, 0);
342 if (desc < 0)
343 return -1;
344 #ifdef SARMAG
345 {
346 char buf[SARMAG];
347 register int nread = read (desc, buf, SARMAG);
348 if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG))
349 {
350 (void) close (desc);
351 return -2;
352 }
353 }
354 #else
355 #ifdef AIAMAG
356 {
357 register int nread = read (desc, &fl_header, FL_HSZ);
358
359 if (nread != FL_HSZ)
360 {
361 (void) close (desc);
362 return -2;
363 }
364 #ifdef AIAMAGBIG
365 /* If this is a "big" archive, then set the flag and
366 re-read the header into the "big" structure. */
367 if (!memcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
368 {
369 big_archive = 1;
370
371 /* seek back to beginning of archive */
372 if (lseek (desc, 0, 0) < 0)
373 {
374 (void) close (desc);
375 return -2;
376 }
377
378 /* re-read the header into the "big" structure */
379 nread = read (desc, &fl_header_big, FL_HSZ_BIG);
380 if (nread != FL_HSZ_BIG)
381 {
382 (void) close (desc);
383 return -2;
384 }
385 }
386 else
387 #endif
388 /* Check to make sure this is a "normal" archive. */
389 if (memcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
390 {
391 (void) close (desc);
392 return -2;
393 }
394 }
395 #else
396 {
397 #ifndef M_XENIX
398 int buf;
399 #else
400 unsigned short int buf;
401 #endif
402 register int nread = read(desc, &buf, sizeof (buf));
403 if (nread != sizeof (buf) || buf != ARMAG)
404 {
405 (void) close (desc);
406 return -2;
407 }
408 }
409 #endif
410 #endif
411
412 /* Now find the members one by one. */
413 {
414 #ifdef SARMAG
415 register long int member_offset = SARMAG;
416 #else
417 #ifdef AIAMAG
418 long int member_offset;
419 long int last_member_offset;
420
421 #ifdef AIAMAGBIG
422 if ( big_archive )
423 {
424 sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
425 sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
426 }
427 else
428 #endif
429 {
430 sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
431 sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
432 }
433
434 if (member_offset == 0)
435 {
436 /* Empty archive. */
437 close (desc);
438 return 0;
439 }
440 #else
441 #ifndef M_XENIX
442 register long int member_offset = sizeof (int);
443 #else /* Xenix. */
444 register long int member_offset = sizeof (unsigned short int);
445 #endif /* Not Xenix. */
446 #endif
447 #endif
448
449 while (1)
450 {
451 register int nread;
452 struct ar_hdr member_header;
453 #ifdef AIAMAGBIG
454 struct ar_hdr_big member_header_big;
455 #endif
456 #ifdef AIAMAG
457 char name[256];
458 int name_len;
459 long int dateval;
460 int uidval, gidval;
461 long int data_offset;
462 #else
463 char namebuf[sizeof member_header.ar_name + 1];
464 char *name;
465 int is_namemap; /* Nonzero if this entry maps long names. */
466 #endif
467 long int eltsize;
468 int eltmode;
469 long int fnval;
470
471 if (lseek (desc, member_offset, 0) < 0)
472 {
473 (void) close (desc);
474 return -2;
475 }
476
477 #ifdef AIAMAG
478 #define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
479
480 #ifdef AIAMAGBIG
481 if (big_archive)
482 {
483 nread = read (desc, &member_header_big,
484 AR_MEMHDR_SZ(member_header_big) );
485
486 if (nread != AR_MEMHDR_SZ(member_header_big))
487 {
488 (void) close (desc);
489 return -2;
490 }
491
492 sscanf (member_header_big.ar_namlen, "%4d", &name_len);
493 nread = read (desc, name, name_len);
494
495 if (nread != name_len)
496 {
497 (void) close (desc);
498 return -2;
499 }
500
501 name[name_len] = 0;
502
503 sscanf (member_header_big.ar_date, "%12ld", &dateval);
504 sscanf (member_header_big.ar_uid, "%12d", &uidval);
505 sscanf (member_header_big.ar_gid, "%12d", &gidval);
506 sscanf (member_header_big.ar_mode, "%12o", &eltmode);
507 sscanf (member_header_big.ar_size, "%20ld", &eltsize);
508
509 data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
510 + name_len + 2);
511 }
512 else
513 #endif
514 {
515 nread = read (desc, &member_header,
516 AR_MEMHDR_SZ(member_header) );
517
518 if (nread != AR_MEMHDR_SZ(member_header))
519 {
520 (void) close (desc);
521 return -2;
522 }
523
524 sscanf (member_header.ar_namlen, "%4d", &name_len);
525 nread = read (desc, name, name_len);
526
527 if (nread != name_len)
528 {
529 (void) close (desc);
530 return -2;
531 }
532
533 name[name_len] = 0;
534
535 sscanf (member_header.ar_date, "%12ld", &dateval);
536 sscanf (member_header.ar_uid, "%12d", &uidval);
537 sscanf (member_header.ar_gid, "%12d", &gidval);
538 sscanf (member_header.ar_mode, "%12o", &eltmode);
539 sscanf (member_header.ar_size, "%12ld", &eltsize);
540
541 data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
542 + name_len + 2);
543 }
544 data_offset += data_offset % 2;
545
546 fnval =
547 (*function) (desc, name, 0,
548 member_offset, data_offset, eltsize,
549 dateval, uidval, gidval,
550 eltmode, arg);
551
552 #else /* Not AIAMAG. */
553 nread = read (desc, &member_header, AR_HDR_SIZE);
554 if (nread == 0)
555 /* No data left means end of file; that is OK. */
556 break;
557
558 if (nread != AR_HDR_SIZE
559 #if defined(ARFMAG) || defined(ARFZMAG)
560 || (
561 # ifdef ARFMAG
562 memcmp (member_header.ar_fmag, ARFMAG, 2)
563 # else
564 1
565 # endif
566 &&
567 # ifdef ARFZMAG
568 memcmp (member_header.ar_fmag, ARFZMAG, 2)
569 # else
570 1
571 # endif
572 )
573 #endif
574 )
575 {
576 (void) close (desc);
577 return -2;
578 }
579
580 name = namebuf;
581 memcpy (name, member_header.ar_name, sizeof member_header.ar_name);
582 {
583 register char *p = name + sizeof member_header.ar_name;
584 do
585 *p = '\0';
586 while (p > name && *--p == ' ');
587
588 #ifndef AIAMAG
589 /* If the member name is "//" or "ARFILENAMES/" this may be
590 a list of file name mappings. The maximum file name
591 length supported by the standard archive format is 14
592 characters. This member will actually always be the
593 first or second entry in the archive, but we don't check
594 that. */
595 is_namemap = (!strcmp (name, "//")
596 || !strcmp (name, "ARFILENAMES/"));
597 #endif /* Not AIAMAG. */
598 /* On some systems, there is a slash after each member name. */
599 if (*p == '/')
600 *p = '\0';
601
602 #ifndef AIAMAG
603 /* If the member name starts with a space or a slash, this
604 is an index into the file name mappings (used by GNU ar).
605 Otherwise if the member name looks like #1/NUMBER the
606 real member name appears in the element data (used by
607 4.4BSD). */
608 if (! is_namemap
609 && (name[0] == ' ' || name[0] == '/')
610 && namemap != 0)
611 {
612 name = namemap + atoi (name + 1);
613 long_name = 1;
614 }
615 else if (name[0] == '#'
616 && name[1] == '1'
617 && name[2] == '/')
618 {
619 int namesize = atoi (name + 3);
620
621 name = alloca (namesize + 1);
622 nread = read (desc, name, namesize);
623 if (nread != namesize)
624 {
625 close (desc);
626 return -2;
627 }
628 name[namesize] = '\0';
629
630 long_name = 1;
631 }
632 #endif /* Not AIAMAG. */
633 }
634
635 #ifndef M_XENIX
636 sscanf (TOCHAR (member_header.ar_mode), "%o", &eltmode);
637 eltsize = atol (TOCHAR (member_header.ar_size));
638 #else /* Xenix. */
639 eltmode = (unsigned short int) member_header.ar_mode;
640 eltsize = member_header.ar_size;
641 #endif /* Not Xenix. */
642
643 fnval =
644 (*function) (desc, name, ! long_name, member_offset,
645 member_offset + AR_HDR_SIZE, eltsize,
646 #ifndef M_XENIX
647 atol (TOCHAR (member_header.ar_date)),
648 atoi (TOCHAR (member_header.ar_uid)),
649 atoi (TOCHAR (member_header.ar_gid)),
650 #else /* Xenix. */
651 member_header.ar_date,
652 member_header.ar_uid,
653 member_header.ar_gid,
654 #endif /* Not Xenix. */
655 eltmode, arg);
656
657 #endif /* AIAMAG. */
658
659 if (fnval)
660 {
661 (void) close (desc);
662 return fnval;
663 }
664
665 #ifdef AIAMAG
666 if (member_offset == last_member_offset)
667 /* End of the chain. */
668 break;
669
670 #ifdef AIAMAGBIG
671 if (big_archive)
672 sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
673 else
674 #endif
675 sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
676
677 if (lseek (desc, member_offset, 0) != member_offset)
678 {
679 (void) close (desc);
680 return -2;
681 }
682 #else
683
684 /* If this member maps archive names, we must read it in. The
685 name map will always precede any members whose names must
686 be mapped. */
687 if (is_namemap)
688 {
689 char *clear;
690 char *limit;
691
692 namemap = alloca (eltsize);
693 nread = read (desc, namemap, eltsize);
694 if (nread != eltsize)
695 {
696 (void) close (desc);
697 return -2;
698 }
699
700 /* The names are separated by newlines. Some formats have
701 a trailing slash. Null terminate the strings for
702 convenience. */
703 limit = namemap + eltsize;
704 for (clear = namemap; clear < limit; clear++)
705 {
706 if (*clear == '\n')
707 {
708 *clear = '\0';
709 if (clear[-1] == '/')
710 clear[-1] = '\0';
711 }
712 }
713
714 is_namemap = 0;
715 }
716
717 member_offset += AR_HDR_SIZE + eltsize;
718 if (member_offset % 2 != 0)
719 member_offset++;
720 #endif
721 }
722 }
723
724 close (desc);
725 return 0;
726 }
727 #endif /* !VMS */
728
729 /* Return nonzero iff NAME matches MEM.
730 If TRUNCATED is nonzero, MEM may be truncated to
731 sizeof (struct ar_hdr.ar_name) - 1. */
732
733 int
ar_name_equal(const char * name,const char * mem,int truncated)734 ar_name_equal (const char *name, const char *mem, int truncated)
735 {
736 const char *p;
737
738 p = strrchr (name, '/');
739 if (p != 0)
740 name = p + 1;
741
742 #ifndef VMS
743 if (truncated)
744 {
745 #ifdef AIAMAG
746 /* TRUNCATED should never be set on this system. */
747 abort ();
748 #else
749 struct ar_hdr hdr;
750 #if !defined (__hpux) && !defined (cray)
751 return strneq (name, mem, sizeof(hdr.ar_name) - 1);
752 #else
753 return strneq (name, mem, sizeof(hdr.ar_name) - 2);
754 #endif /* !__hpux && !cray */
755 #endif /* !AIAMAG */
756 }
757 #endif /* !VMS */
758
759 return !strcmp (name, mem);
760 }
761
762 #ifndef VMS
763 /* ARGSUSED */
764 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,int mode UNUSED,const void * name)765 ar_member_pos (int desc UNUSED, const char *mem, int truncated,
766 long int hdrpos, long int datapos UNUSED, long int size UNUSED,
767 long int date UNUSED, int uid UNUSED, int gid UNUSED,
768 int mode UNUSED, const void *name)
769 {
770 if (!ar_name_equal (name, mem, truncated))
771 return 0;
772 return hdrpos;
773 }
774
775 /* Set date of member MEMNAME in archive ARNAME to current time.
776 Returns 0 if successful,
777 -1 if file ARNAME does not exist,
778 -2 if not a valid archive,
779 -3 if other random system call error (including file read-only),
780 1 if valid but member MEMNAME does not exist. */
781
782 int
ar_member_touch(const char * arname,const char * memname)783 ar_member_touch (const char *arname, const char *memname)
784 {
785 long int pos = ar_scan (arname, ar_member_pos, memname);
786 int fd;
787 struct ar_hdr ar_hdr;
788 int i;
789 unsigned int ui;
790 struct stat statbuf;
791
792 if (pos < 0)
793 return (int) pos;
794 if (!pos)
795 return 1;
796
797 fd = open (arname, O_RDWR, 0666);
798 if (fd < 0)
799 return -3;
800 /* Read in this member's header */
801 if (lseek (fd, pos, 0) < 0)
802 goto lose;
803 if (AR_HDR_SIZE != read (fd, &ar_hdr, AR_HDR_SIZE))
804 goto lose;
805 /* Write back the header, thus touching the archive file. */
806 if (lseek (fd, pos, 0) < 0)
807 goto lose;
808 if (AR_HDR_SIZE != write (fd, &ar_hdr, AR_HDR_SIZE))
809 goto lose;
810 /* The file's mtime is the time we we want. */
811 EINTRLOOP (i, fstat (fd, &statbuf));
812 if (i < 0)
813 goto lose;
814 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
815 /* Advance member's time to that time */
816 for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++)
817 ar_hdr.ar_date[ui] = ' ';
818 sprintf (TOCHAR (ar_hdr.ar_date), "%ld", (long int) statbuf.st_mtime);
819 #ifdef AIAMAG
820 ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
821 #endif
822 #else
823 ar_hdr.ar_date = statbuf.st_mtime;
824 #endif
825 /* Write back this member's header */
826 if (lseek (fd, pos, 0) < 0)
827 goto lose;
828 if (AR_HDR_SIZE != write (fd, &ar_hdr, AR_HDR_SIZE))
829 goto lose;
830 close (fd);
831 return 0;
832
833 lose:
834 i = errno;
835 close (fd);
836 errno = i;
837 return -3;
838 }
839 #endif
840
841 #ifdef TEST
842
843 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,int mode,const void * arg)844 describe_member (int desc, const char *name, int truncated,
845 long int hdrpos, long int datapos, long int size,
846 long int date, int uid, int gid, int mode, const void *arg)
847 {
848 extern char *ctime ();
849
850 printf (_("Member `%s'%s: %ld bytes at %ld (%ld).\n"),
851 name, truncated ? _(" (name might be truncated)") : "",
852 size, hdrpos, datapos);
853 printf (_(" Date %s"), ctime (&date));
854 printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
855
856 return 0;
857 }
858
859 int
main(int argc,char ** argv)860 main (int argc, char **argv)
861 {
862 ar_scan (argv[1], describe_member, NULL);
863 return 0;
864 }
865
866 #endif /* TEST. */
867 #endif /* NO_ARCHIVES. */
868