error_code Archive::Child::getAsBinary(OwningPtr<Binary> &Result) const { OwningPtr<Binary> ret; if (error_code ec = createBinary(getBuffer(), ret)) return ec; Result.swap(ret); return object_error::success; }
error_code Archive::Child::getAsBinary(OwningPtr<Binary> &Result) const { OwningPtr<Binary> ret; OwningPtr<MemoryBuffer> Buff; if (error_code ec = getMemoryBuffer(Buff)) return ec; if (error_code ec = createBinary(Buff.take(), ret)) return ec; Result.swap(ret); return object_error::success; }
error_code object::createBinary(MemoryBuffer *Source, OwningPtr<Binary> &Result) { OwningPtr<MemoryBuffer> scopedSource(Source); if (!Source) return make_error_code(errc::invalid_argument); sys::fs::file_magic type = sys::fs::identify_magic(Source->getBuffer()); error_code ec; switch (type) { case sys::fs::file_magic::archive: { OwningPtr<Binary> ret(new Archive(scopedSource.take(), ec)); if (ec) return ec; Result.swap(ret); return object_error::success; } case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::elf_executable: case sys::fs::file_magic::elf_shared_object: case sys::fs::file_magic::elf_core: { OwningPtr<Binary> ret( ObjectFile::createELFObjectFile(scopedSource.take())); if (!ret) return object_error::invalid_file_type; Result.swap(ret); return object_error::success; } case sys::fs::file_magic::macho_object: case sys::fs::file_magic::macho_executable: case sys::fs::file_magic::macho_fixed_virtual_memory_shared_lib: case sys::fs::file_magic::macho_core: case sys::fs::file_magic::macho_preload_executable: case sys::fs::file_magic::macho_dynamically_linked_shared_lib: case sys::fs::file_magic::macho_dynamic_linker: case sys::fs::file_magic::macho_bundle: case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: case sys::fs::file_magic::macho_dsym_companion: { OwningPtr<Binary> ret( ObjectFile::createMachOObjectFile(scopedSource.take())); if (!ret) return object_error::invalid_file_type; Result.swap(ret); return object_error::success; } case sys::fs::file_magic::macho_universal_binary: { OwningPtr<Binary> ret(new MachOUniversalBinary(scopedSource.take(), ec)); if (ec) return ec; Result.swap(ret); return object_error::success; } case sys::fs::file_magic::coff_object: case sys::fs::file_magic::pecoff_executable: { OwningPtr<Binary> ret( ObjectFile::createCOFFObjectFile(scopedSource.take())); if (!ret) return object_error::invalid_file_type; Result.swap(ret); return object_error::success; } case sys::fs::file_magic::unknown: case sys::fs::file_magic::bitcode: { // Unrecognized object file format. return object_error::invalid_file_type; } } llvm_unreachable("Unexpected Binary File Type"); }
error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, OwningPtr<MemoryBuffer> &result, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator) { static int PageSize = sys::Process::GetPageSize(); // Default is to map the full file. if (MapSize == uint64_t(-1)) { // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. if (FileSize == uint64_t(-1)) { struct stat FileInfo; // TODO: This should use fstat64 when available. if (fstat(FD, &FileInfo) == -1) { return error_code(errno, posix_category()); } FileSize = FileInfo.st_size; } MapSize = FileSize; } if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, PageSize)) { off_t RealMapOffset = Offset & ~(PageSize - 1); off_t Delta = Offset - RealMapOffset; size_t RealMapSize = MapSize + Delta; if (const char *Pages = sys::Path::MapInFilePages(FD, RealMapSize, RealMapOffset)) { result.reset(GetNamedBuffer<MemoryBufferMMapFile>( StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator)); return error_code::success(); } } MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); if (!Buf) { // Failed to create a buffer. The only way it can fail is if // new(std::nothrow) returns 0. return make_error_code(errc::not_enough_memory); } OwningPtr<MemoryBuffer> SB(Buf); char *BufPtr = const_cast<char*>(SB->getBufferStart()); size_t BytesLeft = MapSize; #ifndef HAVE_PREAD if (lseek(FD, Offset, SEEK_SET) == -1) return error_code(errno, posix_category()); #endif while (BytesLeft) { #ifdef HAVE_PREAD ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset); #else ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); #endif if (NumRead == -1) { if (errno == EINTR) continue; // Error while reading. return error_code(errno, posix_category()); } if (NumRead == 0) { assert(0 && "We got inaccurate FileSize value or fstat reported an " "invalid file size."); *BufPtr = '\0'; // null-terminate at the actual size. break; } BytesLeft -= NumRead; BufPtr += NumRead; } result.swap(SB); return error_code::success(); }
static error_code getOpenFileImpl(int FD, const char *Filename, OwningPtr<MemoryBuffer> &result, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator) { static int PageSize = sys::process::get_self()->page_size(); // Default is to map the full file. if (MapSize == uint64_t(-1)) { // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. if (FileSize == uint64_t(-1)) { sys::fs::file_status Status; error_code EC = sys::fs::status(FD, Status); if (EC) return EC; // If this not a file or a block device (e.g. it's a named pipe // or character device), we can't trust the size. Create the memory // buffer by copying off the stream. sys::fs::file_type Type = Status.type(); if (Type != sys::fs::file_type::regular_file && Type != sys::fs::file_type::block_file) return getMemoryBufferForStream(FD, Filename, result); FileSize = Status.getSize(); } MapSize = FileSize; } if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, PageSize)) { error_code EC; result.reset(new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile( RequiresNullTerminator, FD, MapSize, Offset, EC)); if (!EC) return error_code::success(); } MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); if (!Buf) { // Failed to create a buffer. The only way it can fail is if // new(std::nothrow) returns 0. return make_error_code(errc::not_enough_memory); } OwningPtr<MemoryBuffer> SB(Buf); char *BufPtr = const_cast<char*>(SB->getBufferStart()); size_t BytesLeft = MapSize; #ifndef HAVE_PREAD if (lseek(FD, Offset, SEEK_SET) == -1) return error_code(errno, posix_category()); #endif while (BytesLeft) { #ifdef HAVE_PREAD ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset); #else ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); #endif if (NumRead == -1) { if (errno == EINTR) continue; // Error while reading. return error_code(errno, posix_category()); } if (NumRead == 0) { assert(0 && "We got inaccurate FileSize value or fstat reported an " "invalid file size."); *BufPtr = '\0'; // null-terminate at the actual size. break; } BytesLeft -= NumRead; BufPtr += NumRead; } result.swap(SB); return error_code::success(); }