ar.c revision 38889
133965Sjdp/* ar.c - Archive modify and extract. 238889Sjdp Copyright 1991, 92, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. 333965Sjdp 433965SjdpThis file is part of GNU Binutils. 533965Sjdp 633965SjdpThis program is free software; you can redistribute it and/or modify 733965Sjdpit under the terms of the GNU General Public License as published by 833965Sjdpthe Free Software Foundation; either version 2 of the License, or 933965Sjdp(at your option) any later version. 1033965Sjdp 1133965SjdpThis program is distributed in the hope that it will be useful, 1233965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1333965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1433965SjdpGNU General Public License for more details. 1533965Sjdp 1633965SjdpYou should have received a copy of the GNU General Public License 1733965Sjdpalong with this program; if not, write to the Free Software 1833965SjdpFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 1933965Sjdp 2033965Sjdp/* 2133965Sjdp Bugs: should use getopt the way tar does (complete w/optional -) and 2233965Sjdp should have long options too. GNU ar used to check file against filesystem 2333965Sjdp in quick_update and replace operations (would check mtime). Doesn't warn 2433965Sjdp when name truncated. No way to specify pos_end. Error messages should be 2533965Sjdp more consistant. 2633965Sjdp*/ 2733965Sjdp#include "bfd.h" 2833965Sjdp#include "libiberty.h" 2933965Sjdp#include "progress.h" 3033965Sjdp#include "bucomm.h" 3133965Sjdp#include "aout/ar.h" 3233965Sjdp#include "libbfd.h" 3333965Sjdp#include "arsup.h" 3433965Sjdp#include <sys/stat.h> 3533965Sjdp 3633965Sjdp#ifdef HAVE_GOOD_UTIME_H 3733965Sjdp#include <utime.h> 3833965Sjdp#else /* ! HAVE_GOOD_UTIME_H */ 3933965Sjdp#ifdef HAVE_UTIMES 4033965Sjdp#include <sys/time.h> 4133965Sjdp#endif /* HAVE_UTIMES */ 4233965Sjdp#endif /* ! HAVE_GOOD_UTIME_H */ 4333965Sjdp 4433965Sjdp#ifdef __GO32___ 4533965Sjdp#define EXT_NAME_LEN 3 /* bufflen of addition to name if it's MS-DOS */ 4633965Sjdp#else 4733965Sjdp#define EXT_NAME_LEN 6 /* ditto for *NIX */ 4833965Sjdp#endif 4933965Sjdp 5033965Sjdp#define BUFSIZE 8192 5133965Sjdp 5233965Sjdp/* Kludge declaration from BFD! This is ugly! FIXME! XXX */ 5333965Sjdp 5433965Sjdpstruct ar_hdr * 5538889Sjdp bfd_special_undocumented_glue PARAMS ((bfd * abfd, const char *filename)); 5633965Sjdp 5733965Sjdp/* Static declarations */ 5833965Sjdp 5933965Sjdpstatic void 6033965Sjdpmri_emul PARAMS ((void)); 6133965Sjdp 6233965Sjdpstatic const char * 6333965Sjdpnormalize PARAMS ((const char *, bfd *)); 6433965Sjdp 6533965Sjdpstatic void 6633965Sjdpremove_output PARAMS ((void)); 6733965Sjdp 6833965Sjdpstatic void 6933965Sjdpmap_over_members PARAMS ((bfd *, void (*)(bfd *), char **, int)); 7033965Sjdp 7133965Sjdpstatic void 7233965Sjdpprint_contents PARAMS ((bfd * member)); 7333965Sjdp 7433965Sjdpstatic void 7533965Sjdpdelete_members PARAMS ((bfd *, char **files_to_delete)); 7633965Sjdp 7733965Sjdp#if 0 7833965Sjdpstatic void 7933965Sjdpdo_quick_append PARAMS ((const char *archive_filename, 8033965Sjdp char **files_to_append)); 8133965Sjdp#endif 8233965Sjdp 8333965Sjdpstatic void 8433965Sjdpmove_members PARAMS ((bfd *, char **files_to_move)); 8533965Sjdp 8633965Sjdpstatic void 8733965Sjdpreplace_members PARAMS ((bfd *, char **files_to_replace, boolean quick)); 8833965Sjdp 8933965Sjdpstatic void 9033965Sjdpprint_descr PARAMS ((bfd * abfd)); 9133965Sjdp 9233965Sjdpstatic void 9333965Sjdpwrite_archive PARAMS ((bfd *)); 9433965Sjdp 9533965Sjdpstatic void 9633965Sjdpranlib_only PARAMS ((const char *archname)); 9733965Sjdp 9833965Sjdpstatic void 9933965Sjdpranlib_touch PARAMS ((const char *archname)); 10033965Sjdp 10133965Sjdpstatic void 10233965Sjdpusage PARAMS ((int)); 10333965Sjdp 10433965Sjdp/** Globals and flags */ 10533965Sjdp 10633965Sjdpint mri_mode; 10733965Sjdp 10833965Sjdp/* This flag distinguishes between ar and ranlib: 10933965Sjdp 1 means this is 'ranlib'; 0 means this is 'ar'. 11033965Sjdp -1 means if we should use argv[0] to decide. */ 11133965Sjdpextern int is_ranlib; 11233965Sjdp 11333965Sjdp/* Nonzero means don't warn about creating the archive file if necessary. */ 11433965Sjdpint silent_create = 0; 11533965Sjdp 11633965Sjdp/* Nonzero means describe each action performed. */ 11733965Sjdpint verbose = 0; 11833965Sjdp 11933965Sjdp/* Nonzero means preserve dates of members when extracting them. */ 12033965Sjdpint preserve_dates = 0; 12133965Sjdp 12233965Sjdp/* Nonzero means don't replace existing members whose dates are more recent 12333965Sjdp than the corresponding files. */ 12433965Sjdpint newer_only = 0; 12533965Sjdp 12633965Sjdp/* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF 12733965Sjdp member). -1 means we've been explicitly asked to not write a symbol table; 12833965Sjdp +1 means we've been explictly asked to write it; 12933965Sjdp 0 is the default. 13033965Sjdp Traditionally, the default in BSD has been to not write the table. 13133965Sjdp However, for POSIX.2 compliance the default is now to write a symbol table 13233965Sjdp if any of the members are object files. */ 13333965Sjdpint write_armap = 0; 13433965Sjdp 13533965Sjdp/* Nonzero means it's the name of an existing member; position new or moved 13633965Sjdp files with respect to this one. */ 13733965Sjdpchar *posname = NULL; 13833965Sjdp 13933965Sjdp/* Sez how to use `posname': pos_before means position before that member. 14033965Sjdp pos_after means position after that member. pos_end means always at end. 14133965Sjdp pos_default means default appropriately. For the latter two, `posname' 14233965Sjdp should also be zero. */ 14333965Sjdpenum pos 14433965Sjdp { 14533965Sjdp pos_default, pos_before, pos_after, pos_end 14633965Sjdp } postype = pos_default; 14733965Sjdp 14833965Sjdpstatic bfd ** 14938889Sjdpget_pos_bfd PARAMS ((bfd **, enum pos, const char *)); 15033965Sjdp 15133965Sjdp/* Whether to truncate names of files stored in the archive. */ 15233965Sjdpstatic boolean ar_truncate = false; 15333965Sjdp 15433965Sjdpint interactive = 0; 15533965Sjdp 15633965Sjdpstatic void 15733965Sjdpmri_emul () 15833965Sjdp{ 15933965Sjdp interactive = isatty (fileno (stdin)); 16033965Sjdp yyparse (); 16133965Sjdp} 16233965Sjdp 16333965Sjdp/* If COUNT is 0, then FUNCTION is called once on each entry. If nonzero, 16433965Sjdp COUNT is the length of the FILES chain; FUNCTION is called on each entry 16533965Sjdp whose name matches one in FILES. */ 16633965Sjdp 16733965Sjdpstatic void 16833965Sjdpmap_over_members (arch, function, files, count) 16933965Sjdp bfd *arch; 17033965Sjdp void (*function) PARAMS ((bfd *)); 17133965Sjdp char **files; 17233965Sjdp int count; 17333965Sjdp{ 17433965Sjdp bfd *head; 17533965Sjdp 17633965Sjdp if (count == 0) 17733965Sjdp { 17833965Sjdp for (head = arch->next; head; head = head->next) 17933965Sjdp { 18033965Sjdp PROGRESS (1); 18133965Sjdp function (head); 18233965Sjdp } 18333965Sjdp return; 18433965Sjdp } 18533965Sjdp /* This may appear to be a baroque way of accomplishing what we want. 18633965Sjdp However we have to iterate over the filenames in order to notice where 18733965Sjdp a filename is requested but does not exist in the archive. Ditto 18833965Sjdp mapping over each file each time -- we want to hack multiple 18933965Sjdp references. */ 19033965Sjdp 19133965Sjdp for (; count > 0; files++, count--) 19233965Sjdp { 19333965Sjdp boolean found = false; 19433965Sjdp 19533965Sjdp for (head = arch->next; head; head = head->next) 19633965Sjdp { 19733965Sjdp PROGRESS (1); 19833965Sjdp if (head->filename == NULL) 19933965Sjdp { 20033965Sjdp /* Some archive formats don't get the filenames filled in 20133965Sjdp until the elements are opened. */ 20233965Sjdp struct stat buf; 20333965Sjdp bfd_stat_arch_elt (head, &buf); 20433965Sjdp } 20533965Sjdp if ((head->filename != NULL) && 20633965Sjdp (!strcmp (*files, head->filename))) 20733965Sjdp { 20833965Sjdp found = true; 20933965Sjdp function (head); 21033965Sjdp } 21133965Sjdp } 21233965Sjdp if (!found) 21333965Sjdp fprintf (stderr, "no entry %s in archive\n", *files); 21433965Sjdp } 21533965Sjdp} 21633965Sjdp 21733965Sjdpboolean operation_alters_arch = false; 21833965Sjdp 21933965Sjdpstatic void 22033965Sjdpusage (help) 22133965Sjdp int help; 22233965Sjdp{ 22333965Sjdp FILE *s; 22433965Sjdp 22533965Sjdp s = help ? stdout : stderr; 22633965Sjdp if (! is_ranlib) 22733965Sjdp fprintf (s, "\ 22838889SjdpUsage: %s [-]{dmpqrtx}[abcilosSuvV] [member-name] archive-file file...\n\ 22933965Sjdp %s -M [<mri-script]\n", 23033965Sjdp program_name, program_name); 23133965Sjdp else 23233965Sjdp fprintf (s, "\ 23333965SjdpUsage: %s [-vV] archive\n", program_name); 23433965Sjdp 23533965Sjdp list_supported_targets (program_name, stderr); 23633965Sjdp 23733965Sjdp if (help) 23838889Sjdp fprintf (s, "Report bugs to bug-gnu-utils@gnu.org\n"); 23933965Sjdp 24033965Sjdp xexit (help ? 0 : 1); 24133965Sjdp} 24233965Sjdp 24333965Sjdp/* Normalize a file name specified on the command line into a file 24433965Sjdp name which we will use in an archive. */ 24533965Sjdp 24633965Sjdpstatic const char * 24733965Sjdpnormalize (file, abfd) 24833965Sjdp const char *file; 24933965Sjdp bfd *abfd; 25033965Sjdp{ 25133965Sjdp const char *filename; 25233965Sjdp 25333965Sjdp filename = strrchr (file, '/'); 25433965Sjdp if (filename != (char *) NULL) 25533965Sjdp filename++; 25633965Sjdp else 25733965Sjdp filename = file; 25833965Sjdp 25933965Sjdp if (ar_truncate 26033965Sjdp && abfd != NULL 26133965Sjdp && strlen (filename) > abfd->xvec->ar_max_namelen) 26233965Sjdp { 26333965Sjdp char *s; 26433965Sjdp 26533965Sjdp /* Space leak. */ 26633965Sjdp s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1); 26733965Sjdp memcpy (s, filename, abfd->xvec->ar_max_namelen); 26833965Sjdp s[abfd->xvec->ar_max_namelen] = '\0'; 26933965Sjdp filename = s; 27033965Sjdp } 27133965Sjdp 27233965Sjdp return filename; 27333965Sjdp} 27433965Sjdp 27533965Sjdp/* Remove any output file. This is only called via xatexit. */ 27633965Sjdp 27733965Sjdpstatic char *output_filename = NULL; 27833965Sjdpstatic FILE *output_file = NULL; 27933965Sjdpstatic bfd *output_bfd = NULL; 28033965Sjdp 28133965Sjdpstatic void 28233965Sjdpremove_output () 28333965Sjdp{ 28433965Sjdp if (output_filename != NULL) 28533965Sjdp { 28633965Sjdp if (output_bfd != NULL && output_bfd->iostream != NULL) 28733965Sjdp fclose ((FILE *) (output_bfd->iostream)); 28833965Sjdp if (output_file != NULL) 28933965Sjdp fclose (output_file); 29033965Sjdp unlink (output_filename); 29133965Sjdp } 29233965Sjdp} 29333965Sjdp 29433965Sjdp/* The option parsing should be in its own function. 29533965Sjdp It will be when I have getopt working. */ 29633965Sjdp 29733965Sjdpint 29833965Sjdpmain (argc, argv) 29933965Sjdp int argc; 30033965Sjdp char **argv; 30133965Sjdp{ 30233965Sjdp char *arg_ptr; 30333965Sjdp char c; 30433965Sjdp enum 30533965Sjdp { 30633965Sjdp none = 0, delete, replace, print_table, 30733965Sjdp print_files, extract, move, quick_append 30833965Sjdp } operation = none; 30933965Sjdp int arg_index; 31033965Sjdp char **files; 31133965Sjdp char *inarch_filename; 31233965Sjdp int show_version; 31333965Sjdp 31433965Sjdp program_name = argv[0]; 31533965Sjdp xmalloc_set_program_name (program_name); 31633965Sjdp 31733965Sjdp if (is_ranlib < 0) 31833965Sjdp { 31933965Sjdp char *temp; 32033965Sjdp 32133965Sjdp temp = strrchr (program_name, '/'); 32233965Sjdp if (temp == NULL) 32333965Sjdp temp = program_name; 32433965Sjdp else 32533965Sjdp ++temp; 32633965Sjdp if (strlen (temp) >= 6 32733965Sjdp && strcmp (temp + strlen (temp) - 6, "ranlib") == 0) 32833965Sjdp is_ranlib = 1; 32933965Sjdp else 33033965Sjdp is_ranlib = 0; 33133965Sjdp } 33233965Sjdp 33333965Sjdp if (argc > 1 && argv[1][0] == '-') 33433965Sjdp { 33533965Sjdp if (strcmp (argv[1], "--help") == 0) 33633965Sjdp usage (1); 33733965Sjdp else if (strcmp (argv[1], "--version") == 0) 33833965Sjdp { 33933965Sjdp if (is_ranlib) 34033965Sjdp print_version ("ranlib"); 34133965Sjdp else 34233965Sjdp print_version ("ar"); 34333965Sjdp } 34433965Sjdp } 34533965Sjdp 34633965Sjdp START_PROGRESS (program_name, 0); 34733965Sjdp 34833965Sjdp bfd_init (); 34933965Sjdp set_default_bfd_target (); 35033965Sjdp 35133965Sjdp show_version = 0; 35233965Sjdp 35333965Sjdp xatexit (remove_output); 35433965Sjdp 35533965Sjdp if (is_ranlib) 35633965Sjdp { 35733965Sjdp boolean touch = false; 35833965Sjdp 35933965Sjdp if (argc < 2 || strcmp (argv[1], "--help") == 0) 36033965Sjdp usage (0); 36133965Sjdp if (strcmp (argv[1], "-V") == 0 36233965Sjdp || strcmp (argv[1], "-v") == 0 36333965Sjdp || strncmp (argv[1], "--v", 3) == 0) 36433965Sjdp print_version ("ranlib"); 36533965Sjdp arg_index = 1; 36633965Sjdp if (strcmp (argv[1], "-t") == 0) 36733965Sjdp { 36833965Sjdp ++arg_index; 36933965Sjdp touch = true; 37033965Sjdp } 37133965Sjdp while (arg_index < argc) 37233965Sjdp { 37333965Sjdp if (! touch) 37433965Sjdp ranlib_only (argv[arg_index]); 37533965Sjdp else 37633965Sjdp ranlib_touch (argv[arg_index]); 37733965Sjdp ++arg_index; 37833965Sjdp } 37933965Sjdp xexit (0); 38033965Sjdp } 38133965Sjdp 38233965Sjdp if (argc == 2 && strcmp (argv[1], "-M") == 0) 38333965Sjdp { 38433965Sjdp mri_emul (); 38533965Sjdp xexit (0); 38633965Sjdp } 38733965Sjdp 38833965Sjdp if (argc < 2) 38933965Sjdp usage (0); 39033965Sjdp 39133965Sjdp arg_ptr = argv[1]; 39233965Sjdp 39333965Sjdp if (*arg_ptr == '-') 39433965Sjdp ++arg_ptr; /* compatibility */ 39533965Sjdp 39633965Sjdp while ((c = *arg_ptr++) != '\0') 39733965Sjdp { 39833965Sjdp switch (c) 39933965Sjdp { 40033965Sjdp case 'd': 40133965Sjdp case 'm': 40233965Sjdp case 'p': 40333965Sjdp case 'q': 40433965Sjdp case 'r': 40533965Sjdp case 't': 40633965Sjdp case 'x': 40733965Sjdp if (operation != none) 40833965Sjdp fatal ("two different operation options specified"); 40933965Sjdp switch (c) 41033965Sjdp { 41133965Sjdp case 'd': 41233965Sjdp operation = delete; 41333965Sjdp operation_alters_arch = true; 41433965Sjdp break; 41533965Sjdp case 'm': 41633965Sjdp operation = move; 41733965Sjdp operation_alters_arch = true; 41833965Sjdp break; 41933965Sjdp case 'p': 42033965Sjdp operation = print_files; 42133965Sjdp break; 42233965Sjdp case 'q': 42333965Sjdp operation = quick_append; 42433965Sjdp operation_alters_arch = true; 42533965Sjdp break; 42633965Sjdp case 'r': 42733965Sjdp operation = replace; 42833965Sjdp operation_alters_arch = true; 42933965Sjdp break; 43033965Sjdp case 't': 43133965Sjdp operation = print_table; 43233965Sjdp break; 43333965Sjdp case 'x': 43433965Sjdp operation = extract; 43533965Sjdp break; 43633965Sjdp } 43733965Sjdp case 'l': 43833965Sjdp break; 43933965Sjdp case 'c': 44033965Sjdp silent_create = 1; 44133965Sjdp break; 44233965Sjdp case 'o': 44333965Sjdp preserve_dates = 1; 44433965Sjdp break; 44533965Sjdp case 'V': 44633965Sjdp show_version = true; 44733965Sjdp break; 44833965Sjdp case 's': 44933965Sjdp write_armap = 1; 45033965Sjdp break; 45138889Sjdp case 'S': 45238889Sjdp write_armap = -1; 45338889Sjdp break; 45433965Sjdp case 'u': 45533965Sjdp newer_only = 1; 45633965Sjdp break; 45733965Sjdp case 'v': 45833965Sjdp verbose = 1; 45933965Sjdp break; 46033965Sjdp case 'a': 46133965Sjdp postype = pos_after; 46233965Sjdp break; 46333965Sjdp case 'b': 46433965Sjdp postype = pos_before; 46533965Sjdp break; 46633965Sjdp case 'i': 46733965Sjdp postype = pos_before; 46833965Sjdp break; 46933965Sjdp case 'M': 47033965Sjdp mri_mode = 1; 47133965Sjdp break; 47233965Sjdp case 'f': 47333965Sjdp ar_truncate = true; 47433965Sjdp break; 47533965Sjdp default: 47633965Sjdp fprintf (stderr, "%s: illegal option -- %c\n", program_name, c); 47733965Sjdp usage (0); 47833965Sjdp } 47933965Sjdp } 48033965Sjdp 48133965Sjdp if (show_version) 48233965Sjdp print_version ("ar"); 48333965Sjdp 48433965Sjdp if (argc < 3) 48533965Sjdp usage (0); 48633965Sjdp 48733965Sjdp if (mri_mode) 48833965Sjdp { 48933965Sjdp mri_emul (); 49033965Sjdp } 49133965Sjdp else 49233965Sjdp { 49333965Sjdp bfd *arch; 49433965Sjdp 49533965Sjdp /* We can't write an armap when using ar q, so just do ar r 49633965Sjdp instead. */ 49733965Sjdp if (operation == quick_append && write_armap) 49833965Sjdp operation = replace; 49933965Sjdp 50033965Sjdp if ((operation == none || operation == print_table) 50133965Sjdp && write_armap == 1) 50233965Sjdp { 50333965Sjdp ranlib_only (argv[2]); 50433965Sjdp xexit (0); 50533965Sjdp } 50633965Sjdp 50733965Sjdp if (operation == none) 50833965Sjdp fatal ("no operation specified"); 50933965Sjdp 51033965Sjdp if (newer_only && operation != replace) 51133965Sjdp fatal ("`u' is only meaningful with the `r' option."); 51233965Sjdp 51333965Sjdp arg_index = 2; 51433965Sjdp 51533965Sjdp if (postype != pos_default) 51633965Sjdp posname = argv[arg_index++]; 51733965Sjdp 51833965Sjdp inarch_filename = argv[arg_index++]; 51933965Sjdp 52033965Sjdp files = arg_index < argc ? argv + arg_index : NULL; 52133965Sjdp 52233965Sjdp#if 0 52333965Sjdp /* We don't use do_quick_append any more. Too many systems 52433965Sjdp expect ar to always rebuild the symbol table even when q is 52533965Sjdp used. */ 52633965Sjdp 52733965Sjdp /* We can't do a quick append if we need to construct an 52833965Sjdp extended name table, because do_quick_append won't be able to 52933965Sjdp rebuild the name table. Unfortunately, at this point we 53033965Sjdp don't actually know the maximum name length permitted by this 53133965Sjdp object file format. So, we guess. FIXME. */ 53233965Sjdp if (operation == quick_append && ! ar_truncate) 53333965Sjdp { 53433965Sjdp char **chk; 53533965Sjdp 53633965Sjdp for (chk = files; chk != NULL && *chk != '\0'; chk++) 53733965Sjdp { 53833965Sjdp if (strlen (normalize (*chk, (bfd *) NULL)) > 14) 53933965Sjdp { 54033965Sjdp operation = replace; 54133965Sjdp break; 54233965Sjdp } 54333965Sjdp } 54433965Sjdp } 54533965Sjdp 54633965Sjdp if (operation == quick_append) 54733965Sjdp { 54833965Sjdp /* Note that quick appending to a non-existent archive creates it, 54933965Sjdp even if there are no files to append. */ 55033965Sjdp do_quick_append (inarch_filename, files); 55133965Sjdp xexit (0); 55233965Sjdp } 55333965Sjdp#endif 55433965Sjdp 55533965Sjdp arch = open_inarch (inarch_filename, 55633965Sjdp files == NULL ? (char *) NULL : files[0]); 55733965Sjdp 55833965Sjdp switch (operation) 55933965Sjdp { 56033965Sjdp case print_table: 56133965Sjdp map_over_members (arch, print_descr, files, argc - 3); 56233965Sjdp break; 56333965Sjdp 56433965Sjdp case print_files: 56533965Sjdp map_over_members (arch, print_contents, files, argc - 3); 56633965Sjdp break; 56733965Sjdp 56833965Sjdp case extract: 56933965Sjdp map_over_members (arch, extract_file, files, argc - 3); 57033965Sjdp break; 57133965Sjdp 57233965Sjdp case delete: 57333965Sjdp if (files != NULL) 57433965Sjdp delete_members (arch, files); 57533965Sjdp break; 57633965Sjdp 57733965Sjdp case move: 57833965Sjdp if (files != NULL) 57933965Sjdp move_members (arch, files); 58033965Sjdp break; 58133965Sjdp 58233965Sjdp case replace: 58333965Sjdp case quick_append: 58433965Sjdp if (files != NULL || write_armap > 0) 58533965Sjdp replace_members (arch, files, operation == quick_append); 58633965Sjdp break; 58733965Sjdp 58833965Sjdp /* Shouldn't happen! */ 58933965Sjdp default: 59033965Sjdp fprintf (stderr, "%s: internal error -- this option not implemented\n", 59133965Sjdp program_name); 59233965Sjdp xexit (1); 59333965Sjdp } 59433965Sjdp } 59533965Sjdp 59633965Sjdp END_PROGRESS (program_name); 59733965Sjdp 59833965Sjdp xexit (0); 59933965Sjdp return 0; 60033965Sjdp} 60133965Sjdp 60233965Sjdpbfd * 60333965Sjdpopen_inarch (archive_filename, file) 60433965Sjdp const char *archive_filename; 60533965Sjdp const char *file; 60633965Sjdp{ 60733965Sjdp const char *target; 60833965Sjdp bfd **last_one; 60933965Sjdp bfd *next_one; 61033965Sjdp struct stat sbuf; 61133965Sjdp bfd *arch; 61233965Sjdp char **matching; 61333965Sjdp 61433965Sjdp bfd_set_error (bfd_error_no_error); 61533965Sjdp 61633965Sjdp target = NULL; 61733965Sjdp 61833965Sjdp if (stat (archive_filename, &sbuf) != 0) 61933965Sjdp { 62033965Sjdp#ifndef __GO32__ 62133965Sjdp 62233965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why 62333965Sjdp * stat() is wrong ... think it's buried in GO32's IDT 62433965Sjdp * - Jax 62533965Sjdp */ 62633965Sjdp if (errno != ENOENT) 62733965Sjdp bfd_fatal (archive_filename); 62833965Sjdp#endif 62933965Sjdp 63033965Sjdp if (!operation_alters_arch) 63133965Sjdp { 63233965Sjdp fprintf (stderr, "%s: ", program_name); 63333965Sjdp perror (archive_filename); 63433965Sjdp maybequit (); 63533965Sjdp return NULL; 63633965Sjdp } 63733965Sjdp 63833965Sjdp /* Try to figure out the target to use for the archive from the 63933965Sjdp first object on the list. */ 64033965Sjdp if (file != NULL) 64133965Sjdp { 64233965Sjdp bfd *obj; 64333965Sjdp 64433965Sjdp obj = bfd_openr (file, NULL); 64533965Sjdp if (obj != NULL) 64633965Sjdp { 64733965Sjdp if (bfd_check_format (obj, bfd_object)) 64833965Sjdp target = bfd_get_target (obj); 64933965Sjdp (void) bfd_close (obj); 65033965Sjdp } 65133965Sjdp } 65233965Sjdp 65333965Sjdp /* Create an empty archive. */ 65433965Sjdp arch = bfd_openw (archive_filename, target); 65533965Sjdp if (arch == NULL 65633965Sjdp || ! bfd_set_format (arch, bfd_archive) 65733965Sjdp || ! bfd_close (arch)) 65833965Sjdp bfd_fatal (archive_filename); 65933965Sjdp } 66033965Sjdp 66133965Sjdp arch = bfd_openr (archive_filename, target); 66233965Sjdp if (arch == NULL) 66333965Sjdp { 66433965Sjdp bloser: 66533965Sjdp bfd_fatal (archive_filename); 66633965Sjdp } 66733965Sjdp 66833965Sjdp if (! bfd_check_format_matches (arch, bfd_archive, &matching)) 66933965Sjdp { 67033965Sjdp bfd_nonfatal (archive_filename); 67133965Sjdp if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 67233965Sjdp { 67333965Sjdp list_matching_formats (matching); 67433965Sjdp free (matching); 67533965Sjdp } 67633965Sjdp xexit (1); 67733965Sjdp } 67833965Sjdp 67933965Sjdp last_one = &(arch->next); 68033965Sjdp /* Read all the contents right away, regardless. */ 68133965Sjdp for (next_one = bfd_openr_next_archived_file (arch, NULL); 68233965Sjdp next_one; 68333965Sjdp next_one = bfd_openr_next_archived_file (arch, next_one)) 68433965Sjdp { 68533965Sjdp PROGRESS (1); 68633965Sjdp *last_one = next_one; 68733965Sjdp last_one = &next_one->next; 68833965Sjdp } 68933965Sjdp *last_one = (bfd *) NULL; 69033965Sjdp if (bfd_get_error () != bfd_error_no_more_archived_files) 69133965Sjdp goto bloser; 69233965Sjdp return arch; 69333965Sjdp} 69433965Sjdp 69533965Sjdpstatic void 69633965Sjdpprint_contents (abfd) 69733965Sjdp bfd *abfd; 69833965Sjdp{ 69933965Sjdp int ncopied = 0; 70033965Sjdp char *cbuf = xmalloc (BUFSIZE); 70133965Sjdp struct stat buf; 70233965Sjdp long size; 70333965Sjdp if (bfd_stat_arch_elt (abfd, &buf) != 0) 70433965Sjdp fatal ("internal stat error on %s", bfd_get_filename (abfd)); 70533965Sjdp 70633965Sjdp if (verbose) 70733965Sjdp printf ("\n<member %s>\n\n", bfd_get_filename (abfd)); 70833965Sjdp 70933965Sjdp bfd_seek (abfd, 0, SEEK_SET); 71033965Sjdp 71133965Sjdp size = buf.st_size; 71233965Sjdp while (ncopied < size) 71333965Sjdp { 71433965Sjdp 71533965Sjdp int nread; 71633965Sjdp int tocopy = size - ncopied; 71733965Sjdp if (tocopy > BUFSIZE) 71833965Sjdp tocopy = BUFSIZE; 71933965Sjdp 72033965Sjdp nread = bfd_read (cbuf, 1, tocopy, abfd); /* oops -- broke 72133965Sjdp abstraction! */ 72233965Sjdp if (nread != tocopy) 72333965Sjdp fatal ("%s is not a valid archive", 72433965Sjdp bfd_get_filename (bfd_my_archive (abfd))); 72533965Sjdp fwrite (cbuf, 1, nread, stdout); 72633965Sjdp ncopied += tocopy; 72733965Sjdp } 72833965Sjdp free (cbuf); 72933965Sjdp} 73033965Sjdp 73133965Sjdp/* Extract a member of the archive into its own file. 73233965Sjdp 73333965Sjdp We defer opening the new file until after we have read a BUFSIZ chunk of the 73433965Sjdp old one, since we know we have just read the archive header for the old 73533965Sjdp one. Since most members are shorter than BUFSIZ, this means we will read 73633965Sjdp the old header, read the old data, write a new inode for the new file, and 73733965Sjdp write the new data, and be done. This 'optimization' is what comes from 73833965Sjdp sitting next to a bare disk and hearing it every time it seeks. -- Gnu 73933965Sjdp Gilmore */ 74033965Sjdp 74133965Sjdpvoid 74233965Sjdpextract_file (abfd) 74333965Sjdp bfd *abfd; 74433965Sjdp{ 74533965Sjdp FILE *ostream; 74633965Sjdp char *cbuf = xmalloc (BUFSIZE); 74733965Sjdp int nread, tocopy; 74833965Sjdp int ncopied = 0; 74933965Sjdp long size; 75033965Sjdp struct stat buf; 75133965Sjdp if (bfd_stat_arch_elt (abfd, &buf) != 0) 75233965Sjdp fatal ("internal stat error on %s", bfd_get_filename (abfd)); 75333965Sjdp size = buf.st_size; 75433965Sjdp 75533965Sjdp if (verbose) 75633965Sjdp printf ("x - %s\n", bfd_get_filename (abfd)); 75733965Sjdp 75833965Sjdp bfd_seek (abfd, 0, SEEK_SET); 75933965Sjdp 76033965Sjdp ostream = 0; 76133965Sjdp if (size == 0) 76233965Sjdp { 76333965Sjdp /* Seems like an abstraction violation, eh? Well it's OK! */ 76433965Sjdp output_filename = bfd_get_filename (abfd); 76533965Sjdp 76633965Sjdp ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); 76733965Sjdp if (!ostream) 76833965Sjdp { 76933965Sjdp perror (bfd_get_filename (abfd)); 77033965Sjdp xexit (1); 77133965Sjdp } 77233965Sjdp 77333965Sjdp output_file = ostream; 77433965Sjdp } 77533965Sjdp else 77633965Sjdp while (ncopied < size) 77733965Sjdp { 77833965Sjdp tocopy = size - ncopied; 77933965Sjdp if (tocopy > BUFSIZE) 78033965Sjdp tocopy = BUFSIZE; 78133965Sjdp 78233965Sjdp nread = bfd_read (cbuf, 1, tocopy, abfd); 78333965Sjdp if (nread != tocopy) 78433965Sjdp fatal ("%s is not a valid archive", 78533965Sjdp bfd_get_filename (bfd_my_archive (abfd))); 78633965Sjdp 78733965Sjdp /* See comment above; this saves disk arm motion */ 78833965Sjdp if (!ostream) 78933965Sjdp { 79033965Sjdp /* Seems like an abstraction violation, eh? Well it's OK! */ 79133965Sjdp output_filename = bfd_get_filename (abfd); 79233965Sjdp 79333965Sjdp ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); 79433965Sjdp if (!ostream) 79533965Sjdp { 79633965Sjdp perror (bfd_get_filename (abfd)); 79733965Sjdp xexit (1); 79833965Sjdp } 79933965Sjdp 80033965Sjdp output_file = ostream; 80133965Sjdp } 80233965Sjdp fwrite (cbuf, 1, nread, ostream); 80333965Sjdp ncopied += tocopy; 80433965Sjdp } 80533965Sjdp 80633965Sjdp fclose (ostream); 80733965Sjdp 80833965Sjdp output_file = NULL; 80933965Sjdp output_filename = NULL; 81033965Sjdp 81133965Sjdp chmod (bfd_get_filename (abfd), buf.st_mode); 81233965Sjdp 81333965Sjdp if (preserve_dates) 81433965Sjdp { 81533965Sjdp#ifdef HAVE_GOOD_UTIME_H 81633965Sjdp struct utimbuf tb; 81733965Sjdp tb.actime = buf.st_mtime; 81833965Sjdp tb.modtime = buf.st_mtime; 81933965Sjdp utime (bfd_get_filename (abfd), &tb); /* FIXME check result */ 82033965Sjdp#else /* ! HAVE_GOOD_UTIME_H */ 82133965Sjdp#ifndef HAVE_UTIMES 82233965Sjdp long tb[2]; 82333965Sjdp tb[0] = buf.st_mtime; 82433965Sjdp tb[1] = buf.st_mtime; 82533965Sjdp utime (bfd_get_filename (abfd), tb); /* FIXME check result */ 82633965Sjdp#else /* HAVE_UTIMES */ 82733965Sjdp struct timeval tv[2]; 82833965Sjdp tv[0].tv_sec = buf.st_mtime; 82933965Sjdp tv[0].tv_usec = 0; 83033965Sjdp tv[1].tv_sec = buf.st_mtime; 83133965Sjdp tv[1].tv_usec = 0; 83233965Sjdp utimes (bfd_get_filename (abfd), tv); /* FIXME check result */ 83333965Sjdp#endif /* HAVE_UTIMES */ 83433965Sjdp#endif /* ! HAVE_GOOD_UTIME_H */ 83533965Sjdp } 83633965Sjdpfree (cbuf); 83733965Sjdp} 83833965Sjdp 83933965Sjdp#if 0 84033965Sjdp 84133965Sjdp/* We don't use this anymore. Too many systems expect ar to rebuild 84233965Sjdp the symbol table even when q is used. */ 84333965Sjdp 84433965Sjdp/* Just do it quickly; don't worry about dups, armap, or anything like that */ 84533965Sjdp 84633965Sjdpstatic void 84733965Sjdpdo_quick_append (archive_filename, files_to_append) 84833965Sjdp const char *archive_filename; 84933965Sjdp char **files_to_append; 85033965Sjdp{ 85133965Sjdp FILE *ofile, *ifile; 85233965Sjdp char *buf = xmalloc (BUFSIZE); 85333965Sjdp long tocopy, thistime; 85433965Sjdp bfd *temp; 85533965Sjdp struct stat sbuf; 85633965Sjdp boolean newfile = false; 85733965Sjdp bfd_set_error (bfd_error_no_error); 85833965Sjdp 85933965Sjdp if (stat (archive_filename, &sbuf) != 0) 86033965Sjdp { 86133965Sjdp 86233965Sjdp#ifndef __GO32__ 86333965Sjdp 86433965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why 86533965Sjdp * stat() is wrong ... think it's buried in GO32's IDT 86633965Sjdp * - Jax 86733965Sjdp */ 86833965Sjdp 86933965Sjdp if (errno != ENOENT) 87033965Sjdp bfd_fatal (archive_filename); 87133965Sjdp#endif 87233965Sjdp 87333965Sjdp newfile = true; 87433965Sjdp } 87533965Sjdp 87633965Sjdp ofile = fopen (archive_filename, FOPEN_AUB); 87733965Sjdp if (ofile == NULL) 87833965Sjdp { 87933965Sjdp perror (program_name); 88033965Sjdp xexit (1); 88133965Sjdp } 88233965Sjdp 88333965Sjdp temp = bfd_openr (archive_filename, NULL); 88433965Sjdp if (temp == NULL) 88533965Sjdp { 88633965Sjdp bfd_fatal (archive_filename); 88733965Sjdp } 88833965Sjdp if (newfile == false) 88933965Sjdp { 89033965Sjdp if (bfd_check_format (temp, bfd_archive) != true) 89133965Sjdp fatal ("%s is not an archive", archive_filename); 89233965Sjdp } 89333965Sjdp else 89433965Sjdp { 89533965Sjdp fwrite (ARMAG, 1, SARMAG, ofile); 89633965Sjdp if (!silent_create) 89733965Sjdp fprintf (stderr, "%s: creating %s\n", 89833965Sjdp program_name, archive_filename); 89933965Sjdp } 90033965Sjdp 90133965Sjdp if (ar_truncate) 90233965Sjdp temp->flags |= BFD_TRADITIONAL_FORMAT; 90333965Sjdp 90433965Sjdp /* assume it's an achive, go straight to the end, sans $200 */ 90533965Sjdp fseek (ofile, 0, 2); 90633965Sjdp 90733965Sjdp for (; files_to_append && *files_to_append; ++files_to_append) 90833965Sjdp { 90933965Sjdp struct ar_hdr *hdr = bfd_special_undocumented_glue (temp, *files_to_append); 91033965Sjdp if (hdr == NULL) 91133965Sjdp { 91233965Sjdp bfd_fatal (*files_to_append); 91333965Sjdp } 91433965Sjdp 91533965Sjdp BFD_SEND (temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr)); 91633965Sjdp 91733965Sjdp ifile = fopen (*files_to_append, FOPEN_RB); 91833965Sjdp if (ifile == NULL) 91933965Sjdp { 92033965Sjdp bfd_nonfatal (*files_to_append); 92133965Sjdp } 92233965Sjdp 92333965Sjdp if (stat (*files_to_append, &sbuf) != 0) 92433965Sjdp { 92533965Sjdp bfd_nonfatal (*files_to_append); 92633965Sjdp } 92733965Sjdp 92833965Sjdp tocopy = sbuf.st_size; 92933965Sjdp 93033965Sjdp /* XXX should do error-checking! */ 93133965Sjdp fwrite (hdr, 1, sizeof (struct ar_hdr), ofile); 93233965Sjdp 93333965Sjdp while (tocopy > 0) 93433965Sjdp { 93533965Sjdp thistime = tocopy; 93633965Sjdp if (thistime > BUFSIZE) 93733965Sjdp thistime = BUFSIZE; 93833965Sjdp fread (buf, 1, thistime, ifile); 93933965Sjdp fwrite (buf, 1, thistime, ofile); 94033965Sjdp tocopy -= thistime; 94133965Sjdp } 94233965Sjdp fclose (ifile); 94333965Sjdp if ((sbuf.st_size % 2) == 1) 94433965Sjdp putc ('\012', ofile); 94533965Sjdp } 94633965Sjdp fclose (ofile); 94733965Sjdp bfd_close (temp); 94833965Sjdp free (buf); 94933965Sjdp} 95033965Sjdp 95133965Sjdp#endif /* 0 */ 95233965Sjdp 95333965Sjdpstatic void 95433965Sjdpwrite_archive (iarch) 95533965Sjdp bfd *iarch; 95633965Sjdp{ 95733965Sjdp bfd *obfd; 95833965Sjdp char *old_name, *new_name; 95933965Sjdp bfd *contents_head = iarch->next; 96033965Sjdp 96133965Sjdp old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1); 96233965Sjdp strcpy (old_name, bfd_get_filename (iarch)); 96333965Sjdp new_name = make_tempname (old_name); 96433965Sjdp 96533965Sjdp output_filename = new_name; 96633965Sjdp 96733965Sjdp obfd = bfd_openw (new_name, bfd_get_target (iarch)); 96833965Sjdp 96933965Sjdp if (obfd == NULL) 97033965Sjdp bfd_fatal (old_name); 97133965Sjdp 97233965Sjdp output_bfd = obfd; 97333965Sjdp 97433965Sjdp bfd_set_format (obfd, bfd_archive); 97533965Sjdp 97633965Sjdp /* Request writing the archive symbol table unless we've 97733965Sjdp been explicitly requested not to. */ 97833965Sjdp obfd->has_armap = write_armap >= 0; 97933965Sjdp 98033965Sjdp if (ar_truncate) 98133965Sjdp { 98233965Sjdp /* This should really use bfd_set_file_flags, but that rejects 98333965Sjdp archives. */ 98433965Sjdp obfd->flags |= BFD_TRADITIONAL_FORMAT; 98533965Sjdp } 98633965Sjdp 98733965Sjdp if (bfd_set_archive_head (obfd, contents_head) != true) 98833965Sjdp bfd_fatal (old_name); 98933965Sjdp 99033965Sjdp if (!bfd_close (obfd)) 99133965Sjdp bfd_fatal (old_name); 99233965Sjdp 99333965Sjdp output_bfd = NULL; 99433965Sjdp output_filename = NULL; 99533965Sjdp 99633965Sjdp /* We don't care if this fails; we might be creating the archive. */ 99733965Sjdp bfd_close (iarch); 99833965Sjdp unlink (old_name); 99933965Sjdp 100033965Sjdp if (rename (new_name, old_name) != 0) 100133965Sjdp bfd_fatal (old_name); 100233965Sjdp} 100333965Sjdp 100433965Sjdp/* Return a pointer to the pointer to the entry which should be rplacd'd 100533965Sjdp into when altering. DEFAULT_POS should be how to interpret pos_default, 100633965Sjdp and should be a pos value. */ 100733965Sjdp 100833965Sjdpstatic bfd ** 100938889Sjdpget_pos_bfd (contents, default_pos, default_posname) 101033965Sjdp bfd **contents; 101133965Sjdp enum pos default_pos; 101238889Sjdp const char *default_posname; 101333965Sjdp{ 101433965Sjdp bfd **after_bfd = contents; 101538889Sjdp enum pos realpos; 101638889Sjdp const char *realposname; 101733965Sjdp 101838889Sjdp if (postype == pos_default) 101938889Sjdp { 102038889Sjdp realpos = default_pos; 102138889Sjdp realposname = default_posname; 102238889Sjdp } 102338889Sjdp else 102438889Sjdp { 102538889Sjdp realpos = postype; 102638889Sjdp realposname = posname; 102738889Sjdp } 102838889Sjdp 102933965Sjdp if (realpos == pos_end) 103033965Sjdp { 103133965Sjdp while (*after_bfd) 103233965Sjdp after_bfd = &((*after_bfd)->next); 103333965Sjdp } 103433965Sjdp else 103533965Sjdp { 103633965Sjdp for (; *after_bfd; after_bfd = &(*after_bfd)->next) 103738889Sjdp if (strcmp ((*after_bfd)->filename, realposname) == 0) 103833965Sjdp { 103933965Sjdp if (realpos == pos_after) 104033965Sjdp after_bfd = &(*after_bfd)->next; 104133965Sjdp break; 104233965Sjdp } 104333965Sjdp } 104433965Sjdp return after_bfd; 104533965Sjdp} 104633965Sjdp 104733965Sjdpstatic void 104833965Sjdpdelete_members (arch, files_to_delete) 104933965Sjdp bfd *arch; 105033965Sjdp char **files_to_delete; 105133965Sjdp{ 105233965Sjdp bfd **current_ptr_ptr; 105333965Sjdp boolean found; 105433965Sjdp boolean something_changed = false; 105533965Sjdp for (; *files_to_delete != NULL; ++files_to_delete) 105633965Sjdp { 105733965Sjdp /* In a.out systems, the armap is optional. It's also called 105833965Sjdp __.SYMDEF. So if the user asked to delete it, we should remember 105933965Sjdp that fact. This isn't quite right for COFF systems (where 106033965Sjdp __.SYMDEF might be regular member), but it's very unlikely 106133965Sjdp to be a problem. FIXME */ 106233965Sjdp 106333965Sjdp if (!strcmp (*files_to_delete, "__.SYMDEF")) 106433965Sjdp { 106533965Sjdp arch->has_armap = false; 106633965Sjdp write_armap = -1; 106733965Sjdp continue; 106833965Sjdp } 106933965Sjdp 107033965Sjdp found = false; 107133965Sjdp current_ptr_ptr = &(arch->next); 107233965Sjdp while (*current_ptr_ptr) 107333965Sjdp { 107433965Sjdp if (strcmp (*files_to_delete, (*current_ptr_ptr)->filename) == 0) 107533965Sjdp { 107633965Sjdp found = true; 107733965Sjdp something_changed = true; 107833965Sjdp if (verbose) 107933965Sjdp printf ("d - %s\n", 108033965Sjdp *files_to_delete); 108133965Sjdp *current_ptr_ptr = ((*current_ptr_ptr)->next); 108233965Sjdp goto next_file; 108333965Sjdp } 108433965Sjdp else 108533965Sjdp { 108633965Sjdp current_ptr_ptr = &((*current_ptr_ptr)->next); 108733965Sjdp } 108833965Sjdp } 108933965Sjdp 109033965Sjdp if (verbose && found == false) 109133965Sjdp { 109233965Sjdp printf ("No member named `%s'\n", *files_to_delete); 109333965Sjdp } 109433965Sjdp next_file: 109533965Sjdp ; 109633965Sjdp } 109733965Sjdp 109833965Sjdp if (something_changed == true) 109933965Sjdp { 110033965Sjdp write_archive (arch); 110133965Sjdp } 110233965Sjdp} 110333965Sjdp 110433965Sjdp 110533965Sjdp/* Reposition existing members within an archive */ 110633965Sjdp 110733965Sjdpstatic void 110833965Sjdpmove_members (arch, files_to_move) 110933965Sjdp bfd *arch; 111033965Sjdp char **files_to_move; 111133965Sjdp{ 111233965Sjdp bfd **after_bfd; /* New entries go after this one */ 111333965Sjdp bfd **current_ptr_ptr; /* cdr pointer into contents */ 111433965Sjdp 111533965Sjdp for (; *files_to_move; ++files_to_move) 111633965Sjdp { 111733965Sjdp current_ptr_ptr = &(arch->next); 111833965Sjdp while (*current_ptr_ptr) 111933965Sjdp { 112033965Sjdp bfd *current_ptr = *current_ptr_ptr; 112133965Sjdp if (strcmp (normalize (*files_to_move, arch), 112233965Sjdp current_ptr->filename) == 0) 112333965Sjdp { 112433965Sjdp /* Move this file to the end of the list - first cut from 112533965Sjdp where it is. */ 112633965Sjdp bfd *link; 112733965Sjdp *current_ptr_ptr = current_ptr->next; 112833965Sjdp 112933965Sjdp /* Now glue to end */ 113038889Sjdp after_bfd = get_pos_bfd (&arch->next, pos_end, NULL); 113133965Sjdp link = *after_bfd; 113233965Sjdp *after_bfd = current_ptr; 113333965Sjdp current_ptr->next = link; 113433965Sjdp 113533965Sjdp if (verbose) 113633965Sjdp printf ("m - %s\n", *files_to_move); 113733965Sjdp 113833965Sjdp goto next_file; 113933965Sjdp } 114033965Sjdp 114133965Sjdp current_ptr_ptr = &((*current_ptr_ptr)->next); 114233965Sjdp } 114333965Sjdp fprintf (stderr, "%s: no entry %s in archive %s!\n", 114433965Sjdp program_name, *files_to_move, arch->filename); 114533965Sjdp xexit (1); 114633965Sjdp next_file:; 114733965Sjdp } 114833965Sjdp 114933965Sjdp write_archive (arch); 115033965Sjdp} 115133965Sjdp 115233965Sjdp/* Ought to default to replacing in place, but this is existing practice! */ 115333965Sjdp 115433965Sjdpstatic void 115533965Sjdpreplace_members (arch, files_to_move, quick) 115633965Sjdp bfd *arch; 115733965Sjdp char **files_to_move; 115833965Sjdp boolean quick; 115933965Sjdp{ 116033965Sjdp boolean changed = false; 116133965Sjdp bfd **after_bfd; /* New entries go after this one */ 116233965Sjdp bfd *current; 116333965Sjdp bfd **current_ptr; 116433965Sjdp bfd *temp; 116533965Sjdp 116633965Sjdp while (files_to_move && *files_to_move) 116733965Sjdp { 116833965Sjdp if (! quick) 116933965Sjdp { 117033965Sjdp current_ptr = &arch->next; 117133965Sjdp while (*current_ptr) 117233965Sjdp { 117333965Sjdp current = *current_ptr; 117433965Sjdp 117533965Sjdp /* For compatibility with existing ar programs, we 117633965Sjdp permit the same file to be added multiple times. */ 117733965Sjdp if (strcmp (normalize (*files_to_move, arch), 117833965Sjdp normalize (current->filename, arch)) == 0 117933965Sjdp && current->arelt_data != NULL) 118033965Sjdp { 118133965Sjdp if (newer_only) 118233965Sjdp { 118333965Sjdp struct stat fsbuf, asbuf; 118433965Sjdp 118533965Sjdp if (stat (*files_to_move, &fsbuf) != 0) 118633965Sjdp { 118733965Sjdp if (errno != ENOENT) 118833965Sjdp bfd_fatal (*files_to_move); 118933965Sjdp goto next_file; 119033965Sjdp } 119133965Sjdp if (bfd_stat_arch_elt (current, &asbuf) != 0) 119233965Sjdp fatal ("internal stat error on %s", current->filename); 119333965Sjdp 119433965Sjdp if (fsbuf.st_mtime <= asbuf.st_mtime) 119533965Sjdp goto next_file; 119633965Sjdp } 119733965Sjdp 119838889Sjdp after_bfd = get_pos_bfd (&arch->next, pos_after, 119938889Sjdp current->filename); 120038889Sjdp temp = *after_bfd; 120133965Sjdp 120233965Sjdp *after_bfd = bfd_openr (*files_to_move, NULL); 120333965Sjdp if (*after_bfd == (bfd *) NULL) 120433965Sjdp { 120533965Sjdp bfd_fatal (*files_to_move); 120633965Sjdp } 120733965Sjdp (*after_bfd)->next = temp; 120833965Sjdp 120938889Sjdp /* snip out this entry from the chain */ 121038889Sjdp *current_ptr = (*current_ptr)->next; 121138889Sjdp 121233965Sjdp if (verbose) 121333965Sjdp { 121433965Sjdp printf ("r - %s\n", *files_to_move); 121533965Sjdp } 121633965Sjdp 121733965Sjdp changed = true; 121833965Sjdp 121933965Sjdp goto next_file; 122033965Sjdp } 122133965Sjdp current_ptr = &(current->next); 122233965Sjdp } 122333965Sjdp } 122433965Sjdp 122533965Sjdp /* Add to the end of the archive. */ 122633965Sjdp 122738889Sjdp after_bfd = get_pos_bfd (&arch->next, pos_end, NULL); 122833965Sjdp temp = *after_bfd; 122933965Sjdp *after_bfd = bfd_openr (*files_to_move, NULL); 123033965Sjdp if (*after_bfd == (bfd *) NULL) 123133965Sjdp { 123233965Sjdp bfd_fatal (*files_to_move); 123333965Sjdp } 123433965Sjdp if (verbose) 123533965Sjdp { 123633965Sjdp printf ("a - %s\n", *files_to_move); 123733965Sjdp } 123833965Sjdp 123933965Sjdp (*after_bfd)->next = temp; 124033965Sjdp 124133965Sjdp changed = true; 124233965Sjdp 124333965Sjdp next_file:; 124433965Sjdp 124533965Sjdp files_to_move++; 124633965Sjdp } 124733965Sjdp 124833965Sjdp if (changed) 124933965Sjdp write_archive (arch); 125033965Sjdp} 125133965Sjdp 125233965Sjdpstatic void 125333965Sjdpranlib_only (archname) 125433965Sjdp const char *archname; 125533965Sjdp{ 125633965Sjdp bfd *arch; 125733965Sjdp 125833965Sjdp write_armap = 1; 125933965Sjdp arch = open_inarch (archname, (char *) NULL); 126033965Sjdp if (arch == NULL) 126133965Sjdp xexit (1); 126233965Sjdp write_archive (arch); 126333965Sjdp} 126433965Sjdp 126533965Sjdp/* Update the timestamp of the symbol map of an archive. */ 126633965Sjdp 126733965Sjdpstatic void 126833965Sjdpranlib_touch (archname) 126933965Sjdp const char *archname; 127033965Sjdp{ 127133965Sjdp#ifdef __GO32__ 127233965Sjdp /* I don't think updating works on go32. */ 127333965Sjdp ranlib_only (archname); 127433965Sjdp#else 127533965Sjdp int f; 127633965Sjdp bfd *arch; 127733965Sjdp char **matching; 127833965Sjdp 127933965Sjdp f = open (archname, O_RDWR, 0); 128033965Sjdp if (f < 0) 128133965Sjdp { 128233965Sjdp bfd_set_error (bfd_error_system_call); 128333965Sjdp bfd_fatal (archname); 128433965Sjdp } 128533965Sjdp 128633965Sjdp arch = bfd_fdopenr (archname, (const char *) NULL, f); 128733965Sjdp if (arch == NULL) 128833965Sjdp bfd_fatal (archname); 128933965Sjdp if (! bfd_check_format_matches (arch, bfd_archive, &matching)) 129033965Sjdp { 129133965Sjdp bfd_nonfatal (archname); 129233965Sjdp if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 129333965Sjdp { 129433965Sjdp list_matching_formats (matching); 129533965Sjdp free (matching); 129633965Sjdp } 129733965Sjdp xexit (1); 129833965Sjdp } 129933965Sjdp 130033965Sjdp if (! bfd_has_map (arch)) 130133965Sjdp fatal ("%s: no archive map to update", archname); 130233965Sjdp 130333965Sjdp bfd_update_armap_timestamp (arch); 130433965Sjdp 130533965Sjdp if (! bfd_close (arch)) 130633965Sjdp bfd_fatal (archname); 130733965Sjdp#endif 130833965Sjdp} 130933965Sjdp 131033965Sjdp/* Things which are interesting to map over all or some of the files: */ 131133965Sjdp 131233965Sjdpstatic void 131333965Sjdpprint_descr (abfd) 131433965Sjdp bfd *abfd; 131533965Sjdp{ 131633965Sjdp print_arelt_descr (stdout, abfd, verbose); 131733965Sjdp} 1318