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