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 /* Forward declarations */
52 print_contents PARAMS ((bfd * member));
55 delete_members PARAMS ((char **files_to_delete));
58 do_quick_append PARAMS ((char *archive_filename, char **files_to_append));
61 move_members PARAMS ((char **files_to_move));
64 replace_members PARAMS ((char **files_to_replace));
67 print_descr PARAMS ((bfd * abfd));
70 ranlib_only PARAMS ((char *archname));
72 /** Globals and flags */
74 char *program_name = NULL;
75 bfd *inarch; /* The input arch we're manipulating */
78 /* This flag distinguishes between ar and ranlib:
79 1 means this is 'ranlib'; 0 means this is 'ar'.
80 -1 means if we should use argv[0] to decide. */
82 /* Nonzero means don't warn about creating the archive file if necessary. */
83 int silent_create = 0;
84 /* Nonzero means describe each action performed. */
86 /* Nonzero means preserve dates of members when extracting them. */
87 int preserve_dates = 0;
89 Nonzero means don't replace existing members whose dates are more recent
90 than the corresponding files.
93 /* write a __.SYMDEF member into the modified archive. */
94 boolean write_armap = false;
96 Nonzero means don't update __.SYMDEF unless command line explicitly
99 int ignore_symdef = 0;
101 Nonzero means it's the name of an existing member; position new or moved
102 files with respect to this one.
104 char *posname = NULL;
106 Sez how to use `posname': pos_before means position before that member.
107 pos_after means position after that member. pos_end means always at end.
108 pos_default means default appropriately. For the latter two, `posname'
112 pos_default, pos_before, pos_after, pos_end
113 } postype = pos_default;
116 char *default_target;
119 gnu960_verify_target(abfd)
122 if ( abfd->format == bfd_unknown ){
123 bfd_check_format(abfd, bfd_object);
124 /* Don't really care if it's an object --
125 * just want to get the correct xvec.
128 if ( !BFD_COFF_FILE_P(abfd) ){
129 fatal( "'%s' not a COFF file -- operation aborted",
139 interactive = isatty(fileno(stdin)) ;
144 If count is 0, then function is called once on each entry. if nonzero,
145 count is the length of the files chain; function is called on each entry
146 whose name matches one in files
149 DEFUN(map_over_members,(function, files, count),
150 void (*function) () AND
157 for (head = inarch->next; head; head = head->next)
162 This may appear to be a baroque way of accomplishing what we want.
163 however we have to iterate over the filenames in order to notice where
164 a filename is requested but does not exist in the archive. Ditto
165 mapping over each file each time -- we want to hack multiple
169 for (; count > 0; files++, count--) {
170 boolean found = false;
171 for (head = inarch->next; head; head = head->next)
173 if (head->filename == NULL)
175 /* Some archive formats don't get the filenames filled in
176 'till the elements are opened */
178 bfd_stat_arch_elt(head, &buf);
180 if ((head->filename != NULL) &&
181 (!strcmp(*files, head->filename))) {
187 fprintf(stderr, "No entry %s in archive.\n", *files);
192 boolean operation_alters_arch = false;
197 extern char *program_version;
198 printf ("%s version %s\n", program_name, program_version);
202 The option parsing should be in its own function. It will be when I have
213 none = 0, delete, replace, print_table,
214 print_files, extract, move, quick_append
218 char *inarch_filename;
225 check_v960( argc, argv );
226 default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
229 program_name = argv[0];
231 temp = strrchr(program_name, '/');
232 if (temp == (char *) NULL)
233 temp = program_name; /* shouldn't happen, but... */
236 if (is_ranlib > 0 || (is_ranlib < 0 && strcmp(temp, "ranlib") == 0)) {
238 fatal("Too few command arguments.");
240 if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "-v") == 0) {
246 ranlib_only(arg_ptr);
249 if (argc == 2 && strcmp(argv[1],"-M") == 0) {
255 fatal("Too few command arguments.");
260 ++arg_ptr; /* compatibility */
262 while (c = *arg_ptr++) {
271 if (operation != none)
272 fatal("two different operation switches specified");
276 operation_alters_arch = true;
280 operation_alters_arch = true;
283 operation = print_files;
286 operation = quick_append;
287 operation_alters_arch = true;
291 operation_alters_arch = true;
294 operation = print_table;
324 postype = pos_before;
327 postype = pos_before;
334 fatal("invalid option %c", c);
345 fatal("Too few command arguments.");
351 if ((operation == none || operation == print_table)
352 && write_armap == true)
353 ranlib_only(argv[2]);
355 if (operation == none)
356 fatal("no operation specified");
358 if (newer_only && operation != replace)
359 fatal("'u' only meaningful with 'r' option.");
363 if (postype != pos_default)
364 posname = argv[arg_index++];
366 inarch_filename = argv[arg_index++];
368 if (arg_index < argc) {
369 files = argv + arg_index;
370 while (arg_index < argc)
371 if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
379 if (operation == quick_append) {
381 do_quick_append(inarch_filename, files);
386 open_inarch(inarch_filename);
391 map_over_members(print_descr, files, argc - 3);
395 map_over_members(print_contents, files, argc - 3);
399 map_over_members(extract_file, files, argc - 3);
404 delete_members(files);
413 if (files != NULL || write_armap)
414 replace_members(files);
417 /* Shouldn't happen! */
419 fprintf(stderr, "Sorry; this option not implemented.\n");
426 char *normalize(file)
429 char * filename = strrchr(file, '/');
430 if (filename != (char *)NULL) {
440 open_inarch(archive_filename)
441 char *archive_filename;
446 bfd_error = no_error;
447 if (stat(archive_filename, &sbuf) != 0) {
449 bfd_fatal(archive_filename);
450 if (!operation_alters_arch) {
451 fprintf (stderr, "%s: %s not found.\n", program_name,
457 /* This routine is one way to forcibly create the archive. */
458 do_quick_append(archive_filename, 0);
462 inarch = bfd_openr(archive_filename, default_target);
464 inarch = bfd_openr(archive_filename, NULL);
466 if (inarch == NULL) {
468 bfd_perror(archive_filename);
472 if (bfd_check_format(inarch, bfd_archive) != true)
473 fatal("File %s is not an archive.", archive_filename);
475 gnu960_verify_target(inarch); /* Exits on failure */
477 last_one = &(inarch->next);
478 /* Read all the contents right away, regardless. */
479 for (next_one = bfd_openr_next_archived_file(inarch, NULL);
481 next_one = bfd_openr_next_archived_file(inarch, next_one)) {
482 *last_one = next_one;
483 last_one = &next_one->next;
485 *last_one = (bfd *) NULL;
486 if (bfd_error != no_more_archived_files)
502 if (bfd_stat_arch_elt(abfd, &buf) != 0)
503 fatal("Internal stat error on %s", abfd->filename);
506 printf("\n<member %s>\n\n", abfd->filename);
508 bfd_seek(abfd, 0, SEEK_SET);
511 while (ncopied < size) {
514 int tocopy = size - ncopied;
515 if (tocopy > BUFSIZE)
518 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
522 fatal("file %s not a valid archive", abfd->my_archive->filename);
523 fwrite(cbuf, 1, nread, stdout);
530 Extract a member of the archive into its own file.
532 We defer opening the new file until after we have read a BUFSIZ chunk of the
533 old one, since we know we have just read the archive header for the old
534 one. Since most members are shorter than BUFSIZ, this means we will read
535 the old header, read the old data, write a new inode for the new file, and
536 write the new data, and be done. This 'optimization' is what comes from
537 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
552 if (bfd_stat_arch_elt(abfd, &buf) != 0)
553 fatal("Internal stat error on %s", abfd->filename);
557 printf("x - %s\n", abfd->filename);
559 bfd_seek(abfd, 0, SEEK_SET);
563 /* Seems like an abstraction violation, eh? Well it's OK! */
564 ostream = fopen(abfd->filename, FOPEN_WB);
566 perror(abfd->filename);
570 while (ncopied < size) {
571 tocopy = size - ncopied;
572 if (tocopy > BUFSIZE)
575 nread = bfd_read(cbuf, 1, tocopy, abfd);
577 fatal("file %s not a valid archive", abfd->my_archive->filename);
579 /* See comment above; this saves disk arm motion */
581 /* Seems like an abstraction violation, eh? Well it's OK! */
582 ostream = fopen(abfd->filename, FOPEN_WB);
584 perror(abfd->filename);
588 fwrite(cbuf, 1, nread, ostream);
593 chmod(abfd->filename, buf.st_mode);
595 if (preserve_dates) {
598 tb.actime = buf.st_mtime;
599 tb.modtime = buf.st_mtime;
600 utime(abfd->filename, tb); /* FIXME check result */
601 #else /* ! POSIX_UTIME */
604 tb[0] = buf.st_mtime;
605 tb[1] = buf.st_mtime;
606 utime(abfd->filename, tb); /* FIXME check result */
607 #else /* ! USE_UTIME */
608 struct timeval tv[2];
609 tv[0].tv_sec = buf.st_mtime;
611 tv[1].tv_sec = buf.st_mtime;
613 utimes(abfd->filename, tv); /* FIXME check result */
614 #endif /* ! USE_UTIME */
615 #endif /* ! POSIX_UTIME */
620 /* Just do it quickly; don't worry about dups, armap, or anything like that */
622 /* This is ugly! XXX */
624 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
627 do_quick_append(archive_filename, files_to_append)
628 char *archive_filename;
629 char **files_to_append;
639 boolean newfile = false;
640 bfd_error = no_error;
642 if (stat(archive_filename, &sbuf) != 0) {
644 bfd_fatal(archive_filename);
649 ofile = fopen(archive_filename, FOPEN_AUB);
651 perror(program_name);
657 temp = bfd_openr(archive_filename, default_target);
659 temp = bfd_openr(archive_filename, NULL);
662 bfd_perror(archive_filename);
665 if (newfile == false) {
666 if (bfd_check_format(temp, bfd_archive) != true)
667 fatal("File %s is not an archive.", archive_filename);
669 gnu960_verify_target(temp); /* Exits on failure */
673 fwrite(ARMAG, 1, SARMAG, ofile);
675 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
678 /* assume it's an achive, go straight to the end, sans $200 */
681 for (; files_to_append && *files_to_append; ++files_to_append) {
682 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
684 bfd_perror(*files_to_append);
688 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
690 ifile = fopen(*files_to_append, FOPEN_RB);
692 bfd_perror(program_name);
694 if (stat(*files_to_append, &sbuf) != 0)
695 bfd_perror(*files_to_append);
697 tocopy = sbuf.st_size;
699 /* XXX should do error-checking! */
700 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
705 if (thistime > BUFSIZE)
707 fread(buf, 1, thistime, ifile);
708 fwrite(buf, 1, thistime, ofile);
712 if ((sbuf.st_size % 2) == 1)
724 int namelen = strlen(inarch->filename);
725 char *new_name = xmalloc(namelen + 6);
726 bfd *contents_head = inarch->next;
728 strcpy(new_name, inarch->filename);
729 strcpy(new_name + namelen, "-art");
730 obfd = bfd_openw(new_name,
731 /* FIXME: violates abstraction; need a better protocol */
732 (inarch->xvec ? bfd_get_target(inarch) : NULL));
735 bfd_fatal(inarch->filename);
737 bfd_set_format(obfd, bfd_archive);
738 obfd->has_armap = write_armap;
740 if (bfd_set_archive_head(obfd, contents_head) != true)
741 bfd_fatal(inarch->filename);
743 if (!bfd_close(obfd))
744 bfd_fatal(inarch->filename);
746 /* We don't care if this fails, we might be creating the
748 (void) unlink(inarch->filename);
750 if (rename(new_name, inarch->filename) != 0)
751 bfd_fatal(inarch->filename);
757 returns a pointer to the pointer to the entry which should be rplacd'd
758 into when altering. default_pos should be how to interpret pos_default,
759 and should be a pos value.
763 get_pos_bfd(contents, default_pos)
765 enum pos default_pos;
767 bfd **after_bfd = contents;
768 enum pos realpos = (postype == pos_default ? default_pos : postype);
770 if (realpos == pos_end) {
772 after_bfd = &((*after_bfd)->next);
775 for ( ; *after_bfd; after_bfd = &(*after_bfd)->next)
776 if (!strcmp((*after_bfd)->filename, posname)) {
777 if (realpos == pos_after)
778 after_bfd = &(*after_bfd)->next;
787 delete_members(files_to_delete)
788 char **files_to_delete;
790 bfd **current_ptr_ptr;
792 boolean something_changed = false;
793 for (; *files_to_delete != NULL; ++files_to_delete) {
795 In a.out systems, the armap is optional. It's also called
796 __.SYMDEF. So if the user asked to delete it, we should remember
797 that fact. The name is NULL in COFF archives, so using this as a
798 key is as good as anything I suppose
800 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
801 inarch->has_armap = false;
807 current_ptr_ptr = &(inarch->next);
808 while (*current_ptr_ptr) {
809 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
811 something_changed = true;
815 *current_ptr_ptr = ((*current_ptr_ptr)->next);
820 current_ptr_ptr = &((*current_ptr_ptr)->next);
824 if (verbose && found == false) {
825 printf("No member named `%s'\n", *files_to_delete);
831 if (something_changed == true) {
837 /* Reposition existing members within an archive */
840 move_members(files_to_move)
841 char **files_to_move;
843 bfd **after_bfd; /* New entries go after this one */
844 bfd **current_ptr_ptr; /* cdr pointer into contents */
849 for (; *files_to_move; ++files_to_move) {
850 current_ptr_ptr = &(inarch->next);
851 while (*current_ptr_ptr) {
852 bfd *current_ptr = *current_ptr_ptr;
853 if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
855 Move this file to the end of the list - first cut from
858 *current_ptr_ptr = current_ptr->next;
860 /* Now glue to end */
861 after_bfd = get_pos_bfd(&inarch->next, pos_end);
862 *after_bfd = current_ptr;
863 current_ptr->next = (bfd *) NULL;
866 printf("m - %s\n", *files_to_move);
870 current_ptr_ptr = &((*current_ptr_ptr)->next);
872 fprintf(stderr, "No entry %s in archive %s!\n",
873 *files_to_move, inarch->filename);
882 /* Ought to default to replacing in place, but this is existing practice! */
885 replace_members(files_to_move)
886 char **files_to_move;
888 bfd **after_bfd; /* New entries go after this one */
893 If the first item in the archive is an __.SYMDEF then remove it
896 strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
897 inarch->next = inarch->next->next;
902 while (files_to_move && *files_to_move) {
903 current_ptr = &inarch->next;
904 while (*current_ptr) {
905 current = *current_ptr;
907 if (!strcmp(normalize(*files_to_move), current->filename)) {
912 if (current->arelt_data == NULL) {
913 /* This can only happen if you specify a file on the
914 command line more than once. */
915 fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
919 if (stat(*files_to_move, &fsbuf) != 0) {
921 bfd_fatal(*files_to_move);
924 if (bfd_stat_arch_elt(current, &asbuf) != 0)
925 fatal("Internal stat error on %s", current->filename);
927 if (fsbuf.st_mtime <= asbuf.st_mtime)
931 /* snip out this entry from the chain */
932 *current_ptr = current->next;
934 after_bfd = get_pos_bfd(&inarch->next, pos_end);
936 *after_bfd = bfd_openr(*files_to_move, NULL);
937 if (*after_bfd == (bfd *) NULL) {
938 fprintf(stderr, "Can't open file %s\n", *files_to_move);
942 gnu960_verify_target(*after_bfd); /* Exits on failure */
944 (*after_bfd)->next = temp;
947 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
952 current_ptr = &(current->next);
955 /* It isn't in there, so add to end */
957 after_bfd = get_pos_bfd(&inarch->next, pos_end);
959 *after_bfd = bfd_openr(*files_to_move, NULL);
960 if (*after_bfd == (bfd *) NULL) {
961 fprintf(stderr, "Can't open file %s\n", *files_to_move);
965 gnu960_verify_target(*after_bfd); /* Exits on failure */
968 printf("c - %s\n", *files_to_move);
971 (*after_bfd)->next = temp;
983 ranlib_only(archname)
987 open_inarch(archname);
994 /* Things which are interesting to map over all or some of the files: */
1000 print_arelt_descr(stdout,abfd, verbose);