github.com/kidsbmilk/gofronted_all@v0.0.0-20220701224323-6479d5976c5d/go/import-archive.cc (about)

     1  // import-archive.cc -- Go frontend read import data from an archive file.
     2  
     3  // Copyright 2009 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  #include "go-system.h"
     8  
     9  #include "go-diagnostics.h"
    10  #include "import.h"
    11  
    12  #ifndef O_BINARY
    13  #define O_BINARY 0
    14  #endif
    15  
    16  // Archive magic numbers.
    17  
    18  static const char armag[] =
    19  {
    20    '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
    21  };
    22  
    23  static const char armagt[] =
    24  {
    25    '!', '<', 't', 'h', 'i', 'n', '>', '\n'
    26  };
    27  
    28  static const char armagb[] =
    29  {
    30    '<', 'b', 'i', 'g', 'a', 'f', '>', '\n'
    31  };
    32  
    33  static const char arfmag[2] = { '`', '\n' };
    34  
    35  // Archive fixed length header for AIX big format.
    36  
    37  struct Archive_fl_header
    38  {
    39    // Archive magic string.
    40    char fl_magic[8];
    41    // Offset to member table.
    42    char fl_memoff[20];
    43    // Offset to global symbol table.
    44    char fl_gstoff[20];
    45    // Offset to global symbol table for 64-bit objects.
    46    char fl_gst64off[20];
    47    // Offset to first archive member.
    48    char fl_fstmoff[20];
    49    // Offset to last archive member.
    50    char fl_lstmoff[20];
    51    // Offset to first member on free list.
    52    char fl_freeoff[20];
    53  };
    54  
    55  // The header of an entry in an archive.  This is all readable text,
    56  // padded with spaces where necesary.
    57  
    58  struct Archive_header
    59  {
    60    // The entry name.
    61    char ar_name[16];
    62    // The file modification time.
    63    char ar_date[12];
    64    // The user's UID in decimal.
    65    char ar_uid[6];
    66    // The user's GID in decimal.
    67    char ar_gid[6];
    68    // The file mode in octal.
    69    char ar_mode[8];
    70    // The file size in decimal.
    71    char ar_size[10];
    72    // The final magic code.
    73    char ar_fmag[2];
    74  };
    75  
    76  // The header of an entry in an AIX big archive.
    77  // This is followed by ar_namlen bytes + 2 bytes for arfmag.
    78  
    79  struct Archive_big_header
    80  {
    81    // The file size in decimal.
    82    char ar_size[20];
    83    // The next member offset in decimal.
    84    char ar_nxtmem[20];
    85    // The previous member offset in decimal.
    86    char ar_prvmem[20];
    87    // The file modification time in decimal.
    88    char ar_date[12];
    89    // The user's UID in decimal.
    90    char ar_uid[12];
    91    // The user's GID in decimal.
    92    char ar_gid[12];
    93    // The file mode in octal.
    94    char ar_mode[12];
    95    // The file name length in decimal.
    96    char ar_namlen[4];
    97  };
    98  
    99  // The functions in this file extract Go export data from an archive.
   100  
   101  const int Import::archive_magic_len;
   102  
   103  // Return true if BYTES, which are from the start of the file, are an
   104  // archive magic number.
   105  
   106  bool
   107  Import::is_archive_magic(const char* bytes)
   108  {
   109    return (memcmp(bytes, armag, Import::archive_magic_len) == 0
   110  	  || memcmp(bytes, armagt, Import::archive_magic_len) == 0
   111  	  || memcmp(bytes, armagb, Import::archive_magic_len) == 0);
   112  }
   113  
   114  // An object used to read an archive file.
   115  
   116  class Archive_file
   117  {
   118   public:
   119    Archive_file(const std::string& filename, int fd, Location location)
   120      : filename_(filename), fd_(fd), filesize_(-1), first_member_offset_(0),
   121        extended_names_(), is_thin_archive_(false), is_big_archive_(false),
   122        location_(location), nested_archives_()
   123    { }
   124  
   125    // Initialize.
   126    bool
   127    initialize();
   128  
   129    // Return the file name.
   130    const std::string&
   131    filename() const
   132    { return this->filename_; }
   133  
   134    // Get the file size.
   135    off_t
   136    filesize() const
   137    { return this->filesize_; }
   138  
   139    // Return the offset of the first member.
   140    off_t
   141    first_member_offset() const
   142    { return this->first_member_offset_; }
   143  
   144    // Return whether this is a thin archive.
   145    bool
   146    is_thin_archive() const
   147    { return this->is_thin_archive_; }
   148  
   149    // Return whether this is a big archive.
   150    bool
   151    is_big_archive() const
   152    { return this->is_big_archive_; }
   153  
   154    // Return the location of the import statement.
   155    Location
   156    location() const
   157    { return this->location_; }
   158  
   159    // Read bytes.
   160    bool
   161    read(off_t offset, off_t size, char*);
   162  
   163    // Parse a decimal in readable text.
   164    bool
   165    parse_decimal(const char* str, off_t size, long* res) const;
   166  
   167    // Read the archive header at OFF, setting *PNAME, *SIZE,
   168    // *NESTED_OFF and *NEXT_OFF.
   169    bool
   170    read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off,
   171                off_t* next_off);
   172  
   173    // Interpret the header of HDR, the header of the archive member at
   174    // file offset OFF.  Return whether it succeeded.  Set *SIZE to the
   175    // size of the member.  Set *PNAME to the name of the member.  Set
   176    // *NESTED_OFF to the offset in a nested archive.
   177    bool
   178    interpret_header(const Archive_header* hdr, off_t off,
   179  		   std::string* pname, off_t* size, off_t* nested_off) const;
   180  
   181    // Get the file and offset for an archive member.
   182    bool
   183    get_file_and_offset(off_t off, const std::string& hdrname,
   184  		      off_t nested_off, int* memfd, off_t* memoff,
   185  		      std::string* memname);
   186  
   187   private:
   188    // Initialize a big archive (AIX)
   189    bool
   190    initialize_big_archive();
   191  
   192    // Initialize a normal archive
   193    bool
   194    initialize_archive();
   195  
   196    // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF.
   197    bool
   198    read_big_archive_header(off_t off, std::string* pname,
   199                            off_t* size, off_t* next_off);
   200  
   201    // Read the normal archive header at OFF, setting *PNAME, *SIZE,
   202    // *NESTED_OFF and *NEXT_OFF.
   203    bool
   204    read_archive_header(off_t off, std::string* pname, off_t* size,
   205                        off_t* nested_off, off_t* next_off);
   206  
   207    // For keeping track of open nested archives in a thin archive file.
   208    typedef std::map<std::string, Archive_file*> Nested_archive_table;
   209  
   210    // The name of the file.
   211    std::string filename_;
   212    // The file descriptor.
   213    int fd_;
   214    // The file size;
   215    off_t filesize_;
   216    // The first member offset;
   217    off_t first_member_offset_;
   218    // The extended name table.
   219    std::string extended_names_;
   220    // Whether this is a thin archive.
   221    bool is_thin_archive_;
   222    // Whether this is a big archive.
   223    bool is_big_archive_;
   224    // The location of the import statements.
   225    Location location_;
   226    // Table of nested archives.
   227    Nested_archive_table nested_archives_;
   228  };
   229  
   230  bool
   231  Archive_file::initialize()
   232  {
   233    struct stat st;
   234    if (fstat(this->fd_, &st) < 0)
   235      {
   236        go_error_at(this->location_, "%s: %m", this->filename_.c_str());
   237        return false;
   238      }
   239    this->filesize_ = st.st_size;
   240  
   241    char buf[sizeof(armagt)];
   242    if (::lseek(this->fd_, 0, SEEK_SET) < 0
   243        || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt))
   244      {
   245        go_error_at(this->location_, "%s: %m", this->filename_.c_str());
   246        return false;
   247      }
   248    if (memcmp(buf, armagt, sizeof(armagt)) == 0)
   249      this->is_thin_archive_ = true;
   250    else if (memcmp(buf, armagb, sizeof(armagb)) == 0)
   251      this->is_big_archive_ = true;
   252  
   253    if (this->is_big_archive_)
   254      return this->initialize_big_archive();
   255    else
   256      return this->initialize_archive();
   257  }
   258  
   259  // Initialize a big archive (AIX).
   260  
   261  bool
   262  Archive_file::initialize_big_archive()
   263  {
   264    Archive_fl_header flhdr;
   265  
   266    // Read the fixed length header.
   267    if (::lseek(this->fd_, 0, SEEK_SET) < 0
   268        || ::read(this->fd_, &flhdr, sizeof(flhdr)) != sizeof(flhdr))
   269      {
   270        go_error_at(this->location_, "%s: could not read archive header",
   271                    this->filename_.c_str());
   272        return false;
   273      }
   274  
   275    // Parse offset of the first member.
   276    long off;
   277    if (!this->parse_decimal(flhdr.fl_fstmoff, sizeof(flhdr.fl_fstmoff), &off))
   278      {
   279        char* buf = new char[sizeof(flhdr.fl_fstmoff) + 1];
   280        memcpy(buf, flhdr.fl_fstmoff, sizeof(flhdr.fl_fstmoff));
   281        go_error_at(this->location_,
   282                    ("%s: malformed first member offset in archive header"
   283                     " (expected decimal, got %s)"),
   284                    this->filename_.c_str(), buf);
   285        delete[] buf;
   286        return false;
   287      }
   288    if (off == 0) // Empty archive.
   289      this->first_member_offset_ = this->filesize_;
   290    else
   291      this->first_member_offset_ = off;
   292    return true;
   293  }
   294  
   295  // Initialize a normal archive.
   296  
   297  bool
   298  Archive_file::initialize_archive()
   299  {
   300    this->first_member_offset_ = sizeof(armag);
   301    if (this->first_member_offset_ == this->filesize_)
   302      {
   303        // Empty archive.
   304        return true;
   305      }
   306  
   307    // Look for the extended name table.
   308    std::string filename;
   309    off_t size;
   310    off_t next_off;
   311    if (!this->read_header(this->first_member_offset_, &filename,
   312                           &size, NULL, &next_off))
   313      return false;
   314    if (filename.empty())
   315      {
   316        // We found the symbol table.
   317        if (!this->read_header(next_off, &filename, &size, NULL, NULL))
   318  	filename.clear();
   319      }
   320    if (filename == "/")
   321      {
   322        char* rdbuf = new char[size];
   323        if (::read(this->fd_, rdbuf, size) != size)
   324  	{
   325  	  go_error_at(this->location_, "%s: could not read extended names",
   326  		   filename.c_str());
   327  	  delete[] rdbuf;
   328  	  return false;
   329  	}
   330        this->extended_names_.assign(rdbuf, size);
   331        delete[] rdbuf;
   332      }
   333  
   334    return true;
   335  }
   336  
   337  // Read bytes from the file.
   338  
   339  bool
   340  Archive_file::read(off_t offset, off_t size, char* buf)
   341  {
   342    if (::lseek(this->fd_, offset, SEEK_SET) < 0
   343        || ::read(this->fd_, buf, size) != size)
   344      {
   345        go_error_at(this->location_, "%s: %m", this->filename_.c_str());
   346        return false;
   347      }
   348    return true;
   349  }
   350  
   351  // Parse a decimal in readable text.
   352  
   353  bool
   354  Archive_file::parse_decimal(const char* str, off_t size, long* res) const
   355  {
   356    char* buf = new char[size + 1];
   357    memcpy(buf, str, size);
   358    char* ps = buf + size;
   359    while (ps > buf && ps[-1] == ' ')
   360      --ps;
   361    *ps = '\0';
   362  
   363    errno = 0;
   364    char* end;
   365    *res = strtol(buf, &end, 10);
   366    if (*end != '\0'
   367        || *res < 0
   368        || (*res == LONG_MAX && errno == ERANGE))
   369      {
   370        delete[] buf;
   371        return false;
   372      }
   373    delete[] buf;
   374    return true;
   375  }
   376  
   377  // Read the header at OFF.  Set *PNAME to the name, *SIZE to the size,
   378  // *NESTED_OFF to the nested offset, and *NEXT_OFF to the next member offset.
   379  
   380  bool
   381  Archive_file::read_header(off_t off, std::string* pname, off_t* size,
   382  			  off_t* nested_off, off_t* next_off)
   383  {
   384    if (::lseek(this->fd_, off, SEEK_SET) < 0)
   385      {
   386        go_error_at(this->location_, "%s: %m", this->filename_.c_str());
   387        return false;
   388      }
   389    if (this->is_big_archive_)
   390      return this->read_big_archive_header(off, pname, size, next_off);
   391    else
   392      return this->read_archive_header(off, pname, size, nested_off, next_off);
   393  }
   394  
   395  // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF.
   396  
   397  bool
   398  Archive_file::read_big_archive_header(off_t off, std::string* pname,
   399                                        off_t* size, off_t* next_off)
   400  {
   401    Archive_big_header hdr;
   402    ssize_t got;
   403  
   404    got = ::read(this->fd_, &hdr, sizeof hdr);
   405    if (got != sizeof hdr)
   406      {
   407        if (got < 0)
   408          go_error_at(this->location_, "%s: %m", this->filename_.c_str());
   409        else if (got > 0)
   410          go_error_at(this->location_, "%s: short entry header at %ld",
   411                      this->filename_.c_str(), static_cast<long>(off));
   412        else
   413          go_error_at(this->location_, "%s: unexpected EOF at %ld",
   414                      this->filename_.c_str(), static_cast<long>(off));
   415      }
   416  
   417    long local_size;
   418    if (!this->parse_decimal(hdr.ar_size, sizeof(hdr.ar_size), &local_size))
   419      {
   420        char* buf = new char[sizeof(hdr.ar_size) + 1];
   421        memcpy(buf, hdr.ar_size, sizeof(hdr.ar_size));
   422        go_error_at(this->location_,
   423                    ("%s: malformed size in entry header at %ld"
   424                     " (expected decimal, got %s)"),
   425                    this->filename_.c_str(), static_cast<long>(off), buf);
   426        delete[] buf;
   427        return false;
   428      }
   429    *size = local_size;
   430  
   431    long namlen;
   432    if (!this->parse_decimal(hdr.ar_namlen, sizeof(hdr.ar_namlen), &namlen))
   433      {
   434        char* buf = new char[sizeof(hdr.ar_namlen) + 1];
   435        memcpy(buf, hdr.ar_namlen, sizeof(hdr.ar_namlen));
   436        go_error_at(this->location_,
   437                    ("%s: malformed name length in entry header at %ld"
   438                     " (expected decimal, got %s)"),
   439                    this->filename_.c_str(), static_cast<long>(off), buf);
   440        delete[] buf;
   441        return false;
   442      }
   443    // Read member name following member header.
   444    char* rdbuf = new char[namlen];
   445    got = ::read(this->fd_, rdbuf, namlen);
   446    if (got != namlen)
   447      {
   448        go_error_at(this->location_,
   449                    "%s: malformed member name in entry header at %ld",
   450                    this->filename_.c_str(), static_cast<long>(off));
   451        delete[] rdbuf;
   452        return false;
   453      }
   454    pname->assign(rdbuf, namlen);
   455    delete[] rdbuf;
   456  
   457    long local_next_off;
   458    if (!this->parse_decimal(hdr.ar_nxtmem, sizeof(hdr.ar_nxtmem), &local_next_off))
   459      {
   460        char* buf = new char[sizeof(hdr.ar_nxtmem) + 1];
   461        memcpy(buf, hdr.ar_nxtmem, sizeof(hdr.ar_nxtmem));
   462        go_error_at(this->location_,
   463                    ("%s: malformed next member offset in entry header at %ld"
   464                     " (expected decimal, got %s)"),
   465                    this->filename_.c_str(), static_cast<long>(off), buf);
   466        delete[] buf;
   467        return false;
   468      }
   469    if (next_off != NULL)
   470      {
   471        if (local_next_off == 0) // Last member.
   472          *next_off = this->filesize_;
   473        else
   474          *next_off = local_next_off;
   475      }
   476    return true;
   477  }
   478  
   479  // Read the normal archive header at OFF, setting *PNAME, *SIZE,
   480  // *NESTED_OFF and *NEXT_OFF.
   481  
   482  bool
   483  Archive_file::read_archive_header(off_t off, std::string* pname, off_t* size,
   484                                    off_t* nested_off, off_t* next_off)
   485  {
   486    Archive_header hdr;
   487    ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
   488    if (got != sizeof hdr)
   489      {
   490        if (got < 0)
   491  	go_error_at(this->location_, "%s: %m", this->filename_.c_str());
   492        else if (got > 0)
   493  	go_error_at(this->location_, "%s: short archive header at %ld",
   494  		    this->filename_.c_str(), static_cast<long>(off));
   495        else
   496  	go_error_at(this->location_, "%s: unexpected EOF at %ld",
   497  		    this->filename_.c_str(), static_cast<long>(off));
   498      }
   499    off_t local_nested_off;
   500    if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off))
   501      return false;
   502    if (nested_off != NULL)
   503      *nested_off = local_nested_off;
   504  
   505    off_t local_next_off;
   506    local_next_off = off + sizeof(Archive_header);
   507    if (!this->is_thin_archive_ || pname->empty() || *pname == "/")
   508      local_next_off += *size;
   509    if ((local_next_off & 1) != 0)
   510      ++local_next_off;
   511    if (local_next_off > this->filesize_) // Last member.
   512      local_next_off = this->filesize_;
   513    if (next_off != NULL)
   514      *next_off = local_next_off;
   515    return true;
   516  }
   517  
   518  // Interpret the header of HDR, the header of the archive member at
   519  // file offset OFF.
   520  
   521  bool
   522  Archive_file::interpret_header(const Archive_header* hdr, off_t off,
   523  			       std::string* pname, off_t* size,
   524  			       off_t* nested_off) const
   525  {
   526    if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
   527      {
   528        go_error_at(this->location_, "%s: malformed archive header at %lu",
   529  		  this->filename_.c_str(), static_cast<unsigned long>(off));
   530        return false;
   531      }
   532  
   533    long local_size;
   534    if (!this->parse_decimal(hdr->ar_size, sizeof hdr->ar_size, &local_size))
   535      {
   536        go_error_at(this->location_, "%s: malformed archive header size at %lu",
   537  		  this->filename_.c_str(), static_cast<unsigned long>(off));
   538        return false;
   539      }
   540    *size = local_size;
   541  
   542    *nested_off = 0;
   543    if (hdr->ar_name[0] != '/')
   544      {
   545        const char* name_end = strchr(hdr->ar_name, '/');
   546        if (name_end == NULL
   547  	  || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
   548  	{
   549  	  go_error_at(this->location_,
   550  		      "%s: malformed archive header name at %lu",
   551  		      this->filename_.c_str(), static_cast<unsigned long>(off));
   552  	  return false;
   553  	}
   554        pname->assign(hdr->ar_name, name_end - hdr->ar_name);
   555      }
   556    else if (hdr->ar_name[1] == ' ')
   557      {
   558        // This is the symbol table.
   559        pname->clear();
   560      }
   561    else if (hdr->ar_name[1] == 'S' && hdr->ar_name[2] == 'Y'
   562  	   && hdr->ar_name[3] == 'M' && hdr->ar_name[4] == '6'
   563  	   && hdr->ar_name[5] == '4' && hdr->ar_name[6] == '/'
   564  	   && hdr->ar_name[7] == ' '
   565  	  )
   566      {
   567        // 64-bit symbol table.
   568        pname->clear();
   569      }
   570    else if (hdr->ar_name[1] == '/')
   571      {
   572        // This is the extended name table.
   573        pname->assign(1, '/');
   574      }
   575    else
   576      {
   577        char* end;
   578        errno = 0;
   579        long x = strtol(hdr->ar_name + 1, &end, 10);
   580        long y = 0;
   581        if (*end == ':')
   582          y = strtol(end + 1, &end, 10);
   583        if (*end != ' '
   584  	  || x < 0
   585  	  || (x == LONG_MAX && errno == ERANGE)
   586  	  || static_cast<size_t>(x) >= this->extended_names_.size())
   587  	{
   588  	  go_error_at(this->location_, "%s: bad extended name index at %lu",
   589  		      this->filename_.c_str(), static_cast<unsigned long>(off));
   590  	  return false;
   591  	}
   592  
   593        const char* name = this->extended_names_.data() + x;
   594        const char* name_end = strchr(name, '\n');
   595        if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
   596  	  || name_end[-1] != '/')
   597  	{
   598  	  go_error_at(this->location_,
   599  		      "%s: bad extended name entry at header %lu",
   600  		      this->filename_.c_str(), static_cast<unsigned long>(off));
   601  	  return false;
   602  	}
   603        pname->assign(name, name_end - 1 - name);
   604        *nested_off = y;
   605      }
   606  
   607    return true;
   608  }
   609  
   610  // Get the file and offset for an archive member.
   611  
   612  bool
   613  Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
   614  				  off_t nested_off, int* memfd, off_t* memoff,
   615  				  std::string* memname)
   616  {
   617    if (this->is_big_archive_)
   618      {
   619        *memfd = this->fd_;
   620        *memoff = (off + sizeof(Archive_big_header) + hdrname.length()
   621                   + sizeof(arfmag));
   622        if ((*memoff & 1) != 0)
   623          ++*memoff;
   624        *memname = this->filename_ + '(' + hdrname + ')';
   625        return true;
   626      }
   627    else if (!this->is_thin_archive_)
   628      {
   629        *memfd = this->fd_;
   630        *memoff = off + sizeof(Archive_header);
   631        *memname = this->filename_ + '(' + hdrname + ')';
   632        return true;
   633      }
   634  
   635    std::string filename = hdrname;
   636    if (!IS_ABSOLUTE_PATH(filename.c_str()))
   637      {
   638        const char* archive_path = this->filename_.c_str();
   639        const char* basename = lbasename(archive_path);
   640        if (basename > archive_path)
   641  	filename.replace(0, 0,
   642  			 this->filename_.substr(0, basename - archive_path));
   643      }
   644  
   645    if (nested_off > 0)
   646      {
   647        // This is a member of a nested archive.
   648        Archive_file* nfile;
   649        Nested_archive_table::const_iterator p =
   650  	this->nested_archives_.find(filename);
   651        if (p != this->nested_archives_.end())
   652  	nfile = p->second;
   653        else
   654  	{
   655  	  int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
   656  	  if (nfd < 0)
   657  	    {
   658  	      go_error_at(this->location_, "%s: cannot open nested archive %s",
   659  			  this->filename_.c_str(), filename.c_str());
   660  	      return false;
   661  	    }
   662  	  nfile = new Archive_file(filename, nfd, this->location_);
   663  	  if (!nfile->initialize())
   664  	    {
   665  	      delete nfile;
   666  	      return false;
   667  	    }
   668  	  this->nested_archives_[filename] = nfile;
   669  	}
   670  
   671        std::string nname;
   672        off_t nsize;
   673        off_t nnested_off;
   674        if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off, NULL))
   675  	return false;
   676        return nfile->get_file_and_offset(nested_off, nname, nnested_off,
   677  					memfd, memoff, memname);
   678      }
   679  
   680    // An external member of a thin archive.
   681    *memfd = open(filename.c_str(), O_RDONLY | O_BINARY);
   682    if (*memfd < 0)
   683      {
   684        go_error_at(this->location_, "%s: %m", filename.c_str());
   685        return false;
   686      }
   687    *memoff = 0;
   688    *memname = filename;
   689    return true;
   690  }
   691  
   692  // An archive member iterator.  This is more-or-less copied from gold.
   693  
   694  class Archive_iterator
   695  {
   696   public:
   697    // The header of an archive member.  This is what this iterator
   698    // points to.
   699    struct Header
   700    {
   701      // The name of the member.
   702      std::string name;
   703      // The file offset of the member.
   704      off_t off;
   705      // The file offset of a nested archive member.
   706      off_t nested_off;
   707      // The size of the member.
   708      off_t size;
   709    };
   710  
   711    Archive_iterator(Archive_file* afile, off_t off)
   712      : afile_(afile), off_(off)
   713    { this->read_next_header(); }
   714  
   715    const Header&
   716    operator*() const
   717    { return this->header_; }
   718  
   719    const Header*
   720    operator->() const
   721    { return &this->header_; }
   722  
   723    Archive_iterator&
   724    operator++()
   725    {
   726      if (this->off_ == this->afile_->filesize())
   727        return *this;
   728      this->off_ = this->next_off_;
   729      this->read_next_header();
   730      return *this;
   731    }
   732  
   733    Archive_iterator
   734    operator++(int)
   735    {
   736      Archive_iterator ret = *this;
   737      ++*this;
   738      return ret;
   739    }
   740  
   741    bool
   742    operator==(const Archive_iterator& p) const
   743    { return this->off_ == p->off; }
   744  
   745    bool
   746    operator!=(const Archive_iterator& p) const
   747    { return this->off_ != p->off; }
   748  
   749   private:
   750    void
   751    read_next_header();
   752  
   753    // The underlying archive file.
   754    Archive_file* afile_;
   755    // The current offset in the file.
   756    off_t off_;
   757    // The offset of the next member.
   758    off_t next_off_;
   759    // The current archive header.
   760    Header header_;
   761  };
   762  
   763  // Read the next archive header.
   764  
   765  void
   766  Archive_iterator::read_next_header()
   767  {
   768    off_t filesize = this->afile_->filesize();
   769    while (true)
   770      {
   771        if (this->off_ == filesize)
   772  	{
   773  	  this->header_.off = filesize;
   774  	  return;
   775  	}
   776  
   777        if (!this->afile_->read_header(this->off_, &this->header_.name,
   778                                       &this->header_.size,
   779                                       &this->header_.nested_off,
   780                                       &this->next_off_))
   781  	{
   782  	  this->header_.off = filesize;
   783  	  this->off_ = filesize;
   784  	  return;
   785  	}
   786        this->header_.off = this->off_;
   787  
   788        // Skip special members.
   789        if (!this->header_.name.empty() && this->header_.name != "/")
   790  	return;
   791  
   792        this->off_ = this->next_off_;
   793      }
   794  }
   795  
   796  // Initial iterator.
   797  
   798  Archive_iterator
   799  archive_begin(Archive_file* afile)
   800  {
   801    return Archive_iterator(afile, afile->first_member_offset());
   802  }
   803  
   804  // Final iterator.
   805  
   806  Archive_iterator
   807  archive_end(Archive_file* afile)
   808  {
   809    return Archive_iterator(afile, afile->filesize());
   810  }
   811  
   812  // A type of Import_stream which concatenates other Import_streams
   813  // together.
   814  
   815  class Stream_concatenate : public Import::Stream
   816  {
   817   public:
   818    Stream_concatenate()
   819      : inputs_()
   820    { }
   821  
   822    // Add a new stream.
   823    void
   824    add(Import::Stream* is)
   825    { this->inputs_.push_back(is); }
   826  
   827   protected:
   828    bool
   829    do_peek(size_t, const char**);
   830  
   831    void
   832    do_advance(size_t);
   833  
   834   private:
   835    std::list<Import::Stream*> inputs_;
   836  };
   837  
   838  // Peek ahead.
   839  
   840  bool
   841  Stream_concatenate::do_peek(size_t length, const char** bytes)
   842  {
   843    while (true)
   844      {
   845        if (this->inputs_.empty())
   846  	return false;
   847        if (this->inputs_.front()->peek(length, bytes))
   848  	return true;
   849        delete this->inputs_.front();
   850        this->inputs_.pop_front();
   851      }
   852  }
   853  
   854  // Advance.
   855  
   856  void
   857  Stream_concatenate::do_advance(size_t skip)
   858  {
   859    while (true)
   860      {
   861        if (this->inputs_.empty())
   862  	return;
   863        if (!this->inputs_.front()->at_eof())
   864  	{
   865  	  // We just assume that this will do the right thing.  It
   866  	  // should be OK since we should never want to skip past
   867  	  // multiple streams.
   868  	  this->inputs_.front()->advance(skip);
   869  	  return;
   870  	}
   871        delete this->inputs_.front();
   872        this->inputs_.pop_front();
   873      }
   874  }
   875  
   876  // Import data from an archive.  We walk through the archive and
   877  // import data from each member.
   878  
   879  Import::Stream*
   880  Import::find_archive_export_data(const std::string& filename, int fd,
   881  				 Location location)
   882  {
   883    Archive_file afile(filename, fd, location);
   884    if (!afile.initialize())
   885      return NULL;
   886  
   887    Stream_concatenate* ret = new Stream_concatenate;
   888  
   889    bool any_data = false;
   890    bool any_members = false;
   891    Archive_iterator pend = archive_end(&afile);
   892    for (Archive_iterator p = archive_begin(&afile); p != pend; p++)
   893      {
   894        any_members = true;
   895        int member_fd;
   896        off_t member_off;
   897        std::string member_name;
   898        if (!afile.get_file_and_offset(p->off, p->name, p->nested_off,
   899  				     &member_fd, &member_off, &member_name))
   900  	return NULL;
   901  
   902        Import::Stream* is = Import::find_object_export_data(member_name,
   903  							   member_fd,
   904  							   member_off,
   905  							   location);
   906        if (is != NULL)
   907  	{
   908  	  ret->add(is);
   909  	  any_data = true;
   910  	}
   911      }
   912  
   913    if (!any_members)
   914      {
   915        // It's normal to have an empty archive file when using gobuild.
   916        return new Stream_from_string("");
   917      }
   918  
   919    if (!any_data)
   920      {
   921        delete ret;
   922        return NULL;
   923      }
   924  
   925    return ret;
   926  }