Loading base/file.cpp +31 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,37 @@ bool ReadFully(int fd, void* data, size_t byte_count) { return true; } #if defined(_WIN32) // Windows implementation of pread. Note that this DOES move the file descriptors read position, // but it does so atomically. static ssize_t pread(int fd, void* data, size_t byte_count, off64_t offset) { DWORD bytes_read; OVERLAPPED overlapped; memset(&overlapped, 0, sizeof(OVERLAPPED)); overlapped.Offset = static_cast<DWORD>(offset); overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32); if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), data, static_cast<DWORD>(byte_count), &bytes_read, &overlapped)) { // In case someone tries to read errno (since this is masquerading as a POSIX call) errno = EIO; return -1; } return static_cast<ssize_t>(bytes_read); } #endif bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) { uint8_t* p = reinterpret_cast<uint8_t*>(data); while (byte_count > 0) { ssize_t n = TEMP_FAILURE_RETRY(pread(fd, p, byte_count, offset)); if (n <= 0) return false; p += n; byte_count -= n; offset += n; } return true; } bool WriteFully(int fd, const void* data, size_t byte_count) { const uint8_t* p = reinterpret_cast<const uint8_t*>(data); size_t remaining = byte_count; Loading base/include/android-base/file.h +11 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,17 @@ bool WriteStringToFile(const std::string& content, const std::string& path, #endif bool ReadFully(int fd, void* data, size_t byte_count); // Reads `byte_count` bytes from the file descriptor at the specified offset. // Returns false if there was an IO error or EOF was reached before reading `byte_count` bytes. // // NOTE: On Linux/Mac, this function wraps pread, which provides atomic read support without // modifying the read pointer of the file descriptor. On Windows, however, the read pointer does // get modified. This means that ReadFullyAtOffset can be used concurrently with other calls to the // same function, but concurrently seeking or reading incrementally can lead to unexpected // behavior. bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset); bool WriteFully(int fd, const void* data, size_t byte_count); bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr); Loading libziparchive/include/ziparchive/zip_archive_stream_entry.h +2 −1 Original line number Diff line number Diff line Loading @@ -40,7 +40,8 @@ class ZipArchiveStreamEntry { ZipArchiveHandle handle_; uint32_t crc32_; off64_t offset_ = 0; uint32_t crc32_ = 0u; }; #endif // LIBZIPARCHIVE_ZIPARCHIVESTREAMENTRY_H_ libziparchive/zip_archive.cc +27 −52 Original line number Diff line number Diff line Loading @@ -435,13 +435,20 @@ void CloseArchive(ZipArchiveHandle handle) { static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry) { uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)]; if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) { off64_t offset = entry->offset; if (entry->method != kCompressStored) { offset += entry->compressed_length; } else { offset += entry->uncompressed_length; } if (!mapped_zip.ReadAtOffset(ddBuf, sizeof(ddBuf), offset)) { return kIoError; } const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf)); const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0; const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset); const uint16_t ddOffset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0; const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + ddOffset); // Validate that the values in the data descriptor match those in the central // directory. Loading Loading @@ -899,7 +906,9 @@ static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* e /* read as much as we can */ if (zstream.avail_in == 0) { const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length; if (!mapped_zip.ReadData(read_buf.data(), getSize)) { off64_t offset = entry->offset + (entry->compressed_length - compressed_length); // Make sure to read at offset to ensure concurrent access to the fd. if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) { ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno)); return kIoError; } Loading Loading @@ -962,12 +971,15 @@ static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entr uint64_t crc = 0; while (count < length) { uint32_t remaining = length - count; off64_t offset = entry->offset + count; // Safe conversion because kBufSize is narrow enough for a 32 bit signed // value. // Safe conversion because kBufSize is narrow enough for a 32 bit signed value. const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining; if (!mapped_zip.ReadData(buf.data(), block_size)) { ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno)); // Make sure to read at offset to ensure concurrent access to the fd. if (!mapped_zip.ReadAtOffset(buf.data(), block_size, offset)) { ALOGW("CopyFileToFile: copy read failed, block_size = %zu, offset = %" PRId64 ": %s", block_size, static_cast<int64_t>(offset), strerror(errno)); return kIoError; } Loading @@ -986,12 +998,6 @@ static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entr int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) { ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); const uint16_t method = entry->method; off64_t data_offset = entry->offset; if (!archive->mapped_zip.SeekToOffset(data_offset)) { ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset)); return kIoError; } // this should default to kUnknownCompressionMethod. int32_t return_value = -1; Loading Loading @@ -1111,52 +1117,21 @@ off64_t MappedZipFile::GetFileLength() const { } } bool MappedZipFile::SeekToOffset(off64_t offset) { if (has_fd_) { if (lseek64(fd_, offset, SEEK_SET) != offset) { ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno)); return false; } return true; } else { if (offset < 0 || offset > static_cast<off64_t>(data_length_)) { ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", offset, data_length_); return false; } read_pos_ = offset; return true; } } bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) { if (has_fd_) { if (!android::base::ReadFully(fd_, buffer, read_amount)) { ALOGE("Zip: read from %d failed\n", fd_); return false; } } else { memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount); read_pos_ += read_amount; } return true; } // Attempts to read |len| bytes into |buf| at offset |off|. bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) { #if !defined(_WIN32) if (has_fd_) { if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) { if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) { ALOGE("Zip: failed to read at offset %" PRId64 "\n", off); return false; } return true; } #endif if (!SeekToOffset(off)) { } else { if (off < 0 || off > static_cast<off64_t>(data_length_)) { ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", off, data_length_); return false; } return ReadData(buf, len); memcpy(buf, static_cast<uint8_t*>(base_ptr_) + off, len); } return true; } void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) { Loading libziparchive/zip_archive_private.h +2 −12 Original line number Diff line number Diff line Loading @@ -93,14 +93,10 @@ enum ErrorCodes : int32_t { class MappedZipFile { public: explicit MappedZipFile(const int fd) : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0), read_pos_(0) {} : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0) {} explicit MappedZipFile(void* address, size_t length) : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)), read_pos_(0) {} : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)) {} bool HasFd() const { return has_fd_; } Loading @@ -110,10 +106,6 @@ class MappedZipFile { off64_t GetFileLength() const; bool SeekToOffset(off64_t offset); bool ReadData(uint8_t* buffer, size_t read_amount); bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off); private: Loading @@ -127,8 +119,6 @@ class MappedZipFile { void* const base_ptr_; const off64_t data_length_; // read_pos_ is the offset to the base_ptr_ where we read data from. size_t read_pos_; }; class CentralDirectory { Loading Loading
base/file.cpp +31 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,37 @@ bool ReadFully(int fd, void* data, size_t byte_count) { return true; } #if defined(_WIN32) // Windows implementation of pread. Note that this DOES move the file descriptors read position, // but it does so atomically. static ssize_t pread(int fd, void* data, size_t byte_count, off64_t offset) { DWORD bytes_read; OVERLAPPED overlapped; memset(&overlapped, 0, sizeof(OVERLAPPED)); overlapped.Offset = static_cast<DWORD>(offset); overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32); if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), data, static_cast<DWORD>(byte_count), &bytes_read, &overlapped)) { // In case someone tries to read errno (since this is masquerading as a POSIX call) errno = EIO; return -1; } return static_cast<ssize_t>(bytes_read); } #endif bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) { uint8_t* p = reinterpret_cast<uint8_t*>(data); while (byte_count > 0) { ssize_t n = TEMP_FAILURE_RETRY(pread(fd, p, byte_count, offset)); if (n <= 0) return false; p += n; byte_count -= n; offset += n; } return true; } bool WriteFully(int fd, const void* data, size_t byte_count) { const uint8_t* p = reinterpret_cast<const uint8_t*>(data); size_t remaining = byte_count; Loading
base/include/android-base/file.h +11 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,17 @@ bool WriteStringToFile(const std::string& content, const std::string& path, #endif bool ReadFully(int fd, void* data, size_t byte_count); // Reads `byte_count` bytes from the file descriptor at the specified offset. // Returns false if there was an IO error or EOF was reached before reading `byte_count` bytes. // // NOTE: On Linux/Mac, this function wraps pread, which provides atomic read support without // modifying the read pointer of the file descriptor. On Windows, however, the read pointer does // get modified. This means that ReadFullyAtOffset can be used concurrently with other calls to the // same function, but concurrently seeking or reading incrementally can lead to unexpected // behavior. bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset); bool WriteFully(int fd, const void* data, size_t byte_count); bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr); Loading
libziparchive/include/ziparchive/zip_archive_stream_entry.h +2 −1 Original line number Diff line number Diff line Loading @@ -40,7 +40,8 @@ class ZipArchiveStreamEntry { ZipArchiveHandle handle_; uint32_t crc32_; off64_t offset_ = 0; uint32_t crc32_ = 0u; }; #endif // LIBZIPARCHIVE_ZIPARCHIVESTREAMENTRY_H_
libziparchive/zip_archive.cc +27 −52 Original line number Diff line number Diff line Loading @@ -435,13 +435,20 @@ void CloseArchive(ZipArchiveHandle handle) { static int32_t ValidateDataDescriptor(MappedZipFile& mapped_zip, ZipEntry* entry) { uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)]; if (!mapped_zip.ReadData(ddBuf, sizeof(ddBuf))) { off64_t offset = entry->offset; if (entry->method != kCompressStored) { offset += entry->compressed_length; } else { offset += entry->uncompressed_length; } if (!mapped_zip.ReadAtOffset(ddBuf, sizeof(ddBuf), offset)) { return kIoError; } const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf)); const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0; const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset); const uint16_t ddOffset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0; const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + ddOffset); // Validate that the values in the data descriptor match those in the central // directory. Loading Loading @@ -899,7 +906,9 @@ static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* e /* read as much as we can */ if (zstream.avail_in == 0) { const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length; if (!mapped_zip.ReadData(read_buf.data(), getSize)) { off64_t offset = entry->offset + (entry->compressed_length - compressed_length); // Make sure to read at offset to ensure concurrent access to the fd. if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) { ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno)); return kIoError; } Loading Loading @@ -962,12 +971,15 @@ static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entr uint64_t crc = 0; while (count < length) { uint32_t remaining = length - count; off64_t offset = entry->offset + count; // Safe conversion because kBufSize is narrow enough for a 32 bit signed // value. // Safe conversion because kBufSize is narrow enough for a 32 bit signed value. const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining; if (!mapped_zip.ReadData(buf.data(), block_size)) { ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno)); // Make sure to read at offset to ensure concurrent access to the fd. if (!mapped_zip.ReadAtOffset(buf.data(), block_size, offset)) { ALOGW("CopyFileToFile: copy read failed, block_size = %zu, offset = %" PRId64 ": %s", block_size, static_cast<int64_t>(offset), strerror(errno)); return kIoError; } Loading @@ -986,12 +998,6 @@ static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entr int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, Writer* writer) { ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); const uint16_t method = entry->method; off64_t data_offset = entry->offset; if (!archive->mapped_zip.SeekToOffset(data_offset)) { ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset)); return kIoError; } // this should default to kUnknownCompressionMethod. int32_t return_value = -1; Loading Loading @@ -1111,52 +1117,21 @@ off64_t MappedZipFile::GetFileLength() const { } } bool MappedZipFile::SeekToOffset(off64_t offset) { if (has_fd_) { if (lseek64(fd_, offset, SEEK_SET) != offset) { ALOGE("Zip: lseek to %" PRId64 " failed: %s\n", offset, strerror(errno)); return false; } return true; } else { if (offset < 0 || offset > static_cast<off64_t>(data_length_)) { ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", offset, data_length_); return false; } read_pos_ = offset; return true; } } bool MappedZipFile::ReadData(uint8_t* buffer, size_t read_amount) { if (has_fd_) { if (!android::base::ReadFully(fd_, buffer, read_amount)) { ALOGE("Zip: read from %d failed\n", fd_); return false; } } else { memcpy(buffer, static_cast<uint8_t*>(base_ptr_) + read_pos_, read_amount); read_pos_ += read_amount; } return true; } // Attempts to read |len| bytes into |buf| at offset |off|. bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) { #if !defined(_WIN32) if (has_fd_) { if (static_cast<size_t>(TEMP_FAILURE_RETRY(pread64(fd_, buf, len, off))) != len) { if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) { ALOGE("Zip: failed to read at offset %" PRId64 "\n", off); return false; } return true; } #endif if (!SeekToOffset(off)) { } else { if (off < 0 || off > static_cast<off64_t>(data_length_)) { ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", off, data_length_); return false; } return ReadData(buf, len); memcpy(buf, static_cast<uint8_t*>(base_ptr_) + off, len); } return true; } void CentralDirectory::Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size) { Loading
libziparchive/zip_archive_private.h +2 −12 Original line number Diff line number Diff line Loading @@ -93,14 +93,10 @@ enum ErrorCodes : int32_t { class MappedZipFile { public: explicit MappedZipFile(const int fd) : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0), read_pos_(0) {} : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0) {} explicit MappedZipFile(void* address, size_t length) : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)), read_pos_(0) {} : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)) {} bool HasFd() const { return has_fd_; } Loading @@ -110,10 +106,6 @@ class MappedZipFile { off64_t GetFileLength() const; bool SeekToOffset(off64_t offset); bool ReadData(uint8_t* buffer, size_t read_amount); bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off); private: Loading @@ -127,8 +119,6 @@ class MappedZipFile { void* const base_ptr_; const off64_t data_length_; // read_pos_ is the offset to the base_ptr_ where we read data from. size_t read_pos_; }; class CentralDirectory { Loading