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