kosx

Google import-archive.cc

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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×