]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/bucomm.c
Fix heap-use-after-free because all_objfiles_removed triggers tui_display_main
[thirdparty/binutils-gdb.git] / binutils / bucomm.c
CommitLineData
252b5132 1/* bucomm.c -- Bin Utils COMmon code.
fd67aa11 2 Copyright (C) 1991-2024 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"
87b9f255 28#include <time.h>
77f762d6 29#include <assert.h>
3db64b00 30#include "bucomm.h"
252b5132 31\f
06d86cf7 32/* Error reporting. */
252b5132
RH
33
34char *program_name;
35
36void
2da42df6 37bfd_nonfatal (const char *string)
252b5132 38{
a8c62f1c 39 const char *errmsg;
a68aa5d3 40 enum bfd_error err = bfd_get_error ();
252b5132 41
a68aa5d3
NC
42 if (err == bfd_error_no_error)
43 errmsg = _("cause of error unknown");
44 else
45 errmsg = bfd_errmsg (err);
8e085dd2 46 fflush (stdout);
252b5132
RH
47 if (string)
48 fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
49 else
50 fprintf (stderr, "%s: %s\n", program_name, errmsg);
51}
52
2db6cde7
NS
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
df56ecde
AM
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. */
2db6cde7
NS
64
65void
66bfd_nonfatal_message (const char *filename,
91d6fa6a
NC
67 const bfd *abfd,
68 const asection *section,
2db6cde7
NS
69 const char *format, ...)
70{
a8c62f1c
AM
71 const char *errmsg;
72 const char *section_name;
a68aa5d3 73 enum bfd_error err = bfd_get_error ();
2db6cde7 74
a68aa5d3
NC
75 if (err == bfd_error_no_error)
76 errmsg = _("cause of error unknown");
77 else
78 errmsg = bfd_errmsg (err);
8e085dd2 79 fflush (stdout);
a8c62f1c 80 section_name = NULL;
2db6cde7 81 fprintf (stderr, "%s", program_name);
3aade688 82
91d6fa6a 83 if (abfd)
2db6cde7
NS
84 {
85 if (!filename)
91d6fa6a 86 filename = bfd_get_archive_filename (abfd);
2db6cde7 87 if (section)
fd361982 88 section_name = bfd_section_name (section);
2db6cde7
NS
89 }
90 if (section_name)
df56ecde 91 fprintf (stderr, ": %s[%s]", filename, section_name);
2db6cde7 92 else
df56ecde 93 fprintf (stderr, ": %s", filename);
2db6cde7
NS
94
95 if (format)
96 {
bd84a8e2
AM
97 va_list args;
98 va_start (args, format);
2db6cde7
NS
99 fprintf (stderr, ": ");
100 vfprintf (stderr, format, args);
bd84a8e2 101 va_end (args);
2db6cde7
NS
102 }
103 fprintf (stderr, ": %s\n", errmsg);
2db6cde7
NS
104}
105
252b5132 106void
2da42df6 107bfd_fatal (const char *string)
252b5132
RH
108{
109 bfd_nonfatal (string);
110 xexit (1);
111}
112
cba12006 113void
2da42df6 114report (const char * format, va_list args)
252b5132 115{
a8c62f1c 116 fflush (stdout);
252b5132
RH
117 fprintf (stderr, "%s: ", program_name);
118 vfprintf (stderr, format, args);
119 putc ('\n', stderr);
120}
121
252b5132 122void
1651e569 123fatal (const char *format, ...)
252b5132 124{
1651e569
TT
125 va_list args;
126
127 va_start (args, format);
252b5132 128
252b5132 129 report (format, args);
1651e569 130 va_end (args);
252b5132
RH
131 xexit (1);
132}
133
134void
1651e569 135non_fatal (const char *format, ...)
252b5132 136{
1651e569
TT
137 va_list args;
138
139 va_start (args, format);
252b5132 140
252b5132 141 report (format, args);
1651e569 142 va_end (args);
252b5132 143}
252b5132 144
0772dacc
AM
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
149void *
150bfd_xalloc (bfd *abfd, size_t size)
151{
152 void *ret = bfd_alloc (abfd, size);
153 if (ret == NULL)
154 bfd_fatal (NULL);
155 return ret;
156}
157
252b5132
RH
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
163void
2da42df6 164set_default_bfd_target (void)
252b5132
RH
165{
166 /* The macro TARGET is defined by Makefile. */
167 const char *target = TARGET;
168
169 if (! bfd_set_default_target (target))
170 fatal (_("can't set BFD default target to `%s': %s"),
171 target, bfd_errmsg (bfd_get_error ()));
172}
173
b34976b6 174/* After a FALSE return from bfd_check_format_matches with
252b5132 175 bfd_get_error () == bfd_error_file_ambiguously_recognized, print
370426d0 176 the possible matching targets and free the list of targets. */
252b5132
RH
177
178void
370426d0 179list_matching_formats (char **matching)
252b5132 180{
a8c62f1c 181 fflush (stdout);
252b5132 182 fprintf (stderr, _("%s: Matching formats:"), program_name);
370426d0 183 char **p = matching;
252b5132
RH
184 while (*p)
185 fprintf (stderr, " %s", *p++);
370426d0 186 free (matching);
252b5132
RH
187 fputc ('\n', stderr);
188}
189
190/* List the supported targets. */
191
192void
2da42df6 193list_supported_targets (const char *name, FILE *f)
252b5132 194{
252b5132 195 int t;
a8c62f1c 196 const char **targ_names;
252b5132
RH
197
198 if (name == NULL)
199 fprintf (f, _("Supported targets:"));
200 else
201 fprintf (f, _("%s: supported targets:"), name);
48417c1a 202
a8c62f1c 203 targ_names = bfd_target_list ();
48417c1a
AM
204 for (t = 0; targ_names[t] != NULL; t++)
205 fprintf (f, " %s", targ_names[t]);
252b5132 206 fprintf (f, "\n");
48417c1a 207 free (targ_names);
252b5132 208}
2f83960e
AM
209
210/* List the supported architectures. */
211
212void
2da42df6 213list_supported_architectures (const char *name, FILE *f)
2f83960e 214{
d25576aa
NC
215 const char ** arch;
216 const char ** arches;
2f83960e
AM
217
218 if (name == NULL)
219 fprintf (f, _("Supported architectures:"));
220 else
221 fprintf (f, _("%s: supported architectures:"), name);
222
d25576aa 223 for (arch = arches = bfd_arch_list (); *arch; arch++)
2f83960e
AM
224 fprintf (f, " %s", *arch);
225 fprintf (f, "\n");
d25576aa 226 free (arches);
2f83960e 227}
252b5132 228\f
06d86cf7 229static const char *
2da42df6 230endian_string (enum bfd_endian endian)
06d86cf7
NC
231{
232 switch (endian)
233 {
9cf03b7e
NC
234 case BFD_ENDIAN_BIG: return _("big endian");
235 case BFD_ENDIAN_LITTLE: return _("little endian");
236 default: return _("endianness unknown");
06d86cf7
NC
237 }
238}
239
aac502f7
AM
240/* Data passed to do_display_target and other target iterators. */
241
242struct 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
06d86cf7 260/* List the targets that BFD is configured to support, each followed
aac502f7
AM
261 by its endianness and the architectures it supports. Also build
262 info about target/archs. */
06d86cf7
NC
263
264static int
aac502f7 265do_display_target (const bfd_target *targ, void *data)
06d86cf7 266{
aac502f7
AM
267 struct display_target *param = (struct display_target *) data;
268 bfd *abfd;
269 size_t amt;
06d86cf7 270
aac502f7
AM
271 param->count += 1;
272 amt = param->count * sizeof (*param->info);
273 if (param->alloc < amt)
06d86cf7 274 {
aac502f7
AM
275 size_t size = ((param->count < 64 ? 64 : param->count)
276 * sizeof (*param->info) * 2);
277 param->info = xrealloc (param->info, size);
278 memset ((char *) param->info + param->alloc, 0, size - param->alloc);
279 param->alloc = size;
280 }
281 param->info[param->count - 1].name = targ->name;
06d86cf7 282
aac502f7
AM
283 printf (_("%s\n (header %s, data %s)\n"), targ->name,
284 endian_string (targ->header_byteorder),
285 endian_string (targ->byteorder));
06d86cf7 286
aac502f7
AM
287 abfd = bfd_openw (param->filename, targ->name);
288 if (abfd == NULL)
289 {
290 bfd_nonfatal (param->filename);
291 param->error = 1;
292 }
293 else if (!bfd_set_format (abfd, bfd_object))
294 {
295 if (bfd_get_error () != bfd_error_invalid_operation)
06d86cf7 296 {
aac502f7
AM
297 bfd_nonfatal (targ->name);
298 param->error = 1;
06d86cf7 299 }
aac502f7
AM
300 }
301 else
302 {
303 enum bfd_architecture a;
06d86cf7 304
91610c0c 305 for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++)
aac502f7
AM
306 if (bfd_set_arch_mach (abfd, a, 0))
307 {
308 printf (" %s\n", bfd_printable_arch_mach (a, 0));
309 param->info[param->count - 1].arch[a - bfd_arch_obscure - 1] = 1;
310 }
06d86cf7 311 }
aac502f7
AM
312 if (abfd != NULL)
313 bfd_close_all_done (abfd);
06d86cf7 314
aac502f7 315 return param->error;
06d86cf7
NC
316}
317
aac502f7
AM
318static void
319display_target_list (struct display_target *arg)
320{
321 arg->filename = make_temp_file (NULL);
322 arg->error = 0;
323 arg->count = 0;
324 arg->alloc = 0;
325 arg->info = NULL;
326
327 bfd_iterate_over_targets (do_display_target, arg);
328
329 unlink (arg->filename);
330 free (arg->filename);
331}
332
333/* Calculate how many targets we can print across the page. */
06d86cf7
NC
334
335static int
aac502f7 336do_info_size (int targ, int width, const struct display_target *arg)
06d86cf7 337{
aac502f7
AM
338 while (targ < arg->count)
339 {
340 width -= strlen (arg->info[targ].name) + 1;
341 if (width < 0)
342 return targ;
343 ++targ;
344 }
345 return targ;
346}
347
348/* Print header of target names. */
06d86cf7 349
aac502f7
AM
350static void
351do_info_header (int targ, int stop_targ, const struct display_target *arg)
352{
353 while (targ != stop_targ)
354 printf ("%s ", arg->info[targ++].name);
355}
356
357/* Print a table row. */
358
359static void
360do_info_row (int targ, int stop_targ, enum bfd_architecture a,
361 const struct display_target *arg)
362{
363 while (targ != stop_targ)
364 {
365 if (arg->info[targ].arch[a - bfd_arch_obscure - 1])
366 fputs (arg->info[targ].name, stdout);
367 else
368 {
369 int l = strlen (arg->info[targ].name);
370 while (l--)
371 putchar ('-');
372 }
373 ++targ;
374 if (targ != stop_targ)
375 putchar (' ');
376 }
06d86cf7
NC
377}
378
379/* Print tables of all the target-architecture combinations that
380 BFD has been configured to support. */
381
aac502f7
AM
382static void
383display_target_tables (const struct display_target *arg)
06d86cf7 384{
aac502f7
AM
385 const char *columns;
386 int width, start_targ, stop_targ;
387 enum bfd_architecture arch;
388 int longest_arch = 0;
389
390 for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
06d86cf7 391 {
aac502f7
AM
392 const char *s = bfd_printable_arch_mach (arch, 0);
393 int len = strlen (s);
394 if (len > longest_arch)
395 longest_arch = len;
396 }
06d86cf7 397
aac502f7
AM
398 width = 0;
399 columns = getenv ("COLUMNS");
400 if (columns != NULL)
401 width = atoi (columns);
402 if (width == 0)
403 width = 80;
404
405 for (start_targ = 0; start_targ < arg->count; start_targ = stop_targ)
406 {
407 stop_targ = do_info_size (start_targ, width - longest_arch - 1, arg);
408
409 printf ("\n%*s", longest_arch + 1, " ");
410 do_info_header (start_targ, stop_targ, arg);
411 putchar ('\n');
06d86cf7 412
aac502f7
AM
413 for (arch = bfd_arch_obscure + 1; arch < bfd_arch_last; arch++)
414 {
415 if (strcmp (bfd_printable_arch_mach (arch, 0), "UNKNOWN!") != 0)
416 {
417 printf ("%*s ", longest_arch,
418 bfd_printable_arch_mach (arch, 0));
419
420 do_info_row (start_targ, stop_targ, arch, arg);
421 putchar ('\n');
422 }
06d86cf7 423 }
06d86cf7 424 }
06d86cf7
NC
425}
426
427int
2da42df6 428display_info (void)
06d86cf7 429{
aac502f7
AM
430 struct display_target arg;
431
06d86cf7 432 printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
aac502f7
AM
433
434 display_target_list (&arg);
435 if (!arg.error)
436 display_target_tables (&arg);
437
438 return arg.error;
06d86cf7
NC
439}
440\f
252b5132
RH
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
445void
015dc7e1 446print_arelt_descr (FILE *file, bfd *abfd, bool verbose, bool offsets)
252b5132
RH
447{
448 struct stat buf;
449
450 if (verbose)
451 {
452 if (bfd_stat_arch_elt (abfd, &buf) == 0)
453 {
454 char modebuf[11];
455 char timebuf[40];
456 time_t when = buf.st_mtime;
b1f88ebe 457 const char *ctime_result = (const char *) ctime (&when);
252b5132 458
0593bd3a
NC
459 /* PR binutils/17605: Check for corrupt time values. */
460 if (ctime_result == NULL)
461 sprintf (timebuf, _("<time data corrupt>"));
462 else
463 /* POSIX format: skip weekday and seconds from ctime output. */
464 sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
252b5132
RH
465
466 mode_string (buf.st_mode, modebuf);
467 modebuf[10] = '\0';
468 /* POSIX 1003.2/D11 says to skip first character (entry type). */
b8281767 469 fprintf (file, "%s %ld/%ld %6" PRIu64 " %s ", modebuf + 1,
252b5132 470 (long) buf.st_uid, (long) buf.st_gid,
b8281767 471 (uint64_t) buf.st_size, timebuf);
252b5132
RH
472 }
473 }
474
1869e86f
AB
475 fprintf (file, "%s", bfd_get_filename (abfd));
476
477 if (offsets)
478 {
479 if (bfd_is_thin_archive (abfd) && abfd->proxy_origin)
480 fprintf (file, " 0x%lx", (unsigned long) abfd->proxy_origin);
481 else if (!bfd_is_thin_archive (abfd) && abfd->origin)
482 fprintf (file, " 0x%lx", (unsigned long) abfd->origin);
483 }
484
485 fprintf (file, "\n");
252b5132
RH
486}
487
485be063
AM
488/* Return a path for a new temporary file in the same directory
489 as file PATH. */
252b5132 490
485be063
AM
491static char *
492template_in_dir (const char *path)
252b5132 493{
485be063 494#define template "stXXXXXX"
2946671e 495 const char *slash = strrchr (path, '/');
252b5132 496 char *tmpname;
485be063 497 size_t len;
252b5132 498
5af11cab
AM
499#ifdef HAVE_DOS_BASED_FILE_SYSTEM
500 {
501 /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
485be063 502 char *bslash = strrchr (path, '\\');
f9c026a8 503
2ab47eed 504 if (slash == NULL || (bslash != NULL && bslash > slash))
5af11cab 505 slash = bslash;
485be063 506 if (slash == NULL && path[0] != '\0' && path[1] == ':')
2946671e 507 slash = path + 1;
5af11cab 508 }
252b5132
RH
509#endif
510
511 if (slash != (char *) NULL)
512 {
485be063 513 len = slash - path;
3f5e193b 514 tmpname = (char *) xmalloc (len + sizeof (template) + 2);
485be063 515 memcpy (tmpname, path, len);
252b5132 516
5af11cab
AM
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. */
485be063
AM
521 if (len == 2 && tmpname[1] == ':')
522 tmpname[len++] = '.';
5af11cab 523#endif
485be063 524 tmpname[len++] = '/';
252b5132
RH
525 }
526 else
527 {
3f5e193b 528 tmpname = (char *) xmalloc (sizeof (template));
485be063 529 len = 0;
f9c026a8 530 }
485be063
AM
531
532 memcpy (tmpname + len, template, sizeof (template));
533 return tmpname;
534#undef template
535}
536
537/* Return the name of a created temporary file in the same directory
538 as FILENAME. */
539
540char *
365f5fb6 541make_tempname (const char *filename, int *ofd)
485be063
AM
542{
543 char *tmpname = template_in_dir (filename);
544 int fd;
545
546#ifdef HAVE_MKSTEMP
547 fd = mkstemp (tmpname);
548#else
549 tmpname = mktemp (tmpname);
550 if (tmpname == NULL)
d6e1d48c
AM
551 fd = -1;
552 else
553 fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600);
f9c026a8 554#endif
485be063 555 if (fd == -1)
c48d800e
NC
556 {
557 free (tmpname);
5e39600a 558 bfd_set_error (bfd_error_system_call);
c48d800e
NC
559 return NULL;
560 }
365f5fb6 561 *ofd = fd;
f9c026a8
NC
562 return tmpname;
563}
564
485be063
AM
565/* Return the name of a created temporary directory inside the
566 directory containing FILENAME. */
f9c026a8
NC
567
568char *
1ff5d5c4 569make_tempdir (const char *filename)
f9c026a8 570{
485be063 571 char *tmpname = template_in_dir (filename);
d6e1d48c 572 char *ret;
f9c026a8 573
485be063 574#ifdef HAVE_MKDTEMP
d6e1d48c 575 ret = mkdtemp (tmpname);
485be063 576#else
d6e1d48c 577 ret = mktemp (tmpname);
485be063
AM
578#if defined (_WIN32) && !defined (__CYGWIN32__)
579 if (mkdir (tmpname) != 0)
d6e1d48c 580 ret = NULL;
485be063
AM
581#else
582 if (mkdir (tmpname, 0700) != 0)
d6e1d48c 583 ret = NULL;
f9c026a8 584#endif
485be063 585#endif
d6e1d48c 586 if (ret == NULL)
5e39600a
AM
587 {
588 free (tmpname);
589 bfd_set_error (bfd_error_system_call);
590 }
d6e1d48c 591 return ret;
252b5132
RH
592}
593
594/* Parse a string into a VMA, with a fatal error if it can't be
595 parsed. */
596
597bfd_vma
2da42df6 598parse_vma (const char *s, const char *arg)
252b5132
RH
599{
600 bfd_vma ret;
601 const char *end;
602
603 ret = bfd_scan_vma (s, &end, 0);
f462a9ea 604
252b5132
RH
605 if (*end != '\0')
606 fatal (_("%s: bad number: %s"), arg, s);
607
608 return ret;
609}
f24ddbdd
NC
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
a3029abd 613 error message is printed and (off_t) -1 is returned. */
f24ddbdd
NC
614
615off_t
616get_file_size (const char * file_name)
617{
618 struct stat statbuf;
3aade688 619
740a4630
NC
620 if (file_name == NULL)
621 return (off_t) -1;
622
f24ddbdd
NC
623 if (stat (file_name, &statbuf) < 0)
624 {
625 if (errno == ENOENT)
626 non_fatal (_("'%s': No such file"), file_name);
627 else
628 non_fatal (_("Warning: could not locate '%s'. reason: %s"),
629 file_name, strerror (errno));
3aade688 630 }
0602cdad
NC
631 else if (S_ISDIR (statbuf.st_mode))
632 non_fatal (_("Warning: '%s' is a directory"), file_name);
f24ddbdd
NC
633 else if (! S_ISREG (statbuf.st_mode))
634 non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
9849fbfc
NC
635 else if (statbuf.st_size < 0)
636 non_fatal (_("Warning: '%s' has negative size, probably it is too large"),
637 file_name);
a7ad3cb1
EZ
638#if defined (_WIN32) && !defined (__CYGWIN__)
639 else if (statbuf.st_size == 0)
640 {
887854ba
EZ
641 /* MS-Windows 'stat' reports the null device as a regular file;
642 fix that. */
a7ad3cb1
EZ
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
f24ddbdd
NC
653 else
654 return statbuf.st_size;
655
52a476ee 656 return (off_t) -1;
f24ddbdd 657}
77f762d6
L
658
659/* Return the filename in a static buffer. */
660
661const char *
8d8e0703 662bfd_get_archive_filename (const bfd *abfd)
77f762d6
L
663{
664 static size_t curr = 0;
665 static char *buf;
666 size_t needed;
667
668 assert (abfd != NULL);
3aade688 669
b0cffb47
AM
670 if (abfd->my_archive == NULL
671 || bfd_is_thin_archive (abfd->my_archive))
77f762d6
L
672 return bfd_get_filename (abfd);
673
674 needed = (strlen (bfd_get_filename (abfd->my_archive))
675 + strlen (bfd_get_filename (abfd)) + 3);
676 if (needed > curr)
677 {
678 if (curr)
679 free (buf);
680 curr = needed + (needed >> 1);
76e7a751 681 buf = (char *) xmalloc (curr);
77f762d6
L
682 }
683 sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive),
684 bfd_get_filename (abfd));
685 return buf;
686}
dd9b91de
NC
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
015dc7e1 692bool
dd9b91de
NC
693is_valid_archive_path (char const * pathname)
694{
695 const char * n = pathname;
696
697 if (IS_ABSOLUTE_PATH (n))
015dc7e1 698 return false;
dd9b91de
NC
699
700 while (*n)
701 {
702 if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n)))
015dc7e1 703 return false;
dd9b91de
NC
704
705 while (*n && ! IS_DIR_SEPARATOR (*n))
706 n++;
707 while (IS_DIR_SEPARATOR (*n))
708 n++;
709 }
710
015dc7e1 711 return true;
dd9b91de 712}