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
31 #include "../bfd/libbfd.h"
48 PROTO(void, print_contents
, (bfd
* member
));
49 PROTO(void, extract_file
, (bfd
* abfd
));
50 PROTO(void, delete_members
, (char **files_to_delete
));
51 PROTO(void, do_quick_append
, (char *archive_filename
, char **files_to_append
));
52 PROTO(void, move_members
, (char **files_to_move
));
53 PROTO(void, replace_members
, (char **files_to_replace
));
54 PROTO(void, print_descr
, (bfd
* abfd
));
55 PROTO(void, ranlib_only
, (char *archname
));
57 /** Globals and flags */
59 extern *program_version
;
60 char *program_name
= NULL
;
61 bfd
*inarch
; /* The input arch we're manipulating */
64 /* This flag distinguishes between ar and ranlib:
65 1 means this is 'ranlib'; 0 means this is 'ar'.
66 -1 means if we should use argv[0] to decide. */
68 /* Nonzero means don't warn about creating the archive file if necessary. */
69 int silent_create
= 0;
70 /* Nonzero means describe each action performed. */
72 /* Nonzero means preserve dates of members when extracting them. */
73 int preserve_dates
= 0;
75 Nonzero means don't replace existing members whose dates are more recent
76 than the corresponding files.
79 /* write a __.SYMDEF member into the modified archive. */
80 boolean write_armap
= false;
82 Nonzero means don't update __.SYMDEF unless command line explicitly
85 int ignore_symdef
= 0;
87 Nonzero means it's the name of an existing member; position new or moved
88 files with respect to this one.
92 Sez how to use `posname': pos_before means position before that member.
93 pos_after means position after that member. pos_end means always at end.
94 pos_default means default appropriately. For the latter two, `posname'
98 pos_default
, pos_before
, pos_after
, pos_end
99 } postype
= pos_default
;
102 char *default_target
;
105 gnu960_verify_target(abfd
)
108 if ( abfd
->format
== bfd_unknown
){
109 bfd_check_format(abfd
, bfd_object
);
110 /* Don't really care if it's an object --
111 * just want to get the correct xvec.
114 if ( !BFD_COFF_FILE_P(abfd
) ){
115 fatal( "'%s' not a COFF file -- operation aborted",
125 interactive
= isatty(fileno(stdin
)) ;
130 If count is 0, then function is called once on each entry. if nonzero,
131 count is the length of the files chain; function is called on each entry
132 whose name matches one in files
135 DEFUN(map_over_members
,(function
, files
, count
),
136 void (*function
) () AND
143 for (head
= inarch
->next
; head
; head
= head
->next
)
148 This may appear to be a baroque way of accomplishing what we want.
149 however we have to iterate over the filenames in order to notice where
150 a filename is requested but does not exist in the archive. Ditto
151 mapping over each file each time -- we want to hack multiple
155 for (; count
> 0; files
++, count
--) {
156 boolean found
= false;
157 for (head
= inarch
->next
; head
; head
= head
->next
)
158 if ((head
->filename
!= NULL
) &&
159 (!strcmp(*files
, head
->filename
))) {
164 fprintf(stderr
, "No entry %s in archive.\n", *files
);
169 boolean operation_alters_arch
= false;
172 The option parsing should be in its own function. It will be when I have
183 none
= 0, delete, replace
, print_table
,
184 print_files
, extract
, move
, quick_append
188 char *inarch_filename
;
196 check_v960( argc
, argv
);
197 default_target
= bfd_make_targ_name(BFD_COFF_FORMAT
,HOST_BYTE_ORDER_BIG_P
);
200 program_name
= argv
[0];
202 temp
= strrchr(program_name
, '/');
203 if (temp
== (char *) NULL
)
204 temp
= program_name
; /* shouldn't happen, but... */
207 if (is_ranlib
> 0 || (is_ranlib
< 0 && strcmp(temp
, "ranlib") == 0)) {
209 fatal("Too few command arguments.");
210 ranlib_only(argv
[1]);
213 if (argc
== 2 && strcmp(argv
[1],"-M") == 0) {
218 fatal("Too few command arguments.");
223 ++arg_ptr
; /* compatibility */
225 while (c
= *arg_ptr
++) {
234 if (operation
!= none
)
235 fatal("two different operation switches specified");
239 operation_alters_arch
= true;
243 operation_alters_arch
= true;
246 operation
= print_files
;
249 operation
= quick_append
;
250 operation_alters_arch
= true;
254 operation_alters_arch
= true;
257 operation
= print_table
;
287 postype
= pos_before
;
290 postype
= pos_before
;
297 fatal("invalid option %c", c
);
302 printf ("%s version %s\n", program_name
, program_version
);
308 if ((operation
== none
|| operation
== print_table
)
309 && write_armap
== true)
310 ranlib_only(argv
[2]);
312 if (operation
== none
)
313 fatal("no operation specified");
315 if (newer_only
&& operation
!= replace
)
316 fatal("'u' only meaningful with 'r' option.");
320 if (postype
!= pos_default
)
321 posname
= argv
[arg_index
++];
323 inarch_filename
= argv
[arg_index
++];
325 if (arg_index
< argc
) {
326 files
= argv
+ arg_index
;
327 while (arg_index
< argc
)
328 if (!strcmp(argv
[arg_index
++], "__.SYMDEF")) {
336 if (operation
== quick_append
) {
338 do_quick_append(inarch_filename
, files
);
343 open_inarch(inarch_filename
);
348 map_over_members(print_descr
, files
, argc
- 3);
352 map_over_members(print_contents
, files
, argc
- 3);
356 map_over_members(extract_file
, files
, argc
- 3);
361 delete_members(files
);
370 if (files
!= NULL
|| write_armap
)
371 replace_members(files
);
374 /* Shouldn't happen! */
376 fprintf(stderr
, "Sorry; this option not implemented.\n");
383 char *normalize(file
)
386 char * filename
= strrchr(file
, '/');
387 if (filename
!= (char *)NULL
) {
397 open_inarch(archive_filename
)
398 char *archive_filename
;
403 bfd_error
= no_error
;
404 if (stat(archive_filename
, &sbuf
) != 0) {
406 bfd_fatal(archive_filename
);
407 if (!operation_alters_arch
) {
408 fprintf (stderr
, "%s: %s not found.\n", program_name
,
414 /* This routine is one way to forcibly create the archive. */
415 do_quick_append(archive_filename
, 0);
419 inarch
= bfd_openr(archive_filename
, default_target
);
421 inarch
= bfd_openr(archive_filename
, NULL
);
423 if (inarch
== NULL
) {
425 bfd_perror(archive_filename
);
429 if (bfd_check_format(inarch
, bfd_archive
) != true)
430 fatal("File %s is not an archive.", archive_filename
);
432 gnu960_verify_target(inarch
); /* Exits on failure */
434 last_one
= &(inarch
->next
);
435 /* Read all the contents right away, regardless. */
436 for (next_one
= bfd_openr_next_archived_file(inarch
, NULL
);
438 next_one
= bfd_openr_next_archived_file(inarch
, next_one
)) {
439 *last_one
= next_one
;
440 last_one
= &next_one
->next
;
442 *last_one
= (bfd
*) NULL
;
443 if (bfd_error
!= no_more_archived_files
)
459 if (bfd_stat_arch_elt(abfd
, &buf
) != 0)
460 fatal("Internal stat error on %s", abfd
->filename
);
463 printf("\n<member %s>\n\n", abfd
->filename
);
465 bfd_seek(abfd
, 0, SEEK_SET
);
468 while (ncopied
< size
) {
471 int tocopy
= size
- ncopied
;
472 if (tocopy
> BUFSIZE
)
475 nread
= bfd_read(cbuf
, 1, tocopy
, abfd
); /* oops -- broke
479 fatal("file %s not a valid archive", abfd
->my_archive
->filename
);
480 fwrite(cbuf
, 1, nread
, stdout
);
487 Extract a member of the archive into its own file.
489 We defer opening the new file until after we have read a BUFSIZ chunk of the
490 old one, since we know we have just read the archive header for the old
491 one. Since most members are shorter than BUFSIZ, this means we will read
492 the old header, read the old data, write a new inode for the new file, and
493 write the new data, and be done. This 'optimization' is what comes from
494 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
509 if (bfd_stat_arch_elt(abfd
, &buf
) != 0)
510 fatal("Internal stat error on %s", abfd
->filename
);
514 printf("x - %s\n", abfd
->filename
);
516 bfd_seek(abfd
, 0, SEEK_SET
);
520 /* Seems like an abstraction violation, eh? Well it's OK! */
521 ostream
= fopen(abfd
->filename
, FOPEN_WB
);
523 perror(abfd
->filename
);
527 while (ncopied
< size
) {
528 tocopy
= size
- ncopied
;
529 if (tocopy
> BUFSIZE
)
532 nread
= bfd_read(cbuf
, 1, tocopy
, abfd
);
534 fatal("file %s not a valid archive", abfd
->my_archive
->filename
);
536 /* See comment above; this saves disk arm motion */
538 /* Seems like an abstraction violation, eh? Well it's OK! */
539 ostream
= fopen(abfd
->filename
, FOPEN_WB
);
541 perror(abfd
->filename
);
545 fwrite(cbuf
, 1, nread
, ostream
);
550 chmod(abfd
->filename
, buf
.st_mode
);
552 if (preserve_dates
) {
555 tb
[0] = buf
.st_mtime
;
556 tb
[1] = buf
.st_mtime
;
557 utime(abfd
->filename
, tb
); /* FIXME check result */
559 struct timeval tv
[2];
560 tv
[0].tv_sec
= buf
.st_mtime
;
562 tv
[1].tv_sec
= buf
.st_mtime
;
564 utimes(abfd
->filename
, tv
); /* FIXME check result */
570 /* Just do it quickly; don't worry about dups, armap, or anything like that */
572 /* This is ugly! XXX */
574 PROTO(struct ar_hdr
*, bfd_special_undocumented_glue
, (bfd
*abfd
, char *filename
));
577 do_quick_append(archive_filename
, files_to_append
)
578 char *archive_filename
;
579 char **files_to_append
;
589 boolean newfile
= false;
590 bfd_error
= no_error
;
592 if (stat(archive_filename
, &sbuf
) != 0) {
594 bfd_fatal(archive_filename
);
599 ofile
= fopen(archive_filename
, FOPEN_AUB
);
601 perror(program_name
);
607 temp
= bfd_openr(archive_filename
, default_target
);
609 temp
= bfd_openr(archive_filename
, NULL
);
612 bfd_perror(archive_filename
);
615 if (newfile
== false) {
616 if (bfd_check_format(temp
, bfd_archive
) != true)
617 fatal("File %s is not an archive.", archive_filename
);
619 gnu960_verify_target(temp
); /* Exits on failure */
623 fwrite(ARMAG
, 1, SARMAG
, ofile
);
625 fprintf(stderr
, "%s: creating %s\n", program_name
, archive_filename
);
628 /* assume it's an achive, go straight to the end, sans $200 */
631 for (; files_to_append
&& *files_to_append
; ++files_to_append
) {
632 struct ar_hdr
*hdr
= bfd_special_undocumented_glue(temp
, *files_to_append
);
634 bfd_perror(*files_to_append
);
638 BFD_SEND(temp
, _bfd_truncate_arname
, (temp
, *files_to_append
, (char *) hdr
));
640 ifile
= fopen(*files_to_append
, FOPEN_RB
);
642 bfd_perror(program_name
);
644 if (stat(*files_to_append
, &sbuf
) != 0)
645 bfd_perror(*files_to_append
);
647 tocopy
= sbuf
.st_size
;
649 /* XXX should do error-checking! */
650 fwrite(hdr
, 1, sizeof(struct ar_hdr
), ofile
);
655 if (thistime
> BUFSIZE
)
657 fread(buf
, 1, thistime
, ifile
);
658 fwrite(buf
, 1, thistime
, ofile
);
662 if ((sbuf
.st_size
% 2) == 1)
674 int namelen
= strlen(inarch
->filename
);
675 char *new_name
= xmalloc(namelen
+ 6);
676 bfd
*contents_head
= inarch
->next
;
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
);
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
;
717 bfd
**after_bfd
= contents
;
718 enum pos realpos
= (postype
== pos_default
? default_pos
: postype
);
720 if (realpos
== pos_end
) {
722 after_bfd
= &((*after_bfd
)->next
);
725 for ( ; *after_bfd
; after_bfd
= &(*after_bfd
)->next
)
726 if (!strcmp((*after_bfd
)->filename
, posname
)) {
727 if (realpos
== pos_after
)
728 after_bfd
= &(*after_bfd
)->next
;
737 delete_members(files_to_delete
)
738 char **files_to_delete
;
740 bfd
**current_ptr_ptr
;
742 boolean something_changed
= false;
743 for (; *files_to_delete
!= NULL
; ++files_to_delete
) {
745 In a.out systems, the armap is optional. It's also called
746 __.SYMDEF. So if the user asked to delete it, we should remember
747 that fact. The name is NULL in COFF archives, so using this as a
748 key is as good as anything I suppose
750 if (!strcmp(*files_to_delete
, "__.SYMDEF")) {
751 inarch
->has_armap
= false;
757 current_ptr_ptr
= &(inarch
->next
);
758 while (*current_ptr_ptr
) {
759 if (strcmp(*files_to_delete
, (*current_ptr_ptr
)->filename
) == 0) {
761 something_changed
= true;
765 *current_ptr_ptr
= ((*current_ptr_ptr
)->next
);
770 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
774 if (verbose
&& found
== false) {
775 printf("No member named `%s'\n", *files_to_delete
);
781 if (something_changed
== true) {
787 /* Reposition existing members within an archive */
790 move_members(files_to_move
)
791 char **files_to_move
;
793 bfd
**after_bfd
; /* New entries go after this one */
794 bfd
**current_ptr_ptr
; /* cdr pointer into contents */
799 for (; *files_to_move
; ++files_to_move
) {
800 current_ptr_ptr
= &(inarch
->next
);
801 while (*current_ptr_ptr
) {
802 bfd
*current_ptr
= *current_ptr_ptr
;
803 if (strcmp(normalize(*files_to_move
), current_ptr
->filename
) == 0) {
805 Move this file to the end of the list - first cut from
808 *current_ptr_ptr
= current_ptr
->next
;
810 /* Now glue to end */
811 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
812 *after_bfd
= current_ptr
;
813 current_ptr
->next
= (bfd
*) NULL
;
816 printf("m - %s\n", *files_to_move
);
820 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
822 fprintf(stderr
, "No entry %s in archive %s!\n",
823 *files_to_move
, inarch
->filename
);
832 /* Ought to default to replacing in place, but this is existing practice! */
835 replace_members(files_to_move
)
836 char **files_to_move
;
838 bfd
**after_bfd
; /* New entries go after this one */
843 If the first item in the archive is an __.SYMDEF then remove it
846 strcmp(inarch
->next
->filename
, "__.SYMDEF") == 0) {
847 inarch
->next
= inarch
->next
->next
;
852 while (files_to_move
&& *files_to_move
) {
853 current_ptr
= &inarch
->next
;
854 while (*current_ptr
) {
855 current
= *current_ptr
;
857 if (!strcmp(normalize(*files_to_move
), current
->filename
)) {
862 if (current
->arelt_data
== NULL
) {
863 /* This can only happen if you specify a file on the
864 command line more than once. */
865 fprintf (stderr
, "Duplicate file specified: %s -- skipping.\n", *files_to_move
);
869 if (stat(*files_to_move
, &fsbuf
) != 0) {
871 bfd_fatal(*files_to_move
);
874 if (bfd_stat_arch_elt(current
, &asbuf
) != 0)
875 fatal("Internal stat error on %s", current
->filename
);
877 if (fsbuf
.st_mtime
<= asbuf
.st_mtime
)
881 /* snip out this entry from the chain */
882 *current_ptr
= current
->next
;
884 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
886 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
887 if (*after_bfd
== (bfd
*) NULL
) {
888 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
892 gnu960_verify_target(*after_bfd
); /* Exits on failure */
894 (*after_bfd
)->next
= temp
;
897 printf("%c - %s\n", (postype
== pos_after
? 'r' : 'a'),
902 current_ptr
= &(current
->next
);
905 /* It isn't in there, so add to end */
907 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
909 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
910 if (*after_bfd
== (bfd
*) NULL
) {
911 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
915 gnu960_verify_target(*after_bfd
); /* Exits on failure */
918 printf("c - %s\n", *files_to_move
);
921 (*after_bfd
)->next
= temp
;
933 ranlib_only(archname
)
937 open_inarch(archname
);
944 /* Things which are interesting to map over all or some of the files: */
950 print_arelt_descr(stdout
,abfd
, verbose
);