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
);
695 if (unlink(inarch
->filename
) != 0)
696 bfd_fatal(inarch
->filename
);
697 if (rename(new_name
, inarch
->filename
) != 0)
698 bfd_fatal(inarch
->filename
);
707 returns a pointer to the pointer to the entry which should be rplacd'd
708 into when altering. default_pos should be how to interpret pos_default,
709 and should be a pos value.
713 get_pos_bfd(contents
, default_pos
)
715 enum pos default_pos
;
719 enum pos realpos
= (postype
== pos_default
? default_pos
: postype
);
723 after_bfd
= contents
;
725 after_bfd
= &((*after_bfd
)->next
);
731 for (after_bfd
= contents
; after_bfd
; after_bfd
= after_bfd
->next
)
732 if (!strcpy(after_bfd
->filename
, posname
))
736 for (after_bfd
= contents
; after_bfd
; after_bfd
= after_bfd
->next
)
737 if (after_bfd
->next
&& (!strcpy(after_bfd
->next
->filename
, posname
)))
747 delete_members(files_to_delete
)
748 char **files_to_delete
;
750 bfd
**current_ptr_ptr
;
752 boolean something_changed
= false;
753 for (; *files_to_delete
!= NULL
; ++files_to_delete
) {
755 In a.out systems, the armap is optional. It's also called
756 __.SYMDEF. So if the user asked to delete it, we should remember
757 that fact. The name is NULL in COFF archives, so using this as a
758 key is as good as anything I suppose
760 if (!strcmp(*files_to_delete
, "__.SYMDEF")) {
761 inarch
->has_armap
= false;
767 current_ptr_ptr
= &(inarch
->next
);
768 while (*current_ptr_ptr
) {
769 if (strcmp(*files_to_delete
, (*current_ptr_ptr
)->filename
) == 0) {
771 something_changed
= true;
775 *current_ptr_ptr
= ((*current_ptr_ptr
)->next
);
780 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
784 if (verbose
&& found
== false) {
785 printf("No member named `%s'\n", *files_to_delete
);
791 if (something_changed
== true) {
797 /* Reposition existing members within an archive */
800 move_members(files_to_move
)
801 char **files_to_move
;
803 bfd
**after_bfd
; /* New entries go after this one */
804 bfd
**current_ptr_ptr
; /* cdr pointer into contents */
809 for (; *files_to_move
; ++files_to_move
) {
810 current_ptr_ptr
= &(inarch
->next
);
811 while (*current_ptr_ptr
) {
812 bfd
*current_ptr
= *current_ptr_ptr
;
813 if (strcmp(normalize(*files_to_move
), current_ptr
->filename
) == 0) {
815 Move this file to the end of the list - first cut from
818 *current_ptr_ptr
= current_ptr
->next
;
820 /* Now glue to end */
821 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
822 *after_bfd
= current_ptr
;
823 current_ptr
->next
= (bfd
*) NULL
;
826 printf("m - %s\n", *files_to_move
);
830 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
832 fprintf(stderr
, "No entry %s in archive %s!\n",
833 *files_to_move
, inarch
->filename
);
842 /* Ought to default to replacing in place, but this is existing practice! */
845 replace_members(files_to_move
)
846 char **files_to_move
;
848 bfd
**after_bfd
; /* New entries go after this one */
853 If the first item in the archive is an __.SYMDEF then remove it
856 strcmp(inarch
->next
->filename
, "__.SYMDEF") == 0) {
857 inarch
->next
= inarch
->next
->next
;
862 while (files_to_move
&& *files_to_move
) {
863 current_ptr
= &inarch
->next
;
864 while (*current_ptr
) {
865 current
= *current_ptr
;
867 if (!strcmp(normalize(*files_to_move
), current
->filename
)) {
872 if (current
->arelt_data
== NULL
) {
873 /* This can only happen if you specify a file on the
874 command line more than once. */
875 fprintf (stderr
, "Duplicate file specified: %s -- skipping.\n", *files_to_move
);
879 if (stat(*files_to_move
, &fsbuf
) != 0) {
881 bfd_fatal(*files_to_move
);
884 if (bfd_stat_arch_elt(current
, &asbuf
) != 0)
885 fatal("Internal stat error on %s", current
->filename
);
887 if (fsbuf
.st_mtime
<= asbuf
.st_mtime
)
891 /* snip out this entry from the chain */
892 *current_ptr
= current
->next
;
894 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
896 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
897 if (*after_bfd
== (bfd
*) NULL
) {
898 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
902 gnu960_verify_target(*after_bfd
); /* Exits on failure */
904 (*after_bfd
)->next
= temp
;
907 printf("%c - %s\n", (postype
== pos_after
? 'r' : 'a'),
912 current_ptr
= &(current
->next
);
915 /* It isn't in there, so add to end */
917 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
919 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
920 if (*after_bfd
== (bfd
*) NULL
) {
921 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
925 gnu960_verify_target(*after_bfd
); /* Exits on failure */
928 printf("c - %s\n", *files_to_move
);
931 (*after_bfd
)->next
= temp
;
943 ranlib_only(archname
)
947 open_inarch(archname
);