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"
42 void EXFUN(open_inarch,(char *archive_filename));
45 PROTO(void, print_contents, (bfd * member));
46 PROTO(void, extract_file, (bfd * abfd));
47 PROTO(void, delete_members, (char **files_to_delete));
48 PROTO(void, do_quick_append, (char *archive_filename, char **files_to_append));
49 PROTO(void, move_members, (char **files_to_move));
50 PROTO(void, replace_members, (char **files_to_replace));
51 PROTO(void, print_descr, (bfd * abfd));
52 PROTO(void, ranlib_only, (char *archname));
54 /** Globals and flags */
56 char *program_name = NULL;
58 bfd *inarch; /* The input arch we're manipulating */
61 /* This flag distinguishes between ar and ranlib:
62 1 means this is 'ranlib'; 0 means this is 'ar'.
63 -1 means if we should use argv[0] to decide. */
65 /* Nonzero means don't warn about creating the archive file if necessary. */
66 int silent_create = 0;
67 /* Nonzero means describe each action performed. */
69 /* Nonzero means preserve dates of members when extracting them. */
70 int preserve_dates = 0;
72 Nonzero means don't replace existing members whose dates are more recent
73 than the corresponding files.
76 /* write a __.SYMDEF member into the modified archive. */
77 boolean write_armap = false;
79 Nonzero means don't update __.SYMDEF unless command line explicitly
82 int ignore_symdef = 0;
84 Nonzero means it's the name of an existing member; position new or moved
85 files with respect to this one.
89 Sez how to use `posname': pos_before means position before that member.
90 pos_after means position after that member. pos_end means always at end.
91 pos_default means default appropriately. For the latter two, `posname'
95 pos_default, pos_before, pos_after, pos_end
96 } postype = pos_default;
102 gnu960_verify_target(abfd)
105 if ( abfd->format == bfd_unknown ){
106 bfd_check_format(abfd, bfd_object);
107 /* Don't really care if it's an object --
108 * just want to get the correct xvec.
111 if ( !BFD_COFF_FILE_P(abfd) ){
112 fatal( "'%s' not a COFF file -- operation aborted",
122 interactive = isatty(fileno(stdin)) ;
127 If count is 0, then function is called once on each entry. if nonzero,
128 count is the length of the files chain; function is called on each entry
129 whose name matches one in files
132 DEFUN(map_over_members,(function, files, count),
133 void (*function) () AND
140 for (head = inarch->next; head; head = head->next)
145 This may appear to be a baroque way of accomplishing what we want.
146 however we have to iterate over the filenames in order to notice where
147 a filename is requested but does not exist in the archive. Ditto
148 mapping over each file each time -- we want to hack multiple
152 for (; count > 0; files++, count--) {
153 boolean found = false;
154 for (head = inarch->next; head; head = head->next)
155 if ((head->filename != NULL) &&
156 (!strcmp(*files, head->filename))) {
161 fprintf(stderr, "No entry %s in archive.\n", *files);
166 boolean operation_alters_arch = false;
169 The option parsing should be in its own function. It will be when I have
180 none = 0, delete, replace, print_table,
181 print_files, extract, move, quick_append
185 char *inarch_filename;
191 check_v960( argc, argv );
192 default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
195 program_name = argv[0];
197 temp = strrchr(program_name, '/');
198 if (temp == (char *) NULL)
199 temp = program_name; /* shouldn't happen, but... */
202 if (is_ranlib > 0 || (is_ranlib < 0 && strcmp(temp, "ranlib") == 0)) {
204 bfd_fatal("Too few command arguments.");
205 ranlib_only(argv[1]);
208 if (argc == 2 && strcmp(argv[1],"-M") == 0) {
213 bfd_fatal("Too few command arguments.");
218 ++arg_ptr; /* compatibility */
220 while (c = *arg_ptr++) {
229 if (operation != none)
230 fatal("two different operation switches specified");
234 operation_alters_arch = true;
238 operation_alters_arch = true;
241 operation = print_files;
244 operation = quick_append;
245 operation_alters_arch = true;
249 operation_alters_arch = true;
252 operation = print_table;
279 postype = pos_before;
282 postype = pos_before;
289 fatal("invalid option %c", c);
297 if ((operation == none || operation == print_table)
298 && write_armap == true)
299 ranlib_only(argv[2]);
301 if (operation == none)
302 fatal("no operation specified");
304 if (newer_only && operation != replace)
305 fatal("'u' only meaningful with 'r' option.");
309 if (postype != pos_default)
310 posname = argv[arg_index++];
312 inarch_filename = argv[arg_index++];
314 if (arg_index < argc) {
315 files = argv + arg_index;
316 while (arg_index < argc)
317 if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
325 if (operation == quick_append) {
327 do_quick_append(inarch_filename, files);
332 open_inarch(inarch_filename);
334 If we have no archive, and we've been asked to replace then create one
337 if (operation == replace && inarch == &bogus_archive) {
339 do_quick_append(inarch_filename, 0);
340 open_inarch(inarch_filename);
346 map_over_members(print_descr, files, argc - 3);
350 map_over_members(print_contents, files, argc - 3);
354 map_over_members(extract_file, files, argc - 3);
359 delete_members(files);
368 if (files != NULL || write_armap)
369 replace_members(files);
372 /* Shouldn't happen! */
374 fprintf(stderr, "Sorry; this option not implemented.\n");
381 char *normalize(file)
384 char * filename = strrchr(file, '/');
385 if (filename != (char *)NULL) {
395 open_inarch(archive_filename)
396 char *archive_filename;
401 bfd_error = no_error;
402 if (stat(archive_filename, &sbuf) != 0) {
404 bfd_fatal(archive_filename);
405 if (!operation_alters_arch) {
406 fprintf (stderr, "%s: %s not found.\n", program_name,
413 "%s: creating %s\n", program_name, archive_filename);
415 inarch = &bogus_archive;
416 inarch->filename = archive_filename;
417 inarch->has_armap = true;
422 inarch = bfd_openr(archive_filename, default_target);
424 inarch = bfd_openr(archive_filename, NULL);
426 if (inarch == NULL) {
428 bfd_perror(archive_filename);
432 if (bfd_check_format(inarch, bfd_archive) != true)
433 fatal("File %s is not an archive.", archive_filename);
435 gnu960_verify_target(inarch); /* Exits on failure */
437 last_one = &(inarch->next);
438 /* Read all the contents right away, regardless. */
439 for (next_one = bfd_openr_next_archived_file(inarch, NULL);
441 next_one = bfd_openr_next_archived_file(inarch, next_one)) {
442 *last_one = next_one;
443 last_one = &next_one->next;
445 *last_one = (bfd *) NULL;
446 if (bfd_error != no_more_archived_files)
462 if (bfd_stat_arch_elt(abfd, &buf) != 0)
463 fatal("Internal stat error on %s", abfd->filename);
466 printf("\n<member %s>\n\n", abfd->filename);
468 bfd_seek(abfd, 0, SEEK_SET);
471 while (ncopied < size) {
474 int tocopy = size - ncopied;
475 if (tocopy > BUFSIZE)
478 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
482 fatal("file %s not a valid archive", abfd->my_archive->filename);
483 fwrite(cbuf, 1, nread, stdout);
490 Extract a member of the archive into its own file.
492 We defer opening the new file until after we have read a BUFSIZ chunk of the
493 old one, since we know we have just read the archive header for the old
494 one. Since most members are shorter than BUFSIZ, this means we will read
495 the old header, read the old data, write a new inode for the new file, and
496 write the new data, and be done. This 'optimization' is what comes from
497 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
512 if (bfd_stat_arch_elt(abfd, &buf) != 0)
513 fatal("Internal stat error on %s", abfd->filename);
517 printf("x - %s\n", abfd->filename);
519 bfd_seek(abfd, 0, SEEK_SET);
523 /* Seems like an abstraction violation, eh? Well it's OK! */
524 ostream = fopen(abfd->filename, FOPEN_WB);
526 perror(abfd->filename);
530 while (ncopied < size) {
531 tocopy = size - ncopied;
532 if (tocopy > BUFSIZE)
535 nread = bfd_read(cbuf, 1, tocopy, abfd);
537 fatal("file %s not a valid archive", abfd->my_archive->filename);
539 /* See comment above; this saves disk arm motion */
541 /* Seems like an abstraction violation, eh? Well it's OK! */
542 ostream = fopen(abfd->filename, FOPEN_WB);
544 perror(abfd->filename);
548 fwrite(cbuf, 1, nread, ostream);
553 chmod(abfd->filename, buf.st_mode);
555 if (preserve_dates) {
558 tb[0] = buf.st_mtime;
559 tb[1] = buf.st_mtime;
560 utime(abfd->filename, tb); /* FIXME check result */
562 struct timeval tv[2];
563 tv[0].tv_sec = buf.st_mtime;
565 tv[1].tv_sec = buf.st_mtime;
567 utimes(abfd->filename, tv); /* FIXME check result */
573 /* Just do it quickly; don't worry about dups, armap, or anything like that */
575 /* This is ugly! XXX */
577 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
580 do_quick_append(archive_filename, files_to_append)
581 char *archive_filename;
582 char **files_to_append;
592 boolean newfile = false;
593 bfd_error = no_error;
595 if (stat(archive_filename, &sbuf) != 0) {
597 bfd_fatal(archive_filename);
602 ofile = fopen(archive_filename, FOPEN_AUB);
604 perror(program_name);
610 temp = bfd_openr(archive_filename, default_target);
612 temp = bfd_openr(archive_filename, NULL);
615 bfd_perror(archive_filename);
618 if (newfile == false) {
619 if (bfd_check_format(temp, bfd_archive) != true)
620 fatal("File %s is not an archive.", archive_filename);
622 gnu960_verify_target(temp); /* Exits on failure */
626 fwrite(ARMAG, 1, SARMAG, ofile);
628 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
631 /* assume it's an achive, go straight to the end, sans $200 */
634 for (; files_to_append && *files_to_append; ++files_to_append) {
635 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
637 bfd_perror(*files_to_append);
641 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
643 ifile = fopen(*files_to_append, FOPEN_RB);
645 bfd_perror(program_name);
647 if (stat(*files_to_append, &sbuf) != 0)
648 bfd_perror(*files_to_append);
650 tocopy = sbuf.st_size;
652 /* XXX should do error-checking! */
653 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
658 if (thistime > BUFSIZE)
660 fread(buf, 1, thistime, ifile);
661 fwrite(buf, 1, thistime, ofile);
665 if ((sbuf.st_size % 2) == 1)
677 int namelen = strlen(inarch->filename);
678 char *new_name = xmalloc(namelen + 6);
679 bfd *contents_head = inarch->next;
681 if (inarch == &bogus_archive) {
682 /* How can this be ? */
687 strcpy(new_name, inarch->filename);
688 strcpy(new_name + namelen, "-art");
689 obfd = bfd_openw(new_name,
690 /* FIXME: violates abstraction; need a better protocol */
691 (inarch->xvec ? bfd_get_target(inarch) : NULL));
694 bfd_fatal(inarch->filename);
696 bfd_set_format(obfd, bfd_archive);
697 obfd->has_armap = write_armap;
699 if (bfd_set_archive_head(obfd, contents_head) != true)
700 bfd_fatal(inarch->filename);
702 if (!bfd_close(obfd))
703 bfd_fatal(inarch->filename);
705 /* We don't care if this fails, we might be creating the
707 (void) unlink(inarch->filename);
709 if (rename(new_name, inarch->filename) != 0)
710 bfd_fatal(inarch->filename);
719 returns a pointer to the pointer to the entry which should be rplacd'd
720 into when altering. default_pos should be how to interpret pos_default,
721 and should be a pos value.
725 get_pos_bfd(contents, default_pos)
727 enum pos default_pos;
729 bfd **after_bfd = contents;
730 enum pos realpos = (postype == pos_default ? default_pos : postype);
732 if (realpos == pos_end) {
734 after_bfd = &((*after_bfd)->next);
737 for ( ; *after_bfd; after_bfd = &(*after_bfd)->next)
738 if (!strcmp((*after_bfd)->filename, posname)) {
739 if (realpos == pos_after)
740 after_bfd = &(*after_bfd)->next;
749 delete_members(files_to_delete)
750 char **files_to_delete;
752 bfd **current_ptr_ptr;
754 boolean something_changed = false;
755 for (; *files_to_delete != NULL; ++files_to_delete) {
757 In a.out systems, the armap is optional. It's also called
758 __.SYMDEF. So if the user asked to delete it, we should remember
759 that fact. The name is NULL in COFF archives, so using this as a
760 key is as good as anything I suppose
762 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
763 inarch->has_armap = false;
769 current_ptr_ptr = &(inarch->next);
770 while (*current_ptr_ptr) {
771 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
773 something_changed = true;
777 *current_ptr_ptr = ((*current_ptr_ptr)->next);
782 current_ptr_ptr = &((*current_ptr_ptr)->next);
786 if (verbose && found == false) {
787 printf("No member named `%s'\n", *files_to_delete);
793 if (something_changed == true) {
799 /* Reposition existing members within an archive */
802 move_members(files_to_move)
803 char **files_to_move;
805 bfd **after_bfd; /* New entries go after this one */
806 bfd **current_ptr_ptr; /* cdr pointer into contents */
811 for (; *files_to_move; ++files_to_move) {
812 current_ptr_ptr = &(inarch->next);
813 while (*current_ptr_ptr) {
814 bfd *current_ptr = *current_ptr_ptr;
815 if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
817 Move this file to the end of the list - first cut from
820 *current_ptr_ptr = current_ptr->next;
822 /* Now glue to end */
823 after_bfd = get_pos_bfd(&inarch->next, pos_end);
824 *after_bfd = current_ptr;
825 current_ptr->next = (bfd *) NULL;
828 printf("m - %s\n", *files_to_move);
832 current_ptr_ptr = &((*current_ptr_ptr)->next);
834 fprintf(stderr, "No entry %s in archive %s!\n",
835 *files_to_move, inarch->filename);
844 /* Ought to default to replacing in place, but this is existing practice! */
847 replace_members(files_to_move)
848 char **files_to_move;
850 bfd **after_bfd; /* New entries go after this one */
855 If the first item in the archive is an __.SYMDEF then remove it
858 strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
859 inarch->next = inarch->next->next;
864 while (files_to_move && *files_to_move) {
865 current_ptr = &inarch->next;
866 while (*current_ptr) {
867 current = *current_ptr;
869 if (!strcmp(normalize(*files_to_move), current->filename)) {
874 if (current->arelt_data == NULL) {
875 /* This can only happen if you specify a file on the
876 command line more than once. */
877 fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
881 if (stat(*files_to_move, &fsbuf) != 0) {
883 bfd_fatal(*files_to_move);
886 if (bfd_stat_arch_elt(current, &asbuf) != 0)
887 fatal("Internal stat error on %s", current->filename);
889 if (fsbuf.st_mtime <= asbuf.st_mtime)
893 /* snip out this entry from the chain */
894 *current_ptr = current->next;
896 after_bfd = get_pos_bfd(&inarch->next, pos_end);
898 *after_bfd = bfd_openr(*files_to_move, NULL);
899 if (*after_bfd == (bfd *) NULL) {
900 fprintf(stderr, "Can't open file %s\n", *files_to_move);
904 gnu960_verify_target(*after_bfd); /* Exits on failure */
906 (*after_bfd)->next = temp;
909 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
914 current_ptr = &(current->next);
917 /* It isn't in there, so add to end */
919 after_bfd = get_pos_bfd(&inarch->next, pos_end);
921 *after_bfd = bfd_openr(*files_to_move, NULL);
922 if (*after_bfd == (bfd *) NULL) {
923 fprintf(stderr, "Can't open file %s\n", *files_to_move);
927 gnu960_verify_target(*after_bfd); /* Exits on failure */
930 printf("c - %s\n", *files_to_move);
933 (*after_bfd)->next = temp;
945 ranlib_only(archname)
949 open_inarch(archname);
956 /* Things which are interesting to map over all or some of the files: */
962 print_arelt_descr(stdout,abfd, verbose);