* copy.c (main): Even if is_strip, accept -d argument indicating alternate
[binutils-gdb.git] / binutils / ar.c
1 /* ar.c - Archive modify and extract.
2 Copyright (C) 1991 Free Software Foundation, Inc.
3
4 This file is part of GNU Binutils.
5
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.
10
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.
15
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. */
19
20 /*
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
25 more consistant.
26 */
27 #include "bfd.h"
28 #include "sysdep.h"
29 #include "bucomm.h"
30 #include "aout/ar.h"
31 #include "../bfd/libbfd.h"
32 #include "arsup.h"
33 #include <stdio.h>
34 #ifdef USG
35 #include <time.h>
36 #else
37 #include <sys/time.h>
38 #endif
39 #include <errno.h>
40 #ifndef errno
41 extern int errno;
42 #endif
43 #define BUFSIZE 8192
44
45
46
47
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));
56
57 /** Globals and flags */
58
59 extern *program_version;
60 char *program_name = NULL;
61 bfd *inarch; /* The input arch we're manipulating */
62
63 int mri_mode;
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. */
67 extern int is_ranlib;
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. */
71 int verbose = 0;
72 /* Nonzero means preserve dates of members when extracting them. */
73 int preserve_dates = 0;
74 /*
75 Nonzero means don't replace existing members whose dates are more recent
76 than the corresponding files.
77 */
78 int newer_only = 0;
79 /* write a __.SYMDEF member into the modified archive. */
80 boolean write_armap = false;
81 /*
82 Nonzero means don't update __.SYMDEF unless command line explicitly
83 requested it
84 */
85 int ignore_symdef = 0;
86 /*
87 Nonzero means it's the name of an existing member; position new or moved
88 files with respect to this one.
89 */
90 char *posname = NULL;
91 /*
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'
95 should also be zero.
96 */
97 enum pos {
98 pos_default, pos_before, pos_after, pos_end
99 } postype = pos_default;
100
101 #ifdef GNU960
102 char *default_target;
103
104 void
105 gnu960_verify_target(abfd)
106 bfd *abfd;
107 {
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.
112 */
113 }
114 if ( !BFD_COFF_FILE_P(abfd) ){
115 fatal( "'%s' not a COFF file -- operation aborted",
116 abfd->filename );
117 }
118 }
119 #endif
120
121 int interactive = 0;
122 void
123 DEFUN_VOID(mri_emul)
124 {
125 interactive = isatty(fileno(stdin)) ;
126 yyparse();
127 }
128
129 /*
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
133 */
134 void
135 DEFUN(map_over_members,(function, files, count),
136 void (*function) () AND
137 char **files AND
138 int count)
139 {
140 bfd *head;
141
142 if (count == 0) {
143 for (head = inarch->next; head; head = head->next)
144 function(head);
145 return;
146 }
147 /*
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
152 references.
153 */
154
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))) {
160 found = true;
161 function(head);
162 }
163 if (!found)
164 fprintf(stderr, "No entry %s in archive.\n", *files);
165 }
166 }
167
168
169 boolean operation_alters_arch = false;
170
171 /*
172 The option parsing should be in its own function. It will be when I have
173 getopt working.
174 */
175 int
176 main(argc, argv)
177 int argc;
178 char **argv;
179 {
180 char *arg_ptr;
181 char c;
182 enum {
183 none = 0, delete, replace, print_table,
184 print_files, extract, move, quick_append
185 } operation = none;
186 int arg_index;
187 char **files;
188 char *inarch_filename;
189 char *temp;
190 int show_version;
191
192 bfd_init();
193 show_version = 0;
194 #ifdef GNU960
195 check_v960( argc, argv );
196 default_target = bfd_make_targ_name(BFD_COFF_FORMAT,HOST_BYTE_ORDER_BIG_P);
197 #endif
198
199 program_name = argv[0];
200
201 temp = strrchr(program_name, '/');
202 if (temp == (char *) NULL)
203 temp = program_name; /* shouldn't happen, but... */
204 else
205 ++temp;
206 if (is_ranlib > 0 || (is_ranlib < 0 && strcmp(temp, "ranlib") == 0)) {
207 if (argc < 2)
208 fatal("Too few command arguments.");
209 ranlib_only(argv[1]);
210 }
211
212 if (argc == 2 && strcmp(argv[1],"-M") == 0) {
213 mri_emul();
214 exit(0);
215 }
216 if (argc < 3)
217 fatal("Too few command arguments.");
218
219 arg_ptr = argv[1];
220
221 if (*arg_ptr == '-')
222 ++arg_ptr; /* compatibility */
223
224 while (c = *arg_ptr++) {
225 switch (c) {
226 case 'd':
227 case 'm':
228 case 'p':
229 case 'q':
230 case 'r':
231 case 't':
232 case 'x':
233 if (operation != none)
234 fatal("two different operation switches specified");
235 switch (c) {
236 case 'd':
237 operation = delete;
238 operation_alters_arch = true;
239 break;
240 case 'm':
241 operation = move;
242 operation_alters_arch = true;
243 break;
244 case 'p':
245 operation = print_files;
246 break;
247 case 'q':
248 operation = quick_append;
249 operation_alters_arch = true;
250 break;
251 case 'r':
252 operation = replace;
253 operation_alters_arch = true;
254 break;
255 case 't':
256 operation = print_table;
257 break;
258 case 'x':
259 operation = extract;
260 break;
261 }
262 case 'l':
263 break;
264 case 'c':
265 silent_create = 1;
266 break;
267 case 'o':
268 preserve_dates = 1;
269 break;
270 case 'V':
271 show_version = true;
272 break;
273 case 's':
274 write_armap = true;
275 break;
276 case 'u':
277 newer_only = 1;
278 break;
279 case 'v':
280 verbose = 1;
281 break;
282 case 'a':
283 postype = pos_after;
284 break;
285 case 'b':
286 postype = pos_before;
287 break;
288 case 'i':
289 postype = pos_before;
290 break;
291 case 'M':
292
293 mri_mode = 1;
294 break;
295 default:
296 fatal("invalid option %c", c);
297 }
298 }
299
300 if (show_version)
301 printf ("%s version %s\n", program_name, program_version);
302
303 if (mri_mode) {
304 mri_emul();
305 }
306 else {
307 if ((operation == none || operation == print_table)
308 && write_armap == true)
309 ranlib_only(argv[2]);
310
311 if (operation == none)
312 fatal("no operation specified");
313
314 if (newer_only && operation != replace)
315 fatal("'u' only meaningful with 'r' option.");
316
317 arg_index = 2;
318
319 if (postype != pos_default)
320 posname = argv[arg_index++];
321
322 inarch_filename = argv[arg_index++];
323
324 if (arg_index < argc) {
325 files = argv + arg_index;
326 while (arg_index < argc)
327 if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
328 ignore_symdef = 1;
329 break;
330 }
331 }
332 else
333 files = NULL;
334
335 if (operation == quick_append) {
336 if (files != NULL)
337 do_quick_append(inarch_filename, files);
338 exit(0);
339 }
340
341
342 open_inarch(inarch_filename);
343
344 switch (operation) {
345
346 case print_table:
347 map_over_members(print_descr, files, argc - 3);
348 break;
349
350 case print_files:
351 map_over_members(print_contents, files, argc - 3);
352 break;
353
354 case extract:
355 map_over_members(extract_file, files, argc - 3);
356 break;
357
358 case delete:
359 if (files != NULL)
360 delete_members(files);
361 break;
362
363 case move:
364 if (files != NULL)
365 move_members(files);
366 break;
367
368 case replace:
369 if (files != NULL || write_armap)
370 replace_members(files);
371 break;
372
373 /* Shouldn't happen! */
374 default:
375 fprintf(stderr, "Sorry; this option not implemented.\n");
376 }
377 }
378 return (0);
379 } /* main() */
380
381 static
382 char *normalize(file)
383 char *file;
384 {
385 char * filename = strrchr(file, '/');
386 if (filename != (char *)NULL) {
387 filename ++;
388 }
389 else {
390 filename = file;
391 }
392 return filename;
393 }
394
395 int
396 open_inarch(archive_filename)
397 char *archive_filename;
398 {
399 bfd **last_one;
400 bfd *next_one;
401 struct stat sbuf;
402 bfd_error = no_error;
403 if (stat(archive_filename, &sbuf) != 0) {
404 if (errno != ENOENT)
405 bfd_fatal(archive_filename);
406 if (!operation_alters_arch) {
407 fprintf (stderr, "%s: %s not found.\n", program_name,
408 archive_filename);
409 maybequit();
410 return 0;
411 }
412
413 /* This routine is one way to forcibly create the archive. */
414 do_quick_append(archive_filename, 0);
415 }
416
417 #ifdef GNU960
418 inarch = bfd_openr(archive_filename, default_target);
419 #else
420 inarch = bfd_openr(archive_filename, NULL);
421 #endif
422 if (inarch == NULL) {
423 bloser:
424 bfd_perror(archive_filename);
425 exit(1);
426 }
427
428 if (bfd_check_format(inarch, bfd_archive) != true)
429 fatal("File %s is not an archive.", archive_filename);
430 #ifdef GNU960
431 gnu960_verify_target(inarch); /* Exits on failure */
432 #endif
433 last_one = &(inarch->next);
434 /* Read all the contents right away, regardless. */
435 for (next_one = bfd_openr_next_archived_file(inarch, NULL);
436 next_one;
437 next_one = bfd_openr_next_archived_file(inarch, next_one)) {
438 *last_one = next_one;
439 last_one = &next_one->next;
440 }
441 *last_one = (bfd *) NULL;
442 if (bfd_error != no_more_archived_files)
443 goto bloser;
444 return 1;
445 }
446
447
448
449
450
451 void
452 print_contents(abfd)
453 bfd *abfd;
454 {
455 int ncopied = 0;
456 struct stat buf;
457 long size;
458 if (bfd_stat_arch_elt(abfd, &buf) != 0)
459 fatal("Internal stat error on %s", abfd->filename);
460
461 if (verbose)
462 printf("\n<member %s>\n\n", abfd->filename);
463
464 bfd_seek(abfd, 0, SEEK_SET);
465
466 size = buf.st_size;
467 while (ncopied < size) {
468 char cbuf[BUFSIZE];
469 int nread;
470 int tocopy = size - ncopied;
471 if (tocopy > BUFSIZE)
472 tocopy = BUFSIZE;
473
474 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
475 abstraction! */
476
477 if (nread != tocopy)
478 fatal("file %s not a valid archive", abfd->my_archive->filename);
479 fwrite(cbuf, 1, nread, stdout);
480 ncopied += tocopy;
481 }
482 }
483
484
485 /*
486 Extract a member of the archive into its own file.
487
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
494 Gilmore
495 */
496
497 void
498 extract_file(abfd)
499 bfd *abfd;
500 {
501 FILE *ostream;
502 char cbuf[BUFSIZE];
503 int nread,
504 tocopy;
505 int ncopied = 0;
506 long size;
507 struct stat buf;
508 if (bfd_stat_arch_elt(abfd, &buf) != 0)
509 fatal("Internal stat error on %s", abfd->filename);
510 size = buf.st_size;
511
512 if (verbose)
513 printf("x - %s\n", abfd->filename);
514
515 bfd_seek(abfd, 0, SEEK_SET);
516
517 ostream = 0;
518 if (size == 0) {
519 /* Seems like an abstraction violation, eh? Well it's OK! */
520 ostream = fopen(abfd->filename, FOPEN_WB);
521 if (!ostream) {
522 perror(abfd->filename);
523 exit(1);
524 }
525 } else
526 while (ncopied < size) {
527 tocopy = size - ncopied;
528 if (tocopy > BUFSIZE)
529 tocopy = BUFSIZE;
530
531 nread = bfd_read(cbuf, 1, tocopy, abfd);
532 if (nread != tocopy)
533 fatal("file %s not a valid archive", abfd->my_archive->filename);
534
535 /* See comment above; this saves disk arm motion */
536 if (!ostream) {
537 /* Seems like an abstraction violation, eh? Well it's OK! */
538 ostream = fopen(abfd->filename, FOPEN_WB);
539 if (!ostream) {
540 perror(abfd->filename);
541 exit(1);
542 }
543 }
544 fwrite(cbuf, 1, nread, ostream);
545 ncopied += tocopy;
546 }
547
548 fclose(ostream);
549 chmod(abfd->filename, buf.st_mode);
550
551 if (preserve_dates) {
552 #ifdef USG
553 long tb[2];
554 tb[0] = buf.st_mtime;
555 tb[1] = buf.st_mtime;
556 utime(abfd->filename, tb); /* FIXME check result */
557 #else
558 struct timeval tv[2];
559 tv[0].tv_sec = buf.st_mtime;
560 tv[0].tv_usec = 0;
561 tv[1].tv_sec = buf.st_mtime;
562 tv[1].tv_usec = 0;
563 utimes(abfd->filename, tv); /* FIXME check result */
564 #endif
565 }
566 }
567
568
569 /* Just do it quickly; don't worry about dups, armap, or anything like that */
570
571 /* This is ugly! XXX */
572
573 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
574
575 void
576 do_quick_append(archive_filename, files_to_append)
577 char *archive_filename;
578 char **files_to_append;
579
580 {
581 FILE *ofile,
582 *ifile;
583 char buf[BUFSIZE];
584 long tocopy,
585 thistime;
586 bfd *temp;
587 struct stat sbuf;
588 boolean newfile = false;
589 bfd_error = no_error;
590
591 if (stat(archive_filename, &sbuf) != 0) {
592 if (errno != ENOENT)
593 bfd_fatal(archive_filename);
594 newfile = true;
595 }
596
597
598 ofile = fopen(archive_filename, FOPEN_AUB);
599 if (ofile == NULL) {
600 perror(program_name);
601 exit(1);
602 }
603
604 /* bletch */
605 #ifdef GNU960
606 temp = bfd_openr(archive_filename, default_target);
607 #else
608 temp = bfd_openr(archive_filename, NULL);
609 #endif
610 if (temp == NULL) {
611 bfd_perror(archive_filename);
612 exit(1);
613 }
614 if (newfile == false) {
615 if (bfd_check_format(temp, bfd_archive) != true)
616 fatal("File %s is not an archive.", archive_filename);
617 #ifdef GNU960
618 gnu960_verify_target(temp); /* Exits on failure */
619 #endif
620 }
621 else {
622 fwrite(ARMAG, 1, SARMAG, ofile);
623 if (!silent_create)
624 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
625 }
626
627 /* assume it's an achive, go straight to the end, sans $200 */
628 fseek(ofile, 0, 2);
629
630 for (; files_to_append && *files_to_append; ++files_to_append) {
631 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
632 if (hdr == NULL) {
633 bfd_perror(*files_to_append);
634 exit(1);
635 }
636
637 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
638
639 ifile = fopen(*files_to_append, FOPEN_RB);
640 if (ifile == NULL)
641 bfd_perror(program_name);
642
643 if (stat(*files_to_append, &sbuf) != 0)
644 bfd_perror(*files_to_append);
645
646 tocopy = sbuf.st_size;
647
648 /* XXX should do error-checking! */
649 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
650
651
652 while (tocopy > 0) {
653 thistime = tocopy;
654 if (thistime > BUFSIZE)
655 thistime = BUFSIZE;
656 fread(buf, 1, thistime, ifile);
657 fwrite(buf, 1, thistime, ofile);
658 tocopy -= thistime;
659 }
660 fclose(ifile);
661 if ((sbuf.st_size % 2) == 1)
662 putc('\n', ofile);
663 }
664 fclose(ofile);
665 bfd_close(temp);
666 }
667
668
669 void
670 write_archive()
671 {
672 bfd *obfd;
673 int namelen = strlen(inarch->filename);
674 char *new_name = xmalloc(namelen + 6);
675 bfd *contents_head = inarch->next;
676
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));
682
683 if (obfd == NULL)
684 bfd_fatal(inarch->filename);
685
686 bfd_set_format(obfd, bfd_archive);
687 obfd->has_armap = write_armap;
688
689 if (bfd_set_archive_head(obfd, contents_head) != true)
690 bfd_fatal(inarch->filename);
691
692 if (!bfd_close(obfd))
693 bfd_fatal(inarch->filename);
694
695 /* We don't care if this fails, we might be creating the
696 archive */
697 (void) unlink(inarch->filename);
698
699 if (rename(new_name, inarch->filename) != 0)
700 bfd_fatal(inarch->filename);
701 }
702
703
704
705 /*
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.
709 */
710
711 bfd **
712 get_pos_bfd(contents, default_pos)
713 bfd **contents;
714 enum pos default_pos;
715 {
716 bfd **after_bfd = contents;
717 enum pos realpos = (postype == pos_default ? default_pos : postype);
718
719 if (realpos == pos_end) {
720 while (*after_bfd)
721 after_bfd = &((*after_bfd)->next);
722 }
723 else {
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;
728 break;
729 }
730 }
731 return after_bfd;
732 }
733
734
735 void
736 delete_members(files_to_delete)
737 char **files_to_delete;
738 {
739 bfd **current_ptr_ptr;
740 boolean found;
741 boolean something_changed = false;
742 for (; *files_to_delete != NULL; ++files_to_delete) {
743 /*
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
748 */
749 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
750 inarch->has_armap = false;
751 write_armap = false;
752 continue;
753 }
754
755 found = false;
756 current_ptr_ptr = &(inarch->next);
757 while (*current_ptr_ptr) {
758 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
759 found = true;
760 something_changed = true;
761 if (verbose)
762 printf("d - %s\n",
763 *files_to_delete);
764 *current_ptr_ptr = ((*current_ptr_ptr)->next);
765 goto next_file;
766
767 }
768 else {
769 current_ptr_ptr = &((*current_ptr_ptr)->next);
770 }
771 }
772
773 if (verbose && found == false) {
774 printf("No member named `%s'\n", *files_to_delete);
775 }
776 next_file:;
777
778 }
779
780 if (something_changed == true) {
781 write_archive();
782 }
783 }
784
785
786 /* Reposition existing members within an archive */
787
788 void
789 move_members(files_to_move)
790 char **files_to_move;
791 {
792 bfd **after_bfd; /* New entries go after this one */
793 bfd **current_ptr_ptr; /* cdr pointer into contents */
794
795
796
797
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) {
803 /*
804 Move this file to the end of the list - first cut from
805 where it is.
806 */
807 *current_ptr_ptr = current_ptr->next;
808
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;
813
814 if (verbose)
815 printf("m - %s\n", *files_to_move);
816
817 goto next_file;
818 }
819 current_ptr_ptr = &((*current_ptr_ptr)->next);
820 }
821 fprintf(stderr, "No entry %s in archive %s!\n",
822 *files_to_move, inarch->filename);
823 exit(1);
824 next_file:;
825 }
826
827 write_archive();
828 }
829
830
831 /* Ought to default to replacing in place, but this is existing practice! */
832
833 void
834 replace_members(files_to_move)
835 char **files_to_move;
836 {
837 bfd **after_bfd; /* New entries go after this one */
838 bfd *current;
839 bfd **current_ptr;
840 bfd *temp;
841 /*
842 If the first item in the archive is an __.SYMDEF then remove it
843 */
844 if (inarch->next &&
845 strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
846 inarch->next = inarch->next->next;
847 }
848
849
850
851 while (files_to_move && *files_to_move) {
852 current_ptr = &inarch->next;
853 while (*current_ptr) {
854 current = *current_ptr;
855
856 if (!strcmp(normalize(*files_to_move), current->filename)) {
857 if (newer_only) {
858 struct stat fsbuf,
859 asbuf;
860
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);
865 goto next_file;
866 }
867
868 if (stat(*files_to_move, &fsbuf) != 0) {
869 if (errno != ENOENT)
870 bfd_fatal(*files_to_move);
871 goto next_file;
872 }
873 if (bfd_stat_arch_elt(current, &asbuf) != 0)
874 fatal("Internal stat error on %s", current->filename);
875
876 if (fsbuf.st_mtime <= asbuf.st_mtime)
877 goto next_file;
878 }
879
880 /* snip out this entry from the chain */
881 *current_ptr = current->next;
882
883 after_bfd = get_pos_bfd(&inarch->next, pos_end);
884 temp = *after_bfd;
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);
888 exit(1);
889 }
890 #ifdef GNU960
891 gnu960_verify_target(*after_bfd); /* Exits on failure */
892 #endif
893 (*after_bfd)->next = temp;
894
895 if (verbose) {
896 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
897 *files_to_move);
898 }
899 goto next_file;
900 }
901 current_ptr = &(current->next);
902 }
903
904 /* It isn't in there, so add to end */
905
906 after_bfd = get_pos_bfd(&inarch->next, pos_end);
907 temp = *after_bfd;
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);
911 exit(1);
912 }
913 #ifdef GNU960
914 gnu960_verify_target(*after_bfd); /* Exits on failure */
915 #endif
916 if (verbose) {
917 printf("c - %s\n", *files_to_move);
918 }
919
920 (*after_bfd)->next = temp;
921
922 next_file:;
923
924 files_to_move++;
925 }
926
927
928 write_archive();
929 }
930
931 void
932 ranlib_only(archname)
933 char *archname;
934 {
935 write_armap = true;
936 open_inarch(archname);
937 write_archive();
938 exit(0);
939 }
940
941
942
943 /* Things which are interesting to map over all or some of the files: */
944
945 void
946 print_descr(abfd)
947 bfd *abfd;
948 {
949 print_arelt_descr(stdout,abfd, verbose);
950 }
951
952
953