1 /* ar.c - Archive modify and extract.
2 Copyright (C) 1991 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21 Bugs: should use getopt the way tar does (complete w/optional -) and
22 should have long options too. GNU ar used to check file against filesystem
23 in quick_update and replace operations (would check mtime). Doesn't warn
24 when name truncated. No way to specify pos_end. Error messages should be
31 #include "../bfd/libbfd.h"
36 /* PROTO (void, open_inarch, (char *archive_filename)); */
38 static void open_inarch(char *archive_filename);
40 static void open_inarch();
43 PROTO(void, map_over_members, (void (*function) (), char **files, int count));
44 PROTO(void, print_contents, (bfd * member));
45 PROTO(void, extract_file, (bfd * abfd));
46 PROTO(void, delete_members, (char **files_to_delete));
47 PROTO(void, do_quick_append, (char *archive_filename, char **files_to_append));
48 PROTO(void, move_members, (char **files_to_move));
49 PROTO(void, replace_members, (char **files_to_replace));
50 PROTO(void, print_descr, (bfd * abfd));
51 PROTO(void, ranlib_only, (char *archname));
53 /** Globals and flags */
55 char *program_name = NULL;
57 bfd *inarch; /* The input arch we're manipulating */
59 /* This flag distinguishes between ar and ranlib:
60 1 means this is 'ranlib'; 0 means this is 'ar'.
61 -1 means if we should use argv[0] to decide. */
63 /* Nonzero means don't warn about creating the archive file if necessary. */
64 int silent_create = 0;
65 /* Nonzero means describe each action performed. */
67 /* Nonzero means preserve dates of members when extracting them. */
68 int preserve_dates = 0;
70 Nonzero means don't replace existing members whose dates are more recent
71 than the corresponding files.
74 /* write a __.SYMDEF member into the modified archive. */
75 boolean write_armap = false;
77 Nonzero means don't update __.SYMDEF unless command line explicitly
80 int ignore_symdef = 0;
82 Nonzero means it's the name of an existing member; position new or moved
83 files with respect to this one.
87 Sez how to use `posname': pos_before means position before that member.
88 pos_after means position after that member. pos_end means always at end.
89 pos_default means default appropriately. For the latter two, `posname'
93 pos_default, pos_before, pos_after, pos_end
94 } postype = pos_default;
100 gnu960_verify_target(abfd)
103 if ( abfd->format == bfd_unknown ){
104 bfd_check_format(abfd, bfd_object);
105 /* Don't really care if it's an object --
106 * just want to get the correct xvec.
109 if ( !BFD_COFF_FILE_P(abfd) ){
110 fatal( "'%s' not a COFF file -- operation aborted",
118 boolean operation_alters_arch = false;
121 The option parsing should be in its own function. It will be when I have
132 none = 0, delete, replace, print_table,
133 print_files, extract, move, quick_append
137 char *inarch_filename;
143 check_v960( argc, argv );
144 default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
147 program_name = argv[0];
149 temp = strrchr(program_name, '/');
150 if (temp == (char *) NULL)
151 temp = program_name; /* shouldn't happen, but... */
154 if (is_ranlib > 0 || (is_ranlib < 0 && strcmp(temp, "ranlib") == 0)) {
156 bfd_fatal("Too few command arguments.");
157 ranlib_only(argv[1]);
162 bfd_fatal("Too few command arguments.");
167 ++arg_ptr; /* compatibility */
169 while (c = *arg_ptr++) {
178 if (operation != none)
179 fatal("two different operation switches specified");
183 operation_alters_arch = true;
187 operation_alters_arch = true;
190 operation = print_files;
193 operation = quick_append;
194 operation_alters_arch = true;
198 operation_alters_arch = true;
201 operation = print_table;
228 postype = pos_before;
231 postype = pos_before;
234 fatal("invalid option %c", c);
238 if ((operation == none || operation == print_table)
239 && write_armap == true)
240 ranlib_only(argv[2]);
242 if (operation == none)
243 fatal("no operation specified");
245 if (newer_only && operation != replace)
246 fatal("'u' only meaningful with 'r' option.");
250 if (postype != pos_default)
251 posname = argv[arg_index++];
253 inarch_filename = argv[arg_index++];
255 if (arg_index < argc) {
256 files = argv + arg_index;
257 while (arg_index < argc)
258 if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
266 if (operation == quick_append) {
268 do_quick_append(inarch_filename, files);
273 open_inarch(inarch_filename);
275 If we have no archive, and we've been asked to replace then create one
278 if (operation == replace && inarch == &bogus_archive) {
280 do_quick_append(inarch_filename, 0);
281 open_inarch(inarch_filename);
287 map_over_members(print_descr, files, argc - 3);
291 map_over_members(print_contents, files, argc - 3);
295 map_over_members(extract_file, files, argc - 3);
300 delete_members(files);
309 if (files != NULL || write_armap)
310 replace_members(files);
313 /* Shouldn't happen! */
315 fprintf(stderr, "Sorry; this option not implemented.\n");
322 char *normalize(file)
325 char * filename = strrchr(file, '/');
326 if (filename != (char *)NULL) {
336 open_inarch(archive_filename)
337 char *archive_filename;
342 bfd_error = no_error;
343 if (stat(archive_filename, &sbuf) != 0) {
345 bfd_fatal(archive_filename);
346 if (!operation_alters_arch) {
347 fprintf (stderr, "%s: %s not found.\n", program_name,
353 "%s: creating %s\n", program_name, archive_filename);
355 inarch = &bogus_archive;
356 inarch->filename = archive_filename;
357 inarch->has_armap = true;
362 inarch = bfd_openr(archive_filename, default_target);
364 inarch = bfd_openr(archive_filename, NULL);
366 if (inarch == NULL) {
368 bfd_perror(archive_filename);
372 if (bfd_check_format(inarch, bfd_archive) != true)
373 fatal("File %s is not an archive.", archive_filename);
375 gnu960_verify_target(inarch); /* Exits on failure */
377 last_one = &(inarch->next);
378 /* Read all the contents right away, regardless. */
379 for (next_one = bfd_openr_next_archived_file(inarch, NULL);
381 next_one = bfd_openr_next_archived_file(inarch, next_one)) {
382 *last_one = next_one;
383 last_one = &next_one->next;
385 *last_one = (bfd *) NULL;
386 if (bfd_error != no_more_archived_files)
394 If count is 0, then function is called once on each entry. if nonzero,
395 count is the length of the files chain; function is called on each entry
396 whose name matches one in files
399 map_over_members(function, files, count)
410 for (head = inarch->next; head; head = head->next)
415 This may appear to be a baroque way of accomplishing what we want.
416 however we have to iterate over the filenames in order to notice where
417 a filename is requested but does not exist in the archive. Ditto
418 mapping over each file each time -- we want to hack multiple
422 for (; count > 0; files++, count--) {
423 boolean found = false;
424 for (head = inarch->next; head; head = head->next)
425 if ((head->filename != NULL) &&
426 (!strcmp(*files, head->filename))) {
431 fprintf(stderr, "No entry %s in archive.\n", *files);
443 if (bfd_stat_arch_elt(abfd, &buf) != 0)
444 fatal("Internal stat error on %s", abfd->filename);
447 printf("\n<member %s>\n\n", abfd->filename);
449 bfd_seek(abfd, 0, SEEK_SET);
452 while (ncopied < size) {
455 int tocopy = size - ncopied;
456 if (tocopy > BUFSIZE)
459 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
463 fatal("file %s not a valid archive", abfd->my_archive->filename);
464 fwrite(cbuf, 1, nread, stdout);
471 Extract a member of the archive into its own file.
473 We defer opening the new file until after we have read a BUFSIZ chunk of the
474 old one, since we know we have just read the archive header for the old
475 one. Since most members are shorter than BUFSIZ, this means we will read
476 the old header, read the old data, write a new inode for the new file, and
477 write the new data, and be done. This 'optimization' is what comes from
478 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
493 if (bfd_stat_arch_elt(abfd, &buf) != 0)
494 fatal("Internal stat error on %s", abfd->filename);
498 printf("x - %s\n", abfd->filename);
500 bfd_seek(abfd, 0, SEEK_SET);
504 /* Seems like an abstraction violation, eh? Well it's OK! */
505 ostream = fopen(abfd->filename, "wb");
507 perror(abfd->filename);
511 while (ncopied < size) {
512 tocopy = size - ncopied;
513 if (tocopy > BUFSIZE)
516 nread = bfd_read(cbuf, 1, tocopy, abfd);
518 fatal("file %s not a valid archive", abfd->my_archive->filename);
520 /* See comment above; this saves disk arm motion */
522 /* Seems like an abstraction violation, eh? Well it's OK! */
523 ostream = fopen(abfd->filename, "wb");
525 perror(abfd->filename);
529 fwrite(cbuf, 1, nread, ostream);
534 chmod(abfd->filename, buf.st_mode);
536 if (preserve_dates) {
539 tb[0] = buf.st_mtime;
540 tb[1] = buf.st_mtime;
541 utime(abfd->filename, tb); /* FIXME check result */
543 struct timeval tv[2];
544 tv[0].tv_sec = buf.st_mtime;
546 tv[1].tv_sec = buf.st_mtime;
548 utimes(abfd->filename, tv); /* FIXME check result */
554 /* Just do it quickly; don't worry about dups, armap, or anything like that */
556 /* This is ugly! XXX */
558 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
561 do_quick_append(archive_filename, files_to_append)
562 char *archive_filename;
563 char **files_to_append;
573 boolean newfile = false;
574 bfd_error = no_error;
576 if (stat(archive_filename, &sbuf) != 0) {
578 bfd_fatal(archive_filename);
583 ofile = fopen(archive_filename, "a+b");
585 perror(program_name);
591 temp = bfd_openr(archive_filename, default_target);
593 temp = bfd_openr(archive_filename, NULL);
596 bfd_perror(archive_filename);
599 if (newfile == false) {
600 if (bfd_check_format(temp, bfd_archive) != true)
601 fatal("File %s is not an archive.", archive_filename);
603 gnu960_verify_target(temp); /* Exits on failure */
607 fwrite(ARMAG, 1, SARMAG, ofile);
609 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
612 /* assume it's an achive, go straight to the end, sans $200 */
615 for (; files_to_append && *files_to_append; ++files_to_append) {
616 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
618 bfd_perror(*files_to_append);
622 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
624 ifile = fopen(*files_to_append, "rb");
626 bfd_perror(program_name);
628 if (stat(*files_to_append, &sbuf) != 0)
629 bfd_perror(*files_to_append);
631 tocopy = sbuf.st_size;
633 /* XXX should do error-checking! */
634 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
639 if (thistime > BUFSIZE)
641 fread(buf, 1, thistime, ifile);
642 fwrite(buf, 1, thistime, ofile);
646 if ((sbuf.st_size % 2) == 1)
658 int namelen = strlen(inarch->filename);
659 char *new_name = xmalloc(namelen + 6);
660 bfd *contents_head = inarch->next;
662 if (inarch == &bogus_archive) {
663 /* How can this be ? */
668 strcpy(new_name, inarch->filename);
669 strcpy(new_name + namelen, "-art");
670 obfd = bfd_openw(new_name,
671 /* FIXME: violates abstraction; need a better protocol */
672 (inarch->xvec ? bfd_get_target(inarch) : NULL));
675 bfd_fatal(inarch->filename);
677 bfd_set_format(obfd, bfd_archive);
678 obfd->has_armap = write_armap;
680 if (bfd_set_archive_head(obfd, contents_head) != true)
681 bfd_fatal(inarch->filename);
683 if (!bfd_close(obfd))
684 bfd_fatal(inarch->filename);
686 /* We don't care if this fails, we might be creating the
688 (void) unlink(inarch->filename);
690 if (rename(new_name, inarch->filename) != 0)
691 bfd_fatal(inarch->filename);
700 returns a pointer to the pointer to the entry which should be rplacd'd
701 into when altering. default_pos should be how to interpret pos_default,
702 and should be a pos value.
706 get_pos_bfd(contents, default_pos)
708 enum pos default_pos;
710 bfd **after_bfd = contents;
711 enum pos realpos = (postype == pos_default ? default_pos : postype);
713 if (realpos == pos_end) {
715 after_bfd = &((*after_bfd)->next);
718 for ( ; *after_bfd; after_bfd = &(*after_bfd)->next)
719 if (!strcmp((*after_bfd)->filename, posname)) {
720 if (realpos == pos_after)
721 after_bfd = &(*after_bfd)->next;
730 delete_members(files_to_delete)
731 char **files_to_delete;
733 bfd **current_ptr_ptr;
735 boolean something_changed = false;
736 for (; *files_to_delete != NULL; ++files_to_delete) {
738 In a.out systems, the armap is optional. It's also called
739 __.SYMDEF. So if the user asked to delete it, we should remember
740 that fact. The name is NULL in COFF archives, so using this as a
741 key is as good as anything I suppose
743 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
744 inarch->has_armap = false;
750 current_ptr_ptr = &(inarch->next);
751 while (*current_ptr_ptr) {
752 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
754 something_changed = true;
758 *current_ptr_ptr = ((*current_ptr_ptr)->next);
763 current_ptr_ptr = &((*current_ptr_ptr)->next);
767 if (verbose && found == false) {
768 printf("No member named `%s'\n", *files_to_delete);
774 if (something_changed == true) {
780 /* Reposition existing members within an archive */
783 move_members(files_to_move)
784 char **files_to_move;
786 bfd **after_bfd; /* New entries go after this one */
787 bfd **current_ptr_ptr; /* cdr pointer into contents */
792 for (; *files_to_move; ++files_to_move) {
793 current_ptr_ptr = &(inarch->next);
794 while (*current_ptr_ptr) {
795 bfd *current_ptr = *current_ptr_ptr;
796 if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
798 Move this file to the end of the list - first cut from
801 *current_ptr_ptr = current_ptr->next;
803 /* Now glue to end */
804 after_bfd = get_pos_bfd(&inarch->next, pos_end);
805 *after_bfd = current_ptr;
806 current_ptr->next = (bfd *) NULL;
809 printf("m - %s\n", *files_to_move);
813 current_ptr_ptr = &((*current_ptr_ptr)->next);
815 fprintf(stderr, "No entry %s in archive %s!\n",
816 *files_to_move, inarch->filename);
825 /* Ought to default to replacing in place, but this is existing practice! */
828 replace_members(files_to_move)
829 char **files_to_move;
831 bfd **after_bfd; /* New entries go after this one */
836 If the first item in the archive is an __.SYMDEF then remove it
839 strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
840 inarch->next = inarch->next->next;
845 while (files_to_move && *files_to_move) {
846 current_ptr = &inarch->next;
847 while (*current_ptr) {
848 current = *current_ptr;
850 if (!strcmp(normalize(*files_to_move), current->filename)) {
855 if (current->arelt_data == NULL) {
856 /* This can only happen if you specify a file on the
857 command line more than once. */
858 fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
862 if (stat(*files_to_move, &fsbuf) != 0) {
864 bfd_fatal(*files_to_move);
867 if (bfd_stat_arch_elt(current, &asbuf) != 0)
868 fatal("Internal stat error on %s", current->filename);
870 if (fsbuf.st_mtime <= asbuf.st_mtime)
874 /* snip out this entry from the chain */
875 *current_ptr = current->next;
877 after_bfd = get_pos_bfd(&inarch->next, pos_end);
879 *after_bfd = bfd_openr(*files_to_move, NULL);
880 if (*after_bfd == (bfd *) NULL) {
881 fprintf(stderr, "Can't open file %s\n", *files_to_move);
885 gnu960_verify_target(*after_bfd); /* Exits on failure */
887 (*after_bfd)->next = temp;
890 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
895 current_ptr = &(current->next);
898 /* It isn't in there, so add to end */
900 after_bfd = get_pos_bfd(&inarch->next, pos_end);
902 *after_bfd = bfd_openr(*files_to_move, NULL);
903 if (*after_bfd == (bfd *) NULL) {
904 fprintf(stderr, "Can't open file %s\n", *files_to_move);
908 gnu960_verify_target(*after_bfd); /* Exits on failure */
911 printf("c - %s\n", *files_to_move);
914 (*after_bfd)->next = temp;
926 ranlib_only(archname)
930 open_inarch(archname);
937 /* Things which are interesting to map over all or some of the files: */
943 print_arelt_descr(abfd, verbose);