Initial revision
[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 || 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
This page took 0.049155 seconds and 4 git commands to generate.