2000-09-12 Jason Eckhardt <jle@cygnus.com>
[deliverable/binutils-gdb.git] / bfd / archive.c
index 10bf43c2b7f4a602d45f3297f44e8c9191961c09..8807a525bc5f33c9448a9a6bb812a19f53fec36c 100644 (file)
@@ -1,5 +1,5 @@
 /* BFD back-end for archive files (libraries).
-   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 1998
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
    Free Software Foundation, Inc.
    Written by Cygnus Support.  Mostly Gumby Henkel-Wallace's fault.
 
@@ -131,8 +131,6 @@ DESCRIPTION
 #include "libbfd.h"
 #include "aout/ar.h"
 #include "aout/ranlib.h"
-#include <errno.h>
-#include <string.h>            /* For memchr, strrchr and friends */
 #include <ctype.h>
 
 #ifndef errno
@@ -175,7 +173,8 @@ static boolean do_slurp_bsd_armap PARAMS ((bfd *abfd));
 static boolean do_slurp_coff_armap PARAMS ((bfd *abfd));
 static const char *normalize PARAMS ((bfd *, const char *file));
 static struct areltdata *bfd_ar_hdr_from_filesystem PARAMS ((bfd *abfd,
-                                                            const char *));
+                                                            const char *,
+                                                            bfd *member));
 \f
 boolean
 _bfd_generic_mkarchive (abfd)
@@ -317,7 +316,7 @@ _bfd_add_bfd_to_archive_cache (arch_bfd, filepos, new_elt)
 }
 \f
 /* The name begins with space.  Hence the rest of the name is an index into
-   the string table. */
+   the string table.  */
 
 static char *
 get_extended_arelt_filename (arch, name)
@@ -327,9 +326,9 @@ get_extended_arelt_filename (arch, name)
   unsigned long index = 0;
 
   /* Should extract string so that I can guarantee not to overflow into
-     the next region, but I'm too lazy. */
+     the next region, but I'm too lazy.  */
   errno = 0;
-  /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */
+  /* Skip first char, which is '/' in SVR4 or ' ' in some other variants.  */
   index = strtol (name + 1, NULL, 10);
   if (errno != 0)
     {
@@ -397,7 +396,7 @@ _bfd_generic_read_ar_hdr_mag (abfd, mag)
     }
 
   /* Extract the filename from the archive - there are two ways to
-     specify an extendend name table, either the first char of the
+     specify an extended name table, either the first char of the
      name is a space, or it's a slash.  */
   if ((hdr.ar_name[0] == '/'
        || (hdr.ar_name[0] == ' '
@@ -441,23 +440,26 @@ _bfd_generic_read_ar_hdr_mag (abfd, mag)
     {
       /* We judge the end of the name by looking for '/' or ' '.
         Note:  The SYSV format (terminated by '/') allows embedded
-        spaces, so only look for ' ' if we don't find '/'. */
+        spaces, so only look for ' ' if we don't find '/'.  */
 
       char *e;
-      e = memchr(hdr.ar_name, '\0', ar_maxnamelen (abfd));
+      e = memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd));
       if (e == NULL)
        {
-          e = memchr(hdr.ar_name, '/', ar_maxnamelen (abfd));
+          e = memchr (hdr.ar_name, '/', ar_maxnamelen (abfd));
          if (e == NULL)
-            e = memchr(hdr.ar_name, ' ', ar_maxnamelen (abfd));
+            e = memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd));
        }
-      if (e == NULL)
+
+      if (e != NULL)
+       namelen = e - hdr.ar_name;
+      else
        {
-         bfd_set_error (bfd_error_malformed_archive);
-         return NULL;
+         /* If we didn't find a termination character, then the name
+            must be the entire field.  */
+         namelen = ar_maxnamelen (abfd);
        }
 
-      namelen = e - hdr.ar_name;
       allocsize += namelen + 1;
     }
 
@@ -593,7 +595,7 @@ bfd_generic_openr_next_archived_file (archive, last_file)
       unsigned int size = arelt_size (last_file);
       /* Pad to an even boundary...
         Note that last_file->origin can be odd in the case of
-        BSD-4.4-style element with a long odd size. */
+        BSD-4.4-style element with a long odd size.  */
       filestart = last_file->origin + size;
       filestart += filestart % 2;
     }
@@ -601,7 +603,6 @@ bfd_generic_openr_next_archived_file (archive, last_file)
   return _bfd_get_elt_at_filepos (archive, filestart);
 }
 
-
 const bfd_target *
 bfd_generic_archive_p (abfd)
      bfd *abfd;
@@ -628,7 +629,7 @@ bfd_generic_archive_p (abfd)
 #endif
 
   /* We are setting bfd_ardata(abfd) here, but since bfd_ardata
-     involves a cast, we can't do it as the left operand of assignment. */
+     involves a cast, we can't do it as the left operand of assignment.  */
   abfd->tdata.aout_ar_data = ((struct artdata *)
                              bfd_zalloc (abfd, sizeof (struct artdata)));
 
@@ -735,7 +736,7 @@ do_slurp_bsd_armap (abfd)
   if (mapdata == NULL)
     return false;
   parsed_size = mapdata->parsed_size;
-  bfd_release (abfd, (PTR) mapdata);   /* Don't need it any more. */
+  bfd_release (abfd, (PTR) mapdata);   /* Don't need it any more.  */
 
   raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size);
   if (raw_armap == (bfd_byte *) NULL)
@@ -784,7 +785,7 @@ do_slurp_bsd_armap (abfd)
   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
   /* FIXME, we should provide some way to free raw_ardata when
      we are done using the strings from it.  For now, it seems
-     to be allocated on an objalloc anyway... */
+     to be allocated on an objalloc anyway...  */
   bfd_has_map (abfd) = true;
   return true;
 }
@@ -801,7 +802,7 @@ do_slurp_coff_armap (abfd)
   unsigned int stringsize;
   unsigned int parsed_size;
   carsym *carsyms;
-  unsigned int nsymz;          /* Number of symbols in armap. */
+  unsigned int nsymz;          /* Number of symbols in armap.  */
   bfd_vma (*swap) PARAMS ((const bfd_byte *));
   char int_buf[sizeof (long)];
   unsigned int carsym_size, ptrsize, i;
@@ -810,7 +811,7 @@ do_slurp_coff_armap (abfd)
   if (mapdata == NULL)
     return false;
   parsed_size = mapdata->parsed_size;
-  bfd_release (abfd, (PTR) mapdata);   /* Don't need it any more. */
+  bfd_release (abfd, (PTR) mapdata);   /* Don't need it any more.  */
 
   if (bfd_read ((PTR) int_buf, 1, 4, abfd) != 4)
     {
@@ -819,7 +820,7 @@ do_slurp_coff_armap (abfd)
       return false;
     }
   /* It seems that all numeric information in a coff archive is always
-     in big endian format, nomatter the host or target. */
+     in big endian format, nomatter the host or target.  */
   swap = bfd_getb32;
   nsymz = bfd_getb32 ((PTR) int_buf);
   stringsize = parsed_size - (4 * nsymz) - 4;
@@ -842,7 +843,7 @@ do_slurp_coff_armap (abfd)
 #endif
 
   /* The coff armap must be read sequentially.  So we construct a
-     bsd-style one in core all at once, for simplicity. */
+     bsd-style one in core all at once, for simplicity.  */
 
   carsym_size = (nsymz * sizeof (carsym));
   ptrsize = (4 * nsymz);
@@ -853,7 +854,7 @@ do_slurp_coff_armap (abfd)
   carsyms = ardata->symdefs;
   stringbase = ((char *) ardata->symdefs) + carsym_size;
 
-  /* Allocate and read in the raw offsets. */
+  /* Allocate and read in the raw offsets.  */
   raw_armap = (int *) bfd_alloc (abfd, ptrsize);
   if (raw_armap == NULL)
     goto release_symdefs;
@@ -881,21 +882,19 @@ do_slurp_coff_armap (abfd)
   /* Pad to an even boundary if you have to */
   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
 
-
   bfd_has_map (abfd) = true;
   bfd_release (abfd, (PTR) raw_armap);
 
-
   /* Check for a second archive header (as used by PE) */
   {
     struct areltdata *tmp;
 
     bfd_seek (abfd,   ardata->first_file_filepos, SEEK_SET);
     tmp = (struct areltdata *) _bfd_read_ar_hdr (abfd);
-    if (tmp != NULL) 
+    if (tmp != NULL)
       {
        if (tmp->arch_header[0] == '/'
-           && tmp->arch_header[1] == ' ') 
+           && tmp->arch_header[1] == ' ')
          {
            ardata->first_file_filepos +=
              (tmp->parsed_size + sizeof(struct ar_hdr) + 1) & ~1;
@@ -950,7 +949,7 @@ bfd_slurp_armap (abfd)
 /* Returns false on error, true otherwise */
 /* flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the
    header is in a slightly different order and the map name is '/'.
-   This flavour is used by hp300hpux. */
+   This flavour is used by hp300hpux.  */
 
 #define HPUX_SYMDEF_COUNT_SIZE 2
 
@@ -1046,7 +1045,7 @@ bfd_slurp_bsd_armap_f2 (abfd)
   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
   /* FIXME, we should provide some way to free raw_ardata when
      we are done using the strings from it.  For now, it seems
-     to be allocated on an objalloc anyway... */
+     to be allocated on an objalloc anyway...  */
   bfd_has_map (abfd) = true;
   return true;
 }
@@ -1129,7 +1128,7 @@ _bfd_slurp_extended_name_table (abfd)
        (bfd_ardata (abfd)->first_file_filepos) % 2;
 
       /* FIXME, we can't release namedata here because it was allocated
-        below extended_names on the objalloc... */
+        below extended_names on the objalloc...  */
       /* bfd_release (abfd, namedata); */
     }
   return true;
@@ -1176,11 +1175,21 @@ normalize (abfd, file)
 #else
 static const char *
 normalize (abfd, file)
-     bfd *abfd;
+     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 != (char *) NULL)
     filename++;
   else
@@ -1305,7 +1314,7 @@ _bfd_construct_extended_name_table (abfd, trailing_slash, tabloc, tablen)
        {
          /* Works for now; may need to be re-engineered if we
             encounter an oddball archive format and want to
-            generalise this hack. */
+            generalise this hack.  */
          struct ar_hdr *hdr = arch_hdr (current);
          strcpy (strptr, normal);
          if (! trailing_slash)
@@ -1317,7 +1326,7 @@ _bfd_construct_extended_name_table (abfd, trailing_slash, tabloc, tablen)
            }
          hdr->ar_name[0] = ar_padchar (current);
          /* We know there will always be enough room (one of the few
-            cases where you may safely use sprintf). */
+            cases where you may safely use sprintf).  */
          sprintf ((hdr->ar_name) + 1, "%-d", (unsigned) (strptr - *tabloc));
          /* Kinda Kludgy.  We should just use the returned value of
             sprintf but not all implementations get this right */
@@ -1338,21 +1347,58 @@ _bfd_construct_extended_name_table (abfd, trailing_slash, tabloc, tablen)
 \f
 /** A couple of functions for creating ar_hdrs */
 
+#ifdef HPUX_LARGE_AR_IDS
+/* Function to encode large UID/GID values according to HP.  */
+static void
+hpux_uid_gid_encode (str, id)
+     char str[6];
+     long int id;
+{
+  int cnt;
+
+  str[5] = '@' + (id & 3);
+  id >>= 2;
+
+  for (cnt = 4; cnt >= 0; ++cnt, id >>= 6)
+    str[cnt] = ' ' + (id & 0x3f);
+}
+#endif /* HPUX_LARGE_AR_IDS */
+
+#ifndef HAVE_GETUID
+#define getuid() 0
+#endif
+
+#ifndef HAVE_GETGID
+#define getgid() 0
+#endif
+
 /* Takes a filename, returns an arelt_data for it, or NULL if it can't
    make one.  The filename must refer to a filename in the filesystem.
-   The filename field of the ar_hdr will NOT be initialized */
+   The filename field of the ar_hdr will NOT be initialized.  If member
+   is set, and it's an in-memory bfd, we fake it.  */
 
 static struct areltdata *
-bfd_ar_hdr_from_filesystem (abfd, filename)
+bfd_ar_hdr_from_filesystem (abfd, filename, member)
      bfd *abfd;
      const char *filename;
+     bfd *member;
 {
   struct stat status;
   struct areltdata *ared;
   struct ar_hdr *hdr;
   char *temp, *temp1;
 
-  if (stat (filename, &status) != 0)
+  if (member && (member->flags & BFD_IN_MEMORY) != 0)
+    {
+      /* Assume we just "made" the member, and fake it */
+      struct bfd_in_memory *bim = (struct bfd_in_memory *) member->iostream;
+      time(&status.st_mtime);
+      status.st_uid = getuid();
+      status.st_gid = getgid();
+      status.st_mode = 0644;
+      status.st_size = bim->size;
+    }
+  else if (stat (filename, &status) != 0)
     {
       bfd_set_error (bfd_error_system_call);
       return NULL;
@@ -1371,7 +1417,21 @@ bfd_ar_hdr_from_filesystem (abfd, filename)
 
   /* Goddamned sprintf doesn't permit MAXIMUM field lengths */
   sprintf ((hdr->ar_date), "%-12ld", (long) status.st_mtime);
-  sprintf ((hdr->ar_uid), "%ld", (long) status.st_uid);
+#ifdef HPUX_LARGE_AR_IDS
+  /* HP has a very "special" way to handle UID/GID's with numeric values
+     > 99999.  */
+  if (status.st_uid > 99999)
+    hpux_uid_gid_encode (hdr->ar_gid, (long) status.st_uid);
+  else
+#endif
+    sprintf ((hdr->ar_uid), "%ld", (long) status.st_uid);
+#ifdef HPUX_LARGE_AR_IDS
+  /* HP has a very "special" way to handle UID/GID's with numeric values
+     > 99999.  */
+  if (status.st_gid > 99999)
+    hpux_uid_gid_encode (hdr->ar_uid, (long) status.st_gid);
+  else
+#endif
   sprintf ((hdr->ar_gid), "%ld", (long) status.st_gid);
   sprintf ((hdr->ar_mode), "%-8o", (unsigned int) status.st_mode);
   sprintf ((hdr->ar_size), "%-10ld", (long) status.st_size);
@@ -1404,13 +1464,12 @@ bfd_special_undocumented_glue (abfd, filename)
      bfd *abfd;
      const char *filename;
 {
-  struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename);
+  struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename, 0);
   if (ar_elt == NULL)
     return NULL;
   return (struct ar_hdr *) ar_elt->arch_header;
 }
 
-
 /* Analogous to stat call */
 int
 bfd_generic_stat_arch_elt (abfd, buf)
@@ -1431,10 +1490,30 @@ bfd_generic_stat_arch_elt (abfd, buf)
 #define foo(arelt, stelt, size)  \
   buf->stelt = strtol (hdr->arelt, &aloser, size); \
   if (aloser == hdr->arelt) return -1;
+  /* Some platforms support special notations for large IDs.  */
+#ifdef HPUX_LARGE_AR_IDS
+# define foo2(arelt, stelt, size) \
+  if (hdr->arelt[5] == ' ') { foo (arelt, stelt, size); } \
+  else { \
+    int cnt; \
+    for (buf->stelt = cnt = 0; cnt < 5; ++cnt) \
+      { \
+       if (hdr->arelt[cnt] < ' ' || hdr->arelt[cnt] > ' ' + 0x3f) \
+         return -1; \
+       buf->stelt <<= 6; \
+       buf->stelt += hdr->arelt[cnt] - ' '; \
+      } \
+    if (hdr->arelt[5] < '@' || hdr->arelt[5] > '@' + 3) return -1; \
+    buf->stelt <<= 2; \
+    buf->stelt += hdr->arelt[5] - '@'; \
+  }
+#else
+# define foo2(arelt, stelt, size) foo (arelt, stelt, size)
+#endif
 
   foo (ar_date, st_mtime, 10);
-  foo (ar_uid, st_uid, 10);
-  foo (ar_gid, st_gid, 10);
+  foo2 (ar_uid, st_uid, 10);
+  foo2 (ar_gid, st_gid, 10);
   foo (ar_mode, st_mode, 8);
 
   buf->st_size = arch_eltdata (abfd)->parsed_size;
@@ -1451,7 +1530,7 @@ bfd_dont_truncate_arname (abfd, pathname, arhdr)
   /* FIXME: This interacts unpleasantly with ar's quick-append option.
      Fortunately ic960 users will never use that option.  Fixing this
      is very hard; fortunately I know how to do it and will do so once
-     intel's release is out the door. */
+     intel's release is out the door.  */
 
   struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
   size_t length;
@@ -1493,6 +1572,17 @@ bfd_bsd_truncate_arname (abfd, pathname, arhdr)
   CONST char *filename = strrchr (pathname, '/');
   int 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
@@ -1520,7 +1610,7 @@ bfd_bsd_truncate_arname (abfd, pathname, arhdr)
    4> truncate it before the .o, append .o, stuff THAT in.  */
 
 /* This is what gnu ar does.  It's better but incompatible with the
-   bsd ar. */
+   bsd ar.  */
 
 void
 bfd_gnu_truncate_arname (abfd, pathname, arhdr)
@@ -1533,6 +1623,17 @@ bfd_gnu_truncate_arname (abfd, pathname, arhdr)
   CONST char *filename = strrchr (pathname, '/');
   int 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
@@ -1578,6 +1679,11 @@ _bfd_write_archive_contents (arch)
      then construct a fresh ar_hdr for them.  */
   for (current = arch->archive_head; current; current = current->next)
     {
+      /* This check is checking the bfds for the objects we're reading
+        from (which are usually either an object file or archive on
+        disk), not the archive entries we're writing to.  We don't
+        actually create bfds for the archive members, we just copy
+        them byte-wise when we write out the archive.  */
       if (bfd_write_p (current))
        {
          bfd_set_error (bfd_error_invalid_operation);
@@ -1586,7 +1692,7 @@ _bfd_write_archive_contents (arch)
       if (!current->arelt_data)
        {
          current->arelt_data =
-           (PTR) bfd_ar_hdr_from_filesystem (arch, current->filename);
+           (PTR) bfd_ar_hdr_from_filesystem (arch, current->filename, current);
          if (!current->arelt_data)
            return false;
 
@@ -1725,7 +1831,7 @@ _bfd_compute_and_write_armap (arch, elength)
   long syms_max = 0;
   boolean ret;
 
-  /* Dunno if this is the best place for this info... */
+  /* Dunno if this is the best place for this info...  */
   if (elength != 0)
     elength += sizeof (struct ar_hdr);
   elength += elength % 2;
@@ -1866,7 +1972,7 @@ bsd_write_armap (arch, elength, map, orl_count, stridx)
   int padit = stridx & 1;
   unsigned int ranlibsize = orl_count * BSD_SYMDEF_SIZE;
   unsigned int stringsize = stridx + padit;
-  /* Include 8 bytes to store ranlibsize and stringsize in output. */
+  /* Include 8 bytes to store ranlibsize and stringsize in output.  */
   unsigned int mapsize = ranlibsize + stringsize + 8;
   file_ptr firstreal;
   bfd *current = arch->archive_head;
@@ -1887,13 +1993,8 @@ bsd_write_armap (arch, elength, map, orl_count, stridx)
   bfd_ardata (arch)->armap_datepos = (SARMAG
                                      + offsetof (struct ar_hdr, ar_date[0]));
   sprintf (hdr.ar_date, "%ld", bfd_ardata (arch)->armap_timestamp);
-#ifndef _WIN32
   sprintf (hdr.ar_uid, "%ld", (long) getuid ());
   sprintf (hdr.ar_gid, "%ld", (long) getgid ());
-#else
-  sprintf (hdr.ar_uid, "%ld", (long) 666);
-  sprintf (hdr.ar_gid, "%ld", (long) 42);
-#endif
   sprintf (hdr.ar_size, "%-10d", (int) mapsize);
   strncpy (hdr.ar_fmag, ARFMAG, 2);
   for (i = 0; i < sizeof (struct ar_hdr); i++)
@@ -1941,7 +2042,7 @@ bsd_write_armap (arch, elength, map, orl_count, stridx)
     }
 
   /* The spec sez this should be a newline.  But in order to be
-     bug-compatible for sun's ar we use a null. */
+     bug-compatible for sun's ar we use a null.  */
   if (padit)
     {
       if (bfd_write ("", 1, 1, arch) != 1)
@@ -2102,7 +2203,7 @@ coff_write_armap (arch, elength, map, symbol_count, stridx)
     }
 
   /* The spec sez this should be a newline.  But in order to be
-     bug-compatible for arc960 we use a null. */
+     bug-compatible for arc960 we use a null.  */
   if (padit)
     {
       if (bfd_write ("", 1, 1, arch) != 1)
This page took 0.031061 seconds and 4 git commands to generate.