From a456c2134882c7cede4d0f617a20ce0f8f8f3358 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 15 Nov 2016 10:08:07 -0800 Subject: [PATCH] ziparchive: Allow ExtractEntryToFile() to work with block device. FileWriter::Create() calls ftruncate(2) to truncate the destination file, which doesn't work with FD that references a block device. It leads to kIoError when calling ExtractEntryToFile() to extract an entry to block device FD. As a result, it fails the package_extract_file() command in OTA updates (e.g. 'package_extract_file("boot.img", "/dev/block/platform/soc.0/f9824900.sdhci/by-name/boot")'). This CL skips the call to ftruncate(2) if FD references a block device. Bug: 32903624 Test: ziparchive-tests works. Test: Build an OTA updater (m updater) and call package_extract_file(). Change-Id: Ia81116f1a8d7cab802396bdc32c6096b4cb56a3c --- include/ziparchive/zip_archive.h | 3 ++- libziparchive/zip_archive.cc | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h index fc845a44e..54946fc93 100644 --- a/include/ziparchive/zip_archive.h +++ b/include/ziparchive/zip_archive.h @@ -195,7 +195,8 @@ void EndIteration(void* cookie); * Uncompress and write an entry to an open file identified by |fd|. * |entry->uncompressed_length| bytes will be written to the file at * its current offset, and the file will be truncated at the end of - * the uncompressed data. + * the uncompressed data (no truncation if |fd| references a block + * device). * * Returns 0 on success and negative values on failure. */ diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index d36cc3fe5..e6e0276a3 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -781,7 +781,8 @@ class FileWriter : public Writer { // Creates a FileWriter for |fd| and prepare to write |entry| to it, // guaranteeing that the file descriptor is valid and that there's enough // space on the volume to write out the entry completely and that the file - // is truncated to the correct length. + // is truncated to the correct length (no truncation if |fd| references a + // block device). // // Returns a valid FileWriter on success, |nullptr| if an error occurred. static std::unique_ptr Create(int fd, const ZipEntry* entry) { @@ -814,13 +815,22 @@ class FileWriter : public Writer { } #endif // __linux__ - result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); - if (result == -1) { - ALOGW("Zip: unable to truncate file to %" PRId64 ": %s", - static_cast(declared_length + current_offset), strerror(errno)); + struct stat sb; + if (fstat(fd, &sb) == -1) { + ALOGW("Zip: unable to fstat file: %s", strerror(errno)); return std::unique_ptr(nullptr); } + // Block device doesn't support ftruncate(2). + if (!S_ISBLK(sb.st_mode)) { + result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); + if (result == -1) { + ALOGW("Zip: unable to truncate file to %" PRId64 ": %s", + static_cast(declared_length + current_offset), strerror(errno)); + return std::unique_ptr(nullptr); + } + } + return std::unique_ptr(new FileWriter(fd, declared_length)); }