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
34 /* FIXME: Not great to have these here. Should they be exported or not? */
35 PROTO(size_t, bfd_read, (void *ptr, size_t size, size_t nitems, bfd * abfd));
36 PROTO(size_t, bfd_write, (void *ptr, size_t size, size_t nitems, bfd * abfd));
37 /* PROTO (void, open_inarch, (char *archive_filename)); */
39 static void open_inarch(char *archive_filename);
41 static void open_inarch();
44 PROTO(void, map_over_members, (void (*function) (), char **files, int count));
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 */
60 /* This flag distinguishes between ar and ranlib:
61 1 means this is 'ranlib'; -1 means this is 'ar'.
62 0 means if we should use argv[0] to decide. */
64 /* Nonzero means don't warn about creating the archive file if necessary. */
65 int silent_create = 0;
66 /* Nonzero means describe each action performed. */
68 /* Nonzero means preserve dates of members when extracting them. */
69 int preserve_dates = 0;
71 Nonzero means don't replace existing members whose dates are more recent
72 than the corresponding files.
75 /* write a __.SYMDEF member into the modified archive. */
76 boolean write_armap = false;
78 Nonzero means don't update __.SYMDEF unless command line explicitly
81 int ignore_symdef = 0;
83 Nonzero means it's the name of an existing member; position new or moved
84 files with respect to this one.
88 Sez how to use `posname': pos_before means position before that member.
89 pos_after means position after that member. pos_end means always at end.
90 pos_default means default appropriately. For the latter two, `posname'
94 pos_default, pos_before, pos_after, pos_end
95 } postype = pos_default;
101 gnu960_verify_target(abfd)
104 if ( abfd->format == bfd_unknown ){
105 bfd_check_format(abfd, bfd_object);
106 /* Don't really care if it's an object --
107 * just want to get the correct xvec.
110 if ( !BFD_COFF_FILE_P(abfd) ){
111 fatal( "'%s' not a COFF file -- operation aborted",
119 boolean operation_alters_arch = false;
122 The option parsing should be in its own function. It will be when I have
133 none = 0, delete, replace, print_table,
134 print_files, extract, move, quick_append
138 char *inarch_filename;
144 check_v960( argc, argv );
145 default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
148 program_name = argv[0];
150 temp = strrchr(program_name, '/');
151 if (temp == (char *) NULL)
152 temp = program_name; /* shouldn't happen, but... */
155 if (is_ranlib > 0 || (is_ranlib == 0 && strcmp(temp, "ranlib") == 0)) {
157 fatal("Too few command arguments.");
158 ranlib_only(argv[1]);
163 fatal("Too few command arguments.");
168 ++arg_ptr; /* compatibility */
170 while (c = *arg_ptr++) {
179 if (operation != none)
180 fatal("two different operation switches specified");
184 operation_alters_arch = true;
188 operation_alters_arch = true;
191 operation = print_files;
194 operation = quick_append;
195 operation_alters_arch = true;
199 operation_alters_arch = true;
202 operation = print_table;
229 postype = pos_before;
232 postype = pos_before;
235 fatal("invalid option %c", c);
239 if (operation == none && write_armap)
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);
436 /* Things which are interesting to map over all or some of the files: */
442 print_arelt_descr(abfd, verbose);
452 if (bfd_stat_arch_elt(abfd, &buf) != 0)
453 fatal("Internal stat error on %s", abfd->filename);
456 printf("\n<member %s>\n\n", abfd->filename);
458 bfd_seek(abfd, 0, SEEK_SET);
461 while (ncopied < size) {
464 int tocopy = size - ncopied;
465 if (tocopy > BUFSIZE)
468 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
472 fatal("file %s not a valid archive", abfd->my_archive->filename);
473 fwrite(cbuf, 1, nread, stdout);
480 Extract a member of the archive into its own file.
482 We defer opening the new file until after we have read a BUFSIZ chunk of the
483 old one, since we know we have just read the archive header for the old
484 one. Since most members are shorter than BUFSIZ, this means we will read
485 the old header, read the old data, write a new inode for the new file, and
486 write the new data, and be done. This 'optimization' is what comes from
487 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
502 if (bfd_stat_arch_elt(abfd, &buf) != 0)
503 fatal("Internal stat error on %s", abfd->filename);
507 printf("x - %s\n", abfd->filename);
509 bfd_seek(abfd, 0, SEEK_SET);
513 /* Seems like an abstraction violation, eh? Well it's OK! */
514 ostream = fopen(abfd->filename, "w");
516 perror(abfd->filename);
520 while (ncopied < size) {
521 tocopy = size - ncopied;
522 if (tocopy > BUFSIZE)
525 nread = bfd_read(cbuf, 1, tocopy, abfd);
527 fatal("file %s not a valid archive", abfd->my_archive->filename);
529 /* See comment above; this saves disk arm motion */
531 /* Seems like an abstraction violation, eh? Well it's OK! */
532 ostream = fopen(abfd->filename, "w");
534 perror(abfd->filename);
538 fwrite(cbuf, 1, nread, ostream);
543 chmod(abfd->filename, buf.st_mode);
545 if (preserve_dates) {
548 tb[0] = buf.st_mtime;
549 tb[1] = buf.st_mtime;
550 utime(abfd->filename, tb); /* FIXME check result */
552 struct timeval tv[2];
553 tv[0].tv_sec = buf.st_mtime;
555 tv[1].tv_sec = buf.st_mtime;
557 utimes(abfd->filename, tv); /* FIXME check result */
563 /* Just do it quickly; don't worry about dups, armap, or anything like that */
565 /* This is ugly! XXX */
567 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
570 do_quick_append(archive_filename, files_to_append)
571 char *archive_filename;
572 char **files_to_append;
582 boolean newfile = false;
583 bfd_error = no_error;
585 if (stat(archive_filename, &sbuf) != 0) {
587 bfd_fatal(archive_filename);
592 ofile = fopen(archive_filename, "a+");
594 perror(program_name);
600 temp = bfd_openr(archive_filename, default_target);
602 temp = bfd_openr(archive_filename, NULL);
605 bfd_perror(archive_filename);
608 if (newfile == false) {
609 if (bfd_check_format(temp, bfd_archive) != true)
610 fatal("File %s is not an archive.", archive_filename);
612 gnu960_verify_target(temp); /* Exits on failure */
616 fwrite(ARMAG, 1, SARMAG, ofile);
618 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
621 /* assume it's an achive, go straight to the end, sans $200 */
624 for (; files_to_append && *files_to_append; ++files_to_append) {
625 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
627 bfd_perror(*files_to_append);
631 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
633 ifile = fopen(*files_to_append, "r");
635 bfd_perror(program_name);
637 if (stat(*files_to_append, &sbuf) != 0)
638 bfd_perror(*files_to_append);
640 tocopy = sbuf.st_size;
642 /* XXX should do error-checking! */
643 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
648 if (thistime > BUFSIZE)
650 fread(buf, 1, thistime, ifile);
651 fwrite(buf, 1, thistime, ofile);
655 if ((sbuf.st_size % 2) == 1)
668 int namelen = strlen(inarch->filename);
669 char *new_name = xmalloc(namelen + 6);
670 bfd *contents_head = inarch->next;
672 if (inarch == &bogus_archive) {
673 /* How can this be ? */
678 strcpy(new_name, inarch->filename);
679 strcpy(new_name + namelen, ".art");
680 obfd = bfd_openw(new_name,
681 /* FIXME: violates abstraction; need a better protocol */
682 (inarch->xvec ? bfd_get_target(inarch) : NULL));
685 bfd_fatal(inarch->filename);
687 bfd_set_format(obfd, bfd_archive);
688 obfd->has_armap = write_armap;
690 if (bfd_set_archive_head(obfd, contents_head) != true)
691 bfd_fatal(inarch->filename);
693 if (!bfd_close(obfd))
694 bfd_fatal(inarch->filename);
696 /* We don't care if this fails, we might be creating the
698 (void) unlink(inarch->filename);
700 if (rename(new_name, inarch->filename) != 0)
701 bfd_fatal(inarch->filename);
710 returns a pointer to the pointer to the entry which should be rplacd'd
711 into when altering. default_pos should be how to interpret pos_default,
712 and should be a pos value.
716 get_pos_bfd(contents, default_pos)
718 enum pos default_pos;
722 enum pos realpos = (postype == pos_default ? default_pos : postype);
726 after_bfd = contents;
728 after_bfd = &((*after_bfd)->next);
734 for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
735 if (!strcpy(after_bfd->filename, posname))
739 for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
740 if (after_bfd->next && (!strcpy(after_bfd->next->filename, posname)))
750 delete_members(files_to_delete)
751 char **files_to_delete;
753 bfd **current_ptr_ptr;
755 boolean something_changed = false;
756 for (; *files_to_delete != NULL; ++files_to_delete) {
758 In a.out systems, the armap is optional. It's also called
759 __.SYMDEF. So if the user asked to delete it, we should remember
760 that fact. The name is NULL in COFF archives, so using this as a
761 key is as good as anything I suppose
763 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
764 inarch->has_armap = false;
770 current_ptr_ptr = &(inarch->next);
771 while (*current_ptr_ptr) {
772 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
774 something_changed = true;
778 *current_ptr_ptr = ((*current_ptr_ptr)->next);
783 current_ptr_ptr = &((*current_ptr_ptr)->next);
787 if (verbose && found == false) {
788 printf("No member named `%s'\n", *files_to_delete);
794 if (something_changed == true) {
800 /* Reposition existing members within an archive */
803 move_members(files_to_move)
804 char **files_to_move;
806 bfd **after_bfd; /* New entries go after this one */
807 bfd **current_ptr_ptr; /* cdr pointer into contents */
812 for (; *files_to_move; ++files_to_move) {
813 current_ptr_ptr = &(inarch->next);
814 while (*current_ptr_ptr) {
815 bfd *current_ptr = *current_ptr_ptr;
816 if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
818 Move this file to the end of the list - first cut from
821 *current_ptr_ptr = current_ptr->next;
823 /* Now glue to end */
824 after_bfd = get_pos_bfd(&inarch->next, pos_end);
825 *after_bfd = current_ptr;
826 current_ptr->next = (bfd *) NULL;
829 printf("m - %s\n", *files_to_move);
833 current_ptr_ptr = &((*current_ptr_ptr)->next);
835 fprintf(stderr, "No entry %s in archive %s!\n",
836 *files_to_move, inarch->filename);
845 /* Ought to default to replacing in place, but this is existing practice! */
848 replace_members(files_to_move)
849 char **files_to_move;
851 bfd **after_bfd; /* New entries go after this one */
856 If the first item in the archive is an __.SYMDEF then remove it
859 strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
860 inarch->next = inarch->next->next;
865 while (files_to_move && *files_to_move) {
866 current_ptr = &inarch->next;
867 while (*current_ptr) {
868 current = *current_ptr;
870 if (!strcmp(normalize(*files_to_move), current->filename)) {
875 if (current->arelt_data == NULL) {
876 /* This can only happen if you specify a file on the
877 command line more than once. */
878 fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
882 if (stat(*files_to_move, &fsbuf) != 0) {
884 bfd_fatal(*files_to_move);
887 if (bfd_stat_arch_elt(current, &asbuf) != 0)
888 fatal("Internal stat error on %s", current->filename);
890 if (fsbuf.st_mtime <= asbuf.st_mtime)
894 /* snip out this entry from the chain */
895 *current_ptr = current->next;
897 after_bfd = get_pos_bfd(&inarch->next, pos_end);
899 *after_bfd = bfd_openr(*files_to_move, NULL);
900 if (*after_bfd == (bfd *) NULL) {
901 fprintf(stderr, "Can't open file %s\n", *files_to_move);
905 gnu960_verify_target(*after_bfd); /* Exits on failure */
907 (*after_bfd)->next = temp;
910 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
915 current_ptr = &(current->next);
918 /* It isn't in there, so add to end */
920 after_bfd = get_pos_bfd(&inarch->next, pos_end);
922 *after_bfd = bfd_openr(*files_to_move, NULL);
923 if (*after_bfd == (bfd *) NULL) {
924 fprintf(stderr, "Can't open file %s\n", *files_to_move);
928 gnu960_verify_target(*after_bfd); /* Exits on failure */
931 printf("c - %s\n", *files_to_move);
934 (*after_bfd)->next = temp;
946 ranlib_only(archname)
950 open_inarch(archname);