f37713e25fdc60b6be4abd5aee57376835b814ae
[deliverable/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 "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 && write_armap)
240 ranlib_only(argv[2]);
241
242 if (operation == none)
243 fatal("no operation specified");
244
245 if (newer_only && operation != replace)
246 fatal("'u' only meaningful with 'r' option.");
247
248 arg_index = 2;
249
250 if (postype != pos_default)
251 posname = argv[arg_index++];
252
253 inarch_filename = argv[arg_index++];
254
255 if (arg_index < argc) {
256 files = argv + arg_index;
257 while (arg_index < argc)
258 if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
259 ignore_symdef = 1;
260 break;
261 }
262 }
263 else
264 files = NULL;
265
266 if (operation == quick_append) {
267 if (files != NULL)
268 do_quick_append(inarch_filename, files);
269 exit(0);
270 }
271
272
273 open_inarch(inarch_filename);
274 /*
275 If we have no archive, and we've been asked to replace then create one
276 */
277 #if 0
278 if (operation == replace && inarch == &bogus_archive) {
279 silent_create = 1;
280 do_quick_append(inarch_filename, 0);
281 open_inarch(inarch_filename);
282 }
283 #endif
284 switch (operation) {
285
286 case print_table:
287 map_over_members(print_descr, files, argc - 3);
288 break;
289
290 case print_files:
291 map_over_members(print_contents, files, argc - 3);
292 break;
293
294 case extract:
295 map_over_members(extract_file, files, argc - 3);
296 break;
297
298 case delete:
299 if (files != NULL)
300 delete_members(files);
301 break;
302
303 case move:
304 if (files != NULL)
305 move_members(files);
306 break;
307
308 case replace:
309 if (files != NULL || write_armap)
310 replace_members(files);
311 break;
312
313 /* Shouldn't happen! */
314 default:
315 fprintf(stderr, "Sorry; this option not implemented.\n");
316 }
317
318 return (0);
319 } /* main() */
320
321 static
322 char *normalize(file)
323 char *file;
324 {
325 char * filename = strrchr(file, '/');
326 if (filename != (char *)NULL) {
327 filename ++;
328 }
329 else {
330 filename = file;
331 }
332 return filename;
333 }
334
335 static void
336 open_inarch(archive_filename)
337 char *archive_filename;
338 {
339 bfd **last_one;
340 bfd *next_one;
341 struct stat sbuf;
342 bfd_error = no_error;
343 if (stat(archive_filename, &sbuf) != 0) {
344 if (errno != ENOENT)
345 bfd_fatal(archive_filename);
346 if (!operation_alters_arch) {
347 fprintf (stderr, "%s: %s not found.\n", program_name,
348 archive_filename);
349 exit (1);
350 }
351 if (!silent_create)
352 fprintf(stderr,
353 "%s: creating %s\n", program_name, archive_filename);
354
355 inarch = &bogus_archive;
356 inarch->filename = archive_filename;
357 inarch->has_armap = true;
358
359 }
360 else {
361 #ifdef GNU960
362 inarch = bfd_openr(archive_filename, default_target);
363 #else
364 inarch = bfd_openr(archive_filename, NULL);
365 #endif
366 if (inarch == NULL) {
367 bloser:
368 bfd_perror(archive_filename);
369 exit(1);
370 }
371
372 if (bfd_check_format(inarch, bfd_archive) != true)
373 fatal("File %s is not an archive.", archive_filename);
374 #ifdef GNU960
375 gnu960_verify_target(inarch); /* Exits on failure */
376 #endif
377 last_one = &(inarch->next);
378 /* Read all the contents right away, regardless. */
379 for (next_one = bfd_openr_next_archived_file(inarch, NULL);
380 next_one;
381 next_one = bfd_openr_next_archived_file(inarch, next_one)) {
382 *last_one = next_one;
383 last_one = &next_one->next;
384 }
385 *last_one = (bfd *) NULL;
386 if (bfd_error != no_more_archived_files)
387 goto bloser;
388 }
389 }
390
391
392
393 /*
394 If count is 0, then function is called once on each entry. if nonzero,
395 count is the length of the files chain; function is called on each entry
396 whose name matches one in files
397 */
398 void
399 map_over_members(function, files, count)
400 void (*function) ();
401 char **files;
402 int count;
403 {
404 bfd *head;
405
406
407
408
409 if (count == 0) {
410 for (head = inarch->next; head; head = head->next)
411 function(head);
412 return;
413 }
414 /*
415 This may appear to be a baroque way of accomplishing what we want.
416 however we have to iterate over the filenames in order to notice where
417 a filename is requested but does not exist in the archive. Ditto
418 mapping over each file each time -- we want to hack multiple
419 references.
420 */
421
422 for (; count > 0; files++, count--) {
423 boolean found = false;
424 for (head = inarch->next; head; head = head->next)
425 if ((head->filename != NULL) &&
426 (!strcmp(*files, head->filename))) {
427 found = true;
428 function(head);
429 }
430 if (!found)
431 fprintf(stderr, "No entry %s in archive.\n", *files);
432 }
433 }
434
435
436 /* Things which are interesting to map over all or some of the files: */
437
438 void
439 print_descr(abfd)
440 bfd *abfd;
441 {
442 print_arelt_descr(abfd, verbose);
443 }
444
445 void
446 print_contents(abfd)
447 bfd *abfd;
448 {
449 int ncopied = 0;
450 struct stat buf;
451 long size;
452 if (bfd_stat_arch_elt(abfd, &buf) != 0)
453 fatal("Internal stat error on %s", abfd->filename);
454
455 if (verbose)
456 printf("\n<member %s>\n\n", abfd->filename);
457
458 bfd_seek(abfd, 0, SEEK_SET);
459
460 size = buf.st_size;
461 while (ncopied < size) {
462 char cbuf[BUFSIZE];
463 int nread;
464 int tocopy = size - ncopied;
465 if (tocopy > BUFSIZE)
466 tocopy = BUFSIZE;
467
468 nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
469 abstraction! */
470
471 if (nread != tocopy)
472 fatal("file %s not a valid archive", abfd->my_archive->filename);
473 fwrite(cbuf, 1, nread, stdout);
474 ncopied += tocopy;
475 }
476 }
477
478
479 /*
480 Extract a member of the archive into its own file.
481
482 We defer opening the new file until after we have read a BUFSIZ chunk of the
483 old one, since we know we have just read the archive header for the old
484 one. Since most members are shorter than BUFSIZ, this means we will read
485 the old header, read the old data, write a new inode for the new file, and
486 write the new data, and be done. This 'optimization' is what comes from
487 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
488 Gilmore
489 */
490
491 void
492 extract_file(abfd)
493 bfd *abfd;
494 {
495 FILE *ostream;
496 char cbuf[BUFSIZE];
497 int nread,
498 tocopy;
499 int ncopied = 0;
500 long size;
501 struct stat buf;
502 if (bfd_stat_arch_elt(abfd, &buf) != 0)
503 fatal("Internal stat error on %s", abfd->filename);
504 size = buf.st_size;
505
506 if (verbose)
507 printf("x - %s\n", abfd->filename);
508
509 bfd_seek(abfd, 0, SEEK_SET);
510
511 ostream = 0;
512 if (size == 0) {
513 /* Seems like an abstraction violation, eh? Well it's OK! */
514 ostream = fopen(abfd->filename, "w");
515 if (!ostream) {
516 perror(abfd->filename);
517 exit(1);
518 }
519 } else
520 while (ncopied < size) {
521 tocopy = size - ncopied;
522 if (tocopy > BUFSIZE)
523 tocopy = BUFSIZE;
524
525 nread = bfd_read(cbuf, 1, tocopy, abfd);
526 if (nread != tocopy)
527 fatal("file %s not a valid archive", abfd->my_archive->filename);
528
529 /* See comment above; this saves disk arm motion */
530 if (!ostream) {
531 /* Seems like an abstraction violation, eh? Well it's OK! */
532 ostream = fopen(abfd->filename, "w");
533 if (!ostream) {
534 perror(abfd->filename);
535 exit(1);
536 }
537 }
538 fwrite(cbuf, 1, nread, ostream);
539 ncopied += tocopy;
540 }
541
542 fclose(ostream);
543 chmod(abfd->filename, buf.st_mode);
544
545 if (preserve_dates) {
546 #ifdef USG
547 long tb[2];
548 tb[0] = buf.st_mtime;
549 tb[1] = buf.st_mtime;
550 utime(abfd->filename, tb); /* FIXME check result */
551 #else
552 struct timeval tv[2];
553 tv[0].tv_sec = buf.st_mtime;
554 tv[0].tv_usec = 0;
555 tv[1].tv_sec = buf.st_mtime;
556 tv[1].tv_usec = 0;
557 utimes(abfd->filename, tv); /* FIXME check result */
558 #endif
559 }
560 }
561
562
563 /* Just do it quickly; don't worry about dups, armap, or anything like that */
564
565 /* This is ugly! XXX */
566
567 PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (bfd *abfd, char *filename));
568
569 void
570 do_quick_append(archive_filename, files_to_append)
571 char *archive_filename;
572 char **files_to_append;
573
574 {
575 FILE *ofile,
576 *ifile;
577 char buf[BUFSIZE];
578 long tocopy,
579 thistime;
580 bfd *temp;
581 struct stat sbuf;
582 boolean newfile = false;
583 bfd_error = no_error;
584
585 if (stat(archive_filename, &sbuf) != 0) {
586 if (errno != ENOENT)
587 bfd_fatal(archive_filename);
588 newfile = true;
589 }
590
591
592 ofile = fopen(archive_filename, "a+");
593 if (ofile == NULL) {
594 perror(program_name);
595 exit(1);
596 }
597
598 /* bletch */
599 #ifdef GNU960
600 temp = bfd_openr(archive_filename, default_target);
601 #else
602 temp = bfd_openr(archive_filename, NULL);
603 #endif
604 if (temp == NULL) {
605 bfd_perror(archive_filename);
606 exit(1);
607 }
608 if (newfile == false) {
609 if (bfd_check_format(temp, bfd_archive) != true)
610 fatal("File %s is not an archive.", archive_filename);
611 #ifdef GNU960
612 gnu960_verify_target(temp); /* Exits on failure */
613 #endif
614 }
615 else {
616 fwrite(ARMAG, 1, SARMAG, ofile);
617 if (!silent_create)
618 fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
619 }
620
621 /* assume it's an achive, go straight to the end, sans $200 */
622 fseek(ofile, 0, 2);
623
624 for (; files_to_append && *files_to_append; ++files_to_append) {
625 struct ar_hdr *hdr = bfd_special_undocumented_glue(temp, *files_to_append);
626 if (hdr == NULL) {
627 bfd_perror(*files_to_append);
628 exit(1);
629 }
630
631 BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
632
633 ifile = fopen(*files_to_append, "r");
634 if (ifile == NULL)
635 bfd_perror(program_name);
636
637 if (stat(*files_to_append, &sbuf) != 0)
638 bfd_perror(*files_to_append);
639
640 tocopy = sbuf.st_size;
641
642 /* XXX should do error-checking! */
643 fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
644
645
646 while (tocopy > 0) {
647 thistime = tocopy;
648 if (thistime > BUFSIZE)
649 thistime = BUFSIZE;
650 fread(buf, 1, thistime, ifile);
651 fwrite(buf, 1, thistime, ofile);
652 tocopy -= thistime;
653 }
654 fclose(ifile);
655 if ((sbuf.st_size % 2) == 1)
656 putc('\n', ofile);
657 }
658 fclose(ofile);
659 bfd_close(temp);
660 }
661
662
663 void
664 write_archive()
665 {
666 bfd *obfd;
667 char *xmalloc();
668 int namelen = strlen(inarch->filename);
669 char *new_name = xmalloc(namelen + 6);
670 bfd *contents_head = inarch->next;
671 #if 0
672 if (inarch == &bogus_archive) {
673 /* How can this be ? */
674 return;
675 }
676 else {
677 #endif
678 strcpy(new_name, inarch->filename);
679 strcpy(new_name + namelen, ".art");
680 obfd = bfd_openw(new_name,
681 /* FIXME: violates abstraction; need a better protocol */
682 (inarch->xvec ? bfd_get_target(inarch) : NULL));
683
684 if (obfd == NULL)
685 bfd_fatal(inarch->filename);
686
687 bfd_set_format(obfd, bfd_archive);
688 obfd->has_armap = write_armap;
689
690 if (bfd_set_archive_head(obfd, contents_head) != true)
691 bfd_fatal(inarch->filename);
692
693 if (!bfd_close(obfd))
694 bfd_fatal(inarch->filename);
695 if (unlink(inarch->filename) != 0)
696 bfd_fatal(inarch->filename);
697 if (rename(new_name, inarch->filename) != 0)
698 bfd_fatal(inarch->filename);
699 #if 0
700 }
701 #endif
702 }
703
704
705
706 /*
707 returns a pointer to the pointer to the entry which should be rplacd'd
708 into when altering. default_pos should be how to interpret pos_default,
709 and should be a pos value.
710 */
711
712 bfd **
713 get_pos_bfd(contents, default_pos)
714 bfd **contents;
715 enum pos default_pos;
716 {
717 bfd **after_bfd;
718
719 enum pos realpos = (postype == pos_default ? default_pos : postype);
720 switch (realpos) {
721
722 case pos_end:
723 after_bfd = contents;
724 while (*after_bfd) {
725 after_bfd = &((*after_bfd)->next);
726 }
727
728 break;
729 #if 0
730 case pos_after:
731 for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
732 if (!strcpy(after_bfd->filename, posname))
733 break;
734 break;
735 case pos_before:
736 for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
737 if (after_bfd->next && (!strcpy(after_bfd->next->filename, posname)))
738 break;
739 #endif
740 }
741
742 return after_bfd;
743 }
744
745
746 void
747 delete_members(files_to_delete)
748 char **files_to_delete;
749 {
750 bfd **current_ptr_ptr;
751 boolean found;
752 boolean something_changed = false;
753 for (; *files_to_delete != NULL; ++files_to_delete) {
754 /*
755 In a.out systems, the armap is optional. It's also called
756 __.SYMDEF. So if the user asked to delete it, we should remember
757 that fact. The name is NULL in COFF archives, so using this as a
758 key is as good as anything I suppose
759 */
760 if (!strcmp(*files_to_delete, "__.SYMDEF")) {
761 inarch->has_armap = false;
762 write_armap = false;
763 continue;
764 }
765
766 found = false;
767 current_ptr_ptr = &(inarch->next);
768 while (*current_ptr_ptr) {
769 if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
770 found = true;
771 something_changed = true;
772 if (verbose)
773 printf("d - %s\n",
774 *files_to_delete);
775 *current_ptr_ptr = ((*current_ptr_ptr)->next);
776 goto next_file;
777
778 }
779 else {
780 current_ptr_ptr = &((*current_ptr_ptr)->next);
781 }
782 }
783
784 if (verbose && found == false) {
785 printf("No member named `%s'\n", *files_to_delete);
786 }
787 next_file:;
788
789 }
790
791 if (something_changed == true) {
792 write_archive();
793 }
794 }
795
796
797 /* Reposition existing members within an archive */
798
799 void
800 move_members(files_to_move)
801 char **files_to_move;
802 {
803 bfd **after_bfd; /* New entries go after this one */
804 bfd **current_ptr_ptr; /* cdr pointer into contents */
805
806
807
808
809 for (; *files_to_move; ++files_to_move) {
810 current_ptr_ptr = &(inarch->next);
811 while (*current_ptr_ptr) {
812 bfd *current_ptr = *current_ptr_ptr;
813 if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
814 /*
815 Move this file to the end of the list - first cut from
816 where it is.
817 */
818 *current_ptr_ptr = current_ptr->next;
819
820 /* Now glue to end */
821 after_bfd = get_pos_bfd(&inarch->next, pos_end);
822 *after_bfd = current_ptr;
823 current_ptr->next = (bfd *) NULL;
824
825 if (verbose)
826 printf("m - %s\n", *files_to_move);
827
828 goto next_file;
829 }
830 current_ptr_ptr = &((*current_ptr_ptr)->next);
831 }
832 fprintf(stderr, "No entry %s in archive %s!\n",
833 *files_to_move, inarch->filename);
834 exit(1);
835 next_file:;
836 }
837
838 write_archive();
839 }
840
841
842 /* Ought to default to replacing in place, but this is existing practice! */
843
844 void
845 replace_members(files_to_move)
846 char **files_to_move;
847 {
848 bfd **after_bfd; /* New entries go after this one */
849 bfd *current;
850 bfd **current_ptr;
851 bfd *temp;
852 /*
853 If the first item in the archive is an __.SYMDEF then remove it
854 */
855 if (inarch->next &&
856 strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
857 inarch->next = inarch->next->next;
858 }
859
860
861
862 while (files_to_move && *files_to_move) {
863 current_ptr = &inarch->next;
864 while (*current_ptr) {
865 current = *current_ptr;
866
867 if (!strcmp(normalize(*files_to_move), current->filename)) {
868 if (newer_only) {
869 struct stat fsbuf,
870 asbuf;
871
872 if (current->arelt_data == NULL) {
873 /* This can only happen if you specify a file on the
874 command line more than once. */
875 fprintf (stderr, "Duplicate file specified: %s -- skipping.\n", *files_to_move);
876 goto next_file;
877 }
878
879 if (stat(*files_to_move, &fsbuf) != 0) {
880 if (errno != ENOENT)
881 bfd_fatal(*files_to_move);
882 goto next_file;
883 }
884 if (bfd_stat_arch_elt(current, &asbuf) != 0)
885 fatal("Internal stat error on %s", current->filename);
886
887 if (fsbuf.st_mtime <= asbuf.st_mtime)
888 goto next_file;
889 }
890
891 /* snip out this entry from the chain */
892 *current_ptr = current->next;
893
894 after_bfd = get_pos_bfd(&inarch->next, pos_end);
895 temp = *after_bfd;
896 *after_bfd = bfd_openr(*files_to_move, NULL);
897 if (*after_bfd == (bfd *) NULL) {
898 fprintf(stderr, "Can't open file %s\n", *files_to_move);
899 exit(1);
900 }
901 #ifdef GNU960
902 gnu960_verify_target(*after_bfd); /* Exits on failure */
903 #endif
904 (*after_bfd)->next = temp;
905
906 if (verbose) {
907 printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
908 *files_to_move);
909 }
910 goto next_file;
911 }
912 current_ptr = &(current->next);
913 }
914
915 /* It isn't in there, so add to end */
916
917 after_bfd = get_pos_bfd(&inarch->next, pos_end);
918 temp = *after_bfd;
919 *after_bfd = bfd_openr(*files_to_move, NULL);
920 if (*after_bfd == (bfd *) NULL) {
921 fprintf(stderr, "Can't open file %s\n", *files_to_move);
922 exit(1);
923 }
924 #ifdef GNU960
925 gnu960_verify_target(*after_bfd); /* Exits on failure */
926 #endif
927 if (verbose) {
928 printf("c - %s\n", *files_to_move);
929 }
930
931 (*after_bfd)->next = temp;
932
933 next_file:;
934
935 files_to_move++;
936 }
937
938
939 write_archive();
940 }
941
942 void
943 ranlib_only(archname)
944 char *archname;
945 {
946 write_armap = true;
947 open_inarch(archname);
948 write_archive();
949 exit(0);
950 }
951
952
This page took 0.049204 seconds and 4 git commands to generate.