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
;
195 check_v960( argc
, argv
);
196 default_target
= bfd_make_targ_name(BFD_COFF_FORMAT
,HOST_BYTE_ORDER_BIG_P
);
199 program_name
= argv
[0];
201 temp
= strrchr(program_name
, '/');
202 if (temp
== (char *) NULL
)
203 temp
= program_name
; /* shouldn't happen, but... */
206 if (is_ranlib
> 0 || (is_ranlib
< 0 && strcmp(temp
, "ranlib") == 0)) {
208 fatal("Too few command arguments.");
209 ranlib_only(argv
[1]);
212 if (argc
== 2 && strcmp(argv
[1],"-M") == 0) {
217 fatal("Too few command arguments.");
222 ++arg_ptr
; /* compatibility */
224 while (c
= *arg_ptr
++) {
233 if (operation
!= none
)
234 fatal("two different operation switches specified");
238 operation_alters_arch
= true;
242 operation_alters_arch
= true;
245 operation
= print_files
;
248 operation
= quick_append
;
249 operation_alters_arch
= true;
253 operation_alters_arch
= true;
256 operation
= print_table
;
286 postype
= pos_before
;
289 postype
= pos_before
;
296 fatal("invalid option %c", c
);
301 printf ("%s version %s\n", program_name
, program_version
);
307 if ((operation
== none
|| operation
== print_table
)
308 && write_armap
== true)
309 ranlib_only(argv
[2]);
311 if (operation
== none
)
312 fatal("no operation specified");
314 if (newer_only
&& operation
!= replace
)
315 fatal("'u' only meaningful with 'r' option.");
319 if (postype
!= pos_default
)
320 posname
= argv
[arg_index
++];
322 inarch_filename
= argv
[arg_index
++];
324 if (arg_index
< argc
) {
325 files
= argv
+ arg_index
;
326 while (arg_index
< argc
)
327 if (!strcmp(argv
[arg_index
++], "__.SYMDEF")) {
335 if (operation
== quick_append
) {
337 do_quick_append(inarch_filename
, files
);
342 open_inarch(inarch_filename
);
347 map_over_members(print_descr
, files
, argc
- 3);
351 map_over_members(print_contents
, files
, argc
- 3);
355 map_over_members(extract_file
, files
, argc
- 3);
360 delete_members(files
);
369 if (files
!= NULL
|| write_armap
)
370 replace_members(files
);
373 /* Shouldn't happen! */
375 fprintf(stderr
, "Sorry; this option not implemented.\n");
382 char *normalize(file
)
385 char * filename
= strrchr(file
, '/');
386 if (filename
!= (char *)NULL
) {
396 open_inarch(archive_filename
)
397 char *archive_filename
;
402 bfd_error
= no_error
;
403 if (stat(archive_filename
, &sbuf
) != 0) {
405 bfd_fatal(archive_filename
);
406 if (!operation_alters_arch
) {
407 fprintf (stderr
, "%s: %s not found.\n", program_name
,
413 /* This routine is one way to forcibly create the archive. */
414 do_quick_append(archive_filename
, 0);
418 inarch
= bfd_openr(archive_filename
, default_target
);
420 inarch
= bfd_openr(archive_filename
, NULL
);
422 if (inarch
== NULL
) {
424 bfd_perror(archive_filename
);
428 if (bfd_check_format(inarch
, bfd_archive
) != true)
429 fatal("File %s is not an archive.", archive_filename
);
431 gnu960_verify_target(inarch
); /* Exits on failure */
433 last_one
= &(inarch
->next
);
434 /* Read all the contents right away, regardless. */
435 for (next_one
= bfd_openr_next_archived_file(inarch
, NULL
);
437 next_one
= bfd_openr_next_archived_file(inarch
, next_one
)) {
438 *last_one
= next_one
;
439 last_one
= &next_one
->next
;
441 *last_one
= (bfd
*) NULL
;
442 if (bfd_error
!= no_more_archived_files
)
458 if (bfd_stat_arch_elt(abfd
, &buf
) != 0)
459 fatal("Internal stat error on %s", abfd
->filename
);
462 printf("\n<member %s>\n\n", abfd
->filename
);
464 bfd_seek(abfd
, 0, SEEK_SET
);
467 while (ncopied
< size
) {
470 int tocopy
= size
- ncopied
;
471 if (tocopy
> BUFSIZE
)
474 nread
= bfd_read(cbuf
, 1, tocopy
, abfd
); /* oops -- broke
478 fatal("file %s not a valid archive", abfd
->my_archive
->filename
);
479 fwrite(cbuf
, 1, nread
, stdout
);
486 Extract a member of the archive into its own file.
488 We defer opening the new file until after we have read a BUFSIZ chunk of the
489 old one, since we know we have just read the archive header for the old
490 one. Since most members are shorter than BUFSIZ, this means we will read
491 the old header, read the old data, write a new inode for the new file, and
492 write the new data, and be done. This 'optimization' is what comes from
493 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
508 if (bfd_stat_arch_elt(abfd
, &buf
) != 0)
509 fatal("Internal stat error on %s", abfd
->filename
);
513 printf("x - %s\n", abfd
->filename
);
515 bfd_seek(abfd
, 0, SEEK_SET
);
519 /* Seems like an abstraction violation, eh? Well it's OK! */
520 ostream
= fopen(abfd
->filename
, FOPEN_WB
);
522 perror(abfd
->filename
);
526 while (ncopied
< size
) {
527 tocopy
= size
- ncopied
;
528 if (tocopy
> BUFSIZE
)
531 nread
= bfd_read(cbuf
, 1, tocopy
, abfd
);
533 fatal("file %s not a valid archive", abfd
->my_archive
->filename
);
535 /* See comment above; this saves disk arm motion */
537 /* Seems like an abstraction violation, eh? Well it's OK! */
538 ostream
= fopen(abfd
->filename
, FOPEN_WB
);
540 perror(abfd
->filename
);
544 fwrite(cbuf
, 1, nread
, ostream
);
549 chmod(abfd
->filename
, buf
.st_mode
);
551 if (preserve_dates
) {
554 tb
[0] = buf
.st_mtime
;
555 tb
[1] = buf
.st_mtime
;
556 utime(abfd
->filename
, tb
); /* FIXME check result */
558 struct timeval tv
[2];
559 tv
[0].tv_sec
= buf
.st_mtime
;
561 tv
[1].tv_sec
= buf
.st_mtime
;
563 utimes(abfd
->filename
, tv
); /* FIXME check result */
569 /* Just do it quickly; don't worry about dups, armap, or anything like that */
571 /* This is ugly! XXX */
573 PROTO(struct ar_hdr
*, bfd_special_undocumented_glue
, (bfd
*abfd
, char *filename
));
576 do_quick_append(archive_filename
, files_to_append
)
577 char *archive_filename
;
578 char **files_to_append
;
588 boolean newfile
= false;
589 bfd_error
= no_error
;
591 if (stat(archive_filename
, &sbuf
) != 0) {
593 bfd_fatal(archive_filename
);
598 ofile
= fopen(archive_filename
, FOPEN_AUB
);
600 perror(program_name
);
606 temp
= bfd_openr(archive_filename
, default_target
);
608 temp
= bfd_openr(archive_filename
, NULL
);
611 bfd_perror(archive_filename
);
614 if (newfile
== false) {
615 if (bfd_check_format(temp
, bfd_archive
) != true)
616 fatal("File %s is not an archive.", archive_filename
);
618 gnu960_verify_target(temp
); /* Exits on failure */
622 fwrite(ARMAG
, 1, SARMAG
, ofile
);
624 fprintf(stderr
, "%s: creating %s\n", program_name
, archive_filename
);
627 /* assume it's an achive, go straight to the end, sans $200 */
630 for (; files_to_append
&& *files_to_append
; ++files_to_append
) {
631 struct ar_hdr
*hdr
= bfd_special_undocumented_glue(temp
, *files_to_append
);
633 bfd_perror(*files_to_append
);
637 BFD_SEND(temp
, _bfd_truncate_arname
, (temp
, *files_to_append
, (char *) hdr
));
639 ifile
= fopen(*files_to_append
, FOPEN_RB
);
641 bfd_perror(program_name
);
643 if (stat(*files_to_append
, &sbuf
) != 0)
644 bfd_perror(*files_to_append
);
646 tocopy
= sbuf
.st_size
;
648 /* XXX should do error-checking! */
649 fwrite(hdr
, 1, sizeof(struct ar_hdr
), ofile
);
654 if (thistime
> BUFSIZE
)
656 fread(buf
, 1, thistime
, ifile
);
657 fwrite(buf
, 1, thistime
, ofile
);
661 if ((sbuf
.st_size
% 2) == 1)
673 int namelen
= strlen(inarch
->filename
);
674 char *new_name
= xmalloc(namelen
+ 6);
675 bfd
*contents_head
= inarch
->next
;
677 strcpy(new_name
, inarch
->filename
);
678 strcpy(new_name
+ namelen
, "-art");
679 obfd
= bfd_openw(new_name
,
680 /* FIXME: violates abstraction; need a better protocol */
681 (inarch
->xvec
? bfd_get_target(inarch
) : NULL
));
684 bfd_fatal(inarch
->filename
);
686 bfd_set_format(obfd
, bfd_archive
);
687 obfd
->has_armap
= write_armap
;
689 if (bfd_set_archive_head(obfd
, contents_head
) != true)
690 bfd_fatal(inarch
->filename
);
692 if (!bfd_close(obfd
))
693 bfd_fatal(inarch
->filename
);
695 /* We don't care if this fails, we might be creating the
697 (void) unlink(inarch
->filename
);
699 if (rename(new_name
, inarch
->filename
) != 0)
700 bfd_fatal(inarch
->filename
);
706 returns a pointer to the pointer to the entry which should be rplacd'd
707 into when altering. default_pos should be how to interpret pos_default,
708 and should be a pos value.
712 get_pos_bfd(contents
, default_pos
)
714 enum pos default_pos
;
716 bfd
**after_bfd
= contents
;
717 enum pos realpos
= (postype
== pos_default
? default_pos
: postype
);
719 if (realpos
== pos_end
) {
721 after_bfd
= &((*after_bfd
)->next
);
724 for ( ; *after_bfd
; after_bfd
= &(*after_bfd
)->next
)
725 if (!strcmp((*after_bfd
)->filename
, posname
)) {
726 if (realpos
== pos_after
)
727 after_bfd
= &(*after_bfd
)->next
;
736 delete_members(files_to_delete
)
737 char **files_to_delete
;
739 bfd
**current_ptr_ptr
;
741 boolean something_changed
= false;
742 for (; *files_to_delete
!= NULL
; ++files_to_delete
) {
744 In a.out systems, the armap is optional. It's also called
745 __.SYMDEF. So if the user asked to delete it, we should remember
746 that fact. The name is NULL in COFF archives, so using this as a
747 key is as good as anything I suppose
749 if (!strcmp(*files_to_delete
, "__.SYMDEF")) {
750 inarch
->has_armap
= false;
756 current_ptr_ptr
= &(inarch
->next
);
757 while (*current_ptr_ptr
) {
758 if (strcmp(*files_to_delete
, (*current_ptr_ptr
)->filename
) == 0) {
760 something_changed
= true;
764 *current_ptr_ptr
= ((*current_ptr_ptr
)->next
);
769 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
773 if (verbose
&& found
== false) {
774 printf("No member named `%s'\n", *files_to_delete
);
780 if (something_changed
== true) {
786 /* Reposition existing members within an archive */
789 move_members(files_to_move
)
790 char **files_to_move
;
792 bfd
**after_bfd
; /* New entries go after this one */
793 bfd
**current_ptr_ptr
; /* cdr pointer into contents */
798 for (; *files_to_move
; ++files_to_move
) {
799 current_ptr_ptr
= &(inarch
->next
);
800 while (*current_ptr_ptr
) {
801 bfd
*current_ptr
= *current_ptr_ptr
;
802 if (strcmp(normalize(*files_to_move
), current_ptr
->filename
) == 0) {
804 Move this file to the end of the list - first cut from
807 *current_ptr_ptr
= current_ptr
->next
;
809 /* Now glue to end */
810 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
811 *after_bfd
= current_ptr
;
812 current_ptr
->next
= (bfd
*) NULL
;
815 printf("m - %s\n", *files_to_move
);
819 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
821 fprintf(stderr
, "No entry %s in archive %s!\n",
822 *files_to_move
, inarch
->filename
);
831 /* Ought to default to replacing in place, but this is existing practice! */
834 replace_members(files_to_move
)
835 char **files_to_move
;
837 bfd
**after_bfd
; /* New entries go after this one */
842 If the first item in the archive is an __.SYMDEF then remove it
845 strcmp(inarch
->next
->filename
, "__.SYMDEF") == 0) {
846 inarch
->next
= inarch
->next
->next
;
851 while (files_to_move
&& *files_to_move
) {
852 current_ptr
= &inarch
->next
;
853 while (*current_ptr
) {
854 current
= *current_ptr
;
856 if (!strcmp(normalize(*files_to_move
), current
->filename
)) {
861 if (current
->arelt_data
== NULL
) {
862 /* This can only happen if you specify a file on the
863 command line more than once. */
864 fprintf (stderr
, "Duplicate file specified: %s -- skipping.\n", *files_to_move
);
868 if (stat(*files_to_move
, &fsbuf
) != 0) {
870 bfd_fatal(*files_to_move
);
873 if (bfd_stat_arch_elt(current
, &asbuf
) != 0)
874 fatal("Internal stat error on %s", current
->filename
);
876 if (fsbuf
.st_mtime
<= asbuf
.st_mtime
)
880 /* snip out this entry from the chain */
881 *current_ptr
= current
->next
;
883 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
885 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
886 if (*after_bfd
== (bfd
*) NULL
) {
887 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
891 gnu960_verify_target(*after_bfd
); /* Exits on failure */
893 (*after_bfd
)->next
= temp
;
896 printf("%c - %s\n", (postype
== pos_after
? 'r' : 'a'),
901 current_ptr
= &(current
->next
);
904 /* It isn't in there, so add to end */
906 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
908 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
909 if (*after_bfd
== (bfd
*) NULL
) {
910 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
914 gnu960_verify_target(*after_bfd
); /* Exits on failure */
917 printf("c - %s\n", *files_to_move
);
920 (*after_bfd
)->next
= temp
;
932 ranlib_only(archname
)
936 open_inarch(archname
);
943 /* Things which are interesting to map over all or some of the files: */
949 print_arelt_descr(stdout
,abfd
, verbose
);