ar.c revision 77298
133965Sjdp/* ar.c - Archive modify and extract. 260484Sobrien Copyright 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000 360484Sobrien Free Software Foundation, Inc. 433965Sjdp 533965SjdpThis file is part of GNU Binutils. 633965Sjdp 733965SjdpThis program is free software; you can redistribute it and/or modify 833965Sjdpit under the terms of the GNU General Public License as published by 933965Sjdpthe Free Software Foundation; either version 2 of the License, or 1033965Sjdp(at your option) any later version. 1133965Sjdp 1233965SjdpThis program is distributed in the hope that it will be useful, 1333965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1433965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1533965SjdpGNU General Public License for more details. 1633965Sjdp 1733965SjdpYou should have received a copy of the GNU General Public License 1833965Sjdpalong with this program; if not, write to the Free Software 1933965SjdpFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2033965Sjdp 2133965Sjdp/* 2233965Sjdp Bugs: should use getopt the way tar does (complete w/optional -) and 2333965Sjdp should have long options too. GNU ar used to check file against filesystem 2433965Sjdp in quick_update and replace operations (would check mtime). Doesn't warn 2533965Sjdp when name truncated. No way to specify pos_end. Error messages should be 2633965Sjdp more consistant. 2733965Sjdp*/ 2833965Sjdp#include "bfd.h" 2933965Sjdp#include "libiberty.h" 3033965Sjdp#include "progress.h" 3133965Sjdp#include "bucomm.h" 3233965Sjdp#include "aout/ar.h" 3333965Sjdp#include "libbfd.h" 3433965Sjdp#include "arsup.h" 3561843Sobrien#include "filenames.h" 3633965Sjdp#include <sys/stat.h> 3733965Sjdp 3833965Sjdp#ifdef __GO32___ 3933965Sjdp#define EXT_NAME_LEN 3 /* bufflen of addition to name if it's MS-DOS */ 4033965Sjdp#else 4133965Sjdp#define EXT_NAME_LEN 6 /* ditto for *NIX */ 4233965Sjdp#endif 4333965Sjdp 4460484Sobrien/* We need to open files in binary modes on system where that makes a 4560484Sobrien difference. */ 4660484Sobrien#ifndef O_BINARY 4760484Sobrien#define O_BINARY 0 4860484Sobrien#endif 4960484Sobrien 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 15160484Sobrien/* For extract/delete only. If COUNTED_NAME_MODE is true, we only 15260484Sobrien extract the COUNTED_NAME_COUNTER instance of that name. */ 15360484Sobrienstatic boolean counted_name_mode = 0; 15460484Sobrienstatic int counted_name_counter = 0; 15560484Sobrien 15633965Sjdp/* Whether to truncate names of files stored in the archive. */ 15733965Sjdpstatic boolean ar_truncate = false; 15833965Sjdp 15960484Sobrien/* Whether to use a full file name match when searching an archive. 16060484Sobrien This is convenient for archives created by the Microsoft lib 16160484Sobrien program. */ 16260484Sobrienstatic boolean full_pathname = false; 16360484Sobrien 16433965Sjdpint interactive = 0; 16533965Sjdp 16633965Sjdpstatic void 16733965Sjdpmri_emul () 16833965Sjdp{ 16933965Sjdp interactive = isatty (fileno (stdin)); 17033965Sjdp yyparse (); 17133965Sjdp} 17233965Sjdp 17333965Sjdp/* If COUNT is 0, then FUNCTION is called once on each entry. If nonzero, 17433965Sjdp COUNT is the length of the FILES chain; FUNCTION is called on each entry 17533965Sjdp whose name matches one in FILES. */ 17633965Sjdp 17733965Sjdpstatic void 17833965Sjdpmap_over_members (arch, function, files, count) 17933965Sjdp bfd *arch; 18033965Sjdp void (*function) PARAMS ((bfd *)); 18133965Sjdp char **files; 18233965Sjdp int count; 18333965Sjdp{ 18433965Sjdp bfd *head; 18560484Sobrien int match_count; 18633965Sjdp 18733965Sjdp if (count == 0) 18833965Sjdp { 18933965Sjdp for (head = arch->next; head; head = head->next) 19033965Sjdp { 19133965Sjdp PROGRESS (1); 19233965Sjdp function (head); 19333965Sjdp } 19433965Sjdp return; 19533965Sjdp } 19660484Sobrien 19733965Sjdp /* This may appear to be a baroque way of accomplishing what we want. 19833965Sjdp However we have to iterate over the filenames in order to notice where 19933965Sjdp a filename is requested but does not exist in the archive. Ditto 20033965Sjdp mapping over each file each time -- we want to hack multiple 20133965Sjdp references. */ 20233965Sjdp 20333965Sjdp for (; count > 0; files++, count--) 20433965Sjdp { 20533965Sjdp boolean found = false; 20633965Sjdp 20760484Sobrien match_count = 0; 20833965Sjdp for (head = arch->next; head; head = head->next) 20933965Sjdp { 21033965Sjdp PROGRESS (1); 21133965Sjdp if (head->filename == NULL) 21233965Sjdp { 21333965Sjdp /* Some archive formats don't get the filenames filled in 21433965Sjdp until the elements are opened. */ 21533965Sjdp struct stat buf; 21633965Sjdp bfd_stat_arch_elt (head, &buf); 21733965Sjdp } 21833965Sjdp if ((head->filename != NULL) && 21961843Sobrien (!FILENAME_CMP (normalize (*files, arch), head->filename))) 22033965Sjdp { 22160484Sobrien ++match_count; 22260484Sobrien if (counted_name_mode 22360484Sobrien && match_count != counted_name_counter) 22460484Sobrien { 22560484Sobrien /* Counting, and didn't match on count; go on to the 22660484Sobrien next one. */ 22760484Sobrien continue; 22860484Sobrien } 22960484Sobrien 23033965Sjdp found = true; 23133965Sjdp function (head); 23233965Sjdp } 23333965Sjdp } 23433965Sjdp if (!found) 23560484Sobrien /* xgettext:c-format */ 23660484Sobrien fprintf (stderr, _("no entry %s in archive\n"), *files); 23733965Sjdp } 23833965Sjdp} 23933965Sjdp 24033965Sjdpboolean operation_alters_arch = false; 24133965Sjdp 24233965Sjdpstatic void 24333965Sjdpusage (help) 24433965Sjdp int help; 24533965Sjdp{ 24633965Sjdp FILE *s; 24733965Sjdp 24833965Sjdp s = help ? stdout : stderr; 24960484Sobrien 25033965Sjdp if (! is_ranlib) 25160484Sobrien { 25260484Sobrien /* xgettext:c-format */ 25377298Sobrien fprintf (s, _("Usage: %s [-X32_64] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"), 25460484Sobrien program_name); 25560484Sobrien /* xgettext:c-format */ 25660484Sobrien fprintf (s, _(" %s -M [<mri-script]\n"), program_name); 25760484Sobrien fprintf (s, _(" commands:\n")); 25860484Sobrien fprintf (s, _(" d - delete file(s) from the archive\n")); 25960484Sobrien fprintf (s, _(" m[ab] - move file(s) in the archive\n")); 26060484Sobrien fprintf (s, _(" p - print file(s) found in the archive\n")); 26160484Sobrien fprintf (s, _(" q[f] - quick append file(s) to the archive\n")); 26260484Sobrien fprintf (s, _(" r[ab][f][u] - replace existing or insert new file(s) into the archive\n")); 26360484Sobrien fprintf (s, _(" t - display contents of archive\n")); 26460484Sobrien fprintf (s, _(" x[o] - extract file(s) from the archive\n")); 26560484Sobrien fprintf (s, _(" command specific modifiers:\n")); 26660484Sobrien fprintf (s, _(" [a] - put file(s) after [member-name]\n")); 26760484Sobrien fprintf (s, _(" [b] - put file(s) before [member-name] (same as [i])\n")); 26860484Sobrien fprintf (s, _(" [N] - use instance [count] of name\n")); 26960484Sobrien fprintf (s, _(" [f] - truncate inserted file names\n")); 27060484Sobrien fprintf (s, _(" [P] - use full path names when matching\n")); 27160484Sobrien fprintf (s, _(" [o] - preserve original dates\n")); 27260484Sobrien fprintf (s, _(" [u] - only replace files that are newer than current archive contents\n")); 27360484Sobrien fprintf (s, _(" generic modifiers:\n")); 27460484Sobrien fprintf (s, _(" [c] - do not warn if the library had to be created\n")); 27560484Sobrien fprintf (s, _(" [s] - create an archive index (cf. ranlib)\n")); 27660484Sobrien fprintf (s, _(" [S] - do not build a symbol table\n")); 27760484Sobrien fprintf (s, _(" [v] - be verbose\n")); 27860484Sobrien fprintf (s, _(" [V] - display the version number\n")); 27977298Sobrien fprintf (s, _(" [-X32_64] - (ignored)\n")); 28060484Sobrien } 28133965Sjdp else 28260484Sobrien /* xgettext:c-format */ 28360484Sobrien fprintf (s, _("Usage: %s [-vV] archive\n"), program_name); 28433965Sjdp 28533965Sjdp list_supported_targets (program_name, stderr); 28633965Sjdp 28733965Sjdp if (help) 28860484Sobrien fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO); 28933965Sjdp 29033965Sjdp xexit (help ? 0 : 1); 29133965Sjdp} 29233965Sjdp 29333965Sjdp/* Normalize a file name specified on the command line into a file 29433965Sjdp name which we will use in an archive. */ 29533965Sjdp 29633965Sjdpstatic const char * 29733965Sjdpnormalize (file, abfd) 29833965Sjdp const char *file; 29933965Sjdp bfd *abfd; 30033965Sjdp{ 30133965Sjdp const char *filename; 30233965Sjdp 30360484Sobrien if (full_pathname) 30460484Sobrien return file; 30560484Sobrien 30633965Sjdp filename = strrchr (file, '/'); 30761843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM 30861843Sobrien { 30961843Sobrien /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ 31061843Sobrien char *bslash = strrchr (file, '\\'); 31177298Sobrien if (filename == NULL || (bslash != NULL && bslash > filename)) 31261843Sobrien filename = bslash; 31361843Sobrien if (filename == NULL && file[0] != '\0' && file[1] == ':') 31477298Sobrien filename = file + 1; 31561843Sobrien } 31661843Sobrien#endif 31733965Sjdp if (filename != (char *) NULL) 31833965Sjdp filename++; 31933965Sjdp else 32033965Sjdp filename = file; 32133965Sjdp 32233965Sjdp if (ar_truncate 32333965Sjdp && abfd != NULL 32433965Sjdp && strlen (filename) > abfd->xvec->ar_max_namelen) 32533965Sjdp { 32633965Sjdp char *s; 32733965Sjdp 32833965Sjdp /* Space leak. */ 32933965Sjdp s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1); 33033965Sjdp memcpy (s, filename, abfd->xvec->ar_max_namelen); 33133965Sjdp s[abfd->xvec->ar_max_namelen] = '\0'; 33233965Sjdp filename = s; 33333965Sjdp } 33433965Sjdp 33533965Sjdp return filename; 33633965Sjdp} 33733965Sjdp 33833965Sjdp/* Remove any output file. This is only called via xatexit. */ 33933965Sjdp 34060484Sobrienstatic const char *output_filename = NULL; 34133965Sjdpstatic FILE *output_file = NULL; 34233965Sjdpstatic bfd *output_bfd = NULL; 34333965Sjdp 34433965Sjdpstatic void 34533965Sjdpremove_output () 34633965Sjdp{ 34733965Sjdp if (output_filename != NULL) 34833965Sjdp { 34933965Sjdp if (output_bfd != NULL && output_bfd->iostream != NULL) 35033965Sjdp fclose ((FILE *) (output_bfd->iostream)); 35133965Sjdp if (output_file != NULL) 35233965Sjdp fclose (output_file); 35333965Sjdp unlink (output_filename); 35433965Sjdp } 35533965Sjdp} 35633965Sjdp 35733965Sjdp/* The option parsing should be in its own function. 35833965Sjdp It will be when I have getopt working. */ 35933965Sjdp 36033965Sjdpint 36133965Sjdpmain (argc, argv) 36233965Sjdp int argc; 36333965Sjdp char **argv; 36433965Sjdp{ 36533965Sjdp char *arg_ptr; 36633965Sjdp char c; 36733965Sjdp enum 36833965Sjdp { 36933965Sjdp none = 0, delete, replace, print_table, 37033965Sjdp print_files, extract, move, quick_append 37133965Sjdp } operation = none; 37233965Sjdp int arg_index; 37333965Sjdp char **files; 37460484Sobrien int file_count; 37533965Sjdp char *inarch_filename; 37633965Sjdp int show_version; 37733965Sjdp 37860484Sobrien#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 37960484Sobrien setlocale (LC_MESSAGES, ""); 38060484Sobrien#endif 38160484Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 38260484Sobrien textdomain (PACKAGE); 38360484Sobrien 38433965Sjdp program_name = argv[0]; 38533965Sjdp xmalloc_set_program_name (program_name); 38633965Sjdp 38733965Sjdp if (is_ranlib < 0) 38833965Sjdp { 38933965Sjdp char *temp; 39033965Sjdp 39133965Sjdp temp = strrchr (program_name, '/'); 39261843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM 39361843Sobrien { 39461843Sobrien /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ 39561843Sobrien char *bslash = strrchr (program_name, '\\'); 39677298Sobrien if (temp == NULL || (bslash != NULL && bslash > temp)) 39761843Sobrien temp = bslash; 39861843Sobrien if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':') 39961843Sobrien temp = program_name + 1; 40061843Sobrien } 40161843Sobrien#endif 40233965Sjdp if (temp == NULL) 40333965Sjdp temp = program_name; 40433965Sjdp else 40533965Sjdp ++temp; 40633965Sjdp if (strlen (temp) >= 6 40761843Sobrien && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0) 40833965Sjdp is_ranlib = 1; 40933965Sjdp else 41033965Sjdp is_ranlib = 0; 41133965Sjdp } 41233965Sjdp 41333965Sjdp if (argc > 1 && argv[1][0] == '-') 41433965Sjdp { 41533965Sjdp if (strcmp (argv[1], "--help") == 0) 41633965Sjdp usage (1); 41733965Sjdp else if (strcmp (argv[1], "--version") == 0) 41833965Sjdp { 41933965Sjdp if (is_ranlib) 42033965Sjdp print_version ("ranlib"); 42133965Sjdp else 42233965Sjdp print_version ("ar"); 42333965Sjdp } 42433965Sjdp } 42533965Sjdp 42633965Sjdp START_PROGRESS (program_name, 0); 42733965Sjdp 42833965Sjdp bfd_init (); 42933965Sjdp set_default_bfd_target (); 43033965Sjdp 43133965Sjdp show_version = 0; 43233965Sjdp 43333965Sjdp xatexit (remove_output); 43433965Sjdp 43577298Sobrien /* Ignored for (partial) AIX compatibility. On AIX, 43677298Sobrien the -X option can be used to ignore certain kinds 43777298Sobrien of object files in the archive (the 64-bit objects 43877298Sobrien or the 32-bit objects). GNU ar always looks at all 43977298Sobrien kinds of objects in an archive. */ 44077298Sobrien while (argc > 1 && strcmp (argv[1], "-X32_64") == 0) 44177298Sobrien { 44277298Sobrien argv++; 44377298Sobrien argc--; 44477298Sobrien } 44577298Sobrien 44633965Sjdp if (is_ranlib) 44733965Sjdp { 44833965Sjdp boolean touch = false; 44933965Sjdp 45033965Sjdp if (argc < 2 || strcmp (argv[1], "--help") == 0) 45133965Sjdp usage (0); 45233965Sjdp if (strcmp (argv[1], "-V") == 0 45333965Sjdp || strcmp (argv[1], "-v") == 0 45433965Sjdp || strncmp (argv[1], "--v", 3) == 0) 45533965Sjdp print_version ("ranlib"); 45633965Sjdp arg_index = 1; 45733965Sjdp if (strcmp (argv[1], "-t") == 0) 45833965Sjdp { 45933965Sjdp ++arg_index; 46033965Sjdp touch = true; 46133965Sjdp } 46233965Sjdp while (arg_index < argc) 46333965Sjdp { 46433965Sjdp if (! touch) 46533965Sjdp ranlib_only (argv[arg_index]); 46633965Sjdp else 46733965Sjdp ranlib_touch (argv[arg_index]); 46833965Sjdp ++arg_index; 46933965Sjdp } 47033965Sjdp xexit (0); 47133965Sjdp } 47233965Sjdp 47333965Sjdp if (argc == 2 && strcmp (argv[1], "-M") == 0) 47433965Sjdp { 47533965Sjdp mri_emul (); 47633965Sjdp xexit (0); 47733965Sjdp } 47833965Sjdp 47933965Sjdp if (argc < 2) 48033965Sjdp usage (0); 48133965Sjdp 48233965Sjdp arg_ptr = argv[1]; 48333965Sjdp 48433965Sjdp if (*arg_ptr == '-') 48533965Sjdp ++arg_ptr; /* compatibility */ 48633965Sjdp 48733965Sjdp while ((c = *arg_ptr++) != '\0') 48833965Sjdp { 48933965Sjdp switch (c) 49033965Sjdp { 49133965Sjdp case 'd': 49233965Sjdp case 'm': 49333965Sjdp case 'p': 49433965Sjdp case 'q': 49533965Sjdp case 'r': 49633965Sjdp case 't': 49733965Sjdp case 'x': 49833965Sjdp if (operation != none) 49960484Sobrien fatal (_("two different operation options specified")); 50033965Sjdp switch (c) 50133965Sjdp { 50233965Sjdp case 'd': 50333965Sjdp operation = delete; 50433965Sjdp operation_alters_arch = true; 50533965Sjdp break; 50633965Sjdp case 'm': 50733965Sjdp operation = move; 50833965Sjdp operation_alters_arch = true; 50933965Sjdp break; 51033965Sjdp case 'p': 51133965Sjdp operation = print_files; 51233965Sjdp break; 51333965Sjdp case 'q': 51433965Sjdp operation = quick_append; 51533965Sjdp operation_alters_arch = true; 51633965Sjdp break; 51733965Sjdp case 'r': 51833965Sjdp operation = replace; 51933965Sjdp operation_alters_arch = true; 52033965Sjdp break; 52133965Sjdp case 't': 52233965Sjdp operation = print_table; 52333965Sjdp break; 52433965Sjdp case 'x': 52533965Sjdp operation = extract; 52633965Sjdp break; 52733965Sjdp } 52833965Sjdp case 'l': 52933965Sjdp break; 53033965Sjdp case 'c': 53133965Sjdp silent_create = 1; 53233965Sjdp break; 53333965Sjdp case 'o': 53433965Sjdp preserve_dates = 1; 53533965Sjdp break; 53633965Sjdp case 'V': 53733965Sjdp show_version = true; 53833965Sjdp break; 53933965Sjdp case 's': 54033965Sjdp write_armap = 1; 54133965Sjdp break; 54238889Sjdp case 'S': 54338889Sjdp write_armap = -1; 54438889Sjdp break; 54533965Sjdp case 'u': 54633965Sjdp newer_only = 1; 54733965Sjdp break; 54833965Sjdp case 'v': 54933965Sjdp verbose = 1; 55033965Sjdp break; 55133965Sjdp case 'a': 55233965Sjdp postype = pos_after; 55333965Sjdp break; 55433965Sjdp case 'b': 55533965Sjdp postype = pos_before; 55633965Sjdp break; 55733965Sjdp case 'i': 55833965Sjdp postype = pos_before; 55933965Sjdp break; 56033965Sjdp case 'M': 56133965Sjdp mri_mode = 1; 56233965Sjdp break; 56360484Sobrien case 'N': 56460484Sobrien counted_name_mode = true; 56560484Sobrien break; 56633965Sjdp case 'f': 56733965Sjdp ar_truncate = true; 56833965Sjdp break; 56960484Sobrien case 'P': 57060484Sobrien full_pathname = true; 57160484Sobrien break; 57233965Sjdp default: 57360484Sobrien /* xgettext:c-format */ 57460484Sobrien non_fatal (_("illegal option -- %c"), c); 57533965Sjdp usage (0); 57633965Sjdp } 57733965Sjdp } 57833965Sjdp 57933965Sjdp if (show_version) 58033965Sjdp print_version ("ar"); 58133965Sjdp 58233965Sjdp if (argc < 3) 58333965Sjdp usage (0); 58433965Sjdp 58533965Sjdp if (mri_mode) 58633965Sjdp { 58733965Sjdp mri_emul (); 58833965Sjdp } 58933965Sjdp else 59033965Sjdp { 59133965Sjdp bfd *arch; 59233965Sjdp 59333965Sjdp /* We can't write an armap when using ar q, so just do ar r 59433965Sjdp instead. */ 59533965Sjdp if (operation == quick_append && write_armap) 59633965Sjdp operation = replace; 59733965Sjdp 59833965Sjdp if ((operation == none || operation == print_table) 59933965Sjdp && write_armap == 1) 60033965Sjdp { 60133965Sjdp ranlib_only (argv[2]); 60233965Sjdp xexit (0); 60333965Sjdp } 60433965Sjdp 60533965Sjdp if (operation == none) 60660484Sobrien fatal (_("no operation specified")); 60733965Sjdp 60833965Sjdp if (newer_only && operation != replace) 60960484Sobrien fatal (_("`u' is only meaningful with the `r' option.")); 61033965Sjdp 61133965Sjdp arg_index = 2; 61233965Sjdp 61333965Sjdp if (postype != pos_default) 61433965Sjdp posname = argv[arg_index++]; 61533965Sjdp 61660484Sobrien if (counted_name_mode) 61760484Sobrien { 61860484Sobrien if (operation != extract && operation != delete) 61960484Sobrien fatal (_("`N' is only meaningful with the `x' and `d' options.")); 62060484Sobrien counted_name_counter = atoi (argv[arg_index++]); 62160484Sobrien if (counted_name_counter <= 0) 62260484Sobrien fatal (_("Value for `N' must be positive.")); 62360484Sobrien } 62460484Sobrien 62533965Sjdp inarch_filename = argv[arg_index++]; 62633965Sjdp 62733965Sjdp files = arg_index < argc ? argv + arg_index : NULL; 62860484Sobrien file_count = argc - arg_index; 62933965Sjdp 63033965Sjdp#if 0 63133965Sjdp /* We don't use do_quick_append any more. Too many systems 63233965Sjdp expect ar to always rebuild the symbol table even when q is 63333965Sjdp used. */ 63433965Sjdp 63533965Sjdp /* We can't do a quick append if we need to construct an 63633965Sjdp extended name table, because do_quick_append won't be able to 63733965Sjdp rebuild the name table. Unfortunately, at this point we 63833965Sjdp don't actually know the maximum name length permitted by this 63933965Sjdp object file format. So, we guess. FIXME. */ 64033965Sjdp if (operation == quick_append && ! ar_truncate) 64133965Sjdp { 64233965Sjdp char **chk; 64333965Sjdp 64433965Sjdp for (chk = files; chk != NULL && *chk != '\0'; chk++) 64533965Sjdp { 64633965Sjdp if (strlen (normalize (*chk, (bfd *) NULL)) > 14) 64733965Sjdp { 64833965Sjdp operation = replace; 64933965Sjdp break; 65033965Sjdp } 65133965Sjdp } 65233965Sjdp } 65333965Sjdp 65433965Sjdp if (operation == quick_append) 65533965Sjdp { 65633965Sjdp /* Note that quick appending to a non-existent archive creates it, 65733965Sjdp even if there are no files to append. */ 65833965Sjdp do_quick_append (inarch_filename, files); 65933965Sjdp xexit (0); 66033965Sjdp } 66133965Sjdp#endif 66233965Sjdp 66333965Sjdp arch = open_inarch (inarch_filename, 66433965Sjdp files == NULL ? (char *) NULL : files[0]); 66533965Sjdp 66633965Sjdp switch (operation) 66733965Sjdp { 66833965Sjdp case print_table: 66960484Sobrien map_over_members (arch, print_descr, files, file_count); 67033965Sjdp break; 67133965Sjdp 67233965Sjdp case print_files: 67360484Sobrien map_over_members (arch, print_contents, files, file_count); 67433965Sjdp break; 67533965Sjdp 67633965Sjdp case extract: 67760484Sobrien map_over_members (arch, extract_file, files, file_count); 67833965Sjdp break; 67933965Sjdp 68033965Sjdp case delete: 68133965Sjdp if (files != NULL) 68233965Sjdp delete_members (arch, files); 68360484Sobrien else 68460484Sobrien output_filename = NULL; 68533965Sjdp break; 68633965Sjdp 68733965Sjdp case move: 68833965Sjdp if (files != NULL) 68933965Sjdp move_members (arch, files); 69060484Sobrien else 69160484Sobrien output_filename = NULL; 69233965Sjdp break; 69333965Sjdp 69433965Sjdp case replace: 69533965Sjdp case quick_append: 69633965Sjdp if (files != NULL || write_armap > 0) 69733965Sjdp replace_members (arch, files, operation == quick_append); 69860484Sobrien else 69960484Sobrien output_filename = NULL; 70033965Sjdp break; 70133965Sjdp 70233965Sjdp /* Shouldn't happen! */ 70333965Sjdp default: 70460484Sobrien /* xgettext:c-format */ 70560484Sobrien fatal (_("internal error -- this option not implemented")); 70633965Sjdp } 70733965Sjdp } 70833965Sjdp 70933965Sjdp END_PROGRESS (program_name); 71033965Sjdp 71133965Sjdp xexit (0); 71233965Sjdp return 0; 71333965Sjdp} 71433965Sjdp 71533965Sjdpbfd * 71633965Sjdpopen_inarch (archive_filename, file) 71733965Sjdp const char *archive_filename; 71833965Sjdp const char *file; 71933965Sjdp{ 72033965Sjdp const char *target; 72133965Sjdp bfd **last_one; 72233965Sjdp bfd *next_one; 72333965Sjdp struct stat sbuf; 72433965Sjdp bfd *arch; 72533965Sjdp char **matching; 72633965Sjdp 72733965Sjdp bfd_set_error (bfd_error_no_error); 72833965Sjdp 72933965Sjdp target = NULL; 73033965Sjdp 73133965Sjdp if (stat (archive_filename, &sbuf) != 0) 73233965Sjdp { 73361843Sobrien#if !defined(__GO32__) || defined(__DJGPP__) 73433965Sjdp 73561843Sobrien /* FIXME: I don't understand why this fragment was ifndef'ed 73661843Sobrien away for __GO32__; perhaps it was in the days of DJGPP v1.x. 73761843Sobrien stat() works just fine in v2.x, so I think this should be 73861843Sobrien removed. For now, I enable it for DJGPP v2. -- EZ. */ 73961843Sobrien 74033965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why 74161843Sobrien stat() is wrong ... think it's buried in GO32's IDT - Jax */ 74233965Sjdp if (errno != ENOENT) 74333965Sjdp bfd_fatal (archive_filename); 74433965Sjdp#endif 74533965Sjdp 74633965Sjdp if (!operation_alters_arch) 74733965Sjdp { 74833965Sjdp fprintf (stderr, "%s: ", program_name); 74933965Sjdp perror (archive_filename); 75033965Sjdp maybequit (); 75133965Sjdp return NULL; 75233965Sjdp } 75333965Sjdp 75433965Sjdp /* Try to figure out the target to use for the archive from the 75533965Sjdp first object on the list. */ 75633965Sjdp if (file != NULL) 75733965Sjdp { 75833965Sjdp bfd *obj; 75933965Sjdp 76033965Sjdp obj = bfd_openr (file, NULL); 76133965Sjdp if (obj != NULL) 76233965Sjdp { 76333965Sjdp if (bfd_check_format (obj, bfd_object)) 76433965Sjdp target = bfd_get_target (obj); 76533965Sjdp (void) bfd_close (obj); 76633965Sjdp } 76733965Sjdp } 76833965Sjdp 76933965Sjdp /* Create an empty archive. */ 77033965Sjdp arch = bfd_openw (archive_filename, target); 77133965Sjdp if (arch == NULL 77233965Sjdp || ! bfd_set_format (arch, bfd_archive) 77333965Sjdp || ! bfd_close (arch)) 77433965Sjdp bfd_fatal (archive_filename); 77560484Sobrien 77660484Sobrien /* If we die creating a new archive, don't leave it around. */ 77760484Sobrien output_filename = archive_filename; 77833965Sjdp } 77933965Sjdp 78033965Sjdp arch = bfd_openr (archive_filename, target); 78133965Sjdp if (arch == NULL) 78233965Sjdp { 78333965Sjdp bloser: 78433965Sjdp bfd_fatal (archive_filename); 78533965Sjdp } 78633965Sjdp 78733965Sjdp if (! bfd_check_format_matches (arch, bfd_archive, &matching)) 78833965Sjdp { 78933965Sjdp bfd_nonfatal (archive_filename); 79033965Sjdp if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 79133965Sjdp { 79233965Sjdp list_matching_formats (matching); 79333965Sjdp free (matching); 79433965Sjdp } 79533965Sjdp xexit (1); 79633965Sjdp } 79733965Sjdp 79833965Sjdp last_one = &(arch->next); 79933965Sjdp /* Read all the contents right away, regardless. */ 80033965Sjdp for (next_one = bfd_openr_next_archived_file (arch, NULL); 80133965Sjdp next_one; 80233965Sjdp next_one = bfd_openr_next_archived_file (arch, next_one)) 80333965Sjdp { 80433965Sjdp PROGRESS (1); 80533965Sjdp *last_one = next_one; 80633965Sjdp last_one = &next_one->next; 80733965Sjdp } 80833965Sjdp *last_one = (bfd *) NULL; 80933965Sjdp if (bfd_get_error () != bfd_error_no_more_archived_files) 81033965Sjdp goto bloser; 81133965Sjdp return arch; 81233965Sjdp} 81333965Sjdp 81433965Sjdpstatic void 81533965Sjdpprint_contents (abfd) 81633965Sjdp bfd *abfd; 81733965Sjdp{ 81833965Sjdp int ncopied = 0; 81933965Sjdp char *cbuf = xmalloc (BUFSIZE); 82033965Sjdp struct stat buf; 82133965Sjdp long size; 82233965Sjdp if (bfd_stat_arch_elt (abfd, &buf) != 0) 82360484Sobrien /* xgettext:c-format */ 82460484Sobrien fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); 82533965Sjdp 82633965Sjdp if (verbose) 82777298Sobrien /* xgettext:c-format */ 82877298Sobrien printf (_("\n<member %s>\n\n"), bfd_get_filename (abfd)); 82933965Sjdp 83033965Sjdp bfd_seek (abfd, 0, SEEK_SET); 83133965Sjdp 83233965Sjdp size = buf.st_size; 83333965Sjdp while (ncopied < size) 83433965Sjdp { 83533965Sjdp 83633965Sjdp int nread; 83733965Sjdp int tocopy = size - ncopied; 83833965Sjdp if (tocopy > BUFSIZE) 83933965Sjdp tocopy = BUFSIZE; 84033965Sjdp 84133965Sjdp nread = bfd_read (cbuf, 1, tocopy, abfd); /* oops -- broke 84233965Sjdp abstraction! */ 84333965Sjdp if (nread != tocopy) 84460484Sobrien /* xgettext:c-format */ 84560484Sobrien fatal (_("%s is not a valid archive"), 84633965Sjdp bfd_get_filename (bfd_my_archive (abfd))); 84733965Sjdp fwrite (cbuf, 1, nread, stdout); 84833965Sjdp ncopied += tocopy; 84933965Sjdp } 85033965Sjdp free (cbuf); 85133965Sjdp} 85233965Sjdp 85333965Sjdp/* Extract a member of the archive into its own file. 85433965Sjdp 85533965Sjdp We defer opening the new file until after we have read a BUFSIZ chunk of the 85633965Sjdp old one, since we know we have just read the archive header for the old 85733965Sjdp one. Since most members are shorter than BUFSIZ, this means we will read 85833965Sjdp the old header, read the old data, write a new inode for the new file, and 85933965Sjdp write the new data, and be done. This 'optimization' is what comes from 86033965Sjdp sitting next to a bare disk and hearing it every time it seeks. -- Gnu 86133965Sjdp Gilmore */ 86233965Sjdp 86333965Sjdpvoid 86433965Sjdpextract_file (abfd) 86533965Sjdp bfd *abfd; 86633965Sjdp{ 86733965Sjdp FILE *ostream; 86833965Sjdp char *cbuf = xmalloc (BUFSIZE); 86933965Sjdp int nread, tocopy; 87060484Sobrien long ncopied = 0; 87133965Sjdp long size; 87233965Sjdp struct stat buf; 87360484Sobrien 87433965Sjdp if (bfd_stat_arch_elt (abfd, &buf) != 0) 87560484Sobrien /* xgettext:c-format */ 87660484Sobrien fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); 87733965Sjdp size = buf.st_size; 87833965Sjdp 87960484Sobrien if (size < 0) 88060484Sobrien /* xgettext:c-format */ 88160484Sobrien fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd)); 88260484Sobrien 88333965Sjdp if (verbose) 88433965Sjdp printf ("x - %s\n", bfd_get_filename (abfd)); 88533965Sjdp 88633965Sjdp bfd_seek (abfd, 0, SEEK_SET); 88733965Sjdp 88860484Sobrien ostream = NULL; 88933965Sjdp if (size == 0) 89033965Sjdp { 89133965Sjdp /* Seems like an abstraction violation, eh? Well it's OK! */ 89233965Sjdp output_filename = bfd_get_filename (abfd); 89333965Sjdp 89433965Sjdp ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); 89560484Sobrien if (ostream == NULL) 89633965Sjdp { 89733965Sjdp perror (bfd_get_filename (abfd)); 89833965Sjdp xexit (1); 89933965Sjdp } 90033965Sjdp 90133965Sjdp output_file = ostream; 90233965Sjdp } 90333965Sjdp else 90433965Sjdp while (ncopied < size) 90533965Sjdp { 90633965Sjdp tocopy = size - ncopied; 90733965Sjdp if (tocopy > BUFSIZE) 90833965Sjdp tocopy = BUFSIZE; 90933965Sjdp 91033965Sjdp nread = bfd_read (cbuf, 1, tocopy, abfd); 91133965Sjdp if (nread != tocopy) 91260484Sobrien /* xgettext:c-format */ 91360484Sobrien fatal (_("%s is not a valid archive"), 91433965Sjdp bfd_get_filename (bfd_my_archive (abfd))); 91533965Sjdp 91633965Sjdp /* See comment above; this saves disk arm motion */ 91760484Sobrien if (ostream == NULL) 91833965Sjdp { 91933965Sjdp /* Seems like an abstraction violation, eh? Well it's OK! */ 92033965Sjdp output_filename = bfd_get_filename (abfd); 92133965Sjdp 92233965Sjdp ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); 92360484Sobrien if (ostream == NULL) 92433965Sjdp { 92533965Sjdp perror (bfd_get_filename (abfd)); 92633965Sjdp xexit (1); 92733965Sjdp } 92833965Sjdp 92933965Sjdp output_file = ostream; 93033965Sjdp } 93133965Sjdp fwrite (cbuf, 1, nread, ostream); 93233965Sjdp ncopied += tocopy; 93333965Sjdp } 93433965Sjdp 93560484Sobrien if (ostream != NULL) 93660484Sobrien fclose (ostream); 93733965Sjdp 93833965Sjdp output_file = NULL; 93933965Sjdp output_filename = NULL; 94033965Sjdp 94133965Sjdp chmod (bfd_get_filename (abfd), buf.st_mode); 94233965Sjdp 94333965Sjdp if (preserve_dates) 94460484Sobrien set_times (bfd_get_filename (abfd), &buf); 94560484Sobrien 94660484Sobrien free (cbuf); 94733965Sjdp} 94833965Sjdp 94933965Sjdp#if 0 95033965Sjdp 95133965Sjdp/* We don't use this anymore. Too many systems expect ar to rebuild 95233965Sjdp the symbol table even when q is used. */ 95333965Sjdp 95433965Sjdp/* Just do it quickly; don't worry about dups, armap, or anything like that */ 95533965Sjdp 95633965Sjdpstatic void 95733965Sjdpdo_quick_append (archive_filename, files_to_append) 95833965Sjdp const char *archive_filename; 95933965Sjdp char **files_to_append; 96033965Sjdp{ 96133965Sjdp FILE *ofile, *ifile; 96233965Sjdp char *buf = xmalloc (BUFSIZE); 96333965Sjdp long tocopy, thistime; 96433965Sjdp bfd *temp; 96533965Sjdp struct stat sbuf; 96633965Sjdp boolean newfile = false; 96733965Sjdp bfd_set_error (bfd_error_no_error); 96833965Sjdp 96933965Sjdp if (stat (archive_filename, &sbuf) != 0) 97033965Sjdp { 97133965Sjdp 97261843Sobrien#if !defined(__GO32__) || defined(__DJGPP__) 97333965Sjdp 97461843Sobrien /* FIXME: I don't understand why this fragment was ifndef'ed 97561843Sobrien away for __GO32__; perhaps it was in the days of DJGPP v1.x. 97661843Sobrien stat() works just fine in v2.x, so I think this should be 97761843Sobrien removed. For now, I enable it for DJGPP v2. 97861843Sobrien 97961843Sobrien (And yes, I know this is all unused, but somebody, someday, 98061843Sobrien might wish to resurrect this again... -- EZ. */ 98161843Sobrien 98233965Sjdp/* KLUDGE ALERT! Temporary fix until I figger why 98361843Sobrien stat() is wrong ... think it's buried in GO32's IDT - Jax */ 98433965Sjdp 98533965Sjdp if (errno != ENOENT) 98633965Sjdp bfd_fatal (archive_filename); 98733965Sjdp#endif 98833965Sjdp 98933965Sjdp newfile = true; 99033965Sjdp } 99133965Sjdp 99233965Sjdp ofile = fopen (archive_filename, FOPEN_AUB); 99333965Sjdp if (ofile == NULL) 99433965Sjdp { 99533965Sjdp perror (program_name); 99633965Sjdp xexit (1); 99733965Sjdp } 99833965Sjdp 99933965Sjdp temp = bfd_openr (archive_filename, NULL); 100033965Sjdp if (temp == NULL) 100133965Sjdp { 100233965Sjdp bfd_fatal (archive_filename); 100333965Sjdp } 100433965Sjdp if (newfile == false) 100533965Sjdp { 100633965Sjdp if (bfd_check_format (temp, bfd_archive) != true) 100760484Sobrien /* xgettext:c-format */ 100860484Sobrien fatal (_("%s is not an archive"), archive_filename); 100933965Sjdp } 101033965Sjdp else 101133965Sjdp { 101233965Sjdp fwrite (ARMAG, 1, SARMAG, ofile); 101333965Sjdp if (!silent_create) 101460484Sobrien /* xgettext:c-format */ 101560484Sobrien non_fatal (_("creating %s"), archive_filename); 101633965Sjdp } 101733965Sjdp 101833965Sjdp if (ar_truncate) 101933965Sjdp temp->flags |= BFD_TRADITIONAL_FORMAT; 102033965Sjdp 102133965Sjdp /* assume it's an achive, go straight to the end, sans $200 */ 102233965Sjdp fseek (ofile, 0, 2); 102333965Sjdp 102433965Sjdp for (; files_to_append && *files_to_append; ++files_to_append) 102533965Sjdp { 102633965Sjdp struct ar_hdr *hdr = bfd_special_undocumented_glue (temp, *files_to_append); 102733965Sjdp if (hdr == NULL) 102833965Sjdp { 102933965Sjdp bfd_fatal (*files_to_append); 103033965Sjdp } 103133965Sjdp 103233965Sjdp BFD_SEND (temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr)); 103333965Sjdp 103433965Sjdp ifile = fopen (*files_to_append, FOPEN_RB); 103533965Sjdp if (ifile == NULL) 103633965Sjdp { 103733965Sjdp bfd_nonfatal (*files_to_append); 103833965Sjdp } 103933965Sjdp 104033965Sjdp if (stat (*files_to_append, &sbuf) != 0) 104133965Sjdp { 104233965Sjdp bfd_nonfatal (*files_to_append); 104333965Sjdp } 104433965Sjdp 104533965Sjdp tocopy = sbuf.st_size; 104633965Sjdp 104733965Sjdp /* XXX should do error-checking! */ 104833965Sjdp fwrite (hdr, 1, sizeof (struct ar_hdr), ofile); 104933965Sjdp 105033965Sjdp while (tocopy > 0) 105133965Sjdp { 105233965Sjdp thistime = tocopy; 105333965Sjdp if (thistime > BUFSIZE) 105433965Sjdp thistime = BUFSIZE; 105533965Sjdp fread (buf, 1, thistime, ifile); 105633965Sjdp fwrite (buf, 1, thistime, ofile); 105733965Sjdp tocopy -= thistime; 105833965Sjdp } 105933965Sjdp fclose (ifile); 106033965Sjdp if ((sbuf.st_size % 2) == 1) 106133965Sjdp putc ('\012', ofile); 106233965Sjdp } 106333965Sjdp fclose (ofile); 106433965Sjdp bfd_close (temp); 106533965Sjdp free (buf); 106633965Sjdp} 106733965Sjdp 106833965Sjdp#endif /* 0 */ 106933965Sjdp 107033965Sjdpstatic void 107133965Sjdpwrite_archive (iarch) 107233965Sjdp bfd *iarch; 107333965Sjdp{ 107433965Sjdp bfd *obfd; 107533965Sjdp char *old_name, *new_name; 107633965Sjdp bfd *contents_head = iarch->next; 107733965Sjdp 107833965Sjdp old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1); 107933965Sjdp strcpy (old_name, bfd_get_filename (iarch)); 108033965Sjdp new_name = make_tempname (old_name); 108133965Sjdp 108233965Sjdp output_filename = new_name; 108333965Sjdp 108433965Sjdp obfd = bfd_openw (new_name, bfd_get_target (iarch)); 108533965Sjdp 108633965Sjdp if (obfd == NULL) 108733965Sjdp bfd_fatal (old_name); 108833965Sjdp 108933965Sjdp output_bfd = obfd; 109033965Sjdp 109133965Sjdp bfd_set_format (obfd, bfd_archive); 109233965Sjdp 109333965Sjdp /* Request writing the archive symbol table unless we've 109433965Sjdp been explicitly requested not to. */ 109533965Sjdp obfd->has_armap = write_armap >= 0; 109633965Sjdp 109733965Sjdp if (ar_truncate) 109833965Sjdp { 109933965Sjdp /* This should really use bfd_set_file_flags, but that rejects 110033965Sjdp archives. */ 110133965Sjdp obfd->flags |= BFD_TRADITIONAL_FORMAT; 110233965Sjdp } 110333965Sjdp 110433965Sjdp if (bfd_set_archive_head (obfd, contents_head) != true) 110533965Sjdp bfd_fatal (old_name); 110633965Sjdp 110733965Sjdp if (!bfd_close (obfd)) 110833965Sjdp bfd_fatal (old_name); 110933965Sjdp 111033965Sjdp output_bfd = NULL; 111133965Sjdp output_filename = NULL; 111233965Sjdp 111333965Sjdp /* We don't care if this fails; we might be creating the archive. */ 111433965Sjdp bfd_close (iarch); 111533965Sjdp 111660484Sobrien if (smart_rename (new_name, old_name, 0) != 0) 111760484Sobrien xexit (1); 111833965Sjdp} 111933965Sjdp 112033965Sjdp/* Return a pointer to the pointer to the entry which should be rplacd'd 112133965Sjdp into when altering. DEFAULT_POS should be how to interpret pos_default, 112233965Sjdp and should be a pos value. */ 112333965Sjdp 112433965Sjdpstatic bfd ** 112538889Sjdpget_pos_bfd (contents, default_pos, default_posname) 112633965Sjdp bfd **contents; 112733965Sjdp enum pos default_pos; 112838889Sjdp const char *default_posname; 112933965Sjdp{ 113033965Sjdp bfd **after_bfd = contents; 113138889Sjdp enum pos realpos; 113238889Sjdp const char *realposname; 113333965Sjdp 113438889Sjdp if (postype == pos_default) 113538889Sjdp { 113638889Sjdp realpos = default_pos; 113738889Sjdp realposname = default_posname; 113838889Sjdp } 113938889Sjdp else 114038889Sjdp { 114138889Sjdp realpos = postype; 114238889Sjdp realposname = posname; 114338889Sjdp } 114438889Sjdp 114533965Sjdp if (realpos == pos_end) 114633965Sjdp { 114733965Sjdp while (*after_bfd) 114833965Sjdp after_bfd = &((*after_bfd)->next); 114933965Sjdp } 115033965Sjdp else 115133965Sjdp { 115233965Sjdp for (; *after_bfd; after_bfd = &(*after_bfd)->next) 115361843Sobrien if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0) 115433965Sjdp { 115533965Sjdp if (realpos == pos_after) 115633965Sjdp after_bfd = &(*after_bfd)->next; 115733965Sjdp break; 115833965Sjdp } 115933965Sjdp } 116033965Sjdp return after_bfd; 116133965Sjdp} 116233965Sjdp 116333965Sjdpstatic void 116433965Sjdpdelete_members (arch, files_to_delete) 116533965Sjdp bfd *arch; 116633965Sjdp char **files_to_delete; 116733965Sjdp{ 116833965Sjdp bfd **current_ptr_ptr; 116933965Sjdp boolean found; 117033965Sjdp boolean something_changed = false; 117160484Sobrien int match_count; 117260484Sobrien 117333965Sjdp for (; *files_to_delete != NULL; ++files_to_delete) 117433965Sjdp { 117533965Sjdp /* In a.out systems, the armap is optional. It's also called 117633965Sjdp __.SYMDEF. So if the user asked to delete it, we should remember 117733965Sjdp that fact. This isn't quite right for COFF systems (where 117833965Sjdp __.SYMDEF might be regular member), but it's very unlikely 117933965Sjdp to be a problem. FIXME */ 118033965Sjdp 118133965Sjdp if (!strcmp (*files_to_delete, "__.SYMDEF")) 118233965Sjdp { 118333965Sjdp arch->has_armap = false; 118433965Sjdp write_armap = -1; 118533965Sjdp continue; 118633965Sjdp } 118733965Sjdp 118833965Sjdp found = false; 118960484Sobrien match_count = 0; 119033965Sjdp current_ptr_ptr = &(arch->next); 119133965Sjdp while (*current_ptr_ptr) 119233965Sjdp { 119361843Sobrien if (FILENAME_CMP (normalize (*files_to_delete, arch), 119460484Sobrien (*current_ptr_ptr)->filename) == 0) 119533965Sjdp { 119660484Sobrien ++match_count; 119760484Sobrien if (counted_name_mode 119860484Sobrien && match_count != counted_name_counter) 119960484Sobrien { 120060484Sobrien /* Counting, and didn't match on count; go on to the 120160484Sobrien next one. */ 120260484Sobrien } 120360484Sobrien else 120460484Sobrien { 120560484Sobrien found = true; 120660484Sobrien something_changed = true; 120760484Sobrien if (verbose) 120860484Sobrien printf ("d - %s\n", 120960484Sobrien *files_to_delete); 121060484Sobrien *current_ptr_ptr = ((*current_ptr_ptr)->next); 121160484Sobrien goto next_file; 121260484Sobrien } 121333965Sjdp } 121460484Sobrien 121560484Sobrien current_ptr_ptr = &((*current_ptr_ptr)->next); 121633965Sjdp } 121733965Sjdp 121833965Sjdp if (verbose && found == false) 121933965Sjdp { 122060484Sobrien /* xgettext:c-format */ 122160484Sobrien printf (_("No member named `%s'\n"), *files_to_delete); 122233965Sjdp } 122333965Sjdp next_file: 122433965Sjdp ; 122533965Sjdp } 122633965Sjdp 122733965Sjdp if (something_changed == true) 122860484Sobrien write_archive (arch); 122960484Sobrien else 123060484Sobrien output_filename = NULL; 123133965Sjdp} 123233965Sjdp 123333965Sjdp 123433965Sjdp/* Reposition existing members within an archive */ 123533965Sjdp 123633965Sjdpstatic void 123733965Sjdpmove_members (arch, files_to_move) 123833965Sjdp bfd *arch; 123933965Sjdp char **files_to_move; 124033965Sjdp{ 124133965Sjdp bfd **after_bfd; /* New entries go after this one */ 124233965Sjdp bfd **current_ptr_ptr; /* cdr pointer into contents */ 124333965Sjdp 124433965Sjdp for (; *files_to_move; ++files_to_move) 124533965Sjdp { 124633965Sjdp current_ptr_ptr = &(arch->next); 124733965Sjdp while (*current_ptr_ptr) 124833965Sjdp { 124933965Sjdp bfd *current_ptr = *current_ptr_ptr; 125061843Sobrien if (FILENAME_CMP (normalize (*files_to_move, arch), 125161843Sobrien current_ptr->filename) == 0) 125233965Sjdp { 125333965Sjdp /* Move this file to the end of the list - first cut from 125433965Sjdp where it is. */ 125533965Sjdp bfd *link; 125633965Sjdp *current_ptr_ptr = current_ptr->next; 125733965Sjdp 125833965Sjdp /* Now glue to end */ 125938889Sjdp after_bfd = get_pos_bfd (&arch->next, pos_end, NULL); 126033965Sjdp link = *after_bfd; 126133965Sjdp *after_bfd = current_ptr; 126233965Sjdp current_ptr->next = link; 126333965Sjdp 126433965Sjdp if (verbose) 126533965Sjdp printf ("m - %s\n", *files_to_move); 126633965Sjdp 126733965Sjdp goto next_file; 126833965Sjdp } 126933965Sjdp 127033965Sjdp current_ptr_ptr = &((*current_ptr_ptr)->next); 127133965Sjdp } 127260484Sobrien /* xgettext:c-format */ 127360484Sobrien fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename); 127460484Sobrien 127533965Sjdp next_file:; 127633965Sjdp } 127733965Sjdp 127833965Sjdp write_archive (arch); 127933965Sjdp} 128033965Sjdp 128133965Sjdp/* Ought to default to replacing in place, but this is existing practice! */ 128233965Sjdp 128333965Sjdpstatic void 128433965Sjdpreplace_members (arch, files_to_move, quick) 128533965Sjdp bfd *arch; 128633965Sjdp char **files_to_move; 128733965Sjdp boolean quick; 128833965Sjdp{ 128933965Sjdp boolean changed = false; 129033965Sjdp bfd **after_bfd; /* New entries go after this one */ 129133965Sjdp bfd *current; 129233965Sjdp bfd **current_ptr; 129333965Sjdp bfd *temp; 129433965Sjdp 129533965Sjdp while (files_to_move && *files_to_move) 129633965Sjdp { 129733965Sjdp if (! quick) 129833965Sjdp { 129933965Sjdp current_ptr = &arch->next; 130033965Sjdp while (*current_ptr) 130133965Sjdp { 130233965Sjdp current = *current_ptr; 130333965Sjdp 130433965Sjdp /* For compatibility with existing ar programs, we 130533965Sjdp permit the same file to be added multiple times. */ 130661843Sobrien if (FILENAME_CMP (normalize (*files_to_move, arch), 130761843Sobrien normalize (current->filename, arch)) == 0 130833965Sjdp && current->arelt_data != NULL) 130933965Sjdp { 131033965Sjdp if (newer_only) 131133965Sjdp { 131233965Sjdp struct stat fsbuf, asbuf; 131333965Sjdp 131433965Sjdp if (stat (*files_to_move, &fsbuf) != 0) 131533965Sjdp { 131633965Sjdp if (errno != ENOENT) 131733965Sjdp bfd_fatal (*files_to_move); 131833965Sjdp goto next_file; 131933965Sjdp } 132033965Sjdp if (bfd_stat_arch_elt (current, &asbuf) != 0) 132160484Sobrien /* xgettext:c-format */ 132260484Sobrien fatal (_("internal stat error on %s"), current->filename); 132333965Sjdp 132433965Sjdp if (fsbuf.st_mtime <= asbuf.st_mtime) 132533965Sjdp goto next_file; 132633965Sjdp } 132733965Sjdp 132838889Sjdp after_bfd = get_pos_bfd (&arch->next, pos_after, 132938889Sjdp current->filename); 133038889Sjdp temp = *after_bfd; 133133965Sjdp 133233965Sjdp *after_bfd = bfd_openr (*files_to_move, NULL); 133333965Sjdp if (*after_bfd == (bfd *) NULL) 133433965Sjdp { 133533965Sjdp bfd_fatal (*files_to_move); 133633965Sjdp } 133733965Sjdp (*after_bfd)->next = temp; 133833965Sjdp 133938889Sjdp /* snip out this entry from the chain */ 134038889Sjdp *current_ptr = (*current_ptr)->next; 134138889Sjdp 134233965Sjdp if (verbose) 134333965Sjdp { 134433965Sjdp printf ("r - %s\n", *files_to_move); 134533965Sjdp } 134633965Sjdp 134733965Sjdp changed = true; 134833965Sjdp 134933965Sjdp goto next_file; 135033965Sjdp } 135133965Sjdp current_ptr = &(current->next); 135233965Sjdp } 135333965Sjdp } 135433965Sjdp 135533965Sjdp /* Add to the end of the archive. */ 135633965Sjdp 135738889Sjdp after_bfd = get_pos_bfd (&arch->next, pos_end, NULL); 135833965Sjdp temp = *after_bfd; 135933965Sjdp *after_bfd = bfd_openr (*files_to_move, NULL); 136033965Sjdp if (*after_bfd == (bfd *) NULL) 136133965Sjdp { 136233965Sjdp bfd_fatal (*files_to_move); 136333965Sjdp } 136433965Sjdp if (verbose) 136533965Sjdp { 136633965Sjdp printf ("a - %s\n", *files_to_move); 136733965Sjdp } 136833965Sjdp 136933965Sjdp (*after_bfd)->next = temp; 137033965Sjdp 137133965Sjdp changed = true; 137233965Sjdp 137333965Sjdp next_file:; 137433965Sjdp 137533965Sjdp files_to_move++; 137633965Sjdp } 137733965Sjdp 137833965Sjdp if (changed) 137933965Sjdp write_archive (arch); 138060484Sobrien else 138160484Sobrien output_filename = NULL; 138233965Sjdp} 138333965Sjdp 138433965Sjdpstatic void 138533965Sjdpranlib_only (archname) 138633965Sjdp const char *archname; 138733965Sjdp{ 138833965Sjdp bfd *arch; 138933965Sjdp 139033965Sjdp write_armap = 1; 139133965Sjdp arch = open_inarch (archname, (char *) NULL); 139233965Sjdp if (arch == NULL) 139333965Sjdp xexit (1); 139433965Sjdp write_archive (arch); 139533965Sjdp} 139633965Sjdp 139733965Sjdp/* Update the timestamp of the symbol map of an archive. */ 139833965Sjdp 139933965Sjdpstatic void 140033965Sjdpranlib_touch (archname) 140133965Sjdp const char *archname; 140233965Sjdp{ 140333965Sjdp#ifdef __GO32__ 140433965Sjdp /* I don't think updating works on go32. */ 140533965Sjdp ranlib_only (archname); 140633965Sjdp#else 140733965Sjdp int f; 140833965Sjdp bfd *arch; 140933965Sjdp char **matching; 141033965Sjdp 141160484Sobrien f = open (archname, O_RDWR | O_BINARY, 0); 141233965Sjdp if (f < 0) 141333965Sjdp { 141433965Sjdp bfd_set_error (bfd_error_system_call); 141533965Sjdp bfd_fatal (archname); 141633965Sjdp } 141733965Sjdp 141833965Sjdp arch = bfd_fdopenr (archname, (const char *) NULL, f); 141933965Sjdp if (arch == NULL) 142033965Sjdp bfd_fatal (archname); 142133965Sjdp if (! bfd_check_format_matches (arch, bfd_archive, &matching)) 142233965Sjdp { 142333965Sjdp bfd_nonfatal (archname); 142433965Sjdp if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 142533965Sjdp { 142633965Sjdp list_matching_formats (matching); 142733965Sjdp free (matching); 142833965Sjdp } 142933965Sjdp xexit (1); 143033965Sjdp } 143133965Sjdp 143233965Sjdp if (! bfd_has_map (arch)) 143360484Sobrien /* xgettext:c-format */ 143460484Sobrien fatal (_("%s: no archive map to update"), archname); 143533965Sjdp 143633965Sjdp bfd_update_armap_timestamp (arch); 143733965Sjdp 143833965Sjdp if (! bfd_close (arch)) 143933965Sjdp bfd_fatal (archname); 144033965Sjdp#endif 144133965Sjdp} 144233965Sjdp 144333965Sjdp/* Things which are interesting to map over all or some of the files: */ 144433965Sjdp 144533965Sjdpstatic void 144633965Sjdpprint_descr (abfd) 144733965Sjdp bfd *abfd; 144833965Sjdp{ 144933965Sjdp print_arelt_descr (stdout, abfd, verbose); 145033965Sjdp} 1451