BSD 4.4 uses a third scheme: It writes a long filename
directly after the header. This allows 'ar q' to work.
- We currently can read BSD 4.4 archives, but not write them.
*/
/* Summary of archive member names:
"/18 " - SVR4 style, name at offset 18 in name table.
"#1/23 " - Long name (or embedded spaces) 23 characters long,
BSD 4.4 style, full name follows header.
- Implemented for reading, not writing.
" 18 " - Long name 18 characters long, extended pseudo-BSD.
*/
#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
#define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata (bfd)->arch_header)
+
+/* True iff NAME designated a BSD 4.4 extended name. */
+
+#define is_bsd44_extended_name(NAME) \
+ (NAME[0] == '#' && NAME[1] == '1' && NAME[2] == '/' && ISDIGIT (NAME[3]))
\f
void
_bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val)
return arc1->ptr == arc2->ptr;
}
+/* The calloc function doesn't always take size_t (e.g. on VMS)
+ so wrap it to avoid a compile time warning. */
+
+static void *
+_bfd_calloc_wrapper (size_t a, size_t b)
+{
+ return calloc (a, b);
+}
+
/* Kind of stupid to call cons for each one, but we don't do too many. */
bfd_boolean
if (hash_table == NULL)
{
hash_table = htab_create_alloc (16, hash_file_ptr, eq_file_ptr,
- NULL, calloc, free);
+ NULL, _bfd_calloc_wrapper, free);
if (hash_table == NULL)
return FALSE;
bfd_ardata (arch_bfd)->cache = hash_table;
bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr);
char *allocptr = 0;
file_ptr origin = 0;
+ unsigned int extra_size = 0;
if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr))
{
if (filename == NULL)
return NULL;
}
- /* BSD4.4-style long filename.
- Only implemented for reading, so far! */
- else if (hdr.ar_name[0] == '#'
- && hdr.ar_name[1] == '1'
- && hdr.ar_name[2] == '/'
- && ISDIGIT (hdr.ar_name[3]))
+ /* BSD4.4-style long filename. */
+ else if (is_bsd44_extended_name (hdr.ar_name))
{
/* BSD-4.4 extended name */
namelen = atoi (&hdr.ar_name[3]);
allocsize += namelen + 1;
parsed_size -= namelen;
+ extra_size = namelen;
allocptr = (char *) bfd_zalloc (abfd, allocsize);
if (allocptr == NULL)
ared->arch_header = allocptr + sizeof (struct areltdata);
memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr));
ared->parsed_size = parsed_size;
+ ared->extra_size = extra_size;
ared->origin = origin;
if (filename != NULL)
/* Append the relative pathname for a member of the thin archive
to the pathname of the directory containing the archive. */
-static char *
-append_relative_path (bfd *arch, char *elt_name)
+char *
+_bfd_append_relative_path (bfd *arch, char *elt_name)
{
const char *arch_name = arch->filename;
const char *base_name = lbasename (arch_name);
/* This is a proxy entry for an external file. */
if (! IS_ABSOLUTE_PATH (filename))
{
- filename = append_relative_path (archive, filename);
+ filename = _bfd_append_relative_path (archive, filename);
if (filename == NULL)
return NULL;
}
return FALSE;
#endif
}
+ else if (CONST_STRNEQ (nextname, "#1/20 "))
+ {
+ /* Mach-O has a special name for armap when the map is sorted by name.
+ However because this name has a space it is slightly more difficult
+ to check it. */
+ struct ar_hdr hdr;
+ char extname[21];
+
+ if (bfd_bread (&hdr, sizeof (hdr), abfd) != sizeof (hdr))
+ return FALSE;
+ /* Read the extended name. We know its length. */
+ if (bfd_bread (extname, 20, abfd) != 20)
+ return FALSE;
+ if (bfd_seek (abfd, (file_ptr) -(sizeof (hdr) + 20), SEEK_CUR) != 0)
+ return FALSE;
+ if (CONST_STRNEQ (extname, "__.SYMDEF SORTED")
+ || CONST_STRNEQ (extname, "__.SYMDEF"))
+ return do_slurp_bsd_armap (abfd);
+ }
bfd_has_map (abfd) = FALSE;
return TRUE;
static const char *
normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file)
{
- const char *filename = strrchr (file, '/');
-
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
- {
- /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
- char *bslash = strrchr (file, '\\');
- if (filename == NULL || (bslash != NULL && bslash > filename))
- filename = bslash;
- if (filename == NULL && file[0] != '\0' && file[1] == ':')
- filename = file + 1;
- }
-#endif
- if (filename != NULL)
- filename++;
- else
- filename = file;
- return filename;
+ return lbasename (file);
}
#endif
return TRUE;
}
+
+/* Do not construct an extended name table but transforms name field into
+ its extended form. */
+
+bfd_boolean
+_bfd_archive_bsd44_construct_extended_name_table (bfd *abfd,
+ char **tabloc,
+ bfd_size_type *tablen,
+ const char **name)
+{
+ unsigned int maxname = abfd->xvec->ar_max_namelen;
+ bfd *current;
+
+ *tablen = 0;
+ *tabloc = NULL;
+ *name = NULL;
+
+ for (current = abfd->archive_head;
+ current != NULL;
+ current = current->archive_next)
+ {
+ const char *normal = normalize (current, current->filename);
+ int has_space = 0;
+ unsigned int len;
+
+ if (normal == NULL)
+ return FALSE;
+
+ for (len = 0; normal[len]; len++)
+ if (normal[len] == ' ')
+ has_space = 1;
+
+ if (len > maxname || has_space)
+ {
+ struct ar_hdr *hdr = arch_hdr (current);
+
+ len = (len + 3) & ~3;
+ arch_eltdata (current)->extra_size = len;
+ _bfd_ar_spacepad (hdr->ar_name, maxname, "#1/%lu", len);
+ }
+ }
+
+ return TRUE;
+}
+\f
+/* Write an archive header. */
+
+bfd_boolean
+_bfd_generic_write_ar_hdr (bfd *archive, bfd *abfd)
+{
+ struct ar_hdr *hdr = arch_hdr (abfd);
+
+ if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr))
+ return FALSE;
+ return TRUE;
+}
+
+/* Write an archive header using BSD4.4 convention. */
+
+bfd_boolean
+_bfd_bsd44_write_ar_hdr (bfd *archive, bfd *abfd)
+{
+ struct ar_hdr *hdr = arch_hdr (abfd);
+
+ if (is_bsd44_extended_name (hdr->ar_name))
+ {
+ /* This is a BSD 4.4 extended name. */
+ const char *fullname = normalize (abfd, abfd->filename);
+ unsigned int len = strlen (fullname);
+ unsigned int padded_len = (len + 3) & ~3;
+
+ BFD_ASSERT (padded_len == arch_eltdata (abfd)->extra_size);
+
+ _bfd_ar_spacepad (hdr->ar_size, sizeof (hdr->ar_size), "%-10ld",
+ arch_eltdata (abfd)->parsed_size + padded_len);
+
+ if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr))
+ return FALSE;
+
+ if (bfd_bwrite (fullname, len, archive) != len)
+ return FALSE;
+ if (len & 3)
+ {
+ static const char pad[3] = { 0, 0, 0 };
+
+ len = 4 - (len & 3);
+ if (bfd_bwrite (pad, len, archive) != len)
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr))
+ return FALSE;
+ }
+ return TRUE;
+}
\f
/* A couple of functions for creating ar_hdrs. */
{
struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
size_t length;
- const char *filename = strrchr (pathname, '/');
+ const char *filename = lbasename (pathname);
size_t maxlen = ar_maxnamelen (abfd);
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
- {
- /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
- char *bslash = strrchr (pathname, '\\');
- if (filename == NULL || (bslash != NULL && bslash > filename))
- filename = bslash;
- if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
- filename = pathname + 1;
- }
-#endif
-
- if (filename == NULL)
- filename = pathname;
- else
- ++filename;
-
length = strlen (filename);
if (length <= maxlen)
{
struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
size_t length;
- const char *filename = strrchr (pathname, '/');
+ const char *filename = lbasename (pathname);
size_t maxlen = ar_maxnamelen (abfd);
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
- {
- /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
- char *bslash = strrchr (pathname, '\\');
-
- if (filename == NULL || (bslash != NULL && bslash > filename))
- filename = bslash;
- if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
- filename = pathname + 1;
- }
-#endif
-
- if (filename == NULL)
- filename = pathname;
- else
- ++filename;
-
length = strlen (filename);
if (length <= maxlen)
{
char buffer[DEFAULT_BUFFERSIZE];
unsigned int remaining = arelt_size (current);
- struct ar_hdr *hdr = arch_hdr (current);
/* Write ar header. */
- if (bfd_bwrite (hdr, sizeof (*hdr), arch)
- != sizeof (*hdr))
- return FALSE;
+ if (!_bfd_write_ar_hdr (arch, current))
+ return FALSE;
if (bfd_is_thin_archive (arch))
continue;
if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0)
if ((flags & BSF_GLOBAL
|| flags & BSF_WEAK
|| flags & BSF_INDIRECT
+ || flags & BSF_GNU_UNIQUE
|| bfd_is_com_section (sec))
&& ! bfd_is_und_section (sec))
{
{
do
{
- firstreal += arelt_size (current) + sizeof (struct ar_hdr);
+ struct areltdata *ared = arch_eltdata (current);
+
+ firstreal += (ared->parsed_size + ared->extra_size
+ + sizeof (struct ar_hdr));
firstreal += firstreal % 2;
current = current->archive_next;
}