This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/binutils.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 }