1 /* ar.c - Archive modify and extract. */
3 Bugs: should use getopt the way tar does (complete w/optional -) and
4 should have long options too. GNU ar used to check file against filesystem
5 in quick_update and replace operations (would check mtime). Doesn't warn
6 when name truncated. No way to specify pos_end. Error messages should be
16 /* Not great to have these here. Should they be exported or not? */
17 PROTO(size_t, bfd_read
, (void *ptr
, size_t size
, size_t nitems
, bfd
* abfd
));
18 PROTO(size_t, bfd_write
, (void *ptr
, size_t size
, size_t nitems
, bfd
* abfd
));
19 /* PROTO (void, open_inarch, (char *archive_filename)); */
21 static void open_inarch(char *archive_filename
);
23 static void open_inarch();
26 PROTO(void, map_over_members
, (void (*function
) (), char **files
, int count
));
27 PROTO(void, print_contents
, (bfd
* member
));
28 PROTO(void, extract_file
, (bfd
* abfd
));
29 PROTO(void, delete_members
, (char **files_to_delete
));
30 PROTO(void, do_quick_append
, (char *archive_filename
, char **files_to_append
));
31 PROTO(void, move_members
, (char **files_to_move
));
32 PROTO(void, replace_members
, (char **files_to_replace
));
33 PROTO(void, print_descr
, (bfd
* abfd
));
34 PROTO(void, ranlib_only
, (char *archname
));
36 /** Globals and flags */
38 char *program_name
= NULL
;
40 bfd
*inarch
; /* The input arch we're manipulating */
42 /* Nonzero means don't warn about creating the archive file if necessary. */
43 int silent_create
= 0;
44 /* Nonzero means describe each action performed. */
46 /* Nonzero means preserve dates of members when extracting them. */
47 int preserve_dates
= 0;
49 Nonzero means don't replace existing members whose dates are more recent
50 than the corresponding files.
53 /* write a __.SYMDEF member into the modified archive. */
54 boolean write_armap
= false;
56 Nonzero means don't update __.SYMDEF unless command line explicitly
59 int ignore_symdef
= 0;
61 Nonzero means it's the name of an existing member; position new or moved
62 files with respect to this one.
66 Sez how to use `posname': pos_before means position before that member.
67 pos_after means position after that member. pos_end means always at end.
68 pos_default means default appropriately. For the latter two, `posname'
72 pos_default
, pos_before
, pos_after
, pos_end
73 } postype
= pos_default
;
79 gnu960_verify_target(abfd
)
82 if ( abfd
->format
== bfd_unknown
){
83 bfd_check_format(abfd
, bfd_object
);
84 /* Don't really care if it's an object --
85 * just want to get the correct xvec.
88 if ( !BFD_COFF_FILE_P(abfd
) ){
89 fatal( "'%s' not a COFF file -- operation aborted",
97 boolean operation_alters_arch
= false;
100 The option parsing should be in its own function. It will be when I have
111 none
= 0, delete, replace
, print_table
,
112 print_files
, extract
, move
, quick_append
116 char *inarch_filename
;
120 check_v960( argc
, argv
);
121 default_target
= bfd_make_targ_name(BFD_COFF_FORMAT
,HOST_BYTE_ORDER_BIG_P
);
124 program_name
= argv
[0];
126 temp
= strrchr(program_name
, '/');
127 if (temp
== (char *) NULL
)
128 temp
= program_name
; /* shouldn't happen, but... */
131 if (!strcmp(temp
, "ranlib")) {
133 fatal("Too few command arguments.");
134 ranlib_only(argv
[1]);
139 fatal("Too few command arguments.");
144 ++arg_ptr
; /* compatibility */
146 while (c
= *arg_ptr
++) {
155 if (operation
!= none
)
156 fatal("two different operation switches specified");
160 operation_alters_arch
= true;
164 operation_alters_arch
= true;
167 operation
= print_files
;
170 operation
= quick_append
;
171 operation_alters_arch
= true;
175 operation_alters_arch
= true;
178 operation
= print_table
;
205 postype
= pos_before
;
208 postype
= pos_before
;
211 fatal("invalid option %c", c
);
215 if (operation
== none
&& write_armap
)
216 ranlib_only(argv
[2]);
218 if (operation
== none
)
219 fatal("no operation specified");
221 if (newer_only
&& operation
!= replace
)
222 fatal("'u' only meaningful with 'r' option.");
226 if (postype
!= pos_default
)
227 posname
= argv
[arg_index
++];
229 inarch_filename
= argv
[arg_index
++];
231 if (arg_index
< argc
) {
232 files
= argv
+ arg_index
;
233 while (arg_index
< argc
)
234 if (!strcmp(argv
[arg_index
++], "__.SYMDEF")) {
242 if (operation
== quick_append
) {
244 do_quick_append(inarch_filename
, files
);
249 open_inarch(inarch_filename
);
251 If we have no archive, and we've been asked to replace then create one
254 if (operation
== replace
&& inarch
== &bogus_archive
) {
256 do_quick_append(inarch_filename
, 0);
257 open_inarch(inarch_filename
);
263 map_over_members(print_descr
, files
, argc
- 3);
267 map_over_members(print_contents
, files
, argc
- 3);
271 map_over_members(extract_file
, files
, argc
- 3);
276 delete_members(files
);
285 if (files
!= NULL
|| write_armap
)
286 replace_members(files
);
289 /* Shouldn't happen! */
291 fprintf(stderr
, "Sorry; this option not implemented.\n");
298 char *normalize(file
)
301 char * filename
= strrchr(file
, '/');
302 if (filename
!= (char *)NULL
) {
312 open_inarch(archive_filename
)
313 char *archive_filename
;
318 bfd_error
= no_error
;
319 if (stat(archive_filename
, &sbuf
) != 0) {
321 bfd_fatal(archive_filename
);
322 if (!operation_alters_arch
) {
323 fprintf (stderr
, "%s: %s not found.\n", program_name
,
329 "%s: creating %s\n", program_name
, archive_filename
);
331 inarch
= &bogus_archive
;
332 inarch
->filename
= archive_filename
;
333 inarch
->has_armap
= true;
338 inarch
= bfd_openr(archive_filename
, default_target
);
340 inarch
= bfd_openr(archive_filename
, NULL
);
342 if (inarch
== NULL
) {
344 bfd_perror(archive_filename
);
348 if (bfd_check_format(inarch
, bfd_archive
) != true)
349 fatal("File %s is not an archive.", archive_filename
);
351 gnu960_verify_target(inarch
); /* Exits on failure */
353 last_one
= &(inarch
->next
);
354 /* Read all the contents right away, regardless. */
355 for (next_one
= bfd_openr_next_archived_file(inarch
, NULL
);
357 next_one
= bfd_openr_next_archived_file(inarch
, next_one
)) {
358 *last_one
= next_one
;
359 last_one
= &next_one
->next
;
361 *last_one
= (bfd
*) NULL
;
362 if (bfd_error
!= no_more_archived_files
)
370 If count is 0, then function is called once on each entry. if nonzero,
371 count is the length of the files chain; function is called on each entry
372 whose name matches one in files
375 map_over_members(function
, files
, count
)
386 for (head
= inarch
->next
; head
; head
= head
->next
)
391 This may appear to be a baroque way of accomplishing what we want.
392 however we have to iterate over the filenames in order to notice where
393 a filename is requested but does not exist in the archive. Ditto
394 mapping over each file each time -- we want to hack multiple
398 for (; count
> 0; files
++, count
--) {
399 boolean found
= false;
400 for (head
= inarch
->next
; head
; head
= head
->next
)
401 if ((head
->filename
!= NULL
) &&
402 (!strcmp(*files
, head
->filename
))) {
407 fprintf(stderr
, "No entry %s in archive.\n", *files
);
412 /* Things which are interesting to map over all or some of the files: */
418 print_arelt_descr(abfd
, verbose
);
428 if (bfd_stat_arch_elt(abfd
, &buf
) != 0)
429 fatal("Internal stat error on %s", abfd
->filename
);
432 printf("\n<member %s>\n\n", abfd
->filename
);
434 bfd_seek(abfd
, 0, SEEK_SET
);
437 while (ncopied
< size
) {
440 int tocopy
= size
- ncopied
;
441 if (tocopy
> BUFSIZE
)
444 nread
= bfd_read(cbuf
, 1, tocopy
, abfd
); /* oops -- broke
448 fatal("file %s not a valid archive", abfd
->my_archive
->filename
);
449 fwrite(cbuf
, 1, nread
, stdout
);
456 Extract a member of the archive into its own file.
458 We defer opening the new file until after we have read a BUFSIZ chunk of the
459 old one, since we know we have just read the archive header for the old
460 one. Since most members are shorter than BUFSIZ, this means we will read
461 the old header, read the old data, write a new inode for the new file, and
462 write the new data, and be done. This 'optimization' is what comes from
463 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
478 if (bfd_stat_arch_elt(abfd
, &buf
) != 0)
479 fatal("Internal stat error on %s", abfd
->filename
);
483 printf("x - %s\n", abfd
->filename
);
485 bfd_seek(abfd
, 0, SEEK_SET
);
489 /* Seems like an abstraction violation, eh? Well it's OK! */
490 ostream
= fopen(abfd
->filename
, "w");
492 perror(abfd
->filename
);
496 while (ncopied
< size
) {
497 tocopy
= size
- ncopied
;
498 if (tocopy
> BUFSIZE
)
501 nread
= bfd_read(cbuf
, 1, tocopy
, abfd
);
503 fatal("file %s not a valid archive", abfd
->my_archive
->filename
);
505 /* See comment above; this saves disk arm motion */
507 /* Seems like an abstraction violation, eh? Well it's OK! */
508 ostream
= fopen(abfd
->filename
, "w");
510 perror(abfd
->filename
);
514 fwrite(cbuf
, 1, nread
, ostream
);
519 chmod(abfd
->filename
, buf
.st_mode
);
521 if (preserve_dates
) {
524 tb
[0] = buf
.st_mtime
;
525 tb
[1] = buf
.st_mtime
;
526 utime(abfd
->filename
, tb
); /* FIXME check result */
528 struct timeval tv
[2];
529 tv
[0].tv_sec
= buf
.st_mtime
;
531 tv
[1].tv_sec
= buf
.st_mtime
;
533 utimes(abfd
->filename
, tv
); /* FIXME check result */
539 /* Just do it quickly; don't worry about dups, armap, or anything like that */
541 /* This is ugly! XXX */
543 PROTO(struct ar_hdr
*, bfd_special_undocumented_glue
, (char *filename
));
546 do_quick_append(archive_filename
, files_to_append
)
547 char *archive_filename
;
548 char **files_to_append
;
558 boolean newfile
= false;
559 bfd_error
= no_error
;
561 if (stat(archive_filename
, &sbuf
) != 0) {
563 bfd_fatal(archive_filename
);
568 ofile
= fopen(archive_filename
, "a+");
570 perror(program_name
);
576 temp
= bfd_openr(archive_filename
, default_target
);
578 temp
= bfd_openr(archive_filename
, NULL
);
581 bfd_perror(archive_filename
);
584 if (newfile
== false) {
585 if (bfd_check_format(temp
, bfd_archive
) != true)
586 fatal("File %s is not an archive.", archive_filename
);
588 gnu960_verify_target(temp
); /* Exits on failure */
592 fwrite(ARMAG
, 1, SARMAG
, ofile
);
594 fprintf(stderr
, "%s: creating %s\n", program_name
, archive_filename
);
597 /* assume it's an achive, go straight to the end, sans $200 */
600 for (; files_to_append
&& *files_to_append
; ++files_to_append
) {
601 struct ar_hdr
*hdr
= bfd_special_undocumented_glue(*files_to_append
);
603 bfd_perror(*files_to_append
);
607 BFD_SEND(temp
, _bfd_truncate_arname
, (temp
, *files_to_append
, (char *) hdr
));
609 ifile
= fopen(*files_to_append
, "r");
611 bfd_perror(program_name
);
613 if (stat(*files_to_append
, &sbuf
) != 0)
614 bfd_perror(*files_to_append
);
616 tocopy
= sbuf
.st_size
;
618 /* XXX should do error-checking! */
619 fwrite(hdr
, 1, sizeof(struct ar_hdr
), ofile
);
624 if (thistime
> BUFSIZE
)
626 fread(buf
, 1, thistime
, ifile
);
627 fwrite(buf
, 1, thistime
, ofile
);
631 if ((sbuf
.st_size
% 2) == 1)
644 int namelen
= strlen(inarch
->filename
);
645 char *new_name
= xmalloc(namelen
+ 6);
646 bfd
*contents_head
= inarch
->next
;
648 if (inarch
== &bogus_archive
) {
649 /* How can this be ? */
654 strcpy(new_name
, inarch
->filename
);
655 strcpy(new_name
+ namelen
, ".art");
656 obfd
= bfd_openw(new_name
,
657 /* violates abstraction; need a better protocol */
658 (inarch
->xvec
? bfd_get_target(inarch
) : NULL
));
661 bfd_fatal(inarch
->filename
);
663 bfd_set_format(obfd
, bfd_archive
);
664 obfd
->has_armap
= write_armap
;
666 if (bfd_set_archive_head(obfd
, contents_head
) != true)
667 bfd_fatal(inarch
->filename
);
669 if (!bfd_close(obfd
))
670 bfd_fatal(inarch
->filename
);
671 if (rename(new_name
, inarch
->filename
) != 0)
672 bfd_fatal(inarch
->filename
);
681 returns a pointer to the pointer to the entry which should be rplacd'd
682 into when altering. default_pos should be how to interpret pos_default,
683 and should be a pos value.
687 get_pos_bfd(contents
, default_pos
)
689 enum pos default_pos
;
693 enum pos realpos
= (postype
== pos_default
? default_pos
: postype
);
697 after_bfd
= contents
;
699 after_bfd
= &((*after_bfd
)->next
);
705 for (after_bfd
= contents
; after_bfd
; after_bfd
= after_bfd
->next
)
706 if (!strcpy(after_bfd
->filename
, posname
))
710 for (after_bfd
= contents
; after_bfd
; after_bfd
= after_bfd
->next
)
711 if (after_bfd
->next
&& (!strcpy(after_bfd
->next
->filename
, posname
)))
721 delete_members(files_to_delete
)
722 char **files_to_delete
;
724 bfd
**current_ptr_ptr
;
726 boolean something_changed
= false;
727 for (; *files_to_delete
!= NULL
; ++files_to_delete
) {
729 In a.out systems, the armap is optional. It's also called
730 __.SYMDEF. So if the user asked to delete it, we should remember
731 that fact. The name is NULL in COFF archives, so using this as a
732 key is as good as anything I suppose
734 if (!strcmp(*files_to_delete
, "__.SYMDEF")) {
735 inarch
->has_armap
= false;
741 current_ptr_ptr
= &(inarch
->next
);
742 while (*current_ptr_ptr
) {
743 if (strcmp(*files_to_delete
, (*current_ptr_ptr
)->filename
) == 0) {
745 something_changed
= true;
749 *current_ptr_ptr
= ((*current_ptr_ptr
)->next
);
754 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
758 if (verbose
&& found
== false) {
759 printf("No member named `%s'\n", *files_to_delete
);
765 if (something_changed
== true) {
771 /* Reposition existing members within an archive */
774 move_members(files_to_move
)
775 char **files_to_move
;
777 bfd
**after_bfd
; /* New entries go after this one */
778 bfd
**current_ptr_ptr
; /* cdr pointer into contents */
783 for (; *files_to_move
; ++files_to_move
) {
784 current_ptr_ptr
= &(inarch
->next
);
785 while (*current_ptr_ptr
) {
786 bfd
*current_ptr
= *current_ptr_ptr
;
787 if (strcmp(normalize(*files_to_move
), current_ptr
->filename
) == 0) {
789 Move this file to the end of the list - first cut from
792 *current_ptr_ptr
= current_ptr
->next
;
794 /* Now glue to end */
795 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
796 *after_bfd
= current_ptr
;
797 current_ptr
->next
= (bfd
*) NULL
;
800 printf("m - %s\n", *files_to_move
);
804 current_ptr_ptr
= &((*current_ptr_ptr
)->next
);
806 fprintf(stderr
, "No entry %s in archive %s!\n",
807 *files_to_move
, inarch
->filename
);
816 /* Ought to default to replacing in place, but this is existing practice! */
819 replace_members(files_to_move
)
820 char **files_to_move
;
822 bfd
**after_bfd
; /* New entries go after this one */
827 If the first item in the archive is an __.SYMDEF then remove it
830 strcmp(inarch
->next
->filename
, "__.SYMDEF") == 0) {
831 inarch
->next
= inarch
->next
->next
;
836 while (files_to_move
&& *files_to_move
) {
837 current_ptr
= &inarch
->next
;
838 while (*current_ptr
) {
839 current
= *current_ptr
;
841 if (!strcmp(normalize(*files_to_move
), current
->filename
)) {
846 if (current
->arelt_data
== NULL
) {
847 /* This can only happen if you specify a file on the
848 command line more than once. */
849 fprintf (stderr
, "Duplicate file specified: %s -- skipping.\n", *files_to_move
);
853 if (stat(*files_to_move
, &fsbuf
) != 0) {
855 bfd_fatal(*files_to_move
);
858 if (bfd_stat_arch_elt(current
, &asbuf
) != 0)
859 fatal("Internal stat error on %s", current
->filename
);
861 if (fsbuf
.st_mtime
<= asbuf
.st_mtime
)
865 /* snip out this entry from the chain */
866 *current_ptr
= current
->next
;
868 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
870 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
871 if (*after_bfd
== (bfd
*) NULL
) {
872 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
876 gnu960_verify_target(*after_bfd
); /* Exits on failure */
878 (*after_bfd
)->next
= temp
;
881 printf("%c - %s\n", (postype
== pos_after
? 'r' : 'a'),
886 current_ptr
= &(current
->next
);
889 /* It isn't in there, so add to end */
891 after_bfd
= get_pos_bfd(&inarch
->next
, pos_end
);
893 *after_bfd
= bfd_openr(*files_to_move
, NULL
);
894 if (*after_bfd
== (bfd
*) NULL
) {
895 fprintf(stderr
, "Can't open file %s\n", *files_to_move
);
899 gnu960_verify_target(*after_bfd
); /* Exits on failure */
902 printf("c - %s\n", *files_to_move
);
905 (*after_bfd
)->next
= temp
;
917 ranlib_only(archname
)
921 open_inarch(archname
);