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 || operation == print_table)
240 && write_armap == true)
241 ranlib_only(argv[2]);
243 if (operation == none)
244 fatal("no operation specified");
246 if (newer_only && operation != replace)
247 fatal("'u' only meaningful with 'r' option.");
251 if (postype != pos_default)
252 posname = argv[arg_index++];
254 inarch_filename = argv[arg_index++];
256 if (arg_index < argc) {
257 files = argv + arg_index;
258 while (arg_index < argc)
259 if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
267 if (operation == quick_append) {
269 do_quick_append(inarch_filename, files);
274 open_inarch(inarch_filename);
276 If we have no archive, and we've been asked to replace then create one
279 if (operation == replace && inarch == &bogus_archive) {
281 do_quick_append(inarch_filename, 0);
282 open_inarch(inarch_filename);
288 map_over_members(print_descr, files, argc - 3);
292 map_over_members(print_contents, files, argc - 3);
296 map_over_members(extract_file, files, argc - 3);
301 delete_members(files);
310 if (files != NULL || write_armap)
311 replace_members(files);
314 /* Shouldn't happen! */
316 fprintf(stderr, "Sorry; this option not implemented.\n");
323 char *normalize(file)
326 char * filename = strrchr(file, '/');
327 if (filename != (char *)NULL) {
337 open_inarch(archive_filename)
338 char *archive_filename;
343 bfd_error = no_error;
344 if (stat(archive_filename, &sbuf) != 0) {
346 bfd_fatal(archive_filename);
347 if (!operation_alters_arch) {
348 fprintf (stderr, "%s: %s not found.\n", program_name,
354 "%s: creating %s\n", program_name, archive_filename);
356 inarch = &bogus_archive;
357 inarch->filename = archive_filename;
358 inarch->has_armap = true;
363 inarch = bfd_openr(archive_filename, default_target);
365 inarch = bfd_openr(archive_filename, NULL);
367 if (inarch == NULL) {
369 bfd_perror(archive_filename);
373 if (bfd_check_format(inarch, bfd_archive) != true)
374 fatal("File %s is not an archive.", archive_filename);
376 gnu960_verify_target(inarch); /* Exits on failure */
378 last_one = &(inarch->next);
379 /* Read all the contents right away, regardless. */
380 for (next_one = bfd_openr_next_archived_file(inarch, NULL);
382 next_one = bfd_openr_next_archived_file(inarch, next_one)) {
383 *last_one = next_one;
384 last_one = &next_one->next;
386 *last_one = (bfd *) NULL;
387 if (bfd_error != no_more_archived_files)
395 If count is 0, then function is called once on each entry. if nonzero,
396 count is the length of the files chain; function is called on each entry
397 whose name matches one in files
400 map_over_members(function, files, count)
411 for (head = inarch->next; head; head = head->next)
416 This may appear to be a baroque way of accomplishing what we want.
417 however we have to iterate over the filenames in order to notice where
418 a filename is requested but does not exist in the archive. Ditto
419 mapping over each file each time -- we want to hack multiple
423 for (; count > 0; files++, count--) {
424 boolean found = false;
425 for (head = inarch->next; head; head = head->next)
426 if ((head->filename != NULL) &&
427 (!strcmp(*files, head->filename))) {
432 fprintf(stderr, "No entry %s in archive.\n", *files);
437 /* Things which are interesting to map over all or some of the files: */
443 print_arelt_descr(abfd, verbose);
453 if (bfd_stat_arch_elt(abfd, &buf) != 0)
454 fatal("Internal stat error on %s", abfd->filename);
457 printf("\n<member %s>\n\n", abfd->filename);
459 bfd_seek(abfd, 0, SEEK_SET);
462 while (ncopied < size) {
465 int tocopy = size - ncopied;
466 if (tocopy > BUFSIZE)
469 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
473 fatal("file %s not a valid archive", abfd->my_archive->filename);
474 fwrite(cbuf, 1, nread, stdout);
481 Extract a member of the archive into its own file.
483 We defer opening the new file until after we have read a BUFSIZ chunk of the
484 old one, since we know we have just read the archive header for the old
485 one. Since most members are shorter than BUFSIZ, this means we will read
486 the old header, read the old data, write a new inode for the new file, and
487 write the new data, and be done. This 'optimization' is what comes from
488 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
503 if (bfd_stat_arch_elt(abfd, &buf) != 0)
504 fatal("Internal stat error on %s", abfd->filename);
508 printf("x - %s\n", abfd->filename);
510 bfd_seek(abfd, 0, SEEK_SET);
514 /* Seems like an abstraction violation, eh? Well it's OK! */
515 ostream = fopen(abfd->filename, "w");
517 perror(abfd->filename);
521 while (ncopied < size) {
522 tocopy = size - ncopied;
523 if (tocopy > BUFSIZE)
526 nread = bfd_read(cbuf, 1, tocopy, abfd);
528 fatal("file %s not a valid archive", abfd->my_archive->filename);
530 /* See comment above; this saves disk arm motion */
532 /* Seems like an abstraction violation, eh? Well it's OK! */
533 ostream = fopen(abfd->filename, "w");
535 perror(abfd->filename);
539 fwrite(cbuf, 1, nread, ostream);
544 chmod(abfd->filename, buf.st_mode);
546 if (preserve_dates) {
549 tb[0] = buf.st_mtime;
550 tb[1] = buf.st_mtime;
551 utime(abfd->filename, tb); /* FIXME check result */
553 struct timeval tv[2];
554 tv[0].tv_sec = buf.st_mtime;
556 tv[1].tv_sec = buf.st_mtime;
558 utimes(abfd->filename, tv); /* FIXME check result */
564 /* Just do it quickly; don't worry about dups, armap, or anything like that */
566 /* This is ugly! XXX */
568 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
571 do_quick_append(archive_filename, files_to_append)
572 char *archive_filename;
573 char **files_to_append;
583 boolean newfile = false;
584 bfd_error = no_error;
586 if (stat(archive_filename, &sbuf) != 0) {
588 bfd_fatal(archive_filename);
593 ofile = fopen(archive_filename, "a+");
595 perror(program_name);
601 temp = bfd_openr(archive_filename, default_target);
603 temp = bfd_openr(archive_filename, NULL);
606 bfd_perror(archive_filename);
609 if (newfile == false) {
610 if (bfd_check_format(temp, bfd_archive) != true)
611 fatal("File %s is not an archive.", archive_filename);
613 gnu960_verify_target(temp); /* Exits on failure */
617 fwrite(ARMAG, 1, SARMAG, ofile);
619 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
622 /* assume it's an achive, go straight to the end, sans $200 */
625 for (; files_to_append && *files_to_append; ++files_to_append) {
626 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
628 bfd_perror(*files_to_append);
632 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
634 ifile = fopen(*files_to_append, "r");
636 bfd_perror(program_name);
638 if (stat(*files_to_append, &sbuf) != 0)
639 bfd_perror(*files_to_append);
641 tocopy = sbuf.st_size;
643 /* XXX should do error-checking! */
644 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
649 if (thistime > BUFSIZE)
651 fread(buf, 1, thistime, ifile);
652 fwrite(buf, 1, thistime, ofile);
656 if ((sbuf.st_size % 2) == 1)
669 int namelen = strlen(inarch->filename);
670 char *new_name = xmalloc(namelen + 6);
671 bfd *contents_head = inarch->next;
673 if (inarch == &bogus_archive) {
674 /* How can this be ? */
679 strcpy(new_name, inarch->filename);
680 strcpy(new_name + namelen, ".art");
681 obfd = bfd_openw(new_name,
682 /* FIXME: violates abstraction; need a better protocol */
683 (inarch->xvec ? bfd_get_target(inarch) : NULL));
686 bfd_fatal(inarch->filename);
688 bfd_set_format(obfd, bfd_archive);
689 obfd->has_armap = write_armap;
691 if (bfd_set_archive_head(obfd, contents_head) != true)
692 bfd_fatal(inarch->filename);
694 if (!bfd_close(obfd))
695 bfd_fatal(inarch->filename);
697 /* We don't care if this fails, we might be creating the
699 (void) unlink(inarch->filename);
701 if (rename(new_name, inarch->filename) != 0)
702 bfd_fatal(inarch->filename);
711 returns a pointer to the pointer to the entry which should be rplacd'd
712 into when altering. default_pos should be how to interpret pos_default,
713 and should be a pos value.
717 get_pos_bfd(contents, default_pos)
719 enum pos default_pos;
721 bfd **after_bfd = contents;
722 enum pos realpos = (postype == pos_default ? default_pos : postype);
724 if (realpos == pos_end) {
726 after_bfd = &((*after_bfd)->next);
729 for ( ; *after_bfd; after_bfd = &(*after_bfd)->next)
730 if (!strcmp((*after_bfd)->filename, posname)) {
731 if (realpos == pos_after)
732 after_bfd = &(*after_bfd)->next;
740 delete_members(files_to_delete)
741 char **files_to_delete;
743 bfd **current_ptr_ptr;
745 boolean something_changed = false;
746 for (; *files_to_delete != NULL; ++files_to_delete) {
748 In a.out systems, the armap is optional. It's also called
749 __.SYMDEF. So if the user asked to delete it, we should remember
750 that fact. The name is NULL in COFF archives, so using this as a
751 key is as good as anything I suppose
753 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
754 inarch->has_armap = false;
760 current_ptr_ptr = &(inarch->next);
761 while (*current_ptr_ptr) {
762 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
764 something_changed = true;
768 *current_ptr_ptr = ((*current_ptr_ptr)->next);
773 current_ptr_ptr = &((*current_ptr_ptr)->next);
777 if (verbose && found == false) {
778 printf("No member named `%s'\n", *files_to_delete);
784 if (something_changed == true) {
790 /* Reposition existing members within an archive */
793 move_members(files_to_move)
794 char **files_to_move;
796 bfd **after_bfd; /* New entries go after this one */
797 bfd **current_ptr_ptr; /* cdr pointer into contents */
802 for (; *files_to_move; ++files_to_move) {
803 current_ptr_ptr = &(inarch->next);
804 while (*current_ptr_ptr) {
805 bfd *current_ptr = *current_ptr_ptr;
806 if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
808 Move this file to the end of the list - first cut from
811 *current_ptr_ptr = current_ptr->next;
813 /* Now glue to end */
814 after_bfd = get_pos_bfd(&inarch->next, pos_end);
815 *after_bfd = current_ptr;
816 current_ptr->next = (bfd *) NULL;
819 printf("m - %s\n", *files_to_move);
823 current_ptr_ptr = &((*current_ptr_ptr)->next);
825 fprintf(stderr, "No entry %s in archive %s!\n",
826 *files_to_move, inarch->filename);
835 /* Ought to default to replacing in place, but this is existing practice! */
838 replace_members(files_to_move)
839 char **files_to_move;
841 bfd **after_bfd; /* New entries go after this one */
846 If the first item in the archive is an __.SYMDEF then remove it
849 strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
850 inarch->next = inarch->next->next;
855 while (files_to_move && *files_to_move) {
856 current_ptr = &inarch->next;
857 while (*current_ptr) {
858 current = *current_ptr;
860 if (!strcmp(normalize(*files_to_move), current->filename)) {
865 if (current->arelt_data == NULL) {
866 /* This can only happen if you specify a file on the
867 command line more than once. */
868 fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
872 if (stat(*files_to_move, &fsbuf) != 0) {
874 bfd_fatal(*files_to_move);
877 if (bfd_stat_arch_elt(current, &asbuf) != 0)
878 fatal("Internal stat error on %s", current->filename);
880 if (fsbuf.st_mtime <= asbuf.st_mtime)
884 /* snip out this entry from the chain */
885 *current_ptr = current->next;
887 after_bfd = get_pos_bfd(&inarch->next, pos_end);
889 *after_bfd = bfd_openr(*files_to_move, NULL);
890 if (*after_bfd == (bfd *) NULL) {
891 fprintf(stderr, "Can't open file %s\n", *files_to_move);
895 gnu960_verify_target(*after_bfd); /* Exits on failure */
897 (*after_bfd)->next = temp;
900 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
905 current_ptr = &(current->next);
908 /* It isn't in there, so add to end */
910 after_bfd = get_pos_bfd(&inarch->next, pos_end);
912 *after_bfd = bfd_openr(*files_to_move, NULL);
913 if (*after_bfd == (bfd *) NULL) {
914 fprintf(stderr, "Can't open file %s\n", *files_to_move);
918 gnu960_verify_target(*after_bfd); /* Exits on failure */
921 printf("c - %s\n", *files_to_move);
924 (*after_bfd)->next = temp;
936 ranlib_only(archname)
940 open_inarch(archname);