X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;ds=sidebyside;f=lib%2FArchive%2FArchiveWriter.cpp;h=8fcc7aa29cc853ddbe9655088e56a20f24004626;hb=e640a228f6b1ff280d35a6a33bf78c7e544f9926;hp=9d5b025b05719a3a1b721b4d5a21f411ecf85645;hpb=5ba2b702c21052346f171ab277824dc0e549ff77;p=oota-llvm.git diff --git a/lib/Archive/ArchiveWriter.cpp b/lib/Archive/ArchiveWriter.cpp index 9d5b025b057..8fcc7aa29cc 100644 --- a/lib/Archive/ArchiveWriter.cpp +++ b/lib/Archive/ArchiveWriter.cpp @@ -2,20 +2,24 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by Reid Spencer and is distributed under the -// University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // -// Builds up an LLVM archive file (.a) containing LLVM bytecode. +// Builds up an LLVM archive file (.a) containing LLVM bitcode. // //===----------------------------------------------------------------------===// #include "ArchiveInternals.h" -#include "llvm/Bytecode/Reader.h" -#include "llvm/Support/Compressor.h" -#include "llvm/System/Signals.h" -#include "llvm/System/Process.h" +#include "llvm/Module.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" #include #include #include @@ -23,7 +27,7 @@ using namespace llvm; // Write an integer using variable bit rate encoding. This saves a few bytes // per entry in the symbol table. -inline void writeInteger(unsigned num, std::ofstream& ARFile) { +static inline void writeInteger(unsigned num, std::ofstream& ARFile) { while (1) { if (num < 0x80) { // done? ARFile << (unsigned char)num; @@ -39,7 +43,7 @@ inline void writeInteger(unsigned num, std::ofstream& ARFile) { // Compute how many bytes are taken by a given VBR encoded value. This is needed // to pre-compute the size of the symbol table. -inline unsigned numVbrBytes(unsigned num) { +static inline unsigned numVbrBytes(unsigned num) { // Note that the following nested ifs are somewhat equivalent to a binary // search. We split it in half by comparing against 2^14 first. This allows @@ -47,11 +51,12 @@ inline unsigned numVbrBytes(unsigned num) { // small ones and four for large ones. We expect this to access file offsets // in the 2^10 to 2^24 range and symbol lengths in the 2^0 to 2^8 range, // so this approach is reasonable. - if (num < 1<<14) + if (num < 1<<14) { if (num < 1<<7) return 1; else return 2; + } if (num < 1<<21) return 3; @@ -61,9 +66,8 @@ inline unsigned numVbrBytes(unsigned num) { } // Create an empty archive. -Archive* -Archive::CreateEmpty(const sys::Path& FilePath ) { - Archive* result = new Archive(FilePath); +Archive* Archive::CreateEmpty(const sys::Path& FilePath, LLVMContext& C) { + Archive* result = new Archive(FilePath, C); return result; } @@ -93,7 +97,7 @@ Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr, memcpy(hdr.date,buffer,12); // Get rid of trailing blanks in the name - std::string mbrPath = mbr.getPath().toString(); + std::string mbrPath = mbr.getPath().str(); size_t mbrLen = mbrPath.length(); while (mbrLen > 0 && mbrPath[mbrLen-1] == ' ') { mbrPath.erase(mbrLen-1,1); @@ -151,9 +155,10 @@ Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr, // Insert a file into the archive before some other member. This also takes care // of extracting the necessary flags and information from the file. bool -Archive::addFileBefore(const sys::Path& filePath, iterator where, +Archive::addFileBefore(const sys::Path& filePath, iterator where, std::string* ErrMsg) { - if (!filePath.exists()) { + bool Exists; + if (sys::fs::exists(filePath.str(), Exists) || !Exists) { if (ErrMsg) *ErrMsg = "Can not add a non-existent file to archive"; return true; @@ -163,23 +168,26 @@ Archive::addFileBefore(const sys::Path& filePath, iterator where, mbr->data = 0; mbr->path = filePath; - if (mbr->path.getFileStatus(mbr->info, false, ErrMsg)) + const sys::FileStatus *FSInfo = mbr->path.getFileStatus(false, ErrMsg); + if (!FSInfo) { + delete mbr; return true; + } + mbr->info = *FSInfo; unsigned flags = 0; - bool hasSlash = filePath.toString().find('/') != std::string::npos; + bool hasSlash = filePath.str().find('/') != std::string::npos; if (hasSlash) flags |= ArchiveMember::HasPathFlag; - if (hasSlash || filePath.toString().length() > 15) + if (hasSlash || filePath.str().length() > 15) flags |= ArchiveMember::HasLongFilenameFlag; - std::string magic; - mbr->path.getMagicNumber(magic,4); - switch (sys::IdentifyFileType(magic.c_str(),4)) { - case sys::BytecodeFileType: - flags |= ArchiveMember::BytecodeFlag; - break; - case sys::CompressedBytecodeFileType: - flags |= ArchiveMember::CompressedBytecodeFlag; + + sys::LLVMFileType type; + if (sys::fs::identify_magic(mbr->path.str(), type)) + type = sys::Unknown_FileType; + switch (type) { + case sys::Bitcode_FileType: + flags |= ArchiveMember::BitcodeFlag; break; default: break; @@ -206,32 +214,31 @@ Archive::writeMember( // Get the data and its size either from the // member's in-memory data or directly from the file. size_t fSize = member.getSize(); - const char* data = (const char*)member.getData(); - sys::MappedFile* mFile = 0; + const char *data = (const char*)member.getData(); + MemoryBuffer *mFile = 0; if (!data) { - mFile = new sys::MappedFile(); - if (mFile->open(member.getPath(), sys::MappedFile::READ_ACCESS, ErrMsg)) - return true; - if (!(data = (const char*) mFile->map(ErrMsg))) + OwningPtr File; + if (error_code ec = MemoryBuffer::getFile(member.getPath().c_str(), File)) { + if (ErrMsg) + *ErrMsg = ec.message(); return true; - fSize = mFile->size(); + } + mFile = File.take(); + data = mFile->getBufferStart(); + fSize = mFile->getBufferSize(); } // Now that we have the data in memory, update the - // symbol table if its a bytecode file. - if (CreateSymbolTable && - (member.isBytecode() || member.isCompressedBytecode())) { + // symbol table if it's a bitcode file. + if (CreateSymbolTable && member.isBitcode()) { std::vector symbols; - std::string FullMemberName = archPath.toString() + "(" + - member.getPath().toString() + std::string FullMemberName = archPath.str() + "(" + member.getPath().str() + ")"; - ModuleProvider* MP = - GetBytecodeSymbols((const unsigned char*)data,fSize, - FullMemberName, symbols, - Compressor::decompressToNewBuffer, ErrMsg); + Module* M = + GetBitcodeSymbols(data, fSize, FullMemberName, Context, symbols, ErrMsg); - // If the bytecode parsed successfully - if ( MP ) { + // If the bitcode parsed successfully + if ( M ) { for (std::vector::iterator SI = symbols.begin(), SE = symbols.end(); SI != SE; ++SI) { @@ -245,53 +252,17 @@ Archive::writeMember( } } // We don't need this module any more. - delete MP; + delete M; } else { - if (mFile != 0) { - mFile->close(); - delete mFile; - } + delete mFile; if (ErrMsg) - *ErrMsg = "Can't parse bytecode member: " + member.getPath().toString() + *ErrMsg = "Can't parse bitcode member: " + member.getPath().str() + ": " + *ErrMsg; return true; } } - // Determine if we actually should compress this member - bool willCompress = - (ShouldCompress && - !member.isCompressed() && - !member.isCompressedBytecode() && - !member.isLLVMSymbolTable() && - !member.isSVR4SymbolTable() && - !member.isBSD4SymbolTable()); - - // Perform the compression. Note that if the file is uncompressed bytecode - // then we turn the file into compressed bytecode rather than treating it as - // compressed data. This is necessary since it allows us to determine that the - // file contains bytecode instead of looking like a regular compressed data - // member. A compressed bytecode file has its content compressed but has a - // magic number of "llvc". This acounts for the +/-4 arithmetic in the code - // below. - int hdrSize; - if (willCompress) { - char* output = 0; - if (member.isBytecode()) { - data +=4; - fSize -= 4; - } - fSize = Compressor::compressToNewBuffer(data,fSize,output,ErrMsg); - if (fSize == 0) - return true; - data = output; - if (member.isBytecode()) - hdrSize = -fSize-4; - else - hdrSize = -fSize; - } else { - hdrSize = fSize; - } + int hdrSize = fSize; // Compute the fields of the header ArchiveMemberHeader Hdr; @@ -302,14 +273,10 @@ Archive::writeMember( // Write the long filename if its long if (writeLongName) { - ARFile.write(member.getPath().toString().data(), - member.getPath().toString().length()); + ARFile.write(member.getPath().str().data(), + member.getPath().str().length()); } - // Make sure we write the compressed bytecode magic number if we should. - if (willCompress && member.isBytecode()) - ARFile.write("llvc",4); - // Write the (possibly compressed) member's content to the file. ARFile.write(data,fSize); @@ -317,16 +284,8 @@ Archive::writeMember( if ((ARFile.tellp() & 1) == 1) ARFile << ARFILE_PAD; - // Free the compressed data, if necessary - if (willCompress) { - free((void*)data); - } - // Close the mapped file if it was opened - if (mFile != 0) { - mFile->close(); - delete mFile; - } + delete mFile; return false; } @@ -354,8 +313,10 @@ Archive::writeSymbolTable(std::ofstream& ARFile) { // Write the header ARFile.write((char*)&Hdr, sizeof(Hdr)); +#ifndef NDEBUG // Save the starting position of the symbol tables data content. unsigned startpos = ARFile.tellp(); +#endif // Write out the symbols sequentially for ( Archive::SymTabType::iterator I = symTab.begin(), E = symTab.end(); @@ -369,8 +330,10 @@ Archive::writeSymbolTable(std::ofstream& ARFile) { ARFile.write(I->first.data(), I->first.length()); } +#ifndef NDEBUG // Now that we're done with the symbol table, get the ending file position unsigned endpos = ARFile.tellp(); +#endif // Make sure that the amount we wrote is what we pre-computed. This is // critical for file integrity purposes. @@ -391,7 +354,7 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, { // Make sure they haven't opened up the file, not loaded it, // but are now trying to write it which would wipe out the file. - if (members.empty() && mapfile->size() > 8) { + if (members.empty() && mapfile && mapfile->getBufferSize() > 8) { if (ErrMsg) *ErrMsg = "Can't write an archive not opened for writing"; return true; @@ -412,10 +375,9 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, // Check for errors opening or creating archive file. if (!ArchiveFile.is_open() || ArchiveFile.bad()) { - if (TmpArchive.exists()) - TmpArchive.eraseFromDisk(); + TmpArchive.eraseFromDisk(); if (ErrMsg) - *ErrMsg = "Error opening archive file: " + archPath.toString(); + *ErrMsg = "Error opening archive file: " + archPath.str(); return true; } @@ -433,8 +395,7 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, for (MembersList::iterator I = begin(), E = end(); I != E; ++I) { if (writeMember(*I, ArchiveFile, CreateSymbolTable, TruncateNames, Compress, ErrMsg)) { - if (TmpArchive.exists()) - TmpArchive.eraseFromDisk(); + TmpArchive.eraseFromDisk(); ArchiveFile.close(); return true; } @@ -450,28 +411,29 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, // ensure compatibility with other archivers we need to put the symbol // table first in the file. Unfortunately, this means mapping the file // we just wrote back in and copying it to the destination file. + sys::Path FinalFilePath = archPath; // Map in the archive we just wrote. - sys::MappedFile arch; - if (arch.open(TmpArchive, sys::MappedFile::READ_ACCESS, ErrMsg)) - return true; - const char* base; - if (!(base = (const char*) arch.map(ErrMsg))) + { + OwningPtr arch; + if (error_code ec = MemoryBuffer::getFile(TmpArchive.c_str(), arch)) { + if (ErrMsg) + *ErrMsg = ec.message(); return true; + } + const char* base = arch->getBufferStart(); - // Open another temporary file in order to avoid invalidating the + // Open another temporary file in order to avoid invalidating the // mmapped data - sys::Path FinalFilePath = archPath; if (FinalFilePath.createTemporaryFileOnDisk(ErrMsg)) return true; sys::RemoveFileOnSignal(FinalFilePath); std::ofstream FinalFile(FinalFilePath.c_str(), io_mode); if (!FinalFile.is_open() || FinalFile.bad()) { - if (TmpArchive.exists()) - TmpArchive.eraseFromDisk(); + TmpArchive.eraseFromDisk(); if (ErrMsg) - *ErrMsg = "Error opening archive file: " + FinalFilePath.toString(); + *ErrMsg = "Error opening archive file: " + FinalFilePath.str(); return true; } @@ -486,8 +448,7 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, if (foreignST) { if (writeMember(*foreignST, FinalFile, false, false, false, ErrMsg)) { FinalFile.close(); - if (TmpArchive.exists()) - TmpArchive.eraseFromDisk(); + TmpArchive.eraseFromDisk(); return true; } } @@ -498,24 +459,31 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, // Copy the temporary file contents being sure to skip the file's magic // number. FinalFile.write(base + sizeof(ARFILE_MAGIC)-1, - arch.size()-sizeof(ARFILE_MAGIC)+1); + arch->getBufferSize()-sizeof(ARFILE_MAGIC)+1); // Close up shop FinalFile.close(); - arch.close(); - + } // free arch. + // Move the final file over top of TmpArchive if (FinalFilePath.renamePathOnDisk(TmpArchive, ErrMsg)) return true; } - + // Before we replace the actual archive, we need to forget all the // members, since they point to data in that old archive. We need to do // this because we cannot replace an open file on Windows. cleanUpMemory(); - + if (TmpArchive.renamePathOnDisk(archPath, ErrMsg)) return true; + // Set correct read and write permissions after temporary file is moved + // to final destination path. + if (archPath.makeReadableOnDisk(ErrMsg)) + return true; + if (archPath.makeWriteableOnDisk(ErrMsg)) + return true; + return false; }