LCOV - code coverage report
Current view: top level - gcc/rust/metadata - rust-import-archive.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 0.0 % 327 0
Test Date: 2024-12-21 13:15:12 Functions: 0.0 % 19 0
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

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

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.