// Fill the ArchiveMemberHeader with the information from a member. If // TruncateNames is true, names are flattened to 15 chars or less. The sz field // is provided here instead of coming from the mbr because the member might be // stored compressed and the compressed size is not the ArchiveMember's size. // Furthermore compressed files have negative size fields to identify them as // compressed. bool Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr, int sz) const { // Set the permissions mode, uid and gid hdr.init(); char buffer[32]; sprintf(buffer, "%-8o", mbr.getMode()); memcpy(hdr.mode,buffer,8); sprintf(buffer, "%-6u", mbr.getUser()); memcpy(hdr.uid,buffer,6); sprintf(buffer, "%-6u", mbr.getGroup()); memcpy(hdr.gid,buffer,6); // Set the last modification date uint64_t secondsSinceEpoch = mbr.getModTime().toEpochTime(); sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch)); memcpy(hdr.date,buffer,12); std::string mbrPath = sys::path::filename(mbr.getPath()); // Set the name field in one of its various flavors. bool writeLongName = false; if (mbr.isStringTable()) { memcpy(hdr.name,ARFILE_STRTAB_NAME,16); } else if (mbr.isSVR4SymbolTable()) { memcpy(hdr.name,ARFILE_SVR4_SYMTAB_NAME,16); } else if (mbr.isBSD4SymbolTable()) { memcpy(hdr.name,ARFILE_BSD4_SYMTAB_NAME,16); } else if (mbrPath.length() < 16 && mbrPath.find('/') == std::string::npos) { memcpy(hdr.name,mbrPath.c_str(),mbrPath.length()); hdr.name[mbrPath.length()] = '/'; } else { std::string nm = "#1/"; nm += utostr(mbrPath.length()); memcpy(hdr.name,nm.data(),nm.length()); if (sz < 0) sz -= mbrPath.length(); else sz += mbrPath.length(); writeLongName = true; } // Set the size field if (sz < 0) { buffer[0] = '-'; sprintf(&buffer[1],"%-9u",(unsigned)-sz); } else { sprintf(buffer, "%-10u", (unsigned)sz); } memcpy(hdr.size,buffer,10); return writeLongName; }
// This function loads the entire archive and fully populates its ilist with // the members of the archive file. This is typically used in preparation for // editing the contents of the archive. bool Archive::loadArchive(std::string* error) { // Set up parsing members.clear(); const char *At = base; const char *End = mapfile->getBufferEnd(); if (!checkSignature(error)) return false; At += 8; // Skip the magic string. bool foundFirstFile = false; while (At < End) { // parse the member header const char* Save = At; ArchiveMember* mbr = parseMemberHeader(At, End, error); if (!mbr) return false; // check if this is the foreign symbol table if (mbr->isSVR4SymbolTable() || mbr->isBSD4SymbolTable()) { At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; } else if (mbr->isStringTable()) { // Simply suck the entire string table into a string // variable. This will be used to get the names of the // members that use the "/ddd" format for their names // (SVR4 style long names). strtab.assign(At, mbr->getSize()); At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; } else { // This is just a regular file. If its the first one, save its offset. // Otherwise just push it on the list and move on to the next file. if (!foundFirstFile) { firstFileOffset = Save - base; foundFirstFile = true; } members.push_back(mbr); At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; } } return true; }
// Load just the symbol table from the archive file bool Archive::loadSymbolTable(std::string* ErrorMsg) { // Set up parsing members.clear(); const char *At = base; const char *End = mapfile->getBufferEnd(); // Make sure we're dealing with an archive if (!checkSignature(ErrorMsg)) return false; At += 8; // Skip signature // Parse the first file member header const char* FirstFile = At; ArchiveMember* mbr = parseMemberHeader(At, End, ErrorMsg); if (!mbr) return false; if (mbr->isSVR4SymbolTable() || mbr->isBSD4SymbolTable()) { // Skip the foreign symbol table, we don't do anything with it At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; // Read the next one FirstFile = At; mbr = parseMemberHeader(At, End, ErrorMsg); if (!mbr) { delete mbr; return false; } } if (mbr->isStringTable()) { // Process the string table entry strtab.assign((const char*)mbr->getData(), mbr->getSize()); At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; // Get the next one FirstFile = At; mbr = parseMemberHeader(At, End, ErrorMsg); if (!mbr) { delete mbr; return false; } } // There's no symbol table in the file. We have to rebuild it from scratch // because the intent of this method is to get the symbol table loaded so // it can be searched efficiently. // Add the member to the members list members.push_back(mbr); firstFileOffset = FirstFile - base; return true; }
// Fill the ArchiveMemberHeader with the information from a member. If // TruncateNames is true, names are flattened to 15 chars or less. The sz field // is provided here instead of coming from the mbr because the member might be // stored compressed and the compressed size is not the ArchiveMember's size. // Furthermore compressed files have negative size fields to identify them as // compressed. bool Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr, int sz, bool TruncateNames) const { // Set the permissions mode, uid and gid hdr.init(); char buffer[32]; sprintf(buffer, "%-8o", mbr.getMode()); memcpy(hdr.mode,buffer,8); sprintf(buffer, "%-6u", mbr.getUser()); memcpy(hdr.uid,buffer,6); sprintf(buffer, "%-6u", mbr.getGroup()); memcpy(hdr.gid,buffer,6); // Set the last modification date uint64_t secondsSinceEpoch = mbr.getModTime().toEpochTime(); sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch)); memcpy(hdr.date,buffer,12); // Get rid of trailing blanks in the name std::string mbrPath = mbr.getPath().str(); size_t mbrLen = mbrPath.length(); while (mbrLen > 0 && mbrPath[mbrLen-1] == ' ') { mbrPath.erase(mbrLen-1,1); mbrLen--; } // Set the name field in one of its various flavors. bool writeLongName = false; if (mbr.isStringTable()) { memcpy(hdr.name,ARFILE_STRTAB_NAME,16); } else if (mbr.isSVR4SymbolTable()) { memcpy(hdr.name,ARFILE_SVR4_SYMTAB_NAME,16); } else if (mbr.isBSD4SymbolTable()) { memcpy(hdr.name,ARFILE_BSD4_SYMTAB_NAME,16); } else if (mbr.isLLVMSymbolTable()) { memcpy(hdr.name,ARFILE_LLVM_SYMTAB_NAME,16); } else if (TruncateNames) { const char* nm = mbrPath.c_str(); unsigned len = mbrPath.length(); size_t slashpos = mbrPath.rfind('/'); if (slashpos != std::string::npos) { nm += slashpos + 1; len -= slashpos +1; } if (len > 15) len = 15; memcpy(hdr.name,nm,len); hdr.name[len] = '/'; } else if (mbrPath.length() < 16 && mbrPath.find('/') == std::string::npos) { memcpy(hdr.name,mbrPath.c_str(),mbrPath.length()); hdr.name[mbrPath.length()] = '/'; } else { std::string nm = "#1/"; nm += utostr(mbrPath.length()); memcpy(hdr.name,nm.data(),nm.length()); if (sz < 0) sz -= mbrPath.length(); else sz += mbrPath.length(); writeLongName = true; } // Set the size field if (sz < 0) { buffer[0] = '-'; sprintf(&buffer[1],"%-9u",(unsigned)-sz); } else { sprintf(buffer, "%-10u", (unsigned)sz); } memcpy(hdr.size,buffer,10); return writeLongName; }
// This function loads the entire archive and fully populates its ilist with // the members of the archive file. This is typically used in preparation for // editing the contents of the archive. bool Archive::loadArchive(std::string* error) { // Set up parsing members.clear(); symTab.clear(); const char *At = base; const char *End = mapfile->getBufferEnd(); if (!checkSignature(error)) return false; At += 8; // Skip the magic string. bool seenSymbolTable = false; bool foundFirstFile = false; while (At < End) { // parse the member header const char* Save = At; ArchiveMember* mbr = parseMemberHeader(At, End, error); if (!mbr) return false; // check if this is the foreign symbol table if (mbr->isSVR4SymbolTable() || mbr->isBSD4SymbolTable()) { // We just save this but don't do anything special // with it. It doesn't count as the "first file". if (foreignST) { // What? Multiple foreign symbol tables? Just chuck it // and retain the last one found. delete foreignST; } foreignST = mbr; At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; } else if (mbr->isStringTable()) { // Simply suck the entire string table into a string // variable. This will be used to get the names of the // members that use the "/ddd" format for their names // (SVR4 style long names). strtab.assign(At, mbr->getSize()); At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; } else if (mbr->isLLVMSymbolTable()) { // This is the LLVM symbol table for the archive. If we've seen it // already, its an error. Otherwise, parse the symbol table and move on. if (seenSymbolTable) { if (error) *error = "invalid archive: multiple symbol tables"; return false; } if (!parseSymbolTable(mbr->getData(), mbr->getSize(), error)) return false; seenSymbolTable = true; At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; // We don't need this member in the list of members. } else { // This is just a regular file. If its the first one, save its offset. // Otherwise just push it on the list and move on to the next file. if (!foundFirstFile) { firstFileOffset = Save - base; foundFirstFile = true; } members.push_back(mbr); At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; } } return true; }