1 /* ar.c - Archive modify and extract.
2 Copyright 1991, 1992 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 #else /* ! POSIX_UTIME */
39 #else /* ! USE_UTIME */
41 #endif /* ! USE_UTIME */
42 #endif /* ! POSIX_UTIME */
49 /* Kludge declaration from BFD! This is ugly! FIXME! XXX */
52 bfd_special_undocumented_glue PARAMS ((bfd *abfd, char *filename));
54 /* Forward declarations */
57 print_contents PARAMS ((bfd * member));
60 delete_members PARAMS ((char **files_to_delete));
63 do_quick_append PARAMS ((char *archive_filename, char **files_to_append));
66 move_members PARAMS ((char **files_to_move));
69 replace_members PARAMS ((char **files_to_replace));
72 print_descr PARAMS ((bfd * abfd));
75 ranlib_only PARAMS ((char *archname));
77 /** Globals and flags */
79 char *program_name = NULL;
80 bfd *inarch; /* The input arch we're manipulating */
83 /* This flag distinguishes between ar and ranlib:
84 1 means this is 'ranlib'; 0 means this is 'ar'.
85 -1 means if we should use argv[0] to decide. */
87 /* Nonzero means don't warn about creating the archive file if necessary. */
88 int silent_create = 0;
89 /* Nonzero means describe each action performed. */
91 /* Nonzero means preserve dates of members when extracting them. */
92 int preserve_dates = 0;
94 Nonzero means don't replace existing members whose dates are more recent
95 than the corresponding files.
99 /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
100 member). -1 means we've been explicitly asked to not write a symbol table;
101 +1 means we've been explictly asked to write it;
103 Traditionally, the default in BSD has been to not write the table.
104 However, for Posix.2 compliance the default is now to write a symbol table
105 if any of the members are object files. */
109 Nonzero means it's the name of an existing member; position new or moved
110 files with respect to this one.
112 char *posname = NULL;
114 Sez how to use `posname': pos_before means position before that member.
115 pos_after means position after that member. pos_end means always at end.
116 pos_default means default appropriately. For the latter two, `posname'
120 pos_default, pos_before, pos_after, pos_end
121 } postype = pos_default;
124 char *default_target;
127 gnu960_verify_target(abfd)
130 if ( abfd->format == bfd_unknown ){
131 bfd_check_format(abfd, bfd_object);
132 /* Don't really care if it's an object --
133 * just want to get the correct xvec.
136 if ( !BFD_COFF_FILE_P(abfd) ){
137 fatal( "'%s' not a COFF file -- operation aborted",
147 interactive = isatty(fileno(stdin)) ;
152 If count is 0, then function is called once on each entry. if nonzero,
153 count is the length of the files chain; function is called on each entry
154 whose name matches one in files
157 DEFUN(map_over_members,(function, files, count),
158 void (*function) () AND
165 for (head = inarch->next; head; head = head->next)
170 This may appear to be a baroque way of accomplishing what we want.
171 however we have to iterate over the filenames in order to notice where
172 a filename is requested but does not exist in the archive. Ditto
173 mapping over each file each time -- we want to hack multiple
177 for (; count > 0; files++, count--) {
178 boolean found = false;
179 for (head = inarch->next; head; head = head->next)
181 if (head->filename == NULL)
183 /* Some archive formats don't get the filenames filled in
184 'till the elements are opened */
186 bfd_stat_arch_elt(head, &buf);
188 if ((head->filename != NULL) &&
189 (!strcmp(*files, head->filename))) {
195 fprintf(stderr, "No entry %s in archive.\n", *files);
200 boolean operation_alters_arch = false;
202 extern char *program_version;
207 printf ("%s version %s\n", program_name, program_version);
213 fprintf(stderr, "ar %s\n\
214 Usage: %s [-]{dmpqrtx}[abcilosuv] [member-name] archive-file file...\n\
215 %s -M [<mri-script]\n",
216 program_version, program_name, program_name);
221 The option parsing should be in its own function. It will be when I have
232 none = 0, delete, replace, print_table,
233 print_files, extract, move, quick_append
237 char *inarch_filename;
244 check_v960( argc, argv );
245 default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
248 program_name = argv[0];
250 temp = strrchr(program_name, '/');
251 if (temp == (char *) NULL)
252 temp = program_name; /* shouldn't happen, but... */
255 if (is_ranlib > 0 || (is_ranlib < 0 && strcmp(temp, "ranlib") == 0)) {
259 if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "-v") == 0) {
265 ranlib_only(arg_ptr);
268 if (argc == 2 && strcmp(argv[1],"-M") == 0) {
279 ++arg_ptr; /* compatibility */
281 while (c = *arg_ptr++) {
290 if (operation != none)
291 fatal("two different operation switches specified");
295 operation_alters_arch = true;
299 operation_alters_arch = true;
302 operation = print_files;
305 operation = quick_append;
306 operation_alters_arch = true;
310 operation_alters_arch = true;
313 operation = print_table;
343 postype = pos_before;
346 postype = pos_before;
353 fatal("invalid option %c", c);
370 if ((operation == none || operation == print_table)
372 ranlib_only(argv[2]);
374 if (operation == none)
375 fatal("no operation specified");
377 if (newer_only && operation != replace)
378 fatal("'u' only meaningful with 'r' option.");
382 if (postype != pos_default)
383 posname = argv[arg_index++];
385 inarch_filename = argv[arg_index++];
387 files = arg_index < argc ? argv + arg_index : NULL;
389 if (operation == quick_append) {
391 do_quick_append(inarch_filename, files);
396 open_inarch(inarch_filename);
401 map_over_members(print_descr, files, argc - 3);
405 map_over_members(print_contents, files, argc - 3);
409 map_over_members(extract_file, files, argc - 3);
414 delete_members(files);
423 if (files != NULL || write_armap > 0)
424 replace_members(files);
427 /* Shouldn't happen! */
429 fprintf(stderr, "Sorry; this option not implemented.\n");
436 char *normalize(file)
439 char * filename = strrchr(file, '/');
440 if (filename != (char *)NULL) {
450 open_inarch(archive_filename)
451 char *archive_filename;
456 bfd_error = no_error;
457 if (stat(archive_filename, &sbuf) != 0) {
459 bfd_fatal(archive_filename);
460 if (!operation_alters_arch) {
461 fprintf (stderr, "%s: %s not found.\n", program_name,
467 /* This routine is one way to forcibly create the archive. */
468 do_quick_append(archive_filename, 0);
472 inarch = bfd_openr(archive_filename, default_target);
474 inarch = bfd_openr(archive_filename, NULL);
476 if (inarch == NULL) {
478 fprintf (stderr, "%s: ", program_name);
479 bfd_perror(archive_filename);
483 if (bfd_check_format(inarch, bfd_archive) != true)
484 fatal("File %s is not an archive.", archive_filename);
486 gnu960_verify_target(inarch); /* Exits on failure */
488 last_one = &(inarch->next);
489 /* Read all the contents right away, regardless. */
490 for (next_one = bfd_openr_next_archived_file(inarch, NULL);
492 next_one = bfd_openr_next_archived_file(inarch, next_one)) {
493 *last_one = next_one;
494 last_one = &next_one->next;
496 *last_one = (bfd *) NULL;
497 if (bfd_error != no_more_archived_files)
513 if (bfd_stat_arch_elt(abfd, &buf) != 0)
514 fatal("Internal stat error on %s", abfd->filename);
517 printf("\n<member %s>\n\n", abfd->filename);
519 bfd_seek(abfd, 0, SEEK_SET);
522 while (ncopied < size) {
525 int tocopy = size - ncopied;
526 if (tocopy > BUFSIZE)
529 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
533 fatal("file %s not a valid archive", abfd->my_archive->filename);
534 fwrite(cbuf, 1, nread, stdout);
541 Extract a member of the archive into its own file.
543 We defer opening the new file until after we have read a BUFSIZ chunk of the
544 old one, since we know we have just read the archive header for the old
545 one. Since most members are shorter than BUFSIZ, this means we will read
546 the old header, read the old data, write a new inode for the new file, and
547 write the new data, and be done. This 'optimization' is what comes from
548 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
563 if (bfd_stat_arch_elt(abfd, &buf) != 0)
564 fatal("Internal stat error on %s", abfd->filename);
568 printf("x - %s\n", abfd->filename);
570 bfd_seek(abfd, 0, SEEK_SET);
574 /* Seems like an abstraction violation, eh? Well it's OK! */
575 ostream = fopen(abfd->filename, FOPEN_WB);
577 perror(abfd->filename);
581 while (ncopied < size) {
582 tocopy = size - ncopied;
583 if (tocopy > BUFSIZE)
586 nread = bfd_read(cbuf, 1, tocopy, abfd);
588 fatal("file %s not a valid archive", abfd->my_archive->filename);
590 /* See comment above; this saves disk arm motion */
592 /* Seems like an abstraction violation, eh? Well it's OK! */
593 ostream = fopen(abfd->filename, FOPEN_WB);
595 perror(abfd->filename);
599 fwrite(cbuf, 1, nread, ostream);
604 chmod(abfd->filename, buf.st_mode);
606 if (preserve_dates) {
609 tb.actime = buf.st_mtime;
610 tb.modtime = buf.st_mtime;
611 utime(abfd->filename, &tb); /* FIXME check result */
612 #else /* ! POSIX_UTIME */
615 tb[0] = buf.st_mtime;
616 tb[1] = buf.st_mtime;
617 utime(abfd->filename, tb); /* FIXME check result */
618 #else /* ! USE_UTIME */
619 struct timeval tv[2];
620 tv[0].tv_sec = buf.st_mtime;
622 tv[1].tv_sec = buf.st_mtime;
624 utimes(abfd->filename, tv); /* FIXME check result */
625 #endif /* ! USE_UTIME */
626 #endif /* ! POSIX_UTIME */
631 /* Just do it quickly; don't worry about dups, armap, or anything like that */
634 do_quick_append(archive_filename, files_to_append)
635 char *archive_filename;
636 char **files_to_append;
646 boolean newfile = false;
647 bfd_error = no_error;
649 if (stat(archive_filename, &sbuf) != 0) {
651 bfd_fatal(archive_filename);
656 ofile = fopen(archive_filename, FOPEN_AUB);
658 perror(program_name);
664 temp = bfd_openr(archive_filename, default_target);
666 temp = bfd_openr(archive_filename, NULL);
669 fprintf (stderr, "%s: ", program_name);
670 bfd_perror(archive_filename);
673 if (newfile == false) {
674 if (bfd_check_format(temp, bfd_archive) != true)
675 fatal("File %s is not an archive.", archive_filename);
677 gnu960_verify_target(temp); /* Exits on failure */
681 fwrite(ARMAG, 1, SARMAG, ofile);
683 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
686 /* assume it's an achive, go straight to the end, sans $200 */
689 for (; files_to_append && *files_to_append; ++files_to_append) {
690 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
692 fprintf (stderr, "%s: ", program_name);
693 bfd_perror(*files_to_append);
697 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
699 ifile = fopen(*files_to_append, FOPEN_RB);
702 bfd_perror(program_name);
705 if (stat(*files_to_append, &sbuf) != 0)
707 fprintf (stderr, "%s: ", program_name);
708 bfd_perror(*files_to_append);
711 tocopy = sbuf.st_size;
713 /* XXX should do error-checking! */
714 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
719 if (thistime > BUFSIZE)
721 fread(buf, 1, thistime, ifile);
722 fwrite(buf, 1, thistime, ofile);
726 if ((sbuf.st_size % 2) == 1)
738 int namelen = strlen(inarch->filename);
739 char *new_name = xmalloc(namelen + 6);
740 bfd *contents_head = inarch->next;
742 strcpy(new_name, inarch->filename);
743 strcpy(new_name + namelen, "-art");
744 obfd = bfd_openw(new_name,
745 /* FIXME: violates abstraction; need a better protocol */
746 (inarch->xvec ? bfd_get_target(inarch) : NULL));
749 bfd_fatal(inarch->filename);
751 bfd_set_format(obfd, bfd_archive);
753 /* Request writing the archive symbol table unless we've
754 been explicitly requested not to. */
755 obfd->has_armap = write_armap >= 0;
757 if (bfd_set_archive_head(obfd, contents_head) != true)
758 bfd_fatal(inarch->filename);
760 if (!bfd_close(obfd))
761 bfd_fatal(inarch->filename);
763 /* We don't care if this fails, we might be creating the
765 (void) unlink(inarch->filename);
767 if (rename(new_name, inarch->filename) != 0)
768 bfd_fatal(inarch->filename);
774 returns a pointer to the pointer to the entry which should be rplacd'd
775 into when altering. default_pos should be how to interpret pos_default,
776 and should be a pos value.
780 get_pos_bfd(contents, default_pos)
782 enum pos default_pos;
784 bfd **after_bfd = contents;
785 enum pos realpos = (postype == pos_default ? default_pos : postype);
787 if (realpos == pos_end) {
789 after_bfd = &((*after_bfd)->next);
792 for ( ; *after_bfd; after_bfd = &(*after_bfd)->next)
793 if (!strcmp((*after_bfd)->filename, posname)) {
794 if (realpos == pos_after)
795 after_bfd = &(*after_bfd)->next;
804 delete_members(files_to_delete)
805 char **files_to_delete;
807 bfd **current_ptr_ptr;
809 boolean something_changed = false;
810 for (; *files_to_delete != NULL; ++files_to_delete) {
812 In a.out systems, the armap is optional. It's also called
813 __.SYMDEF. So if the user asked to delete it, we should remember
814 that fact. This isn't quite right for COFF systems (where
815 __.SYMDEF might be regular member), but it's very unlikely
816 to be a problem. FIXME */
818 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
819 inarch->has_armap = false;
825 current_ptr_ptr = &(inarch->next);
826 while (*current_ptr_ptr) {
827 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
829 something_changed = true;
833 *current_ptr_ptr = ((*current_ptr_ptr)->next);
838 current_ptr_ptr = &((*current_ptr_ptr)->next);
842 if (verbose && found == false) {
843 printf("No member named `%s'\n", *files_to_delete);
849 if (something_changed == true) {
855 /* Reposition existing members within an archive */
858 move_members(files_to_move)
859 char **files_to_move;
861 bfd **after_bfd; /* New entries go after this one */
862 bfd **current_ptr_ptr; /* cdr pointer into contents */
867 for (; *files_to_move; ++files_to_move) {
868 current_ptr_ptr = &(inarch->next);
869 while (*current_ptr_ptr) {
870 bfd *current_ptr = *current_ptr_ptr;
871 if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
873 Move this file to the end of the list - first cut from
876 *current_ptr_ptr = current_ptr->next;
878 /* Now glue to end */
879 after_bfd = get_pos_bfd(&inarch->next, pos_end);
880 *after_bfd = current_ptr;
881 current_ptr->next = (bfd *) NULL;
884 printf("m - %s\n", *files_to_move);
888 current_ptr_ptr = &((*current_ptr_ptr)->next);
890 fprintf(stderr, "No entry %s in archive %s!\n",
891 *files_to_move, inarch->filename);
900 /* Ought to default to replacing in place, but this is existing practice! */
903 replace_members(files_to_move)
904 char **files_to_move;
906 bfd **after_bfd; /* New entries go after this one */
911 while (files_to_move && *files_to_move) {
912 current_ptr = &inarch->next;
913 while (*current_ptr) {
914 current = *current_ptr;
916 if (!strcmp(normalize(*files_to_move), current->filename)) {
921 if (current->arelt_data == NULL) {
922 /* This can only happen if you specify a file on the
923 command line more than once. */
924 fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
928 if (stat(*files_to_move, &fsbuf) != 0) {
930 bfd_fatal(*files_to_move);
933 if (bfd_stat_arch_elt(current, &asbuf) != 0)
934 fatal("Internal stat error on %s", current->filename);
936 if (fsbuf.st_mtime <= asbuf.st_mtime)
940 /* snip out this entry from the chain */
941 *current_ptr = current->next;
943 after_bfd = get_pos_bfd(&inarch->next, pos_end);
945 *after_bfd = bfd_openr(*files_to_move, NULL);
946 if (*after_bfd == (bfd *) NULL) {
947 fprintf(stderr, "Can't open file %s\n", *files_to_move);
951 gnu960_verify_target(*after_bfd); /* Exits on failure */
953 (*after_bfd)->next = temp;
956 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
961 current_ptr = &(current->next);
964 /* It isn't in there, so add to end */
966 after_bfd = get_pos_bfd(&inarch->next, pos_end);
968 *after_bfd = bfd_openr(*files_to_move, NULL);
969 if (*after_bfd == (bfd *) NULL) {
970 fprintf(stderr, "Can't open file %s\n", *files_to_move);
974 gnu960_verify_target(*after_bfd); /* Exits on failure */
977 printf("c - %s\n", *files_to_move);
980 (*after_bfd)->next = temp;
992 ranlib_only(archname)
996 open_inarch(archname);
1003 /* Things which are interesting to map over all or some of the files: */
1009 print_arelt_descr(stdout,abfd, verbose);