]>
Commit | Line | Data |
---|---|---|
252b5132 | 1 | /* bucomm.c -- Bin Utils COMmon code. |
219d1afa | 2 | Copyright (C) 1991-2018 Free Software Foundation, Inc. |
252b5132 RH |
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 | |
32866df7 | 8 | the Free Software Foundation; either version 3 of the License, or |
252b5132 RH |
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 | |
b43b5d5f NC |
18 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA |
19 | 02110-1301, USA. */ | |
252b5132 RH |
20 | \f |
21 | /* We might put this in a library someday so it could be dynamically | |
22 | loaded, but for now it's not necessary. */ | |
23 | ||
3db64b00 | 24 | #include "sysdep.h" |
252b5132 RH |
25 | #include "bfd.h" |
26 | #include "libiberty.h" | |
5af11cab | 27 | #include "filenames.h" |
252b5132 | 28 | |
252b5132 | 29 | #include <time.h> /* ctime, maybe time_t */ |
77f762d6 | 30 | #include <assert.h> |
3db64b00 | 31 | #include "bucomm.h" |
252b5132 RH |
32 | |
33 | #ifndef HAVE_TIME_T_IN_TIME_H | |
34 | #ifndef HAVE_TIME_T_IN_TYPES_H | |
35 | typedef long time_t; | |
36 | #endif | |
37 | #endif | |
252b5132 | 38 | \f |
06d86cf7 | 39 | /* Error reporting. */ |
252b5132 RH |
40 | |
41 | char *program_name; | |
42 | ||
43 | void | |
2da42df6 | 44 | bfd_nonfatal (const char *string) |
252b5132 | 45 | { |
a8c62f1c | 46 | const char *errmsg; |
252b5132 | 47 | |
a8c62f1c | 48 | errmsg = bfd_errmsg (bfd_get_error ()); |
8e085dd2 | 49 | fflush (stdout); |
252b5132 RH |
50 | if (string) |
51 | fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); | |
52 | else | |
53 | fprintf (stderr, "%s: %s\n", program_name, errmsg); | |
54 | } | |
55 | ||
2db6cde7 NS |
56 | /* Issue a non fatal error message. FILENAME, or if NULL then BFD, |
57 | are used to indicate the problematic file. SECTION, if non NULL, | |
58 | is used to provide a section name. If FORMAT is non-null, then it | |
59 | is used to print additional information via vfprintf. Finally the | |
60 | bfd error message is printed. In summary, error messages are of | |
61 | one of the following forms: | |
62 | ||
63 | PROGRAM:file: bfd-error-message | |
64 | PROGRAM:file[section]: bfd-error-message | |
65 | PROGRAM:file: printf-message: bfd-error-message | |
91d6fa6a | 66 | PROGRAM:file[section]: printf-message: bfd-error-message. */ |
2db6cde7 NS |
67 | |
68 | void | |
69 | bfd_nonfatal_message (const char *filename, | |
91d6fa6a NC |
70 | const bfd *abfd, |
71 | const asection *section, | |
2db6cde7 NS |
72 | const char *format, ...) |
73 | { | |
a8c62f1c AM |
74 | const char *errmsg; |
75 | const char *section_name; | |
2db6cde7 NS |
76 | va_list args; |
77 | ||
a8c62f1c | 78 | errmsg = bfd_errmsg (bfd_get_error ()); |
8e085dd2 | 79 | fflush (stdout); |
a8c62f1c | 80 | section_name = NULL; |
2db6cde7 NS |
81 | va_start (args, format); |
82 | fprintf (stderr, "%s", program_name); | |
3aade688 | 83 | |
91d6fa6a | 84 | if (abfd) |
2db6cde7 NS |
85 | { |
86 | if (!filename) | |
91d6fa6a | 87 | filename = bfd_get_archive_filename (abfd); |
2db6cde7 | 88 | if (section) |
91d6fa6a | 89 | section_name = bfd_get_section_name (abfd, section); |
2db6cde7 NS |
90 | } |
91 | if (section_name) | |
92 | fprintf (stderr, ":%s[%s]", filename, section_name); | |
93 | else | |
94 | fprintf (stderr, ":%s", filename); | |
95 | ||
96 | if (format) | |
97 | { | |
98 | fprintf (stderr, ": "); | |
99 | vfprintf (stderr, format, args); | |
100 | } | |
101 | fprintf (stderr, ": %s\n", errmsg); | |
102 | va_end (args); | |
103 | } | |
104 | ||
252b5132 | 105 | void |
2da42df6 | 106 | bfd_fatal (const char *string) |
252b5132 RH |
107 | { |
108 | bfd_nonfatal (string); | |
109 | xexit (1); | |
110 | } | |
111 | ||
cba12006 | 112 | void |
2da42df6 | 113 | report (const char * format, va_list args) |
252b5132 | 114 | { |
a8c62f1c | 115 | fflush (stdout); |
252b5132 RH |
116 | fprintf (stderr, "%s: ", program_name); |
117 | vfprintf (stderr, format, args); | |
118 | putc ('\n', stderr); | |
119 | } | |
120 | ||
252b5132 | 121 | void |
1651e569 | 122 | fatal (const char *format, ...) |
252b5132 | 123 | { |
1651e569 TT |
124 | va_list args; |
125 | ||
126 | va_start (args, format); | |
252b5132 | 127 | |
252b5132 | 128 | report (format, args); |
1651e569 | 129 | va_end (args); |
252b5132 RH |
130 | xexit (1); |
131 | } | |
132 | ||
133 | void | |
1651e569 | 134 | non_fatal (const char *format, ...) |
252b5132 | 135 | { |
1651e569 TT |
136 | va_list args; |
137 | ||
138 | va_start (args, format); | |
252b5132 | 139 | |
252b5132 | 140 | report (format, args); |
1651e569 | 141 | va_end (args); |
252b5132 | 142 | } |
252b5132 RH |
143 | |
144 | /* Set the default BFD target based on the configured target. Doing | |
145 | this permits the binutils to be configured for a particular target, | |
146 | and linked against a shared BFD library which was configured for a | |
147 | different target. */ | |
148 | ||
149 | void | |
2da42df6 | 150 | set_default_bfd_target (void) |
252b5132 RH |
151 | { |
152 | /* The macro TARGET is defined by Makefile. */ | |
153 | const char *target = TARGET; | |
154 | ||
155 | if (! bfd_set_default_target (target)) | |
156 | fatal (_("can't set BFD default target to `%s': %s"), | |
157 | target, bfd_errmsg (bfd_get_error ())); | |
158 | } | |
159 | ||
b34976b6 | 160 | /* After a FALSE return from bfd_check_format_matches with |
252b5132 RH |
161 | bfd_get_error () == bfd_error_file_ambiguously_recognized, print |
162 | the possible matching targets. */ | |
163 | ||
164 | void | |
2da42df6 | 165 | list_matching_formats (char **p) |
252b5132 | 166 | { |
a8c62f1c | 167 | fflush (stdout); |
252b5132 RH |
168 | fprintf (stderr, _("%s: Matching formats:"), program_name); |
169 | while (*p) | |
170 | fprintf (stderr, " %s", *p++); | |
171 | fputc ('\n', stderr); | |
172 | } | |
173 | ||
174 | /* List the supported targets. */ | |
175 | ||
176 | void | |
2da42df6 | 177 | list_supported_targets (const char *name, FILE *f) |
252b5132 | 178 | { |
252b5132 | 179 | int t; |
a8c62f1c | 180 | const char **targ_names; |
252b5132 RH |
181 | |
182 | if (name == NULL) | |
183 | fprintf (f, _("Supported targets:")); | |
184 | else | |
185 | fprintf (f, _("%s: supported targets:"), name); | |
48417c1a | 186 | |
a8c62f1c | 187 | targ_names = bfd_target_list (); |
48417c1a AM |
188 | for (t = 0; targ_names[t] != NULL; t++) |
189 | fprintf (f, " %s", targ_names[t]); | |
252b5132 | 190 | fprintf (f, "\n"); |
48417c1a | 191 | free (targ_names); |
252b5132 | 192 | } |
2f83960e AM |
193 | |
194 | /* List the supported architectures. */ | |
195 | ||
196 | void | |
2da42df6 | 197 | list_supported_architectures (const char *name, FILE *f) |
2f83960e | 198 | { |
d25576aa NC |
199 | const char ** arch; |
200 | const char ** arches; | |
2f83960e AM |
201 | |
202 | if (name == NULL) | |
203 | fprintf (f, _("Supported architectures:")); | |
204 | else | |
205 | fprintf (f, _("%s: supported architectures:"), name); | |
206 | ||
d25576aa | 207 | for (arch = arches = bfd_arch_list (); *arch; arch++) |
2f83960e AM |
208 | fprintf (f, " %s", *arch); |
209 | fprintf (f, "\n"); | |
d25576aa | 210 | free (arches); |
2f83960e | 211 | } |
252b5132 | 212 | \f |
06d86cf7 | 213 | static const char * |
2da42df6 | 214 | endian_string (enum bfd_endian endian) |
06d86cf7 NC |
215 | { |
216 | switch (endian) | |
217 | { | |
9cf03b7e NC |
218 | case BFD_ENDIAN_BIG: return _("big endian"); |
219 | case BFD_ENDIAN_LITTLE: return _("little endian"); | |
220 | default: return _("endianness unknown"); | |
06d86cf7 NC |
221 | } |
222 | } | |
223 | ||
aac502f7 AM |
224 | /* Data passed to do_display_target and other target iterators. */ |
225 | ||
226 | struct display_target { | |
227 | /* Temp file. */ | |
228 | char *filename; | |
229 | /* Return status. */ | |
230 | int error; | |
231 | /* Number of targets. */ | |
232 | int count; | |
233 | /* Size of info in bytes. */ | |
234 | size_t alloc; | |
235 | /* Per-target info. */ | |
236 | struct { | |
237 | /* Target name. */ | |
238 | const char *name; | |
239 | /* Non-zero if target/arch combination supported. */ | |
240 | unsigned char arch[bfd_arch_last - bfd_arch_obscure - 1]; | |
241 | } *info; | |
242 | }; | |
243 | ||
06d86cf7 | 244 | /* List the targets that BFD is configured to support, each followed |
aac502f7 AM |
245 | by its endianness and the architectures it supports. Also build |
246 | info about target/archs. */ | |
06d86cf7 NC |
247 | |
248 | static int | |
aac502f7 | 249 | do_display_target (const bfd_target *targ, void *data) |
06d86cf7 | 250 | { |
aac502f7 AM |
251 | struct display_target *param = (struct display_target *) data; |
252 | bfd *abfd; | |
253 | size_t amt; | |
06d86cf7 | 254 | |
aac502f7 AM |
255 | param->count += 1; |
256 | amt = param->count * sizeof (*param->info); | |
257 | if (param->alloc < amt) | |
06d86cf7 | 258 | { |
aac502f7 AM |
259 | size_t size = ((param->count < 64 ? 64 : param->count) |
260 | * sizeof (*param->info) * 2); | |
261 | param->info = xrealloc (param->info, size); | |
262 | memset ((char *) param->info + param->alloc, 0, size - param->alloc); | |
263 | param->alloc = size; | |
264 | } | |
265 | param->info[param->count - 1].name = targ->name; | |
06d86cf7 | 266 | |
aac502f7 AM |
267 | printf (_("%s\n (header %s, data %s)\n"), targ->name, |
268 | endian_string (targ->header_byteorder), | |
269 | endian_string (targ->byteorder)); | |
06d86cf7 | 270 | |
aac502f7 AM |
271 | abfd = bfd_openw (param->filename, targ->name); |
272 | if (abfd == NULL) | |
273 | { | |
274 | bfd_nonfatal (param->filename); | |
275 | param->error = 1; | |
276 | } | |
277 | else if (!bfd_set_format (abfd, bfd_object)) | |
278 | { | |
279 | if (bfd_get_error () != bfd_error_invalid_operation) | |
06d86cf7 | 280 | { |
aac502f7 AM |
281 | bfd_nonfatal (targ->name); |
282 | param->error = 1; | |
06d86cf7 | 283 | } |
aac502f7 AM |
284 | } |
285 | else | |
286 | { | |
287 | enum bfd_architecture a; | |
06d86cf7 | 288 | |
91610c0c | 289 | for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) |
aac502f7 AM |
290 | if (bfd_set_arch_mach (abfd, a, 0)) |
291 | { | |
292 | printf (" %s\n", bfd_printable_arch_mach (a, 0)); | |
293 | param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1; | |
294 | } | |
06d86cf7 | 295 | } |
aac502f7 AM |
296 | if (abfd != NULL) |
297 | bfd_close_all_done (abfd); | |
06d86cf7 | 298 | |
aac502f7 | 299 | return param->error; |
06d86cf7 NC |
300 | } |
301 | ||
aac502f7 AM |
302 | static void |
303 | display_target_list (struct display_target *arg) | |
304 | { | |
305 | arg->filename = make_temp_file (NULL); | |
306 | arg->error = 0; | |
307 | arg->count = 0; | |
308 | arg->alloc = 0; | |
309 | arg->info = NULL; | |
310 | ||
311 | bfd_iterate_over_targets (do_display_target, arg); | |
312 | ||
313 | unlink (arg->filename); | |
314 | free (arg->filename); | |
315 | } | |
316 | ||
317 | /* Calculate how many targets we can print across the page. */ | |
06d86cf7 NC |
318 | |
319 | static int | |
aac502f7 | 320 | do_info_size (int targ, int width, const struct display_target *arg) |
06d86cf7 | 321 | { |
aac502f7 AM |
322 | while (targ < arg->count) |
323 | { | |
324 | width -= strlen (arg->info[targ].name) + 1; | |
325 | if (width < 0) | |
326 | return targ; | |
327 | ++targ; | |
328 | } | |
329 | return targ; | |
330 | } | |
331 | ||
332 | /* Print header of target names. */ | |
06d86cf7 | 333 | |
aac502f7 AM |
334 | static void |
335 | do_info_header (int targ, int stop_targ, const struct display_target *arg) | |
336 | { | |
337 | while (targ != stop_targ) | |
338 | printf ("%s ", arg->info[targ++].name); | |
339 | } | |
340 | ||
341 | /* Print a table row. */ | |
342 | ||
343 | static void | |
344 | do_info_row (int targ, int stop_targ, enum bfd_architecture a, | |
345 | const struct display_target *arg) | |
346 | { | |
347 | while (targ != stop_targ) | |
348 | { | |
349 | if (arg->info[targ].arch[a - bfd_arch_obscure - 1]) | |
350 | fputs (arg->info[targ].name, stdout); | |
351 | else | |
352 | { | |
353 | int l = strlen (arg->info[targ].name); | |
354 | while (l--) | |
355 | putchar ('-'); | |
356 | } | |
357 | ++targ; | |
358 | if (targ != stop_targ) | |
359 | putchar (' '); | |
360 | } | |
06d86cf7 NC |
361 | } |
362 | ||
363 | /* Print tables of all the target-architecture combinations that | |
364 | BFD has been configured to support. */ | |
365 | ||
aac502f7 AM |
366 | static void |
367 | display_target_tables (const struct display_target *arg) | |
06d86cf7 | 368 | { |
aac502f7 AM |
369 | const char *columns; |
370 | int width, start_targ, stop_targ; | |
371 | enum bfd_architecture arch; | |
372 | int longest_arch = 0; | |
373 | ||
374 | for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++) | |
06d86cf7 | 375 | { |
aac502f7 AM |
376 | const char *s = bfd_printable_arch_mach (arch, 0); |
377 | int len = strlen (s); | |
378 | if (len > longest_arch) | |
379 | longest_arch = len; | |
380 | } | |
06d86cf7 | 381 | |
aac502f7 AM |
382 | width = 0; |
383 | columns = getenv ("COLUMNS"); | |
384 | if (columns != NULL) | |
385 | width = atoi (columns); | |
386 | if (width == 0) | |
387 | width = 80; | |
388 | ||
389 | for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ) | |
390 | { | |
391 | stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg); | |
392 | ||
393 | printf ("\n%*s", longest_arch + 1, " "); | |
394 | do_info_header (start_targ, stop_targ, arg); | |
395 | putchar ('\n'); | |
06d86cf7 | 396 | |
aac502f7 AM |
397 | for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++) |
398 | { | |
399 | if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0) | |
400 | { | |
401 | printf ("%*s ", longest_arch, | |
402 | bfd_printable_arch_mach (arch, 0)); | |
403 | ||
404 | do_info_row (start_targ, stop_targ, arch, arg); | |
405 | putchar ('\n'); | |
406 | } | |
06d86cf7 | 407 | } |
06d86cf7 | 408 | } |
06d86cf7 NC |
409 | } |
410 | ||
411 | int | |
2da42df6 | 412 | display_info (void) |
06d86cf7 | 413 | { |
aac502f7 AM |
414 | struct display_target arg; |
415 | ||
06d86cf7 | 416 | printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); |
aac502f7 AM |
417 | |
418 | display_target_list (&arg); | |
419 | if (!arg.error) | |
420 | display_target_tables (&arg); | |
421 | ||
422 | return arg.error; | |
06d86cf7 NC |
423 | } |
424 | \f | |
252b5132 RH |
425 | /* Display the archive header for an element as if it were an ls -l listing: |
426 | ||
427 | Mode User\tGroup\tSize\tDate Name */ | |
428 | ||
429 | void | |
2da42df6 | 430 | print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose) |
252b5132 RH |
431 | { |
432 | struct stat buf; | |
433 | ||
434 | if (verbose) | |
435 | { | |
436 | if (bfd_stat_arch_elt (abfd, &buf) == 0) | |
437 | { | |
438 | char modebuf[11]; | |
439 | char timebuf[40]; | |
440 | time_t when = buf.st_mtime; | |
b1f88ebe | 441 | const char *ctime_result = (const char *) ctime (&when); |
34debcd1 | 442 | bfd_size_type size; |
252b5132 | 443 | |
0593bd3a NC |
444 | /* PR binutils/17605: Check for corrupt time values. */ |
445 | if (ctime_result == NULL) | |
446 | sprintf (timebuf, _("<time data corrupt>")); | |
447 | else | |
448 | /* POSIX format: skip weekday and seconds from ctime output. */ | |
449 | sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); | |
252b5132 RH |
450 | |
451 | mode_string (buf.st_mode, modebuf); | |
452 | modebuf[10] = '\0'; | |
34debcd1 | 453 | size = buf.st_size; |
252b5132 | 454 | /* POSIX 1003.2/D11 says to skip first character (entry type). */ |
34debcd1 | 455 | fprintf (file, "%s %ld/%ld %6" BFD_VMA_FMT "u %s ", modebuf + 1, |
252b5132 | 456 | (long) buf.st_uid, (long) buf.st_gid, |
34debcd1 | 457 | size, timebuf); |
252b5132 RH |
458 | } |
459 | } | |
460 | ||
461 | fprintf (file, "%s\n", bfd_get_filename (abfd)); | |
462 | } | |
463 | ||
485be063 AM |
464 | /* Return a path for a new temporary file in the same directory |
465 | as file PATH. */ | |
252b5132 | 466 | |
485be063 AM |
467 | static char * |
468 | template_in_dir (const char *path) | |
252b5132 | 469 | { |
485be063 | 470 | #define template "stXXXXXX" |
2946671e | 471 | const char *slash = strrchr (path, '/'); |
252b5132 | 472 | char *tmpname; |
485be063 | 473 | size_t len; |
252b5132 | 474 | |
5af11cab AM |
475 | #ifdef HAVE_DOS_BASED_FILE_SYSTEM |
476 | { | |
477 | /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ | |
485be063 | 478 | char *bslash = strrchr (path, '\\'); |
f9c026a8 | 479 | |
2ab47eed | 480 | if (slash == NULL || (bslash != NULL && bslash > slash)) |
5af11cab | 481 | slash = bslash; |
485be063 | 482 | if (slash == NULL && path[0] != '\0' && path[1] == ':') |
2946671e | 483 | slash = path + 1; |
5af11cab | 484 | } |
252b5132 RH |
485 | #endif |
486 | ||
487 | if (slash != (char *) NULL) | |
488 | { | |
485be063 | 489 | len = slash - path; |
3f5e193b | 490 | tmpname = (char *) xmalloc (len + sizeof (template) + 2); |
485be063 | 491 | memcpy (tmpname, path, len); |
252b5132 | 492 | |
5af11cab AM |
493 | #ifdef HAVE_DOS_BASED_FILE_SYSTEM |
494 | /* If tmpname is "X:", appending a slash will make it a root | |
495 | directory on drive X, which is NOT the same as the current | |
496 | directory on drive X. */ | |
485be063 AM |
497 | if (len == 2 && tmpname[1] == ':') |
498 | tmpname[len++] = '.'; | |
5af11cab | 499 | #endif |
485be063 | 500 | tmpname[len++] = '/'; |
252b5132 RH |
501 | } |
502 | else | |
503 | { | |
3f5e193b | 504 | tmpname = (char *) xmalloc (sizeof (template)); |
485be063 | 505 | len = 0; |
f9c026a8 | 506 | } |
485be063 AM |
507 | |
508 | memcpy (tmpname + len, template, sizeof (template)); | |
509 | return tmpname; | |
510 | #undef template | |
511 | } | |
512 | ||
513 | /* Return the name of a created temporary file in the same directory | |
514 | as FILENAME. */ | |
515 | ||
516 | char * | |
517 | make_tempname (char *filename) | |
518 | { | |
519 | char *tmpname = template_in_dir (filename); | |
520 | int fd; | |
521 | ||
522 | #ifdef HAVE_MKSTEMP | |
523 | fd = mkstemp (tmpname); | |
524 | #else | |
525 | tmpname = mktemp (tmpname); | |
526 | if (tmpname == NULL) | |
f9c026a8 | 527 | return NULL; |
485be063 | 528 | fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600); |
f9c026a8 | 529 | #endif |
485be063 | 530 | if (fd == -1) |
c48d800e NC |
531 | { |
532 | free (tmpname); | |
533 | return NULL; | |
534 | } | |
485be063 | 535 | close (fd); |
f9c026a8 NC |
536 | return tmpname; |
537 | } | |
538 | ||
485be063 AM |
539 | /* Return the name of a created temporary directory inside the |
540 | directory containing FILENAME. */ | |
f9c026a8 NC |
541 | |
542 | char * | |
543 | make_tempdir (char *filename) | |
544 | { | |
485be063 | 545 | char *tmpname = template_in_dir (filename); |
f9c026a8 | 546 | |
485be063 AM |
547 | #ifdef HAVE_MKDTEMP |
548 | return mkdtemp (tmpname); | |
549 | #else | |
550 | tmpname = mktemp (tmpname); | |
551 | if (tmpname == NULL) | |
552 | return NULL; | |
553 | #if defined (_WIN32) && !defined (__CYGWIN32__) | |
554 | if (mkdir (tmpname) != 0) | |
555 | return NULL; | |
556 | #else | |
557 | if (mkdir (tmpname, 0700) != 0) | |
558 | return NULL; | |
f9c026a8 | 559 | #endif |
252b5132 | 560 | return tmpname; |
485be063 | 561 | #endif |
252b5132 RH |
562 | } |
563 | ||
564 | /* Parse a string into a VMA, with a fatal error if it can't be | |
565 | parsed. */ | |
566 | ||
567 | bfd_vma | |
2da42df6 | 568 | parse_vma (const char *s, const char *arg) |
252b5132 RH |
569 | { |
570 | bfd_vma ret; | |
571 | const char *end; | |
572 | ||
573 | ret = bfd_scan_vma (s, &end, 0); | |
f462a9ea | 574 | |
252b5132 RH |
575 | if (*end != '\0') |
576 | fatal (_("%s: bad number: %s"), arg, s); | |
577 | ||
578 | return ret; | |
579 | } | |
f24ddbdd NC |
580 | |
581 | /* Returns the size of the named file. If the file does not | |
582 | exist, or if it is not a real file, then a suitable non-fatal | |
a3029abd | 583 | error message is printed and (off_t) -1 is returned. */ |
f24ddbdd NC |
584 | |
585 | off_t | |
586 | get_file_size (const char * file_name) | |
587 | { | |
588 | struct stat statbuf; | |
3aade688 | 589 | |
740a4630 NC |
590 | if (file_name == NULL) |
591 | return (off_t) -1; | |
592 | ||
f24ddbdd NC |
593 | if (stat (file_name, &statbuf) < 0) |
594 | { | |
595 | if (errno == ENOENT) | |
596 | non_fatal (_("'%s': No such file"), file_name); | |
597 | else | |
598 | non_fatal (_("Warning: could not locate '%s'. reason: %s"), | |
599 | file_name, strerror (errno)); | |
3aade688 | 600 | } |
0602cdad NC |
601 | else if (S_ISDIR (statbuf.st_mode)) |
602 | non_fatal (_("Warning: '%s' is a directory"), file_name); | |
f24ddbdd NC |
603 | else if (! S_ISREG (statbuf.st_mode)) |
604 | non_fatal (_("Warning: '%s' is not an ordinary file"), file_name); | |
9849fbfc NC |
605 | else if (statbuf.st_size < 0) |
606 | non_fatal (_("Warning: '%s' has negative size, probably it is too large"), | |
607 | file_name); | |
f24ddbdd NC |
608 | else |
609 | return statbuf.st_size; | |
610 | ||
52a476ee | 611 | return (off_t) -1; |
f24ddbdd | 612 | } |
77f762d6 L |
613 | |
614 | /* Return the filename in a static buffer. */ | |
615 | ||
616 | const char * | |
8d8e0703 | 617 | bfd_get_archive_filename (const bfd *abfd) |
77f762d6 L |
618 | { |
619 | static size_t curr = 0; | |
620 | static char *buf; | |
621 | size_t needed; | |
622 | ||
623 | assert (abfd != NULL); | |
3aade688 | 624 | |
b0cffb47 AM |
625 | if (abfd->my_archive == NULL |
626 | || bfd_is_thin_archive (abfd->my_archive)) | |
77f762d6 L |
627 | return bfd_get_filename (abfd); |
628 | ||
629 | needed = (strlen (bfd_get_filename (abfd->my_archive)) | |
630 | + strlen (bfd_get_filename (abfd)) + 3); | |
631 | if (needed > curr) | |
632 | { | |
633 | if (curr) | |
634 | free (buf); | |
635 | curr = needed + (needed >> 1); | |
76e7a751 | 636 | buf = (char *) xmalloc (curr); |
77f762d6 L |
637 | } |
638 | sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), | |
639 | bfd_get_filename (abfd)); | |
640 | return buf; | |
641 | } | |
dd9b91de NC |
642 | |
643 | /* Returns TRUE iff PATHNAME, a filename of an archive member, | |
644 | is valid for writing. For security reasons absolute paths | |
645 | and paths containing /../ are not allowed. See PR 17533. */ | |
646 | ||
647 | bfd_boolean | |
648 | is_valid_archive_path (char const * pathname) | |
649 | { | |
650 | const char * n = pathname; | |
651 | ||
652 | if (IS_ABSOLUTE_PATH (n)) | |
653 | return FALSE; | |
654 | ||
655 | while (*n) | |
656 | { | |
657 | if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n))) | |
658 | return FALSE; | |
659 | ||
660 | while (*n && ! IS_DIR_SEPARATOR (*n)) | |
661 | n++; | |
662 | while (IS_DIR_SEPARATOR (*n)) | |
663 | n++; | |
664 | } | |
665 | ||
666 | return TRUE; | |
667 | } |