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"
48 PROTO(void, print_contents, (bfd * member));
49 PROTO(void, extract_file, (bfd * abfd));
50 PROTO(void, delete_members, (char **files_to_delete));
51 PROTO(void, do_quick_append, (char *archive_filename, char **files_to_append));
52 PROTO(void, move_members, (char **files_to_move));
53 PROTO(void, replace_members, (char **files_to_replace));
54 PROTO(void, print_descr, (bfd * abfd));
55 PROTO(void, ranlib_only, (char *archname));
57 /** Globals and flags */
59 char *program_name = NULL;
61 bfd *inarch; /* The input arch we're manipulating */
64 /* This flag distinguishes between ar and ranlib:
65 1 means this is 'ranlib'; 0 means this is 'ar'.
66 -1 means if we should use argv[0] to decide. */
68 /* Nonzero means don't warn about creating the archive file if necessary. */
69 int silent_create = 0;
70 /* Nonzero means describe each action performed. */
72 /* Nonzero means preserve dates of members when extracting them. */
73 int preserve_dates = 0;
75 Nonzero means don't replace existing members whose dates are more recent
76 than the corresponding files.
79 /* write a __.SYMDEF member into the modified archive. */
80 boolean write_armap = false;
82 Nonzero means don't update __.SYMDEF unless command line explicitly
85 int ignore_symdef = 0;
87 Nonzero means it's the name of an existing member; position new or moved
88 files with respect to this one.
92 Sez how to use `posname': pos_before means position before that member.
93 pos_after means position after that member. pos_end means always at end.
94 pos_default means default appropriately. For the latter two, `posname'
98 pos_default, pos_before, pos_after, pos_end
99 } postype = pos_default;
102 char *default_target;
105 gnu960_verify_target(abfd)
108 if ( abfd->format == bfd_unknown ){
109 bfd_check_format(abfd, bfd_object);
110 /* Don't really care if it's an object --
111 * just want to get the correct xvec.
114 if ( !BFD_COFF_FILE_P(abfd) ){
115 fatal( "'%s' not a COFF file -- operation aborted",
125 interactive = isatty(fileno(stdin)) ;
130 If count is 0, then function is called once on each entry. if nonzero,
131 count is the length of the files chain; function is called on each entry
132 whose name matches one in files
135 DEFUN(map_over_members,(function, files, count),
136 void (*function) () AND
143 for (head = inarch->next; head; head = head->next)
148 This may appear to be a baroque way of accomplishing what we want.
149 however we have to iterate over the filenames in order to notice where
150 a filename is requested but does not exist in the archive. Ditto
151 mapping over each file each time -- we want to hack multiple
155 for (; count > 0; files++, count--) {
156 boolean found = false;
157 for (head = inarch->next; head; head = head->next)
158 if ((head->filename != NULL) &&
159 (!strcmp(*files, head->filename))) {
164 fprintf(stderr, "No entry %s in archive.\n", *files);
169 boolean operation_alters_arch = false;
172 The option parsing should be in its own function. It will be when I have
183 none = 0, delete, replace, print_table,
184 print_files, extract, move, quick_append
188 char *inarch_filename;
194 check_v960( argc, argv );
195 default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
198 program_name = argv[0];
200 temp = strrchr(program_name, '/');
201 if (temp == (char *) NULL)
202 temp = program_name; /* shouldn't happen, but... */
205 if (is_ranlib > 0 || (is_ranlib < 0 && strcmp(temp, "ranlib") == 0)) {
207 bfd_fatal("Too few command arguments.");
208 ranlib_only(argv[1]);
211 if (argc == 2 && strcmp(argv[1],"-M") == 0) {
216 bfd_fatal("Too few command arguments.");
221 ++arg_ptr; /* compatibility */
223 while (c = *arg_ptr++) {
232 if (operation != none)
233 fatal("two different operation switches specified");
237 operation_alters_arch = true;
241 operation_alters_arch = true;
244 operation = print_files;
247 operation = quick_append;
248 operation_alters_arch = true;
252 operation_alters_arch = true;
255 operation = print_table;
282 postype = pos_before;
285 postype = pos_before;
292 fatal("invalid option %c", c);
300 if ((operation == none || operation == print_table)
301 && write_armap == true)
302 ranlib_only(argv[2]);
304 if (operation == none)
305 fatal("no operation specified");
307 if (newer_only && operation != replace)
308 fatal("'u' only meaningful with 'r' option.");
312 if (postype != pos_default)
313 posname = argv[arg_index++];
315 inarch_filename = argv[arg_index++];
317 if (arg_index < argc) {
318 files = argv + arg_index;
319 while (arg_index < argc)
320 if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
328 if (operation == quick_append) {
330 do_quick_append(inarch_filename, files);
335 open_inarch(inarch_filename);
337 If we have no archive, and we've been asked to replace then create one
340 if (operation == replace && inarch == &bogus_archive) {
342 do_quick_append(inarch_filename, 0);
343 open_inarch(inarch_filename);
349 map_over_members(print_descr, files, argc - 3);
353 map_over_members(print_contents, files, argc - 3);
357 map_over_members(extract_file, files, argc - 3);
362 delete_members(files);
371 if (files != NULL || write_armap)
372 replace_members(files);
375 /* Shouldn't happen! */
377 fprintf(stderr, "Sorry; this option not implemented.\n");
384 char *normalize(file)
387 char * filename = strrchr(file, '/');
388 if (filename != (char *)NULL) {
398 open_inarch(archive_filename)
399 char *archive_filename;
404 bfd_error = no_error;
405 if (stat(archive_filename, &sbuf) != 0) {
407 bfd_fatal(archive_filename);
408 if (!operation_alters_arch) {
409 fprintf (stderr, "%s: %s not found.\n", program_name,
416 "%s: creating %s\n", program_name, archive_filename);
418 inarch = &bogus_archive;
419 inarch->filename = archive_filename;
420 inarch->has_armap = true;
425 inarch = bfd_openr(archive_filename, default_target);
427 inarch = bfd_openr(archive_filename, NULL);
429 if (inarch == NULL) {
431 bfd_perror(archive_filename);
435 if (bfd_check_format(inarch, bfd_archive) != true)
436 fatal("File %s is not an archive.", archive_filename);
438 gnu960_verify_target(inarch); /* Exits on failure */
440 last_one = &(inarch->next);
441 /* Read all the contents right away, regardless. */
442 for (next_one = bfd_openr_next_archived_file(inarch, NULL);
444 next_one = bfd_openr_next_archived_file(inarch, next_one)) {
445 *last_one = next_one;
446 last_one = &next_one->next;
448 *last_one = (bfd *) NULL;
449 if (bfd_error != no_more_archived_files)
466 if (bfd_stat_arch_elt(abfd, &buf) != 0)
467 fatal("Internal stat error on %s", abfd->filename);
470 printf("\n<member %s>\n\n", abfd->filename);
472 bfd_seek(abfd, 0, SEEK_SET);
475 while (ncopied < size) {
478 int tocopy = size - ncopied;
479 if (tocopy > BUFSIZE)
482 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
486 fatal("file %s not a valid archive", abfd->my_archive->filename);
487 fwrite(cbuf, 1, nread, stdout);
494 Extract a member of the archive into its own file.
496 We defer opening the new file until after we have read a BUFSIZ chunk of the
497 old one, since we know we have just read the archive header for the old
498 one. Since most members are shorter than BUFSIZ, this means we will read
499 the old header, read the old data, write a new inode for the new file, and
500 write the new data, and be done. This 'optimization' is what comes from
501 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
516 if (bfd_stat_arch_elt(abfd, &buf) != 0)
517 fatal("Internal stat error on %s", abfd->filename);
521 printf("x - %s\n", abfd->filename);
523 bfd_seek(abfd, 0, SEEK_SET);
527 /* Seems like an abstraction violation, eh? Well it's OK! */
528 ostream = fopen(abfd->filename, FOPEN_WB);
530 perror(abfd->filename);
534 while (ncopied < size) {
535 tocopy = size - ncopied;
536 if (tocopy > BUFSIZE)
539 nread = bfd_read(cbuf, 1, tocopy, abfd);
541 fatal("file %s not a valid archive", abfd->my_archive->filename);
543 /* See comment above; this saves disk arm motion */
545 /* Seems like an abstraction violation, eh? Well it's OK! */
546 ostream = fopen(abfd->filename, FOPEN_WB);
548 perror(abfd->filename);
552 fwrite(cbuf, 1, nread, ostream);
557 chmod(abfd->filename, buf.st_mode);
559 if (preserve_dates) {
562 tb[0] = buf.st_mtime;
563 tb[1] = buf.st_mtime;
564 utime(abfd->filename, tb); /* FIXME check result */
566 struct timeval tv[2];
567 tv[0].tv_sec = buf.st_mtime;
569 tv[1].tv_sec = buf.st_mtime;
571 utimes(abfd->filename, tv); /* FIXME check result */
577 /* Just do it quickly; don't worry about dups, armap, or anything like that */
579 /* This is ugly! XXX */
581 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
584 do_quick_append(archive_filename, files_to_append)
585 char *archive_filename;
586 char **files_to_append;
596 boolean newfile = false;
597 bfd_error = no_error;
599 if (stat(archive_filename, &sbuf) != 0) {
601 bfd_fatal(archive_filename);
606 ofile = fopen(archive_filename, FOPEN_AUB);
608 perror(program_name);
614 temp = bfd_openr(archive_filename, default_target);
616 temp = bfd_openr(archive_filename, NULL);
619 bfd_perror(archive_filename);
622 if (newfile == false) {
623 if (bfd_check_format(temp, bfd_archive) != true)
624 fatal("File %s is not an archive.", archive_filename);
626 gnu960_verify_target(temp); /* Exits on failure */
630 fwrite(ARMAG, 1, SARMAG, ofile);
632 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
635 /* assume it's an achive, go straight to the end, sans $200 */
638 for (; files_to_append && *files_to_append; ++files_to_append) {
639 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
641 bfd_perror(*files_to_append);
645 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
647 ifile = fopen(*files_to_append, FOPEN_RB);
649 bfd_perror(program_name);
651 if (stat(*files_to_append, &sbuf) != 0)
652 bfd_perror(*files_to_append);
654 tocopy = sbuf.st_size;
656 /* XXX should do error-checking! */
657 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
662 if (thistime > BUFSIZE)
664 fread(buf, 1, thistime, ifile);
665 fwrite(buf, 1, thistime, ofile);
669 if ((sbuf.st_size % 2) == 1)
681 int namelen = strlen(inarch->filename);
682 char *new_name = xmalloc(namelen + 6);
683 bfd *contents_head = inarch->next;
685 if (inarch == &bogus_archive) {
686 /* How can this be ? */
691 strcpy(new_name, inarch->filename);
692 strcpy(new_name + namelen, "-art");
693 obfd = bfd_openw(new_name,
694 /* FIXME: violates abstraction; need a better protocol */
695 (inarch->xvec ? bfd_get_target(inarch) : NULL));
698 bfd_fatal(inarch->filename);
700 bfd_set_format(obfd, bfd_archive);
701 obfd->has_armap = write_armap;
703 if (bfd_set_archive_head(obfd, contents_head) != true)
704 bfd_fatal(inarch->filename);
706 if (!bfd_close(obfd))
707 bfd_fatal(inarch->filename);
709 /* We don't care if this fails, we might be creating the
711 (void) unlink(inarch->filename);
713 if (rename(new_name, inarch->filename) != 0)
714 bfd_fatal(inarch->filename);
723 returns a pointer to the pointer to the entry which should be rplacd'd
724 into when altering. default_pos should be how to interpret pos_default,
725 and should be a pos value.
729 get_pos_bfd(contents, default_pos)
731 enum pos default_pos;
733 bfd **after_bfd = contents;
734 enum pos realpos = (postype == pos_default ? default_pos : postype);
736 if (realpos == pos_end) {
738 after_bfd = &((*after_bfd)->next);
741 for ( ; *after_bfd; after_bfd = &(*after_bfd)->next)
742 if (!strcmp((*after_bfd)->filename, posname)) {
743 if (realpos == pos_after)
744 after_bfd = &(*after_bfd)->next;
753 delete_members(files_to_delete)
754 char **files_to_delete;
756 bfd **current_ptr_ptr;
758 boolean something_changed = false;
759 for (; *files_to_delete != NULL; ++files_to_delete) {
761 In a.out systems, the armap is optional. It's also called
762 __.SYMDEF. So if the user asked to delete it, we should remember
763 that fact. The name is NULL in COFF archives, so using this as a
764 key is as good as anything I suppose
766 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
767 inarch->has_armap = false;
773 current_ptr_ptr = &(inarch->next);
774 while (*current_ptr_ptr) {
775 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
777 something_changed = true;
781 *current_ptr_ptr = ((*current_ptr_ptr)->next);
786 current_ptr_ptr = &((*current_ptr_ptr)->next);
790 if (verbose && found == false) {
791 printf("No member named `%s'\n", *files_to_delete);
797 if (something_changed == true) {
803 /* Reposition existing members within an archive */
806 move_members(files_to_move)
807 char **files_to_move;
809 bfd **after_bfd; /* New entries go after this one */
810 bfd **current_ptr_ptr; /* cdr pointer into contents */
815 for (; *files_to_move; ++files_to_move) {
816 current_ptr_ptr = &(inarch->next);
817 while (*current_ptr_ptr) {
818 bfd *current_ptr = *current_ptr_ptr;
819 if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
821 Move this file to the end of the list - first cut from
824 *current_ptr_ptr = current_ptr->next;
826 /* Now glue to end */
827 after_bfd = get_pos_bfd(&inarch->next, pos_end);
828 *after_bfd = current_ptr;
829 current_ptr->next = (bfd *) NULL;
832 printf("m - %s\n", *files_to_move);
836 current_ptr_ptr = &((*current_ptr_ptr)->next);
838 fprintf(stderr, "No entry %s in archive %s!\n",
839 *files_to_move, inarch->filename);
848 /* Ought to default to replacing in place, but this is existing practice! */
851 replace_members(files_to_move)
852 char **files_to_move;
854 bfd **after_bfd; /* New entries go after this one */
859 If the first item in the archive is an __.SYMDEF then remove it
862 strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
863 inarch->next = inarch->next->next;
868 while (files_to_move && *files_to_move) {
869 current_ptr = &inarch->next;
870 while (*current_ptr) {
871 current = *current_ptr;
873 if (!strcmp(normalize(*files_to_move), current->filename)) {
878 if (current->arelt_data == NULL) {
879 /* This can only happen if you specify a file on the
880 command line more than once. */
881 fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
885 if (stat(*files_to_move, &fsbuf) != 0) {
887 bfd_fatal(*files_to_move);
890 if (bfd_stat_arch_elt(current, &asbuf) != 0)
891 fatal("Internal stat error on %s", current->filename);
893 if (fsbuf.st_mtime <= asbuf.st_mtime)
897 /* snip out this entry from the chain */
898 *current_ptr = current->next;
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 */
910 (*after_bfd)->next = temp;
913 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
918 current_ptr = &(current->next);
921 /* It isn't in there, so add to end */
923 after_bfd = get_pos_bfd(&inarch->next, pos_end);
925 *after_bfd = bfd_openr(*files_to_move, NULL);
926 if (*after_bfd == (bfd *) NULL) {
927 fprintf(stderr, "Can't open file %s\n", *files_to_move);
931 gnu960_verify_target(*after_bfd); /* Exits on failure */
934 printf("c - %s\n", *files_to_move);
937 (*after_bfd)->next = temp;
949 ranlib_only(archname)
953 open_inarch(archname);
960 /* Things which are interesting to map over all or some of the files: */
966 print_arelt_descr(stdout,abfd, verbose);