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