Sat Feb 26 13:23:06 1994 Stan Shebs (shebs@andros.cygnus.com)
[deliverable/binutils-gdb.git] / binutils / ar.c
CommitLineData
5f0e8767 1/* ar.c - Archive modify and extract.
0c62139f 2 Copyright 1991, 92, 93, 94 Free Software Foundation, Inc.
5f0e8767
SC
3
4This file is part of GNU Binutils.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
0c62139f 19\f
2fa0b342
DHW
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*/
2fa0b342 27#include "bfd.h"
5f0e8767 28#include "sysdep.h"
4b5ea362
SC
29#include "bucomm.h"
30#include "aout/ar.h"
37853673 31#include "libbfd.h"
c0cc6912 32#include "arsup.h"
2fa0b342 33#include <stdio.h>
42b600fa
ILT
34#ifdef POSIX_UTIME
35#include <utime.h>
36#else /* ! POSIX_UTIME */
37#ifdef USE_UTIME
c0cc6912 38#include <time.h>
42b600fa 39#else /* ! USE_UTIME */
2fa0b342 40#include <sys/time.h>
42b600fa
ILT
41#endif /* ! USE_UTIME */
42#endif /* ! POSIX_UTIME */
2fa0b342 43#include <errno.h>
5b07d693
PB
44#ifndef errno
45extern int errno;
46#endif
2fa0b342 47#define BUFSIZE 8192
2fa0b342 48
6336b309 49#ifdef __GO32___
0c62139f 50#define EXT_NAME_LEN 3 /* bufflen of addition to name if it's MS-DOS */
6336b309 51#else
0c62139f 52#define EXT_NAME_LEN 6 /* ditto for *NIX */
6336b309
ILT
53#endif
54
e87cc816
JG
55/* Kludge declaration from BFD! This is ugly! FIXME! XXX */
56
57struct ar_hdr *
0c62139f 58 bfd_special_undocumented_glue PARAMS ((bfd * abfd, char *filename));
e87cc816 59
151a6341 60/* Forward declarations */
5b07d693 61
151a6341
JG
62static void
63print_contents PARAMS ((bfd * member));
c0cc6912 64
151a6341
JG
65static void
66delete_members PARAMS ((char **files_to_delete));
c0cc6912 67
151a6341
JG
68static void
69do_quick_append PARAMS ((char *archive_filename, char **files_to_append));
70
71static void
72move_members PARAMS ((char **files_to_move));
73
74static void
75replace_members PARAMS ((char **files_to_replace));
76
77static void
78print_descr PARAMS ((bfd * abfd));
79
80static void
81ranlib_only PARAMS ((char *archname));
0c62139f 82\f
2fa0b342
DHW
83/** Globals and flags */
84
0c62139f
DM
85/* The input archive we're manipulating. */
86bfd *inarch;
2fa0b342 87
c0cc6912 88int mri_mode;
0c62139f 89
5f0e8767 90/* This flag distinguishes between ar and ranlib:
4b5ea362 91 1 means this is 'ranlib'; 0 means this is 'ar'.
0c62139f 92 -1 means if we should use argv[0] to decide. */
5f0e8767 93extern int is_ranlib;
0c62139f 94
2fa0b342 95/* Nonzero means don't warn about creating the archive file if necessary. */
0c62139f
DM
96int silent_create = 0;
97
2fa0b342 98/* Nonzero means describe each action performed. */
0c62139f
DM
99int verbose = 0;
100
2fa0b342 101/* Nonzero means preserve dates of members when extracting them. */
0c62139f
DM
102int preserve_dates = 0;
103
104/* Nonzero means don't replace existing members whose dates are more recent
105 than the corresponding files. */
106int newer_only = 0;
d2442698
DM
107
108/* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
109 member). -1 means we've been explicitly asked to not write a symbol table;
110 +1 means we've been explictly asked to write it;
111 0 is the default.
112 Traditionally, the default in BSD has been to not write the table.
0c62139f
DM
113 However, for POSIX.2 compliance the default is now to write a symbol table
114 if any of the members are object files. */
d2442698
DM
115int write_armap = 0;
116
0c62139f
DM
117/* Nonzero means it's the name of an existing member; position new or moved
118 files with respect to this one. */
119char *posname = NULL;
120
121/* Sez how to use `posname': pos_before means position before that member.
2fa0b342
DHW
122 pos_after means position after that member. pos_end means always at end.
123 pos_default means default appropriately. For the latter two, `posname'
0c62139f
DM
124 should also be zero. */
125enum pos
126 {
2fa0b342 127 pos_default, pos_before, pos_after, pos_end
0c62139f 128 } postype = pos_default;
2fa0b342 129
c0cc6912 130int interactive = 0;
0c62139f 131
c0cc6912 132void
0c62139f 133mri_emul ()
c0cc6912 134{
0c62139f
DM
135 interactive = isatty (fileno (stdin));
136 yyparse ();
c0cc6912
SC
137}
138
0c62139f
DM
139/* If COUNT is 0, then FUNCTION is called once on each entry. If nonzero,
140 COUNT is the length of the FILES chain; FUNCTION is called on each entry
141 whose name matches one in FILES. */
142
c0cc6912 143void
0c62139f
DM
144map_over_members (function, files, count)
145 void (*function) ();
146 char **files;
147 int count;
c0cc6912 148{
0c62139f
DM
149 bfd *head;
150
151 if (count == 0)
42b600fa 152 {
0c62139f
DM
153 for (head = inarch->next; head; head = head->next)
154 function (head);
155 return;
42b600fa 156 }
0c62139f
DM
157 /* This may appear to be a baroque way of accomplishing what we want.
158 However we have to iterate over the filenames in order to notice where
159 a filename is requested but does not exist in the archive. Ditto
160 mapping over each file each time -- we want to hack multiple
161 references. */
8ab76aa7 162
0c62139f
DM
163 for (; count > 0; files++, count--)
164 {
165 boolean found = false;
166 for (head = inarch->next; head; head = head->next)
167 {
168 if (head->filename == NULL)
169 {
170 /* Some archive formats don't get the filenames filled in
171 until the elements are opened. */
172 struct stat buf;
173 bfd_stat_arch_elt (head, &buf);
174 }
175 if ((head->filename != NULL) &&
176 (!strcmp (*files, head->filename)))
177 {
178 found = true;
179 function (head);
180 }
181 }
182 if (!found)
183 fprintf (stderr, "no entry %s in archive\n", *files);
184 }
185}
186\f
8ab76aa7
DHW
187boolean operation_alters_arch = false;
188
d2442698
DM
189extern char *program_version;
190
42b600fa
ILT
191void
192do_show_version ()
193{
6336b309
ILT
194 printf ("GNU %s version %s\n", program_name, program_version);
195 exit (0);
42b600fa
ILT
196}
197
d2442698
DM
198void
199usage ()
200{
6336b309 201 if (is_ranlib == 0)
0c62139f 202 fprintf (stderr, "\
6336b309 203Usage: %s [-]{dmpqrtx}[abcilosuvV] [member-name] archive-file file...\n\
d2442698 204 %s -M [<mri-script]\n",
0c62139f 205 program_name, program_name);
6336b309 206 else
0c62139f 207 fprintf (stderr, "\
6336b309 208Usage: %s [-vV] archive\n", program_name);
0c62139f 209 exit (1);
d2442698
DM
210}
211
0c62139f
DM
212/* The option parsing should be in its own function.
213 It will be when I have getopt working. */
214
2fa0b342 215int
0c62139f
DM
216main (argc, argv)
217 int argc;
218 char **argv;
2fa0b342 219{
0c62139f
DM
220 char *arg_ptr;
221 char c;
222 enum
223 {
224 none = 0, delete, replace, print_table,
225 print_files, extract, move, quick_append
226 } operation = none;
227 int arg_index;
228 char **files;
229 char *inarch_filename;
230 char *temp;
231 int show_version;
232
233 bfd_init ();
8fb94c7a 234 show_version = 0;
ab01cf22 235
c0cc6912
SC
236 program_name = argv[0];
237
0c62139f 238 temp = strrchr (program_name, '/');
c0cc6912 239 if (temp == (char *) NULL)
0c62139f 240 temp = program_name; /* shouldn't happen, but... */
c0cc6912 241 else
0c62139f
DM
242 ++temp;
243 if (is_ranlib > 0 || (is_ranlib < 0 && strcmp (temp, "ranlib") == 0))
244 {
245 is_ranlib = 1;
246 if (argc < 2 || argc > 3)
247 usage ();
248 arg_ptr = argv[1];
249 if (strcmp (argv[1], "-V") == 0 || strcmp (argv[1], "-v") == 0)
250 do_show_version ();
251 ranlib_only (arg_ptr);
252 }
6336b309
ILT
253 else
254 is_ranlib = 0;
c0cc6912 255
0c62139f
DM
256 if (argc == 2 && strcmp (argv[1], "-M") == 0)
257 {
258 mri_emul ();
259 exit (0);
260 }
42b600fa
ILT
261
262 if (argc < 2)
d2442698 263 usage ();
c0cc6912
SC
264
265 arg_ptr = argv[1];
266
267 if (*arg_ptr == '-')
0c62139f
DM
268 ++arg_ptr; /* compatibility */
269
270 while ((c = *arg_ptr++) != '\0')
271 {
272 switch (c)
273 {
274 case 'd':
275 case 'm':
276 case 'p':
277 case 'q':
278 case 'r':
279 case 't':
280 case 'x':
281 if (operation != none)
282 fatal ("two different operation options specified");
283 switch (c)
284 {
285 case 'd':
286 operation = delete;
287 operation_alters_arch = true;
288 break;
289 case 'm':
290 operation = move;
291 operation_alters_arch = true;
292 break;
293 case 'p':
294 operation = print_files;
295 break;
296 case 'q':
297 operation = quick_append;
298 operation_alters_arch = true;
299 break;
300 case 'r':
301 operation = replace;
302 operation_alters_arch = true;
303 break;
304 case 't':
305 operation = print_table;
306 break;
307 case 'x':
308 operation = extract;
309 break;
310 }
311 case 'l':
312 break;
313 case 'c':
314 silent_create = 1;
315 break;
316 case 'o':
317 preserve_dates = 1;
318 break;
319 case 'V':
320 show_version = true;
321 break;
322 case 's':
323 write_armap = 1;
324 break;
325 case 'u':
326 newer_only = 1;
327 break;
328 case 'v':
329 verbose = 1;
330 break;
331 case 'a':
332 postype = pos_after;
333 break;
334 case 'b':
335 postype = pos_before;
336 break;
337 case 'i':
338 postype = pos_before;
339 break;
340 case 'M':
341 mri_mode = 1;
342 break;
343 default:
344 fprintf (stderr, "%s: illegal option -- %c\n", program_name, c);
345 usage ();
346 }
2fa0b342
DHW
347 }
348
8fb94c7a 349 if (show_version)
0c62139f 350 do_show_version ();
42b600fa
ILT
351
352 if (argc < 3)
6336b309 353 usage ();
8fb94c7a 354
0c62139f
DM
355 if (mri_mode)
356 {
357 mri_emul ();
358 }
359 else
360 {
361 if ((operation == none || operation == print_table)
362 && write_armap == 1)
363 ranlib_only (argv[2]);
a00721fc 364
0c62139f
DM
365 if (operation == none)
366 fatal ("no operation specified");
2fa0b342 367
0c62139f
DM
368 if (newer_only && operation != replace)
369 fatal ("`u' is only meaningful with the `r' option.");
2fa0b342 370
0c62139f 371 arg_index = 2;
2fa0b342 372
0c62139f
DM
373 if (postype != pos_default)
374 posname = argv[arg_index++];
2fa0b342 375
0c62139f 376 inarch_filename = argv[arg_index++];
2fa0b342 377
0c62139f 378 files = arg_index < argc ? argv + arg_index : NULL;
2fa0b342 379
0c62139f
DM
380 if (operation == quick_append)
381 {
382 /* Note that quick appending to a non-existent archive creates it,
383 even if there are no files to append. */
384 do_quick_append (inarch_filename, files);
385 exit (0);
386 }
2fa0b342 387
0c62139f
DM
388 open_inarch (inarch_filename);
389
390 switch (operation)
391 {
392 case print_table:
393 map_over_members (print_descr, files, argc - 3);
394 break;
395
396 case print_files:
397 map_over_members (print_contents, files, argc - 3);
398 break;
399
400 case extract:
401 map_over_members (extract_file, files, argc - 3);
402 break;
403
404 case delete:
405 if (files != NULL)
406 delete_members (files);
407 break;
408
409 case move:
410 if (files != NULL)
411 move_members (files);
412 break;
413
414 case replace:
415 if (files != NULL || write_armap > 0)
416 replace_members (files);
417 break;
418
419 /* Shouldn't happen! */
420 default:
421 fprintf (stderr, "%s: internal error -- this option not implemented\n",
422 program_name);
423 exit (1);
424 }
2fa0b342 425 }
0c62139f
DM
426 return 0;
427}
2fa0b342 428
0c62139f
DM
429static char *
430normalize (file)
431 char *file;
2fa0b342 432{
0c62139f
DM
433 char *filename = strrchr (file, '/');
434 if (filename != (char *) NULL)
435 {
436 filename++;
2fa0b342 437 }
0c62139f
DM
438 else
439 {
440 filename = file;
2fa0b342 441 }
0c62139f 442 return filename;
2fa0b342
DHW
443}
444
0c62139f
DM
445int
446open_inarch (archive_filename)
447 char *archive_filename;
2fa0b342 448{
0c62139f
DM
449 bfd **last_one;
450 bfd *next_one;
451 struct stat sbuf;
452 bfd_error = no_error;
6336b309 453
0c62139f
DM
454 if (stat (archive_filename, &sbuf) != 0)
455 {
6336b309
ILT
456
457#ifndef __GO32__
458
459/* KLUDGE ALERT! Temporary fix until I figger why
460 * stat() is wrong ... think it's buried in GO32's IDT
461 * - Jax
462 */
0c62139f
DM
463 if (errno != ENOENT)
464 bfd_fatal (archive_filename);
6336b309
ILT
465#endif
466
0c62139f
DM
467 if (!operation_alters_arch)
468 {
6336b309
ILT
469 fprintf (stderr, "%s: ", program_name);
470 perror (archive_filename);
0c62139f 471 maybequit ();
5b07d693 472 return 0;
0c62139f 473 }
2fa0b342 474
0c62139f 475 /* This routine is one way to forcibly create the archive. */
6336b309 476
0c62139f 477 do_quick_append (archive_filename, 0);
2fa0b342 478 }
a00721fc 479
0c62139f
DM
480 inarch = bfd_openr (archive_filename, NULL);
481 if (inarch == NULL)
482 {
483 bloser:
484 bfd_fatal (archive_filename);
a00721fc 485 }
2fa0b342 486
0c62139f
DM
487 if (bfd_check_format (inarch, bfd_archive) != true)
488 fatal ("%s is not an archive", archive_filename);
489 last_one = &(inarch->next);
490 /* Read all the contents right away, regardless. */
491 for (next_one = bfd_openr_next_archived_file (inarch, NULL);
492 next_one;
493 next_one = bfd_openr_next_archived_file (inarch, next_one))
494 {
495 *last_one = next_one;
496 last_one = &next_one->next;
2fa0b342 497 }
0c62139f
DM
498 *last_one = (bfd *) NULL;
499 if (bfd_error != no_more_archived_files)
500 goto bloser;
501 return 1;
2fa0b342
DHW
502}
503
0c62139f
DM
504static void
505print_contents (abfd)
506 bfd *abfd;
507{
508 int ncopied = 0;
509 struct stat buf;
510 long size;
511 if (bfd_stat_arch_elt (abfd, &buf) != 0)
512 fatal ("internal stat error on %s", bfd_get_filename (abfd));
2fa0b342 513
0c62139f
DM
514 if (verbose)
515 printf ("\n<member %s>\n\n", bfd_get_filename (abfd));
2fa0b342 516
0c62139f 517 bfd_seek (abfd, 0, SEEK_SET);
2fa0b342 518
0c62139f
DM
519 size = buf.st_size;
520 while (ncopied < size)
521 {
522 char cbuf[BUFSIZE];
523 int nread;
524 int tocopy = size - ncopied;
525 if (tocopy > BUFSIZE)
526 tocopy = BUFSIZE;
2fa0b342 527
0c62139f 528 nread = bfd_read (cbuf, 1, tocopy, abfd); /* oops -- broke
2fa0b342 529 abstraction! */
0c62139f 530 if (nread != tocopy)
0c5dc23c
DM
531 fatal ("%s is not a valid archive",
532 bfd_get_filename (bfd_my_archive (abfd)));
0c62139f
DM
533 fwrite (cbuf, 1, nread, stdout);
534 ncopied += tocopy;
2fa0b342
DHW
535 }
536}
537
0c62139f 538/* Extract a member of the archive into its own file.
2fa0b342 539
0c62139f 540 We defer opening the new file until after we have read a BUFSIZ chunk of the
2fa0b342
DHW
541 old one, since we know we have just read the archive header for the old
542 one. Since most members are shorter than BUFSIZ, this means we will read
543 the old header, read the old data, write a new inode for the new file, and
544 write the new data, and be done. This 'optimization' is what comes from
545 sitting next to a bare disk and hearing it every time it seeks. -- Gnu
0c62139f 546 Gilmore */
2fa0b342
DHW
547
548void
0c62139f
DM
549extract_file (abfd)
550 bfd *abfd;
2fa0b342 551{
0c62139f
DM
552 FILE *ostream;
553 char cbuf[BUFSIZE];
554 int nread, tocopy;
555 int ncopied = 0;
556 long size;
557 struct stat buf;
558 if (bfd_stat_arch_elt (abfd, &buf) != 0)
559 fatal ("internal stat error on %s", bfd_get_filename (abfd));
560 size = buf.st_size;
561
562 if (verbose)
563 printf ("x - %s\n", bfd_get_filename (abfd));
564
565 bfd_seek (abfd, 0, SEEK_SET);
566
567 ostream = 0;
568 if (size == 0)
569 {
8ab76aa7 570 /* Seems like an abstraction violation, eh? Well it's OK! */
0c62139f
DM
571 ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
572 if (!ostream)
573 {
574 perror (bfd_get_filename (abfd));
575 exit (1);
576 }
577 }
578 else
579 while (ncopied < size)
580 {
2fa0b342
DHW
581 tocopy = size - ncopied;
582 if (tocopy > BUFSIZE)
0c62139f 583 tocopy = BUFSIZE;
2fa0b342 584
0c62139f 585 nread = bfd_read (cbuf, 1, tocopy, abfd);
2fa0b342 586 if (nread != tocopy)
0c5dc23c
DM
587 fatal ("%s is not a valid archive",
588 bfd_get_filename (bfd_my_archive (abfd)));
2fa0b342
DHW
589
590 /* See comment above; this saves disk arm motion */
0c62139f
DM
591 if (!ostream)
592 {
2fa0b342 593 /* Seems like an abstraction violation, eh? Well it's OK! */
0c62139f
DM
594 ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
595 if (!ostream)
596 {
597 perror (bfd_get_filename (abfd));
598 exit (1);
599 }
600 }
601 fwrite (cbuf, 1, nread, ostream);
2fa0b342 602 ncopied += tocopy;
0c62139f 603 }
2fa0b342 604
0c62139f
DM
605 fclose (ostream);
606 chmod (bfd_get_filename (abfd), buf.st_mode);
2fa0b342 607
0c62139f
DM
608 if (preserve_dates)
609 {
42b600fa 610#ifdef POSIX_UTIME
0c62139f
DM
611 struct utimbuf tb;
612 tb.actime = buf.st_mtime;
613 tb.modtime = buf.st_mtime;
614 utime (bfd_get_filename (abfd), &tb); /* FIXME check result */
42b600fa
ILT
615#else /* ! POSIX_UTIME */
616#ifdef USE_UTIME
0c62139f
DM
617 long tb[2];
618 tb[0] = buf.st_mtime;
619 tb[1] = buf.st_mtime;
620 utime (bfd_get_filename (abfd), tb); /* FIXME check result */
42b600fa 621#else /* ! USE_UTIME */
0c62139f
DM
622 struct timeval tv[2];
623 tv[0].tv_sec = buf.st_mtime;
624 tv[0].tv_usec = 0;
625 tv[1].tv_sec = buf.st_mtime;
626 tv[1].tv_usec = 0;
627 utimes (bfd_get_filename (abfd), tv); /* FIXME check result */
42b600fa
ILT
628#endif /* ! USE_UTIME */
629#endif /* ! POSIX_UTIME */
2fa0b342
DHW
630 }
631}
632
2fa0b342
DHW
633/* Just do it quickly; don't worry about dups, armap, or anything like that */
634
151a6341 635static void
0c62139f
DM
636do_quick_append (archive_filename, files_to_append)
637 char *archive_filename;
638 char **files_to_append;
2fa0b342 639{
0c62139f
DM
640 FILE *ofile, *ifile;
641 char buf[BUFSIZE];
642 long tocopy, thistime;
643 bfd *temp;
644 struct stat sbuf;
645 boolean newfile = false;
646 bfd_error = no_error;
647
648 if (stat (archive_filename, &sbuf) != 0)
649 {
6336b309
ILT
650
651#ifndef __GO32__
652
653/* KLUDGE ALERT! Temporary fix until I figger why
654 * stat() is wrong ... think it's buried in GO32's IDT
655 * - Jax
656 */
657
0c62139f
DM
658 if (errno != ENOENT)
659 bfd_fatal (archive_filename);
6336b309
ILT
660#endif
661
0c62139f 662 newfile = true;
2fa0b342
DHW
663 }
664
0c62139f
DM
665 ofile = fopen (archive_filename, FOPEN_AUB);
666 if (ofile == NULL)
667 {
668 perror (program_name);
669 exit (1);
2fa0b342
DHW
670 }
671
0c62139f
DM
672 temp = bfd_openr (archive_filename, NULL);
673 if (temp == NULL)
674 {
675 bfd_fatal (archive_filename);
2fa0b342 676 }
0c62139f
DM
677 if (newfile == false)
678 {
679 if (bfd_check_format (temp, bfd_archive) != true)
680 fatal ("%s is not an archive", archive_filename);
2fa0b342 681 }
0c62139f
DM
682 else
683 {
684 fwrite (ARMAG, 1, SARMAG, ofile);
685 if (!silent_create)
686 fprintf (stderr, "%s: creating %s\n",
687 program_name, archive_filename);
2fa0b342
DHW
688 }
689
0c62139f
DM
690 /* assume it's an achive, go straight to the end, sans $200 */
691 fseek (ofile, 0, 2);
2fa0b342 692
0c62139f
DM
693 for (; files_to_append && *files_to_append; ++files_to_append)
694 {
695 struct ar_hdr *hdr = bfd_special_undocumented_glue (temp, *files_to_append);
696 if (hdr == NULL)
697 {
698 bfd_fatal (*files_to_append);
2fa0b342
DHW
699 }
700
0c62139f 701 BFD_SEND (temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
2fa0b342 702
0c62139f
DM
703 ifile = fopen (*files_to_append, FOPEN_RB);
704 if (ifile == NULL)
705 {
706 bfd_nonfatal (*files_to_append);
707 }
2fa0b342 708
0c62139f
DM
709 if (stat (*files_to_append, &sbuf) != 0)
710 {
711 bfd_nonfatal (*files_to_append);
712 }
2fa0b342 713
0c62139f 714 tocopy = sbuf.st_size;
2fa0b342 715
0c62139f
DM
716 /* XXX should do error-checking! */
717 fwrite (hdr, 1, sizeof (struct ar_hdr), ofile);
2fa0b342 718
0c62139f
DM
719 while (tocopy > 0)
720 {
721 thistime = tocopy;
722 if (thistime > BUFSIZE)
723 thistime = BUFSIZE;
724 fread (buf, 1, thistime, ifile);
725 fwrite (buf, 1, thistime, ofile);
726 tocopy -= thistime;
2fa0b342 727 }
0c62139f
DM
728 fclose (ifile);
729 if ((sbuf.st_size % 2) == 1)
730 putc ('\n', ofile);
2fa0b342 731 }
0c62139f
DM
732 fclose (ofile);
733 bfd_close (temp);
2fa0b342
DHW
734}
735
736
737void
0c62139f 738write_archive ()
2fa0b342 739{
0c62139f
DM
740 bfd *obfd;
741 int namelen = strlen (inarch->filename);
742 char *new_name = xmalloc (namelen + EXT_NAME_LEN);
743 bfd *contents_head = inarch->next;
a00721fc 744
0c62139f 745 strcpy (new_name, inarch->filename);
6336b309 746
0c62139f
DM
747#ifdef __GO32__ /* avoid long .extensions for MS-DOS */
748 strcpy (new_name + namelen, "-a");
6336b309 749#else
0c62139f 750 strcpy (new_name + namelen, "-art");
6336b309
ILT
751#endif
752
0c62139f
DM
753 obfd = bfd_openw (new_name,
754 /* FIXME: violates abstraction; need a better protocol */
755 (inarch->xvec ? bfd_get_target (inarch) : NULL));
2fa0b342 756
0c62139f
DM
757 if (obfd == NULL)
758 bfd_fatal (inarch->filename);
2fa0b342 759
0c62139f 760 bfd_set_format (obfd, bfd_archive);
d2442698 761
0c62139f
DM
762 /* Request writing the archive symbol table unless we've
763 been explicitly requested not to. */
764 obfd->has_armap = write_armap >= 0;
2fa0b342 765
0c62139f
DM
766 if (bfd_set_archive_head (obfd, contents_head) != true)
767 bfd_fatal (inarch->filename);
2fa0b342 768
0c62139f
DM
769 if (!bfd_close (obfd))
770 bfd_fatal (inarch->filename);
0885eef1 771
0c62139f
DM
772 /* We don't care if this fails; we might be creating the archive. */
773 unlink (inarch->filename);
0885eef1 774
0c62139f
DM
775 if (rename (new_name, inarch->filename) != 0)
776 bfd_fatal (inarch->filename);
2fa0b342
DHW
777}
778
0c62139f
DM
779/* Return a pointer to the pointer to the entry which should be rplacd'd
780 into when altering. DEFAULT_POS should be how to interpret pos_default,
781 and should be a pos value. */
2fa0b342
DHW
782
783bfd **
0c62139f
DM
784get_pos_bfd (contents, default_pos)
785 bfd **contents;
786 enum pos default_pos;
2fa0b342 787{
0c62139f
DM
788 bfd **after_bfd = contents;
789 enum pos realpos = (postype == pos_default ? default_pos : postype);
2fa0b342 790
0c62139f
DM
791 if (realpos == pos_end)
792 {
793 while (*after_bfd)
794 after_bfd = &((*after_bfd)->next);
bb5ae298 795 }
0c62139f
DM
796 else
797 {
798 for (; *after_bfd; after_bfd = &(*after_bfd)->next)
799 if (!strcmp ((*after_bfd)->filename, posname))
800 {
801 if (realpos == pos_after)
802 after_bfd = &(*after_bfd)->next;
803 break;
804 }
2fa0b342 805 }
0c62139f 806 return after_bfd;
2fa0b342
DHW
807}
808
151a6341 809static void
0c62139f
DM
810delete_members (files_to_delete)
811 char **files_to_delete;
2fa0b342 812{
0c62139f
DM
813 bfd **current_ptr_ptr;
814 boolean found;
815 boolean something_changed = false;
816 for (; *files_to_delete != NULL; ++files_to_delete)
817 {
818 /* In a.out systems, the armap is optional. It's also called
819 __.SYMDEF. So if the user asked to delete it, we should remember
820 that fact. This isn't quite right for COFF systems (where
821 __.SYMDEF might be regular member), but it's very unlikely
822 to be a problem. FIXME */
823
824 if (!strcmp (*files_to_delete, "__.SYMDEF"))
825 {
826 inarch->has_armap = false;
827 write_armap = -1;
828 continue;
2fa0b342
DHW
829 }
830
0c62139f
DM
831 found = false;
832 current_ptr_ptr = &(inarch->next);
833 while (*current_ptr_ptr)
834 {
835 if (strcmp (*files_to_delete, (*current_ptr_ptr)->filename) == 0)
836 {
837 found = true;
838 something_changed = true;
839 if (verbose)
840 printf ("d - %s\n",
841 *files_to_delete);
842 *current_ptr_ptr = ((*current_ptr_ptr)->next);
843 goto next_file;
2fa0b342 844 }
0c62139f
DM
845 else
846 {
847 current_ptr_ptr = &((*current_ptr_ptr)->next);
2fa0b342
DHW
848 }
849 }
850
0c62139f
DM
851 if (verbose && found == false)
852 {
853 printf ("No member named `%s'\n", *files_to_delete);
2fa0b342 854 }
0c62139f
DM
855 next_file:
856 ;
2fa0b342
DHW
857 }
858
0c62139f
DM
859 if (something_changed == true)
860 {
861 write_archive ();
2fa0b342
DHW
862 }
863}
864
865
866/* Reposition existing members within an archive */
867
151a6341 868static void
0c62139f
DM
869move_members (files_to_move)
870 char **files_to_move;
2fa0b342 871{
0c62139f
DM
872 bfd **after_bfd; /* New entries go after this one */
873 bfd **current_ptr_ptr; /* cdr pointer into contents */
2fa0b342 874
0c62139f
DM
875 for (; *files_to_move; ++files_to_move)
876 {
877 current_ptr_ptr = &(inarch->next);
878 while (*current_ptr_ptr)
879 {
880 bfd *current_ptr = *current_ptr_ptr;
881 if (strcmp (normalize (*files_to_move), current_ptr->filename) == 0)
882 {
883 /* Move this file to the end of the list - first cut from
884 where it is. */
885 *current_ptr_ptr = current_ptr->next;
886
887 /* Now glue to end */
888 after_bfd = get_pos_bfd (&inarch->next, pos_end);
889 *after_bfd = current_ptr;
890 current_ptr->next = (bfd *) NULL;
891
892 if (verbose)
893 printf ("m - %s\n", *files_to_move);
894
895 goto next_file;
2fa0b342 896 }
0c62139f 897 current_ptr_ptr = &((*current_ptr_ptr)->next);
2fa0b342 898 }
0c62139f
DM
899 fprintf (stderr, "%s: no entry %s in archive %s!\n",
900 program_name, *files_to_move, inarch->filename);
901 exit (1);
902 next_file:;
2fa0b342
DHW
903 }
904
0c62139f 905 write_archive ();
2fa0b342
DHW
906}
907
0c62139f 908/* Ought to default to replacing in place, but this is existing practice! */
2fa0b342 909
151a6341 910static void
0c62139f
DM
911replace_members (files_to_move)
912 char **files_to_move;
2fa0b342 913{
0c62139f
DM
914 bfd **after_bfd; /* New entries go after this one */
915 bfd *current;
916 bfd **current_ptr;
917 bfd *temp;
918
919 while (files_to_move && *files_to_move)
920 {
921 current_ptr = &inarch->next;
922 while (*current_ptr)
923 {
924 current = *current_ptr;
925
926 if (!strcmp (normalize (*files_to_move), current->filename))
927 {
928 if (newer_only)
929 {
930 struct stat fsbuf, asbuf;
931
932 if (current->arelt_data == NULL)
933 {
931004e4
DHW
934 /* This can only happen if you specify a file on the
935 command line more than once. */
0c62139f
DM
936 fprintf (stderr,
937 "%s: duplicate file specified: %s -- skipping\n",
938 program_name, *files_to_move);
931004e4
DHW
939 goto next_file;
940 }
941
0c62139f
DM
942 if (stat (*files_to_move, &fsbuf) != 0)
943 {
944 if (errno != ENOENT)
945 bfd_fatal (*files_to_move);
946 goto next_file;
2fa0b342 947 }
0c62139f
DM
948 if (bfd_stat_arch_elt (current, &asbuf) != 0)
949 fatal ("internal stat error on %s", current->filename);
2fa0b342 950
0c62139f
DM
951 if (fsbuf.st_mtime <= asbuf.st_mtime)
952 goto next_file;
2fa0b342
DHW
953 }
954
0c62139f
DM
955 /* snip out this entry from the chain */
956 *current_ptr = current->next;
2fa0b342 957
0c62139f
DM
958 after_bfd = get_pos_bfd (&inarch->next, pos_end);
959 temp = *after_bfd;
960 *after_bfd = bfd_openr (*files_to_move, NULL);
961 if (*after_bfd == (bfd *) NULL)
962 {
963 bfd_fatal (*files_to_move);
2fa0b342 964 }
0c62139f 965 (*after_bfd)->next = temp;
2fa0b342 966
0c62139f
DM
967 if (verbose)
968 {
969 printf ("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
970 *files_to_move);
2fa0b342 971 }
0c62139f 972 goto next_file;
2fa0b342 973 }
0c62139f 974 current_ptr = &(current->next);
2fa0b342
DHW
975 }
976
0c62139f 977 /* It isn't in there, so add to end */
2fa0b342 978
0c62139f
DM
979 after_bfd = get_pos_bfd (&inarch->next, pos_end);
980 temp = *after_bfd;
981 *after_bfd = bfd_openr (*files_to_move, NULL);
982 if (*after_bfd == (bfd *) NULL)
983 {
984 bfd_fatal (*files_to_move);
2fa0b342 985 }
0c62139f
DM
986 if (verbose)
987 {
988 printf ("c - %s\n", *files_to_move);
2fa0b342
DHW
989 }
990
0c62139f 991 (*after_bfd)->next = temp;
2fa0b342 992
0c62139f 993 next_file:;
2fa0b342 994
0c62139f 995 files_to_move++;
2fa0b342
DHW
996 }
997
0c62139f 998 write_archive ();
2fa0b342
DHW
999}
1000
151a6341 1001static void
0c62139f
DM
1002ranlib_only (archname)
1003 char *archname;
2fa0b342 1004{
0c62139f
DM
1005 write_armap = 1;
1006 open_inarch (archname);
1007 write_archive ();
1008 exit (0);
2fa0b342 1009}
ab01cf22 1010
4b5ea362
SC
1011/* Things which are interesting to map over all or some of the files: */
1012
151a6341 1013static void
0c62139f
DM
1014print_descr (abfd)
1015 bfd *abfd;
4b5ea362 1016{
0c62139f 1017 print_arelt_descr (stdout, abfd, verbose);
4b5ea362 1018}
This page took 0.151872 seconds and 4 git commands to generate.