diff options
| author | 2015-12-09 07:50:57 -0800 | |
|---|---|---|
| committer | 2015-12-09 07:50:57 -0800 | |
| commit | 783b80fe6725a50e75b2a80e634964dcd30ebe47 (patch) | |
| tree | d013aab7b474910ae0b503c3da32a05302cc68a9 | |
| parent | ce025fa3dabb408e3b4f66b58b28cfaa99da9995 (diff) | |
| parent | 7678a1a0609cc9e0ed25cea5b473d3f098c09338 (diff) | |
Merge "ART: Add FdFile::Copy() to copy data from another file." am: 976af0a291
am: 7678a1a060
* commit '7678a1a0609cc9e0ed25cea5b473d3f098c09338':
ART: Add FdFile::Copy() to copy data from another file.
| -rw-r--r-- | runtime/Android.mk | 1 | ||||
| -rw-r--r-- | runtime/base/file_magic.cc | 58 | ||||
| -rw-r--r-- | runtime/base/file_magic.h | 36 | ||||
| -rw-r--r-- | runtime/base/unix_file/fd_file.cc | 56 | ||||
| -rw-r--r-- | runtime/base/unix_file/fd_file.h | 15 | ||||
| -rw-r--r-- | runtime/base/unix_file/fd_file_test.cc | 30 | ||||
| -rw-r--r-- | runtime/dex_file.cc | 21 | ||||
| -rw-r--r-- | runtime/utils.cc | 15 | ||||
| -rw-r--r-- | runtime/utils.h | 5 |
9 files changed, 191 insertions, 46 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk index c1b74f6aaf..c4b4a70315 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -27,6 +27,7 @@ LIBART_COMMON_SRC_FILES := \ base/arena_allocator.cc \ base/arena_bit_vector.cc \ base/bit_vector.cc \ + base/file_magic.cc \ base/hex_dump.cc \ base/logging.cc \ base/mutex.cc \ diff --git a/runtime/base/file_magic.cc b/runtime/base/file_magic.cc new file mode 100644 index 0000000000..97563382a1 --- /dev/null +++ b/runtime/base/file_magic.cc @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "file_magic.h" + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "base/logging.h" +#include "dex_file.h" +#include "stringprintf.h" + +namespace art { + +ScopedFd OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg) { + CHECK(magic != nullptr); + ScopedFd fd(open(filename, O_RDONLY, 0)); + if (fd.get() == -1) { + *error_msg = StringPrintf("Unable to open '%s' : %s", filename, strerror(errno)); + return ScopedFd(); + } + int n = TEMP_FAILURE_RETRY(read(fd.get(), magic, sizeof(*magic))); + if (n != sizeof(*magic)) { + *error_msg = StringPrintf("Failed to find magic in '%s'", filename); + return ScopedFd(); + } + if (lseek(fd.get(), 0, SEEK_SET) != 0) { + *error_msg = StringPrintf("Failed to seek to beginning of file '%s' : %s", filename, + strerror(errno)); + return ScopedFd(); + } + return fd; +} + +bool IsZipMagic(uint32_t magic) { + return (('P' == ((magic >> 0) & 0xff)) && + ('K' == ((magic >> 8) & 0xff))); +} + +bool IsDexMagic(uint32_t magic) { + return DexFile::IsMagicValid(reinterpret_cast<const uint8_t*>(&magic)); +} + +} // namespace art diff --git a/runtime/base/file_magic.h b/runtime/base/file_magic.h new file mode 100644 index 0000000000..f7e4bad16d --- /dev/null +++ b/runtime/base/file_magic.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_BASE_FILE_MAGIC_H_ +#define ART_RUNTIME_BASE_FILE_MAGIC_H_ + +#include <stdint.h> +#include <string> + +#include "ScopedFd.h" + +namespace art { + +// Open file and read magic number +ScopedFd OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg); + +// Check whether the given magic matches a known file type. +bool IsZipMagic(uint32_t magic); +bool IsDexMagic(uint32_t magic); + +} // namespace art + +#endif // ART_RUNTIME_BASE_FILE_MAGIC_H_ diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc index 07cadc48d6..78bc3d5f9f 100644 --- a/runtime/base/unix_file/fd_file.cc +++ b/runtime/base/unix_file/fd_file.cc @@ -17,12 +17,22 @@ #include "base/unix_file/fd_file.h" #include <errno.h> +#include <limits> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include "base/logging.h" +// Includes needed for FdFile::Copy(). +#ifdef __linux__ +#include <sys/sendfile.h> +#else +#include <algorithm> +#include "base/stl_util.h" +#include "globals.h" +#endif + namespace unix_file { FdFile::FdFile() : guard_state_(GuardState::kClosed), fd_(-1), auto_close_(true) { @@ -222,6 +232,52 @@ bool FdFile::WriteFully(const void* buffer, size_t byte_count) { return true; } +bool FdFile::Copy(FdFile* input_file, int64_t offset, int64_t size) { + off_t off = static_cast<off_t>(offset); + off_t sz = static_cast<off_t>(size); + if (offset < 0 || static_cast<int64_t>(off) != offset || + size < 0 || static_cast<int64_t>(sz) != size || + sz > std::numeric_limits<off_t>::max() - off) { + errno = EINVAL; + return false; + } + if (size == 0) { + return true; + } +#ifdef __linux__ + // Use sendfile(), available for files since linux kernel 2.6.33. + off_t end = off + sz; + while (off != end) { + int result = TEMP_FAILURE_RETRY( + sendfile(Fd(), input_file->Fd(), &off, end - off)); + if (result == -1) { + return false; + } + // Ignore the number of bytes in `result`, sendfile() already updated `off`. + } +#else + if (lseek(input_file->Fd(), off, SEEK_SET) != off) { + return false; + } + constexpr size_t kMaxBufferSize = 4 * ::art::kPageSize; + const size_t buffer_size = std::min<uint64_t>(size, kMaxBufferSize); + art::UniqueCPtr<void> buffer(malloc(buffer_size)); + if (buffer == nullptr) { + errno = ENOMEM; + return false; + } + while (size != 0) { + size_t chunk_size = std::min<uint64_t>(buffer_size, size); + if (!input_file->ReadFully(buffer.get(), chunk_size) || + !WriteFully(buffer.get(), chunk_size)) { + return false; + } + size -= chunk_size; + } +#endif + return true; +} + void FdFile::Erase() { TEMP_FAILURE_RETRY(SetLength(0)); TEMP_FAILURE_RETRY(Flush()); diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h index f47368b180..231a1ab145 100644 --- a/runtime/base/unix_file/fd_file.h +++ b/runtime/base/unix_file/fd_file.h @@ -50,12 +50,12 @@ class FdFile : public RandomAccessFile { bool Open(const std::string& file_path, int flags, mode_t mode); // RandomAccessFile API. - virtual int Close() WARN_UNUSED; - virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const WARN_UNUSED; - virtual int SetLength(int64_t new_length) WARN_UNUSED; - virtual int64_t GetLength() const; - virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset) WARN_UNUSED; - virtual int Flush() WARN_UNUSED; + int Close() OVERRIDE WARN_UNUSED; + int64_t Read(char* buf, int64_t byte_count, int64_t offset) const OVERRIDE WARN_UNUSED; + int SetLength(int64_t new_length) OVERRIDE WARN_UNUSED; + int64_t GetLength() const OVERRIDE; + int64_t Write(const char* buf, int64_t byte_count, int64_t offset) OVERRIDE WARN_UNUSED; + int Flush() OVERRIDE WARN_UNUSED; // Short for SetLength(0); Flush(); Close(); void Erase(); @@ -77,6 +77,9 @@ class FdFile : public RandomAccessFile { bool PreadFully(void* buffer, size_t byte_count, size_t offset) WARN_UNUSED; bool WriteFully(const void* buffer, size_t byte_count) WARN_UNUSED; + // Copy data from another file. + bool Copy(FdFile* input_file, int64_t offset, int64_t size); + // This enum is public so that we can define the << operator over it. enum class GuardState { kBase, // Base, file has not been flushed or closed. diff --git a/runtime/base/unix_file/fd_file_test.cc b/runtime/base/unix_file/fd_file_test.cc index 388f717922..ecf607c892 100644 --- a/runtime/base/unix_file/fd_file_test.cc +++ b/runtime/base/unix_file/fd_file_test.cc @@ -110,4 +110,34 @@ TEST_F(FdFileTest, ReadFullyWithOffset) { ASSERT_EQ(file.Close(), 0); } +TEST_F(FdFileTest, Copy) { + art::ScratchFile src_tmp; + FdFile src; + ASSERT_TRUE(src.Open(src_tmp.GetFilename(), O_RDWR)); + ASSERT_GE(src.Fd(), 0); + ASSERT_TRUE(src.IsOpened()); + + char src_data[] = "Some test data."; + ASSERT_TRUE(src.WriteFully(src_data, sizeof(src_data))); // Including the zero terminator. + ASSERT_EQ(0, src.Flush()); + ASSERT_EQ(static_cast<int64_t>(sizeof(src_data)), src.GetLength()); + + art::ScratchFile dest_tmp; + FdFile dest; + ASSERT_TRUE(dest.Open(src_tmp.GetFilename(), O_RDWR)); + ASSERT_GE(dest.Fd(), 0); + ASSERT_TRUE(dest.IsOpened()); + + ASSERT_TRUE(dest.Copy(&src, 0, sizeof(src_data))); + ASSERT_EQ(0, dest.Flush()); + ASSERT_EQ(static_cast<int64_t>(sizeof(src_data)), dest.GetLength()); + + char check_data[sizeof(src_data)]; + ASSERT_TRUE(dest.PreadFully(check_data, sizeof(src_data), 0u)); + CHECK_EQ(0, memcmp(check_data, src_data, sizeof(src_data))); + + ASSERT_EQ(0, dest.Close()); + ASSERT_EQ(0, src.Close()); +} + } // namespace unix_file diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 4163e2efdf..30d921afe6 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -29,6 +29,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" +#include "base/file_magic.h" #include "base/hash_map.h" #include "base/logging.h" #include "base/stl_util.h" @@ -62,26 +63,6 @@ namespace art { const uint8_t DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' }; const uint8_t DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' }; -static int OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg) { - CHECK(magic != nullptr); - ScopedFd fd(open(filename, O_RDONLY, 0)); - if (fd.get() == -1) { - *error_msg = StringPrintf("Unable to open '%s' : %s", filename, strerror(errno)); - return -1; - } - int n = TEMP_FAILURE_RETRY(read(fd.get(), magic, sizeof(*magic))); - if (n != sizeof(*magic)) { - *error_msg = StringPrintf("Failed to find magic in '%s'", filename); - return -1; - } - if (lseek(fd.get(), 0, SEEK_SET) != 0) { - *error_msg = StringPrintf("Failed to seek to beginning of file '%s' : %s", filename, - strerror(errno)); - return -1; - } - return fd.release(); -} - bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg) { CHECK(checksum != nullptr); uint32_t magic; diff --git a/runtime/utils.cc b/runtime/utils.cc index 68db7e3a73..eddc3a417a 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -1392,21 +1392,6 @@ std::string GetSystemImageFilename(const char* location, const InstructionSet is return filename; } -bool IsZipMagic(uint32_t magic) { - return (('P' == ((magic >> 0) & 0xff)) && - ('K' == ((magic >> 8) & 0xff))); -} - -bool IsDexMagic(uint32_t magic) { - return DexFile::IsMagicValid(reinterpret_cast<const uint8_t*>(&magic)); -} - -bool IsOatMagic(uint32_t magic) { - return (memcmp(reinterpret_cast<const uint8_t*>(magic), - OatHeader::kOatMagic, - sizeof(OatHeader::kOatMagic)) == 0); -} - bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) { const std::string command_line(Join(arg_vector, ' ')); diff --git a/runtime/utils.h b/runtime/utils.h index 8b7941a1b2..5b9e963919 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -273,11 +273,6 @@ std::string GetDalvikCacheFilenameOrDie(const char* file_location, // Returns the system location for an image std::string GetSystemImageFilename(const char* location, InstructionSet isa); -// Check whether the given magic matches a known file type. -bool IsZipMagic(uint32_t magic); -bool IsDexMagic(uint32_t magic); -bool IsOatMagic(uint32_t magic); - // Wrapper on fork/execv to run a command in a subprocess. bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg); |