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