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