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 char *program_name
= NULL
;
60 bfd
*inarch
; /* The input arch we're manipulating */
63 /* This flag distinguishes between ar and ranlib:
64 1 means this is 'ranlib'; 0 means this is 'ar'.
65 -1 means if we should use argv[0] to decide. */
67 /* Nonzero means don't warn about creating the archive file if necessary. */
68 int silent_create
= 0;
69 /* Nonzero means describe each action performed. */
71 /* Nonzero means preserve dates of members when extracting them. */
72 int preserve_dates
= 0;
74 Nonzero means don't replace existing members whose dates are more recent
75 than the corresponding files.
78 /* write a __.SYMDEF member into the modified archive. */
79 boolean write_armap
= false;
81 Nonzero means don't update __.SYMDEF unless command line explicitly
84 int ignore_symdef
= 0;
86 Nonzero means it's the name of an existing member; position new or moved
87 files with respect to this one.
91 Sez how to use `posname': pos_before means position before that member.
92 pos_after means position after that member. pos_end means always at end.
93 pos_default means default appropriately. For the latter two, `posname'
97 pos_default
, pos_before
, pos_after
, pos_end
98 } postype
= pos_default
;
101 char *default_target
;
104 gnu960_verify_target(abfd
)
107 if ( abfd
->format
== bfd_unknown
){
108 bfd_check_format(abfd
, bfd_object
);
109 /* Don't really care if it's an object --
110 * just want to get the correct xvec.
113 if ( !BFD_COFF_FILE_P(abfd
) ){
114 fatal( "'%s' not a COFF file -- operation aborted",
124 interactive
= isatty(fileno(stdin
)) ;
129 If count is 0, then function is called once on each entry. if nonzero,
130 count is the length of the files chain; function is called on each entry
131 whose name matches one in files
134 DEFUN(map_over_members
,(function
, files
, count
),
135 void (*function
) () AND
142 for (head
= inarch
->next
; head
; head
= head
->next
)
147 This may appear to be a baroque way of accomplishing what we want.
148 however we have to iterate over the filenames in order to notice where
149 a filename is requested but does not exist in the archive. Ditto
150 mapping over each file each time -- we want to hack multiple
154 for (; count
> 0; files
++, count
--) {
155 boolean found
= false;
156 for (head
= inarch
->next
; head
; head
= head
->next
)
157 if ((head
->filename
!= NULL
) &&
158 (!strcmp(*files
, head
->filename
))) {
163 fprintf(stderr
, "No entry %s in archive.\n", *files
);
168 boolean operation_alters_arch
= false;
171 The option parsing should be in its own function. It will be when I have
182 none
= 0, delete, replace
, print_table
,
183 print_files
, extract
, move
, quick_append
187 char *inarch_filename
;
192 check_v960( argc
, argv
);
193 default_target
= bfd_make_targ_name(BFD_COFF_FORMAT
,HOST_BYTE_ORDER_BIG_P
);
196 program_name
= argv
[0];
198 temp
= strrchr(program_name
, '/');
199 if (temp
== (char *) NULL
)
200 temp
= program_name
; /* shouldn't happen, but... */
203 if (is_ranlib
> 0 || (is_ranlib
< 0 && strcmp(temp
, "ranlib") == 0)) {
205 fatal("Too few command arguments.");
206 ranlib_only(argv
[1]);
209 if (argc
== 2 && strcmp(argv
[1],"-M") == 0) {
214 fatal("Too few command arguments.");
219 ++arg_ptr
; /* compatibility */
221 while (c
= *arg_ptr
++) {
230 if (operation
!= none
)
231 fatal("two different operation switches specified");
235 operation_alters_arch
= true;
239 operation_alters_arch
= true;
242 operation
= print_files
;
245 operation
= quick_append
;
246 operation_alters_arch
= true;
250 operation_alters_arch
= true;
253 operation
= print_table
;
280 postype
= pos_before
;
283 postype
= pos_before
;
290 fatal("invalid option %c", c
);
298 if ((operation
== none
|| operation
== print_table
)
299 && write_armap
== true)
300 ranlib_only(argv
[2]);
302 if (operation
== none
)
303 fatal("no operation specified");
305 if (newer_only
&& operation
!= replace
)
306 fatal("'u' only meaningful with 'r' option.");
310 if (postype
!= pos_default
)
311 posname
= argv
[arg_index
++];
313 inarch_filename
= argv
[arg_index
++];
315 if (arg_index
< argc
) {
316 files
= argv
+ arg_index
;
317 while (arg_index
< argc
)
318 if (!strcmp(argv
[arg_index
++], "__.SYMDEF")) {
326 if (operation
== quick_append
) {
328 do_quick_append(inarch_filename
, files
);
333 open_inarch(inarch_filename
);
338 map_over_members(print_descr
, files
, argc
- 3);
342 map_over_members(print_contents
, files
, argc
- 3);
346 map_over_members(extract_file
, files
, argc
- 3);
351 delete_members(files
);
360 if (files
!= NULL
|| write_armap
)
361 replace_members(files
);
364 /* Shouldn't happen! */
366 fprintf(stderr
, "Sorry; this option not implemented.\n");
373 char *normalize(file
)
376 char * filename
= strrchr(file
, '/');
377 if (filename
!= (char *)NULL
) {
387 open_inarch(archive_filename
)
388 char *archive_filename
;
393 bfd_error
= no_error
;
394 if (stat(archive_filename
, &sbuf
) != 0) {
396 bfd_fatal(archive_filename
);
397 if (!operation_alters_arch
) {
398 fprintf (stderr
, "%s: %s not found.\n", program_name
,
404 /* This routine is one way to forcibly create the archive. */
405 do_quick_append(archive_filename
, 0);
409 inarch
= bfd_openr(archive_filename
, default_target
);
411 inarch
= bfd_openr(archive_filename
, NULL
);
413 if (inarch
== NULL
) {
415 bfd_perror(archive_filename
);
419 if (bfd_check_format(inarch
, bfd_archive
) != true)
420 fatal("File %s is not an archive.", archive_filename
);
422 gnu960_verify_target(inarch
); /* Exits on failure */
424 last_one
= &(inarch
->next
);
425 /* Read all the contents right away, regardless. */
426 for (next_one
= bfd_openr_next_archived_file(inarch
, NULL
);
428 next_one
= bfd_openr_next_archived_file(inarch
, next_one
)) {
429 *last_one
= next_one
;
430 last_one
= &next_one
->next
;
432 *last_one
= (bfd
*) NULL
;
433 if (bfd_error
!= no_more_archived_files
)
449 if (bfd_stat_arch_elt(abfd
, &buf
) != 0)
450 fatal("Internal stat error on %s", abfd
->filename
);
453 printf("\n<member %s>\n\n", abfd
->filename
);
455 bfd_seek(abfd
, 0, SEEK_SET
);
458 while (ncopied
< size
) {
461 int tocopy
= size
- ncopied
;
462 if (tocopy
> BUFSIZE
)
465 nread
= bfd_read(cbuf
, 1, tocopy
, abfd
); /* oops -- broke
469 fatal("file %s not a valid archive", abfd
->my_archive
->filename
);
470 fwrite(cbuf
, 1, nread
, stdout
);
477 Extract a member of the archive into its own file.
479 We defer opening the new file until after we have read a BUFSIZ chunk of the
480 old one, since we know we have just read the archive header for the old
481 one. Since most members are shorter than BUFSIZ, this means we will read
482 the old header, read the old data, write a new inode for the new file, and
483 write the new data, and be done. This 'optimization' is what comes from
484 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
499 if (bfd_stat_arch_elt(abfd
, &buf
) != 0)
500 fatal("Internal stat error on %s", abfd
->filename
);
504 printf("x - %s\n", abfd
->filename
);
506 bfd_seek(abfd
, 0, SEEK_SET
);
510 /* Seems like an abstraction violation, eh? Well it's OK! */
511 ostream
= fopen(abfd
->filename
, FOPEN_WB
);
513 perror(abfd
->filename
);
517 while (ncopied
< size
) {
518 tocopy
= size
- ncopied
;
519 if (tocopy
> BUFSIZE
)
522 nread
= bfd_read(cbuf
, 1, tocopy
, abfd
);
524 fatal("file %s not a valid archive", abfd
->my_archive
->filename
);
526 /* See comment above; this saves disk arm motion */
528 /* Seems like an abstraction violation, eh? Well it's OK! */
529 ostream
= fopen(abfd
->filename
, FOPEN_WB
);
531 perror(abfd
->filename
);
535 fwrite(cbuf
, 1, nread
, ostream
);
540 chmod(abfd
->filename
, buf
.st_mode
);
542 if (preserve_dates
) {
545 tb
[0] = buf
.st_mtime
;
546 tb
[1] = buf
.st_mtime
;
547 utime(abfd
->filename
, tb
); /* FIXME check result */
549 struct timeval tv
[2];
550 tv
[0].tv_sec
= buf
.st_mtime
;
552 tv
[1].tv_sec
= buf
.st_mtime
;
554 utimes(abfd
->filename
, tv
); /* FIXME check result */
560 /* Just do it quickly; don't worry about dups, armap, or anything like that */
562 /* This is ugly! XXX */
564 PROTO(struct ar_hdr
*, bfd_special_undocumented_glue
, (bfd
*abfd
, char *filename
));
567 do_quick_append(archive_filename
, files_to_append
)
568 char *archive_filename
;
569 char **files_to_append
;
579 boolean newfile
= false;
580 bfd_error
= no_error
;
582 if (stat(archive_filename
, &sbuf
) != 0) {
584 bfd_fatal(archive_filename
);
589 ofile
= fopen(archive_filename
, FOPEN_AUB
);
591 perror(program_name
);
597 temp
= bfd_openr(archive_filename
, default_target
);
599 temp
= bfd_openr(archive_filename
, NULL
);
602 bfd_perror(archive_filename
);
605 if (newfile
== false) {
606 if (bfd_check_format(temp
, bfd_archive
) != true)
607 fatal("File %s is not an archive.", archive_filename
);
609 gnu960_verify_target(temp
); /* Exits on failure */
613 fwrite(ARMAG
, 1, SARMAG
, ofile
);
615 fprintf(stderr
, "%s: creating %s\n", program_name
, archive_filename
);
618 /* assume it's an achive, go straight to the end, sans $200 */
621 for (; files_to_append
&& *files_to_append
; ++files_to_append
) {
622 struct ar_hdr
*hdr
= bfd_special_undocumented_glue(temp
, *files_to_append
);
624 bfd_perror(*files_to_append
);
628 BFD_SEND(temp
, _bfd_truncate_arname
, (temp
, *files_to_append
, (char *) hdr
));
630 ifile
= fopen(*files_to_append
, FOPEN_RB
);
632 bfd_perror(program_name
);
634 if (stat(*files_to_append
, &sbuf
) != 0)
635 bfd_perror(*files_to_append
);
637 tocopy
= sbuf
.st_size
;
639 /* XXX should do error-checking! */
640 fwrite(hdr
, 1, sizeof(struct ar_hdr
), ofile
);
645 if (thistime
> BUFSIZE
)
647 fread(buf
, 1, thistime
, ifile
);
648 fwrite(buf
, 1, thistime
, ofile
);
652 if ((sbuf
.st_size
% 2) == 1)
664 int namelen
= strlen(inarch
->filename
);
665 char *new_name
= xmalloc(namelen
+ 6);
666 bfd
*contents_head
= inarch
->next
;
668 strcpy(new_name
, inarch
->filename
);
669 strcpy(new_name
+ namelen
, "-art");
670 obfd
= bfd_openw(new_name
,
671 /* FIXME: violates abstraction; need a better protocol */
672 (inarch
->xvec
? bfd_get_target(inarch
) : NULL
));
675 bfd_fatal(inarch
->filename
);
677 bfd_set_format(obfd
, bfd_archive
);
678 obfd
->has_armap
= write_armap
;
680 if (bfd_set_archive_head(obfd
, contents_head
) != true)
681 bfd_fatal(inarch
->filename
);
683 if (!bfd_close(obfd
))
684 bfd_fatal(inarch
->filename
);
686 /* We don't care if this fails, we might be creating the
688 (void) unlink(inarch
->filename
);
690 if (rename(new_name
, inarch
->filename
) != 0)
691 bfd_fatal(inarch
->filename
);
697 returns a pointer to the pointer to the entry which should be rplacd'd
698 into when altering. default_pos should be how to interpret pos_default,
699 and should be a pos value.
703 get_pos_bfd(contents
, default_pos
)
705 enum pos default_pos
;
707 bfd
**after_bfd
= contents
;
708 enum pos realpos
= (postype
== pos_default
? default_pos
: postype
);
710 if (realpos
== pos_end
) {
712 after_bfd
= &((*after_bfd
)->next
);
715 for ( ; *after_bfd
; after_bfd
= &(*after_bfd
)->next
)
716 if (!strcmp((*after_bfd
)->filename
, posname
)) {
717 if (realpos
== pos_after
)
718 after_bfd
= &(*after_bfd
)->next
;
727 delete_members(files_to_delete
)
728 char **files_to_delete
;
730 bfd
**current_ptr_ptr
;
732 boolean something_changed
= false;
733 for (; *files_to_delete
!= NULL
; ++files_to_delete
) {
735 In a.out systems, the armap is optional. It's also called
736 __.SYMDEF. So if the user asked to delete it, we should remember
737 that fact. The name is NULL in COFF archives, so using this as a
738 key is as good as anything I suppose
740 if (!strcmp(*files_to_delete
, "__.SYMDEF")) {
741 inarch
->has_armap
= false;
747 current_ptr_ptr
= &(inarch
->next
);
748 while (*current_ptr_ptr
) {
749 if (strcmp(*files_to_delete
, (*current_ptr_ptr
)->filename
) == 0) {
751 something_changed
= true;
755 *current_ptr_ptr
= ((*current_ptr_ptr
)->next
);
760 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
764 if (verbose
&& found
== false) {
765 printf("No member named `%s'\n", *files_to_delete
);
771 if (something_changed
== true) {
777 /* Reposition existing members within an archive */
780 move_members(files_to_move
)
781 char **files_to_move
;
783 bfd
**after_bfd
; /* New entries go after this one */
784 bfd
**current_ptr_ptr
; /* cdr pointer into contents */
789 for (; *files_to_move
; ++files_to_move
) {
790 current_ptr_ptr
= &(inarch
->next
);
791 while (*current_ptr_ptr
) {
792 bfd
*current_ptr
= *current_ptr_ptr
;
793 if (strcmp(normalize(*files_to_move
), current_ptr
->filename
) == 0) {
795 Move this file to the end of the list - first cut from
798 *current_ptr_ptr
= current_ptr
->next
;
800 /* Now glue to end */
801 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
802 *after_bfd
= current_ptr
;
803 current_ptr
->next
= (bfd
*) NULL
;
806 printf("m - %s\n", *files_to_move
);
810 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
812 fprintf(stderr
, "No entry %s in archive %s!\n",
813 *files_to_move
, inarch
->filename
);
822 /* Ought to default to replacing in place, but this is existing practice! */
825 replace_members(files_to_move
)
826 char **files_to_move
;
828 bfd
**after_bfd
; /* New entries go after this one */
833 If the first item in the archive is an __.SYMDEF then remove it
836 strcmp(inarch
->next
->filename
, "__.SYMDEF") == 0) {
837 inarch
->next
= inarch
->next
->next
;
842 while (files_to_move
&& *files_to_move
) {
843 current_ptr
= &inarch
->next
;
844 while (*current_ptr
) {
845 current
= *current_ptr
;
847 if (!strcmp(normalize(*files_to_move
), current
->filename
)) {
852 if (current
->arelt_data
== NULL
) {
853 /* This can only happen if you specify a file on the
854 command line more than once. */
855 fprintf (stderr
, "Duplicate file specified: %s -- skipping.\n", *files_to_move
);
859 if (stat(*files_to_move
, &fsbuf
) != 0) {
861 bfd_fatal(*files_to_move
);
864 if (bfd_stat_arch_elt(current
, &asbuf
) != 0)
865 fatal("Internal stat error on %s", current
->filename
);
867 if (fsbuf
.st_mtime
<= asbuf
.st_mtime
)
871 /* snip out this entry from the chain */
872 *current_ptr
= current
->next
;
874 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
876 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
877 if (*after_bfd
== (bfd
*) NULL
) {
878 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
882 gnu960_verify_target(*after_bfd
); /* Exits on failure */
884 (*after_bfd
)->next
= temp
;
887 printf("%c - %s\n", (postype
== pos_after
? 'r' : 'a'),
892 current_ptr
= &(current
->next
);
895 /* It isn't in there, so add to end */
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 */
908 printf("c - %s\n", *files_to_move
);
911 (*after_bfd
)->next
= temp
;
923 ranlib_only(archname
)
927 open_inarch(archname
);
934 /* Things which are interesting to map over all or some of the files: */
940 print_arelt_descr(stdout
,abfd
, verbose
);