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