133965Sjdp/* ar.c - Archive modify and extract. 289857Sobrien Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 3218822Sdim 2001, 2002, 2003, 2004, 2005, 2006, 2007 460484Sobrien Free Software Foundation, Inc. 533965Sjdp 6104834Sobrien This file is part of GNU Binutils. 733965Sjdp 8104834Sobrien This program is free software; you can redistribute it and/or modify 9104834Sobrien it under the terms of the GNU General Public License as published by 10104834Sobrien the Free Software Foundation; either version 2 of the License, or 11104834Sobrien (at your option) any later version. 1233965Sjdp 13104834Sobrien This program is distributed in the hope that it will be useful, 14104834Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 15104834Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16104834Sobrien GNU General Public License for more details. 1733965Sjdp 18104834Sobrien You should have received a copy of the GNU General Public License 19104834Sobrien along with this program; if not, write to the Free Software 20218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2133965Sjdp 2233965Sjdp/* 2333965Sjdp Bugs: should use getopt the way tar does (complete w/optional -) and 2433965Sjdp should have long options too. GNU ar used to check file against filesystem 2533965Sjdp in quick_update and replace operations (would check mtime). Doesn't warn 2633965Sjdp when name truncated. No way to specify pos_end. Error messages should be 27130561Sobrien more consistent. */ 28104834Sobrien 29218822Sdim#include "sysdep.h" 3033965Sjdp#include "bfd.h" 3133965Sjdp#include "libiberty.h" 3233965Sjdp#include "progress.h" 3333965Sjdp#include "aout/ar.h" 3433965Sjdp#include "libbfd.h" 35218822Sdim#include "bucomm.h" 3633965Sjdp#include "arsup.h" 3761843Sobrien#include "filenames.h" 38104834Sobrien#include "binemul.h" 3933965Sjdp#include <sys/stat.h> 4033965Sjdp 4133965Sjdp#ifdef __GO32___ 4233965Sjdp#define EXT_NAME_LEN 3 /* bufflen of addition to name if it's MS-DOS */ 4333965Sjdp#else 4433965Sjdp#define EXT_NAME_LEN 6 /* ditto for *NIX */ 4533965Sjdp#endif 4633965Sjdp 4760484Sobrien/* We need to open files in binary modes on system where that makes a 4860484Sobrien difference. */ 4960484Sobrien#ifndef O_BINARY 5060484Sobrien#define O_BINARY 0 5160484Sobrien#endif 5260484Sobrien 5333965Sjdp/* Kludge declaration from BFD! This is ugly! FIXME! XXX */ 5433965Sjdp 5533965Sjdpstruct ar_hdr * 56130561Sobrien bfd_special_undocumented_glue (bfd * abfd, const char *filename); 5733965Sjdp 5833965Sjdp/* Static declarations */ 5933965Sjdp 60130561Sobrienstatic void mri_emul (void); 61130561Sobrienstatic const char *normalize (const char *, bfd *); 62130561Sobrienstatic void remove_output (void); 63130561Sobrienstatic void map_over_members (bfd *, void (*)(bfd *), char **, int); 64130561Sobrienstatic void print_contents (bfd * member); 65130561Sobrienstatic void delete_members (bfd *, char **files_to_delete); 6633965Sjdp 67130561Sobrienstatic void move_members (bfd *, char **files_to_move); 68130561Sobrienstatic void replace_members 69130561Sobrien (bfd *, char **files_to_replace, bfd_boolean quick); 70130561Sobrienstatic void print_descr (bfd * abfd); 71130561Sobrienstatic void write_archive (bfd *); 72218822Sdimstatic int ranlib_only (const char *archname); 73218822Sdimstatic int ranlib_touch (const char *archname); 74130561Sobrienstatic void usage (int); 7533965Sjdp 7633965Sjdp/** Globals and flags */ 7733965Sjdp 78218822Sdimstatic int mri_mode; 7933965Sjdp 8033965Sjdp/* This flag distinguishes between ar and ranlib: 8133965Sjdp 1 means this is 'ranlib'; 0 means this is 'ar'. 8233965Sjdp -1 means if we should use argv[0] to decide. */ 8333965Sjdpextern int is_ranlib; 8433965Sjdp 8533965Sjdp/* Nonzero means don't warn about creating the archive file if necessary. */ 8633965Sjdpint silent_create = 0; 8733965Sjdp 8833965Sjdp/* Nonzero means describe each action performed. */ 8933965Sjdpint verbose = 0; 9033965Sjdp 9133965Sjdp/* Nonzero means preserve dates of members when extracting them. */ 9233965Sjdpint preserve_dates = 0; 9333965Sjdp 9433965Sjdp/* Nonzero means don't replace existing members whose dates are more recent 9533965Sjdp than the corresponding files. */ 9633965Sjdpint newer_only = 0; 9733965Sjdp 9833965Sjdp/* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF 9933965Sjdp member). -1 means we've been explicitly asked to not write a symbol table; 100130561Sobrien +1 means we've been explicitly asked to write it; 10133965Sjdp 0 is the default. 10233965Sjdp Traditionally, the default in BSD has been to not write the table. 10333965Sjdp However, for POSIX.2 compliance the default is now to write a symbol table 10433965Sjdp if any of the members are object files. */ 10533965Sjdpint write_armap = 0; 10633965Sjdp 10733965Sjdp/* Nonzero means it's the name of an existing member; position new or moved 10833965Sjdp files with respect to this one. */ 10933965Sjdpchar *posname = NULL; 11033965Sjdp 11133965Sjdp/* Sez how to use `posname': pos_before means position before that member. 11233965Sjdp pos_after means position after that member. pos_end means always at end. 11333965Sjdp pos_default means default appropriately. For the latter two, `posname' 11433965Sjdp should also be zero. */ 11533965Sjdpenum pos 11633965Sjdp { 11733965Sjdp pos_default, pos_before, pos_after, pos_end 11833965Sjdp } postype = pos_default; 11933965Sjdp 12033965Sjdpstatic bfd ** 121130561Sobrienget_pos_bfd (bfd **, enum pos, const char *); 12233965Sjdp 123130561Sobrien/* For extract/delete only. If COUNTED_NAME_MODE is TRUE, we only 12460484Sobrien extract the COUNTED_NAME_COUNTER instance of that name. */ 125130561Sobrienstatic bfd_boolean counted_name_mode = 0; 12660484Sobrienstatic int counted_name_counter = 0; 12760484Sobrien 12833965Sjdp/* Whether to truncate names of files stored in the archive. */ 129130561Sobrienstatic bfd_boolean ar_truncate = FALSE; 13033965Sjdp 13160484Sobrien/* Whether to use a full file name match when searching an archive. 13260484Sobrien This is convenient for archives created by the Microsoft lib 13360484Sobrien program. */ 134130561Sobrienstatic bfd_boolean full_pathname = FALSE; 13560484Sobrien 13633965Sjdpint interactive = 0; 13733965Sjdp 13833965Sjdpstatic void 139130561Sobrienmri_emul (void) 14033965Sjdp{ 14133965Sjdp interactive = isatty (fileno (stdin)); 14233965Sjdp yyparse (); 14333965Sjdp} 14433965Sjdp 14533965Sjdp/* If COUNT is 0, then FUNCTION is called once on each entry. If nonzero, 14633965Sjdp COUNT is the length of the FILES chain; FUNCTION is called on each entry 14733965Sjdp whose name matches one in FILES. */ 14833965Sjdp 14933965Sjdpstatic void 150130561Sobrienmap_over_members (bfd *arch, void (*function)(bfd *), char **files, int count) 15133965Sjdp{ 15233965Sjdp bfd *head; 15360484Sobrien int match_count; 15433965Sjdp 15533965Sjdp if (count == 0) 15633965Sjdp { 157218822Sdim for (head = arch->archive_next; head; head = head->archive_next) 15833965Sjdp { 15933965Sjdp PROGRESS (1); 16033965Sjdp function (head); 16133965Sjdp } 16233965Sjdp return; 16333965Sjdp } 16460484Sobrien 16533965Sjdp /* This may appear to be a baroque way of accomplishing what we want. 16633965Sjdp However we have to iterate over the filenames in order to notice where 16733965Sjdp a filename is requested but does not exist in the archive. Ditto 16833965Sjdp mapping over each file each time -- we want to hack multiple 16933965Sjdp references. */ 17033965Sjdp 17133965Sjdp for (; count > 0; files++, count--) 17233965Sjdp { 173130561Sobrien bfd_boolean found = FALSE; 17433965Sjdp 17560484Sobrien match_count = 0; 176218822Sdim for (head = arch->archive_next; head; head = head->archive_next) 17733965Sjdp { 17833965Sjdp PROGRESS (1); 17933965Sjdp if (head->filename == NULL) 18033965Sjdp { 18133965Sjdp /* Some archive formats don't get the filenames filled in 18233965Sjdp until the elements are opened. */ 18333965Sjdp struct stat buf; 18433965Sjdp bfd_stat_arch_elt (head, &buf); 18533965Sjdp } 18633965Sjdp if ((head->filename != NULL) && 18761843Sobrien (!FILENAME_CMP (normalize (*files, arch), head->filename))) 18833965Sjdp { 18960484Sobrien ++match_count; 19060484Sobrien if (counted_name_mode 191104834Sobrien && match_count != counted_name_counter) 19260484Sobrien { 19360484Sobrien /* Counting, and didn't match on count; go on to the 19460484Sobrien next one. */ 19560484Sobrien continue; 19660484Sobrien } 19760484Sobrien 198130561Sobrien found = TRUE; 19933965Sjdp function (head); 20033965Sjdp } 20133965Sjdp } 20233965Sjdp if (!found) 20360484Sobrien /* xgettext:c-format */ 20460484Sobrien fprintf (stderr, _("no entry %s in archive\n"), *files); 20533965Sjdp } 20633965Sjdp} 20733965Sjdp 208130561Sobrienbfd_boolean operation_alters_arch = FALSE; 20933965Sjdp 21033965Sjdpstatic void 211130561Sobrienusage (int help) 21233965Sjdp{ 21333965Sjdp FILE *s; 21433965Sjdp 21533965Sjdp s = help ? stdout : stderr; 216104834Sobrien 21733965Sjdp if (! is_ranlib) 21860484Sobrien { 21960484Sobrien /* xgettext:c-format */ 220104834Sobrien fprintf (s, _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"), 22160484Sobrien program_name); 22260484Sobrien /* xgettext:c-format */ 22360484Sobrien fprintf (s, _(" %s -M [<mri-script]\n"), program_name); 22460484Sobrien fprintf (s, _(" commands:\n")); 22560484Sobrien fprintf (s, _(" d - delete file(s) from the archive\n")); 22660484Sobrien fprintf (s, _(" m[ab] - move file(s) in the archive\n")); 22760484Sobrien fprintf (s, _(" p - print file(s) found in the archive\n")); 22860484Sobrien fprintf (s, _(" q[f] - quick append file(s) to the archive\n")); 22960484Sobrien fprintf (s, _(" r[ab][f][u] - replace existing or insert new file(s) into the archive\n")); 23060484Sobrien fprintf (s, _(" t - display contents of archive\n")); 23160484Sobrien fprintf (s, _(" x[o] - extract file(s) from the archive\n")); 23260484Sobrien fprintf (s, _(" command specific modifiers:\n")); 23360484Sobrien fprintf (s, _(" [a] - put file(s) after [member-name]\n")); 23460484Sobrien fprintf (s, _(" [b] - put file(s) before [member-name] (same as [i])\n")); 23560484Sobrien fprintf (s, _(" [N] - use instance [count] of name\n")); 23660484Sobrien fprintf (s, _(" [f] - truncate inserted file names\n")); 23760484Sobrien fprintf (s, _(" [P] - use full path names when matching\n")); 23860484Sobrien fprintf (s, _(" [o] - preserve original dates\n")); 23960484Sobrien fprintf (s, _(" [u] - only replace files that are newer than current archive contents\n")); 24060484Sobrien fprintf (s, _(" generic modifiers:\n")); 24160484Sobrien fprintf (s, _(" [c] - do not warn if the library had to be created\n")); 24260484Sobrien fprintf (s, _(" [s] - create an archive index (cf. ranlib)\n")); 24360484Sobrien fprintf (s, _(" [S] - do not build a symbol table\n")); 24460484Sobrien fprintf (s, _(" [v] - be verbose\n")); 24560484Sobrien fprintf (s, _(" [V] - display the version number\n")); 246218822Sdim fprintf (s, _(" @<file> - read options from <file>\n")); 247218822Sdim 248104834Sobrien ar_emul_usage (s); 24960484Sobrien } 25033965Sjdp else 25189857Sobrien { 252104834Sobrien /* xgettext:c-format */ 25389857Sobrien fprintf (s, _("Usage: %s [options] archive\n"), program_name); 25489857Sobrien fprintf (s, _(" Generate an index to speed access to archives\n")); 25589857Sobrien fprintf (s, _(" The options are:\n\ 256218822Sdim @<file> Read options from <file>\n\ 25789857Sobrien -h --help Print this help message\n\ 25889857Sobrien -V --version Print version information\n")); 25989857Sobrien } 26033965Sjdp 261218822Sdim list_supported_targets (program_name, s); 26233965Sjdp 263218822Sdim if (REPORT_BUGS_TO[0] && help) 26460484Sobrien fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); 26533965Sjdp 26633965Sjdp xexit (help ? 0 : 1); 26733965Sjdp} 26833965Sjdp 26933965Sjdp/* Normalize a file name specified on the command line into a file 27033965Sjdp name which we will use in an archive. */ 27133965Sjdp 27233965Sjdpstatic const char * 273130561Sobriennormalize (const char *file, bfd *abfd) 27433965Sjdp{ 27533965Sjdp const char *filename; 27633965Sjdp 27760484Sobrien if (full_pathname) 27860484Sobrien return file; 27960484Sobrien 28033965Sjdp filename = strrchr (file, '/'); 28161843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM 28261843Sobrien { 28361843Sobrien /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ 28461843Sobrien char *bslash = strrchr (file, '\\'); 28577298Sobrien if (filename == NULL || (bslash != NULL && bslash > filename)) 28661843Sobrien filename = bslash; 28761843Sobrien if (filename == NULL && file[0] != '\0' && file[1] == ':') 28877298Sobrien filename = file + 1; 28961843Sobrien } 29061843Sobrien#endif 29133965Sjdp if (filename != (char *) NULL) 29233965Sjdp filename++; 29333965Sjdp else 29433965Sjdp filename = file; 29533965Sjdp 29633965Sjdp if (ar_truncate 29733965Sjdp && abfd != NULL 29833965Sjdp && strlen (filename) > abfd->xvec->ar_max_namelen) 29933965Sjdp { 30033965Sjdp char *s; 30133965Sjdp 30233965Sjdp /* Space leak. */ 30333965Sjdp s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1); 30433965Sjdp memcpy (s, filename, abfd->xvec->ar_max_namelen); 30533965Sjdp s[abfd->xvec->ar_max_namelen] = '\0'; 30633965Sjdp filename = s; 30733965Sjdp } 30833965Sjdp 30933965Sjdp return filename; 31033965Sjdp} 31133965Sjdp 31233965Sjdp/* Remove any output file. This is only called via xatexit. */ 31333965Sjdp 31460484Sobrienstatic const char *output_filename = NULL; 31533965Sjdpstatic FILE *output_file = NULL; 31633965Sjdpstatic bfd *output_bfd = NULL; 31733965Sjdp 31833965Sjdpstatic void 319130561Sobrienremove_output (void) 32033965Sjdp{ 32133965Sjdp if (output_filename != NULL) 32233965Sjdp { 323130561Sobrien if (output_bfd != NULL) 324130561Sobrien bfd_cache_close (output_bfd); 32533965Sjdp if (output_file != NULL) 32633965Sjdp fclose (output_file); 327218822Sdim unlink_if_ordinary (output_filename); 32833965Sjdp } 32933965Sjdp} 33033965Sjdp 33133965Sjdp/* The option parsing should be in its own function. 33233965Sjdp It will be when I have getopt working. */ 33333965Sjdp 334130561Sobrienint main (int, char **); 33589857Sobrien 33633965Sjdpint 337130561Sobrienmain (int argc, char **argv) 33833965Sjdp{ 33933965Sjdp char *arg_ptr; 34033965Sjdp char c; 34133965Sjdp enum 34233965Sjdp { 34333965Sjdp none = 0, delete, replace, print_table, 34433965Sjdp print_files, extract, move, quick_append 34533965Sjdp } operation = none; 34633965Sjdp int arg_index; 34733965Sjdp char **files; 34860484Sobrien int file_count; 34933965Sjdp char *inarch_filename; 35033965Sjdp int show_version; 351104834Sobrien int i; 352130561Sobrien int do_posix = 0; 35333965Sjdp 35460484Sobrien#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 35560484Sobrien setlocale (LC_MESSAGES, ""); 35660484Sobrien#endif 35789857Sobrien#if defined (HAVE_SETLOCALE) 35889857Sobrien setlocale (LC_CTYPE, ""); 35989857Sobrien#endif 36060484Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 36160484Sobrien textdomain (PACKAGE); 36260484Sobrien 36333965Sjdp program_name = argv[0]; 36433965Sjdp xmalloc_set_program_name (program_name); 36533965Sjdp 366218822Sdim expandargv (&argc, &argv); 367218822Sdim 36833965Sjdp if (is_ranlib < 0) 36933965Sjdp { 37033965Sjdp char *temp; 37133965Sjdp 37233965Sjdp temp = strrchr (program_name, '/'); 37361843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM 374104834Sobrien { 375104834Sobrien /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ 376104834Sobrien char *bslash = strrchr (program_name, '\\'); 377104834Sobrien if (temp == NULL || (bslash != NULL && bslash > temp)) 378104834Sobrien temp = bslash; 379104834Sobrien if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':') 380104834Sobrien temp = program_name + 1; 381104834Sobrien } 38261843Sobrien#endif 38333965Sjdp if (temp == NULL) 38433965Sjdp temp = program_name; 38533965Sjdp else 38633965Sjdp ++temp; 38733965Sjdp if (strlen (temp) >= 6 38861843Sobrien && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0) 38933965Sjdp is_ranlib = 1; 39033965Sjdp else 39133965Sjdp is_ranlib = 0; 39233965Sjdp } 39333965Sjdp 39433965Sjdp if (argc > 1 && argv[1][0] == '-') 39533965Sjdp { 39633965Sjdp if (strcmp (argv[1], "--help") == 0) 39733965Sjdp usage (1); 39833965Sjdp else if (strcmp (argv[1], "--version") == 0) 39933965Sjdp { 40033965Sjdp if (is_ranlib) 40133965Sjdp print_version ("ranlib"); 40233965Sjdp else 40333965Sjdp print_version ("ar"); 40433965Sjdp } 40533965Sjdp } 40633965Sjdp 40733965Sjdp START_PROGRESS (program_name, 0); 40833965Sjdp 40933965Sjdp bfd_init (); 41033965Sjdp set_default_bfd_target (); 41133965Sjdp 41233965Sjdp show_version = 0; 41333965Sjdp 41433965Sjdp xatexit (remove_output); 41533965Sjdp 416104834Sobrien for (i = 1; i < argc; i++) 417104834Sobrien if (! ar_emul_parse_arg (argv[i])) 418104834Sobrien break; 419104834Sobrien argv += (i - 1); 420104834Sobrien argc -= (i - 1); 42177298Sobrien 42233965Sjdp if (is_ranlib) 42333965Sjdp { 424218822Sdim int status = 0; 425130561Sobrien bfd_boolean touch = FALSE; 42633965Sjdp 42789857Sobrien if (argc < 2 42889857Sobrien || strcmp (argv[1], "--help") == 0 42989857Sobrien || strcmp (argv[1], "-h") == 0 43089857Sobrien || strcmp (argv[1], "-H") == 0) 43133965Sjdp usage (0); 43233965Sjdp if (strcmp (argv[1], "-V") == 0 43333965Sjdp || strcmp (argv[1], "-v") == 0 434218822Sdim || CONST_STRNEQ (argv[1], "--v")) 43533965Sjdp print_version ("ranlib"); 43633965Sjdp arg_index = 1; 43733965Sjdp if (strcmp (argv[1], "-t") == 0) 43833965Sjdp { 43933965Sjdp ++arg_index; 440130561Sobrien touch = TRUE; 44133965Sjdp } 44233965Sjdp while (arg_index < argc) 44333965Sjdp { 44433965Sjdp if (! touch) 445218822Sdim status |= ranlib_only (argv[arg_index]); 44633965Sjdp else 447218822Sdim status |= ranlib_touch (argv[arg_index]); 44833965Sjdp ++arg_index; 44933965Sjdp } 450218822Sdim xexit (status); 45133965Sjdp } 45233965Sjdp 45333965Sjdp if (argc == 2 && strcmp (argv[1], "-M") == 0) 45433965Sjdp { 45533965Sjdp mri_emul (); 45633965Sjdp xexit (0); 45733965Sjdp } 45833965Sjdp 45933965Sjdp if (argc < 2) 46033965Sjdp usage (0); 46133965Sjdp 462130561Sobrien arg_index = 1; 463130561Sobrien arg_ptr = argv[arg_index]; 46433965Sjdp 46533965Sjdp if (*arg_ptr == '-') 466130561Sobrien { 467130561Sobrien /* When the first option starts with '-' we support POSIX-compatible 468130561Sobrien option parsing. */ 469130561Sobrien do_posix = 1; 470130561Sobrien ++arg_ptr; /* compatibility */ 471130561Sobrien } 47233965Sjdp 473130561Sobrien do 47433965Sjdp { 475130561Sobrien while ((c = *arg_ptr++) != '\0') 47633965Sjdp { 47733965Sjdp switch (c) 47833965Sjdp { 47933965Sjdp case 'd': 48033965Sjdp case 'm': 48133965Sjdp case 'p': 48233965Sjdp case 'q': 48333965Sjdp case 'r': 48433965Sjdp case 't': 48533965Sjdp case 'x': 486130561Sobrien if (operation != none) 487130561Sobrien fatal (_("two different operation options specified")); 488130561Sobrien switch (c) 489130561Sobrien { 490130561Sobrien case 'd': 491130561Sobrien operation = delete; 492130561Sobrien operation_alters_arch = TRUE; 493130561Sobrien break; 494130561Sobrien case 'm': 495130561Sobrien operation = move; 496130561Sobrien operation_alters_arch = TRUE; 497130561Sobrien break; 498130561Sobrien case 'p': 499130561Sobrien operation = print_files; 500130561Sobrien break; 501130561Sobrien case 'q': 502130561Sobrien operation = quick_append; 503130561Sobrien operation_alters_arch = TRUE; 504130561Sobrien break; 505130561Sobrien case 'r': 506130561Sobrien operation = replace; 507130561Sobrien operation_alters_arch = TRUE; 508130561Sobrien break; 509130561Sobrien case 't': 510130561Sobrien operation = print_table; 511130561Sobrien break; 512130561Sobrien case 'x': 513130561Sobrien operation = extract; 514130561Sobrien break; 515130561Sobrien } 516130561Sobrien case 'l': 51733965Sjdp break; 518130561Sobrien case 'c': 519130561Sobrien silent_create = 1; 520130561Sobrien break; 521130561Sobrien case 'o': 522130561Sobrien preserve_dates = 1; 523130561Sobrien break; 524130561Sobrien case 'V': 525130561Sobrien show_version = TRUE; 526130561Sobrien break; 527130561Sobrien case 's': 528130561Sobrien write_armap = 1; 529130561Sobrien break; 530130561Sobrien case 'S': 531130561Sobrien write_armap = -1; 532130561Sobrien break; 533130561Sobrien case 'u': 534130561Sobrien newer_only = 1; 535130561Sobrien break; 536130561Sobrien case 'v': 537130561Sobrien verbose = 1; 538130561Sobrien break; 539130561Sobrien case 'a': 540130561Sobrien postype = pos_after; 541130561Sobrien break; 542130561Sobrien case 'b': 543130561Sobrien postype = pos_before; 544130561Sobrien break; 545130561Sobrien case 'i': 546130561Sobrien postype = pos_before; 547130561Sobrien break; 548130561Sobrien case 'M': 549130561Sobrien mri_mode = 1; 550130561Sobrien break; 551130561Sobrien case 'N': 552130561Sobrien counted_name_mode = TRUE; 553130561Sobrien break; 554130561Sobrien case 'f': 555130561Sobrien ar_truncate = TRUE; 556130561Sobrien break; 557130561Sobrien case 'P': 558130561Sobrien full_pathname = TRUE; 559130561Sobrien break; 560130561Sobrien default: 561130561Sobrien /* xgettext:c-format */ 562130561Sobrien non_fatal (_("illegal option -- %c"), c); 563130561Sobrien usage (0); 56433965Sjdp } 56533965Sjdp } 566130561Sobrien 567130561Sobrien /* With POSIX-compatible option parsing continue with the next 568130561Sobrien argument if it starts with '-'. */ 569130561Sobrien if (do_posix && arg_index + 1 < argc && argv[arg_index + 1][0] == '-') 570130561Sobrien arg_ptr = argv[++arg_index] + 1; 571130561Sobrien else 572130561Sobrien do_posix = 0; 57333965Sjdp } 574130561Sobrien while (do_posix); 57533965Sjdp 57633965Sjdp if (show_version) 57733965Sjdp print_version ("ar"); 57833965Sjdp 579130561Sobrien ++arg_index; 580130561Sobrien if (arg_index >= argc) 58133965Sjdp usage (0); 58233965Sjdp 58333965Sjdp if (mri_mode) 58433965Sjdp { 58533965Sjdp mri_emul (); 58633965Sjdp } 58733965Sjdp else 58833965Sjdp { 58933965Sjdp bfd *arch; 59033965Sjdp 591218822Sdim /* We don't use do_quick_append any more. Too many systems 592218822Sdim expect ar to always rebuild the symbol table even when q is 593218822Sdim used. */ 594218822Sdim 59533965Sjdp /* We can't write an armap when using ar q, so just do ar r 59633965Sjdp instead. */ 59733965Sjdp if (operation == quick_append && write_armap) 59833965Sjdp operation = replace; 59933965Sjdp 60033965Sjdp if ((operation == none || operation == print_table) 60133965Sjdp && write_armap == 1) 602218822Sdim xexit (ranlib_only (argv[arg_index])); 60333965Sjdp 60433965Sjdp if (operation == none) 60560484Sobrien fatal (_("no operation specified")); 60633965Sjdp 60733965Sjdp if (newer_only && operation != replace) 60860484Sobrien fatal (_("`u' is only meaningful with the `r' option.")); 60933965Sjdp 61033965Sjdp if (postype != pos_default) 61133965Sjdp posname = argv[arg_index++]; 61233965Sjdp 613104834Sobrien if (counted_name_mode) 61460484Sobrien { 615104834Sobrien if (operation != extract && operation != delete) 61660484Sobrien fatal (_("`N' is only meaningful with the `x' and `d' options.")); 61760484Sobrien counted_name_counter = atoi (argv[arg_index++]); 618104834Sobrien if (counted_name_counter <= 0) 61960484Sobrien fatal (_("Value for `N' must be positive.")); 62060484Sobrien } 62160484Sobrien 62233965Sjdp inarch_filename = argv[arg_index++]; 62333965Sjdp 62433965Sjdp files = arg_index < argc ? argv + arg_index : NULL; 62560484Sobrien file_count = argc - arg_index; 62633965Sjdp 62733965Sjdp arch = open_inarch (inarch_filename, 62833965Sjdp files == NULL ? (char *) NULL : files[0]); 62933965Sjdp 63033965Sjdp switch (operation) 63133965Sjdp { 63233965Sjdp case print_table: 63360484Sobrien map_over_members (arch, print_descr, files, file_count); 63433965Sjdp break; 63533965Sjdp 63633965Sjdp case print_files: 63760484Sobrien map_over_members (arch, print_contents, files, file_count); 63833965Sjdp break; 63933965Sjdp 64033965Sjdp case extract: 64160484Sobrien map_over_members (arch, extract_file, files, file_count); 64233965Sjdp break; 64333965Sjdp 64433965Sjdp case delete: 64533965Sjdp if (files != NULL) 64633965Sjdp delete_members (arch, files); 64760484Sobrien else 64860484Sobrien output_filename = NULL; 64933965Sjdp break; 65033965Sjdp 65133965Sjdp case move: 65233965Sjdp if (files != NULL) 65333965Sjdp move_members (arch, files); 65460484Sobrien else 65560484Sobrien output_filename = NULL; 65633965Sjdp break; 65733965Sjdp 65833965Sjdp case replace: 65933965Sjdp case quick_append: 66033965Sjdp if (files != NULL || write_armap > 0) 66133965Sjdp replace_members (arch, files, operation == quick_append); 66260484Sobrien else 66360484Sobrien output_filename = NULL; 66433965Sjdp break; 66533965Sjdp 66633965Sjdp /* Shouldn't happen! */ 66733965Sjdp default: 66860484Sobrien /* xgettext:c-format */ 66960484Sobrien fatal (_("internal error -- this option not implemented")); 67033965Sjdp } 67133965Sjdp } 67233965Sjdp 67333965Sjdp END_PROGRESS (program_name); 67433965Sjdp 67533965Sjdp xexit (0); 67633965Sjdp return 0; 67733965Sjdp} 67833965Sjdp 67933965Sjdpbfd * 680130561Sobrienopen_inarch (const char *archive_filename, const char *file) 68133965Sjdp{ 68233965Sjdp const char *target; 68333965Sjdp bfd **last_one; 68433965Sjdp bfd *next_one; 68533965Sjdp struct stat sbuf; 68633965Sjdp bfd *arch; 68733965Sjdp char **matching; 68833965Sjdp 68933965Sjdp bfd_set_error (bfd_error_no_error); 69033965Sjdp 69133965Sjdp target = NULL; 69233965Sjdp 69333965Sjdp if (stat (archive_filename, &sbuf) != 0) 69433965Sjdp { 69561843Sobrien#if !defined(__GO32__) || defined(__DJGPP__) 69633965Sjdp 69761843Sobrien /* FIXME: I don't understand why this fragment was ifndef'ed 69861843Sobrien away for __GO32__; perhaps it was in the days of DJGPP v1.x. 69961843Sobrien stat() works just fine in v2.x, so I think this should be 70061843Sobrien removed. For now, I enable it for DJGPP v2. -- EZ. */ 70161843Sobrien 70233965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why 70361843Sobrien stat() is wrong ... think it's buried in GO32's IDT - Jax */ 70433965Sjdp if (errno != ENOENT) 70533965Sjdp bfd_fatal (archive_filename); 70633965Sjdp#endif 70733965Sjdp 70833965Sjdp if (!operation_alters_arch) 70933965Sjdp { 71033965Sjdp fprintf (stderr, "%s: ", program_name); 71133965Sjdp perror (archive_filename); 71233965Sjdp maybequit (); 71333965Sjdp return NULL; 71433965Sjdp } 71533965Sjdp 71633965Sjdp /* Try to figure out the target to use for the archive from the 71733965Sjdp first object on the list. */ 71833965Sjdp if (file != NULL) 71933965Sjdp { 72033965Sjdp bfd *obj; 72133965Sjdp 72233965Sjdp obj = bfd_openr (file, NULL); 72333965Sjdp if (obj != NULL) 72433965Sjdp { 72533965Sjdp if (bfd_check_format (obj, bfd_object)) 72633965Sjdp target = bfd_get_target (obj); 72733965Sjdp (void) bfd_close (obj); 72833965Sjdp } 72933965Sjdp } 73033965Sjdp 73133965Sjdp /* Create an empty archive. */ 73233965Sjdp arch = bfd_openw (archive_filename, target); 73333965Sjdp if (arch == NULL 73433965Sjdp || ! bfd_set_format (arch, bfd_archive) 73533965Sjdp || ! bfd_close (arch)) 73633965Sjdp bfd_fatal (archive_filename); 737130561Sobrien else if (!silent_create) 738130561Sobrien non_fatal (_("creating %s"), archive_filename); 73960484Sobrien 74060484Sobrien /* If we die creating a new archive, don't leave it around. */ 74160484Sobrien output_filename = archive_filename; 74233965Sjdp } 74333965Sjdp 74433965Sjdp arch = bfd_openr (archive_filename, target); 74533965Sjdp if (arch == NULL) 74633965Sjdp { 74733965Sjdp bloser: 74833965Sjdp bfd_fatal (archive_filename); 74933965Sjdp } 75033965Sjdp 75133965Sjdp if (! bfd_check_format_matches (arch, bfd_archive, &matching)) 75233965Sjdp { 75333965Sjdp bfd_nonfatal (archive_filename); 75433965Sjdp if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 75533965Sjdp { 75633965Sjdp list_matching_formats (matching); 75733965Sjdp free (matching); 75833965Sjdp } 75933965Sjdp xexit (1); 76033965Sjdp } 76133965Sjdp 762218822Sdim last_one = &(arch->archive_next); 76333965Sjdp /* Read all the contents right away, regardless. */ 76433965Sjdp for (next_one = bfd_openr_next_archived_file (arch, NULL); 76533965Sjdp next_one; 76633965Sjdp next_one = bfd_openr_next_archived_file (arch, next_one)) 76733965Sjdp { 76833965Sjdp PROGRESS (1); 76933965Sjdp *last_one = next_one; 770218822Sdim last_one = &next_one->archive_next; 77133965Sjdp } 77233965Sjdp *last_one = (bfd *) NULL; 77333965Sjdp if (bfd_get_error () != bfd_error_no_more_archived_files) 77433965Sjdp goto bloser; 77533965Sjdp return arch; 77633965Sjdp} 77733965Sjdp 77833965Sjdpstatic void 779130561Sobrienprint_contents (bfd *abfd) 78033965Sjdp{ 781218822Sdim size_t ncopied = 0; 78233965Sjdp char *cbuf = xmalloc (BUFSIZE); 78333965Sjdp struct stat buf; 784218822Sdim size_t size; 78533965Sjdp if (bfd_stat_arch_elt (abfd, &buf) != 0) 78660484Sobrien /* xgettext:c-format */ 78760484Sobrien fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); 78833965Sjdp 78933965Sjdp if (verbose) 79077298Sobrien /* xgettext:c-format */ 791130561Sobrien printf (_("\n<%s>\n\n"), bfd_get_filename (abfd)); 79233965Sjdp 79389857Sobrien bfd_seek (abfd, (file_ptr) 0, SEEK_SET); 79433965Sjdp 79533965Sjdp size = buf.st_size; 79633965Sjdp while (ncopied < size) 79733965Sjdp { 79833965Sjdp 799218822Sdim size_t nread; 800218822Sdim size_t tocopy = size - ncopied; 80133965Sjdp if (tocopy > BUFSIZE) 80233965Sjdp tocopy = BUFSIZE; 80333965Sjdp 80489857Sobrien nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd); 80533965Sjdp if (nread != tocopy) 80660484Sobrien /* xgettext:c-format */ 80760484Sobrien fatal (_("%s is not a valid archive"), 80833965Sjdp bfd_get_filename (bfd_my_archive (abfd))); 809218822Sdim 810218822Sdim /* fwrite in mingw32 may return int instead of size_t. Cast the 811218822Sdim return value to size_t to avoid comparison between signed and 812218822Sdim unsigned values. */ 813218822Sdim if ((size_t) fwrite (cbuf, 1, nread, stdout) != nread) 814218822Sdim fatal ("stdout: %s", strerror (errno)); 81533965Sjdp ncopied += tocopy; 81633965Sjdp } 81733965Sjdp free (cbuf); 81833965Sjdp} 81933965Sjdp 82033965Sjdp/* Extract a member of the archive into its own file. 82133965Sjdp 82233965Sjdp We defer opening the new file until after we have read a BUFSIZ chunk of the 82333965Sjdp old one, since we know we have just read the archive header for the old 82433965Sjdp one. Since most members are shorter than BUFSIZ, this means we will read 82533965Sjdp the old header, read the old data, write a new inode for the new file, and 82633965Sjdp write the new data, and be done. This 'optimization' is what comes from 82733965Sjdp sitting next to a bare disk and hearing it every time it seeks. -- Gnu 82833965Sjdp Gilmore */ 82933965Sjdp 83033965Sjdpvoid 831130561Sobrienextract_file (bfd *abfd) 83233965Sjdp{ 83333965Sjdp FILE *ostream; 83433965Sjdp char *cbuf = xmalloc (BUFSIZE); 835218822Sdim size_t nread, tocopy; 836218822Sdim size_t ncopied = 0; 837218822Sdim size_t size; 83833965Sjdp struct stat buf; 839104834Sobrien 84033965Sjdp if (bfd_stat_arch_elt (abfd, &buf) != 0) 84160484Sobrien /* xgettext:c-format */ 84260484Sobrien fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); 84333965Sjdp size = buf.st_size; 84433965Sjdp 84533965Sjdp if (verbose) 84633965Sjdp printf ("x - %s\n", bfd_get_filename (abfd)); 84733965Sjdp 84889857Sobrien bfd_seek (abfd, (file_ptr) 0, SEEK_SET); 84933965Sjdp 85060484Sobrien ostream = NULL; 85133965Sjdp if (size == 0) 85233965Sjdp { 85333965Sjdp /* Seems like an abstraction violation, eh? Well it's OK! */ 85433965Sjdp output_filename = bfd_get_filename (abfd); 85533965Sjdp 85633965Sjdp ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); 85760484Sobrien if (ostream == NULL) 85833965Sjdp { 85933965Sjdp perror (bfd_get_filename (abfd)); 86033965Sjdp xexit (1); 86133965Sjdp } 86233965Sjdp 86333965Sjdp output_file = ostream; 86433965Sjdp } 86533965Sjdp else 86633965Sjdp while (ncopied < size) 86733965Sjdp { 86833965Sjdp tocopy = size - ncopied; 86933965Sjdp if (tocopy > BUFSIZE) 87033965Sjdp tocopy = BUFSIZE; 87133965Sjdp 87289857Sobrien nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd); 87333965Sjdp if (nread != tocopy) 87460484Sobrien /* xgettext:c-format */ 87560484Sobrien fatal (_("%s is not a valid archive"), 87633965Sjdp bfd_get_filename (bfd_my_archive (abfd))); 87733965Sjdp 87833965Sjdp /* See comment above; this saves disk arm motion */ 87960484Sobrien if (ostream == NULL) 88033965Sjdp { 88133965Sjdp /* Seems like an abstraction violation, eh? Well it's OK! */ 88233965Sjdp output_filename = bfd_get_filename (abfd); 88333965Sjdp 88433965Sjdp ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); 88560484Sobrien if (ostream == NULL) 88633965Sjdp { 88733965Sjdp perror (bfd_get_filename (abfd)); 88833965Sjdp xexit (1); 88933965Sjdp } 89033965Sjdp 89133965Sjdp output_file = ostream; 89233965Sjdp } 893218822Sdim 894218822Sdim /* fwrite in mingw32 may return int instead of size_t. Cast 895218822Sdim the return value to size_t to avoid comparison between 896218822Sdim signed and unsigned values. */ 897218822Sdim if ((size_t) fwrite (cbuf, 1, nread, ostream) != nread) 898218822Sdim fatal ("%s: %s", output_filename, strerror (errno)); 89933965Sjdp ncopied += tocopy; 90033965Sjdp } 90133965Sjdp 90260484Sobrien if (ostream != NULL) 90360484Sobrien fclose (ostream); 90433965Sjdp 90533965Sjdp output_file = NULL; 90633965Sjdp output_filename = NULL; 90733965Sjdp 90833965Sjdp chmod (bfd_get_filename (abfd), buf.st_mode); 90933965Sjdp 91033965Sjdp if (preserve_dates) 91133965Sjdp { 912218822Sdim /* Set access time to modification time. Only st_mtime is 913218822Sdim initialized by bfd_stat_arch_elt. */ 914218822Sdim buf.st_atime = buf.st_mtime; 915218822Sdim set_times (bfd_get_filename (abfd), &buf); 91633965Sjdp } 91733965Sjdp 918218822Sdim free (cbuf); 91933965Sjdp} 92033965Sjdp 92133965Sjdpstatic void 922130561Sobrienwrite_archive (bfd *iarch) 92333965Sjdp{ 92433965Sjdp bfd *obfd; 92533965Sjdp char *old_name, *new_name; 926218822Sdim bfd *contents_head = iarch->archive_next; 92733965Sjdp 92833965Sjdp old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1); 92933965Sjdp strcpy (old_name, bfd_get_filename (iarch)); 93033965Sjdp new_name = make_tempname (old_name); 93133965Sjdp 932218822Sdim if (new_name == NULL) 933218822Sdim bfd_fatal ("could not create temporary file whilst writing archive"); 934218822Sdim 93533965Sjdp output_filename = new_name; 93633965Sjdp 93733965Sjdp obfd = bfd_openw (new_name, bfd_get_target (iarch)); 93833965Sjdp 93933965Sjdp if (obfd == NULL) 94033965Sjdp bfd_fatal (old_name); 94133965Sjdp 94233965Sjdp output_bfd = obfd; 94333965Sjdp 94433965Sjdp bfd_set_format (obfd, bfd_archive); 94533965Sjdp 94633965Sjdp /* Request writing the archive symbol table unless we've 94733965Sjdp been explicitly requested not to. */ 94833965Sjdp obfd->has_armap = write_armap >= 0; 94933965Sjdp 95033965Sjdp if (ar_truncate) 95133965Sjdp { 95233965Sjdp /* This should really use bfd_set_file_flags, but that rejects 95333965Sjdp archives. */ 95433965Sjdp obfd->flags |= BFD_TRADITIONAL_FORMAT; 95533965Sjdp } 95633965Sjdp 957130561Sobrien if (!bfd_set_archive_head (obfd, contents_head)) 95833965Sjdp bfd_fatal (old_name); 95933965Sjdp 96033965Sjdp if (!bfd_close (obfd)) 96133965Sjdp bfd_fatal (old_name); 96233965Sjdp 96333965Sjdp output_bfd = NULL; 96433965Sjdp output_filename = NULL; 96533965Sjdp 96633965Sjdp /* We don't care if this fails; we might be creating the archive. */ 96733965Sjdp bfd_close (iarch); 96833965Sjdp 96960484Sobrien if (smart_rename (new_name, old_name, 0) != 0) 97060484Sobrien xexit (1); 97133965Sjdp} 97233965Sjdp 97333965Sjdp/* Return a pointer to the pointer to the entry which should be rplacd'd 97433965Sjdp into when altering. DEFAULT_POS should be how to interpret pos_default, 97533965Sjdp and should be a pos value. */ 97633965Sjdp 97733965Sjdpstatic bfd ** 978130561Sobrienget_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname) 97933965Sjdp{ 98033965Sjdp bfd **after_bfd = contents; 98138889Sjdp enum pos realpos; 98238889Sjdp const char *realposname; 98333965Sjdp 98438889Sjdp if (postype == pos_default) 98538889Sjdp { 98638889Sjdp realpos = default_pos; 98738889Sjdp realposname = default_posname; 98838889Sjdp } 98938889Sjdp else 99038889Sjdp { 99138889Sjdp realpos = postype; 99238889Sjdp realposname = posname; 99338889Sjdp } 99438889Sjdp 99533965Sjdp if (realpos == pos_end) 99633965Sjdp { 99733965Sjdp while (*after_bfd) 998218822Sdim after_bfd = &((*after_bfd)->archive_next); 99933965Sjdp } 100033965Sjdp else 100133965Sjdp { 1002218822Sdim for (; *after_bfd; after_bfd = &(*after_bfd)->archive_next) 100361843Sobrien if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0) 100433965Sjdp { 100533965Sjdp if (realpos == pos_after) 1006218822Sdim after_bfd = &(*after_bfd)->archive_next; 100733965Sjdp break; 100833965Sjdp } 100933965Sjdp } 101033965Sjdp return after_bfd; 101133965Sjdp} 101233965Sjdp 101333965Sjdpstatic void 1014130561Sobriendelete_members (bfd *arch, char **files_to_delete) 101533965Sjdp{ 101633965Sjdp bfd **current_ptr_ptr; 1017130561Sobrien bfd_boolean found; 1018130561Sobrien bfd_boolean something_changed = FALSE; 101960484Sobrien int match_count; 102060484Sobrien 102133965Sjdp for (; *files_to_delete != NULL; ++files_to_delete) 102233965Sjdp { 102333965Sjdp /* In a.out systems, the armap is optional. It's also called 102433965Sjdp __.SYMDEF. So if the user asked to delete it, we should remember 102533965Sjdp that fact. This isn't quite right for COFF systems (where 102633965Sjdp __.SYMDEF might be regular member), but it's very unlikely 102733965Sjdp to be a problem. FIXME */ 102833965Sjdp 102933965Sjdp if (!strcmp (*files_to_delete, "__.SYMDEF")) 103033965Sjdp { 1031130561Sobrien arch->has_armap = FALSE; 103233965Sjdp write_armap = -1; 103333965Sjdp continue; 103433965Sjdp } 103533965Sjdp 1036130561Sobrien found = FALSE; 103760484Sobrien match_count = 0; 1038218822Sdim current_ptr_ptr = &(arch->archive_next); 103933965Sjdp while (*current_ptr_ptr) 104033965Sjdp { 104161843Sobrien if (FILENAME_CMP (normalize (*files_to_delete, arch), 1042104834Sobrien (*current_ptr_ptr)->filename) == 0) 104333965Sjdp { 104460484Sobrien ++match_count; 104560484Sobrien if (counted_name_mode 1046104834Sobrien && match_count != counted_name_counter) 104760484Sobrien { 104860484Sobrien /* Counting, and didn't match on count; go on to the 104960484Sobrien next one. */ 105060484Sobrien } 105160484Sobrien else 105260484Sobrien { 1053130561Sobrien found = TRUE; 1054130561Sobrien something_changed = TRUE; 105560484Sobrien if (verbose) 105660484Sobrien printf ("d - %s\n", 105760484Sobrien *files_to_delete); 1058218822Sdim *current_ptr_ptr = ((*current_ptr_ptr)->archive_next); 105960484Sobrien goto next_file; 106060484Sobrien } 106133965Sjdp } 106260484Sobrien 1063218822Sdim current_ptr_ptr = &((*current_ptr_ptr)->archive_next); 106433965Sjdp } 106533965Sjdp 1066130561Sobrien if (verbose && !found) 106733965Sjdp { 106860484Sobrien /* xgettext:c-format */ 106960484Sobrien printf (_("No member named `%s'\n"), *files_to_delete); 107033965Sjdp } 107133965Sjdp next_file: 107233965Sjdp ; 107333965Sjdp } 107433965Sjdp 1075130561Sobrien if (something_changed) 107660484Sobrien write_archive (arch); 107760484Sobrien else 107860484Sobrien output_filename = NULL; 107933965Sjdp} 108033965Sjdp 108133965Sjdp 108233965Sjdp/* Reposition existing members within an archive */ 108333965Sjdp 108433965Sjdpstatic void 1085130561Sobrienmove_members (bfd *arch, char **files_to_move) 108633965Sjdp{ 108733965Sjdp bfd **after_bfd; /* New entries go after this one */ 108833965Sjdp bfd **current_ptr_ptr; /* cdr pointer into contents */ 108933965Sjdp 109033965Sjdp for (; *files_to_move; ++files_to_move) 109133965Sjdp { 1092218822Sdim current_ptr_ptr = &(arch->archive_next); 109333965Sjdp while (*current_ptr_ptr) 109433965Sjdp { 109533965Sjdp bfd *current_ptr = *current_ptr_ptr; 109661843Sobrien if (FILENAME_CMP (normalize (*files_to_move, arch), 109761843Sobrien current_ptr->filename) == 0) 109833965Sjdp { 109933965Sjdp /* Move this file to the end of the list - first cut from 110033965Sjdp where it is. */ 110133965Sjdp bfd *link; 1102218822Sdim *current_ptr_ptr = current_ptr->archive_next; 110333965Sjdp 110433965Sjdp /* Now glue to end */ 1105218822Sdim after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL); 110633965Sjdp link = *after_bfd; 110733965Sjdp *after_bfd = current_ptr; 1108218822Sdim current_ptr->archive_next = link; 110933965Sjdp 111033965Sjdp if (verbose) 111133965Sjdp printf ("m - %s\n", *files_to_move); 111233965Sjdp 111333965Sjdp goto next_file; 111433965Sjdp } 111533965Sjdp 1116218822Sdim current_ptr_ptr = &((*current_ptr_ptr)->archive_next); 111733965Sjdp } 111860484Sobrien /* xgettext:c-format */ 111960484Sobrien fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename); 112060484Sobrien 112133965Sjdp next_file:; 112233965Sjdp } 112333965Sjdp 112433965Sjdp write_archive (arch); 112533965Sjdp} 112633965Sjdp 112733965Sjdp/* Ought to default to replacing in place, but this is existing practice! */ 112833965Sjdp 112933965Sjdpstatic void 1130130561Sobrienreplace_members (bfd *arch, char **files_to_move, bfd_boolean quick) 113133965Sjdp{ 1132130561Sobrien bfd_boolean changed = FALSE; 1133218822Sdim bfd **after_bfd; /* New entries go after this one. */ 113433965Sjdp bfd *current; 113533965Sjdp bfd **current_ptr; 113633965Sjdp 113733965Sjdp while (files_to_move && *files_to_move) 113833965Sjdp { 113933965Sjdp if (! quick) 114033965Sjdp { 1141218822Sdim current_ptr = &arch->archive_next; 114233965Sjdp while (*current_ptr) 114333965Sjdp { 114433965Sjdp current = *current_ptr; 114533965Sjdp 114633965Sjdp /* For compatibility with existing ar programs, we 114733965Sjdp permit the same file to be added multiple times. */ 114861843Sobrien if (FILENAME_CMP (normalize (*files_to_move, arch), 114961843Sobrien normalize (current->filename, arch)) == 0 115033965Sjdp && current->arelt_data != NULL) 115133965Sjdp { 115233965Sjdp if (newer_only) 115333965Sjdp { 115433965Sjdp struct stat fsbuf, asbuf; 115533965Sjdp 115633965Sjdp if (stat (*files_to_move, &fsbuf) != 0) 115733965Sjdp { 115833965Sjdp if (errno != ENOENT) 115933965Sjdp bfd_fatal (*files_to_move); 116033965Sjdp goto next_file; 116133965Sjdp } 116233965Sjdp if (bfd_stat_arch_elt (current, &asbuf) != 0) 116360484Sobrien /* xgettext:c-format */ 1164104834Sobrien fatal (_("internal stat error on %s"), 1165104834Sobrien current->filename); 116633965Sjdp 116733965Sjdp if (fsbuf.st_mtime <= asbuf.st_mtime) 116833965Sjdp goto next_file; 116933965Sjdp } 117033965Sjdp 1171218822Sdim after_bfd = get_pos_bfd (&arch->archive_next, pos_after, 117238889Sjdp current->filename); 1173104834Sobrien if (ar_emul_replace (after_bfd, *files_to_move, 1174104834Sobrien verbose)) 117533965Sjdp { 1176104834Sobrien /* Snip out this entry from the chain. */ 1177218822Sdim *current_ptr = (*current_ptr)->archive_next; 1178130561Sobrien changed = TRUE; 117933965Sjdp } 118033965Sjdp 118133965Sjdp goto next_file; 118233965Sjdp } 1183218822Sdim current_ptr = &(current->archive_next); 118433965Sjdp } 118533965Sjdp } 118633965Sjdp 118733965Sjdp /* Add to the end of the archive. */ 1188218822Sdim after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL); 118933965Sjdp 1190218822Sdim if (ar_emul_append (after_bfd, *files_to_move, verbose)) 1191130561Sobrien changed = TRUE; 1192130561Sobrien 119333965Sjdp next_file:; 119433965Sjdp 119533965Sjdp files_to_move++; 119633965Sjdp } 119733965Sjdp 119833965Sjdp if (changed) 119933965Sjdp write_archive (arch); 120060484Sobrien else 120160484Sobrien output_filename = NULL; 120233965Sjdp} 120333965Sjdp 1204218822Sdimstatic int 1205130561Sobrienranlib_only (const char *archname) 120633965Sjdp{ 120733965Sjdp bfd *arch; 120833965Sjdp 1209130561Sobrien if (get_file_size (archname) < 1) 1210218822Sdim return 1; 121133965Sjdp write_armap = 1; 121233965Sjdp arch = open_inarch (archname, (char *) NULL); 121333965Sjdp if (arch == NULL) 121433965Sjdp xexit (1); 121533965Sjdp write_archive (arch); 1216218822Sdim return 0; 121733965Sjdp} 121833965Sjdp 121933965Sjdp/* Update the timestamp of the symbol map of an archive. */ 122033965Sjdp 1221218822Sdimstatic int 1222130561Sobrienranlib_touch (const char *archname) 122333965Sjdp{ 122433965Sjdp#ifdef __GO32__ 122533965Sjdp /* I don't think updating works on go32. */ 122633965Sjdp ranlib_only (archname); 122733965Sjdp#else 122833965Sjdp int f; 122933965Sjdp bfd *arch; 123033965Sjdp char **matching; 123133965Sjdp 1232130561Sobrien if (get_file_size (archname) < 1) 1233218822Sdim return 1; 123460484Sobrien f = open (archname, O_RDWR | O_BINARY, 0); 123533965Sjdp if (f < 0) 123633965Sjdp { 123733965Sjdp bfd_set_error (bfd_error_system_call); 123833965Sjdp bfd_fatal (archname); 123933965Sjdp } 124033965Sjdp 124133965Sjdp arch = bfd_fdopenr (archname, (const char *) NULL, f); 124233965Sjdp if (arch == NULL) 124333965Sjdp bfd_fatal (archname); 124433965Sjdp if (! bfd_check_format_matches (arch, bfd_archive, &matching)) 124533965Sjdp { 124633965Sjdp bfd_nonfatal (archname); 124733965Sjdp if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 124833965Sjdp { 124933965Sjdp list_matching_formats (matching); 125033965Sjdp free (matching); 125133965Sjdp } 125233965Sjdp xexit (1); 125333965Sjdp } 125433965Sjdp 125533965Sjdp if (! bfd_has_map (arch)) 125660484Sobrien /* xgettext:c-format */ 125760484Sobrien fatal (_("%s: no archive map to update"), archname); 125833965Sjdp 125933965Sjdp bfd_update_armap_timestamp (arch); 126033965Sjdp 126133965Sjdp if (! bfd_close (arch)) 126233965Sjdp bfd_fatal (archname); 126333965Sjdp#endif 1264218822Sdim return 0; 126533965Sjdp} 126633965Sjdp 126733965Sjdp/* Things which are interesting to map over all or some of the files: */ 126833965Sjdp 126933965Sjdpstatic void 1270130561Sobrienprint_descr (bfd *abfd) 127133965Sjdp{ 127233965Sjdp print_arelt_descr (stdout, abfd, verbose); 127333965Sjdp} 1274