diff options
author | 2012-12-12 16:31:20 -0800 | |
---|---|---|
committer | 2012-12-12 16:31:20 -0800 | |
commit | 761600567d73b23324ae0251e871c15d6849ffd8 (patch) | |
tree | 4757cb01233394fa2e9c461a68fc37a35c12dabb | |
parent | 89c41e5f2fa10e7b97698b9714bd4883a73132f0 (diff) |
Switch over to the google3 unix_file File*.
I also moved macros.h to base/macros.h to ease google3 porting, at
the expense of a larger than necessary change. (I learned my lesson,
though, and didn't make the equivalent base/logging.h change.)
I'm not sure whether we want to keep the unix_file MappedFile given
our existing MemMap, but it's easier to bring it over and then remove
it (and possibly revert the removal) than to bring it over later.
Change-Id: Id50a66faa5ab17b9bc936cc9043dbc26f791f0ca
93 files changed, 1721 insertions, 472 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk index 7873645414..cd0b27f6c9 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -132,6 +132,11 @@ OATEXEC_SRC_FILES := \ LIBART_COMMON_SRC_FILES := \ src/atomic.cc.arm \ + src/base/unix_file/fd_file.cc \ + src/base/unix_file/mapped_file.cc \ + src/base/unix_file/null_file.cc \ + src/base/unix_file/random_access_file_utils.cc \ + src/base/unix_file/string_file.cc \ src/barrier.cc \ src/check_jni.cc \ src/class_linker.cc \ @@ -148,8 +153,6 @@ LIBART_COMMON_SRC_FILES := \ src/disassembler_mips.cc \ src/disassembler_x86.cc \ src/dlmalloc.cc \ - src/file.cc \ - src/file_linux.cc \ src/gc/card_table.cc \ src/gc/garbage_collector.cc \ src/gc/heap_bitmap.cc \ @@ -358,13 +361,17 @@ LIBARTTEST_COMMON_SRC_FILES := \ TEST_COMMON_SRC_FILES := \ src/barrier_test.cc \ + src/base/unix_file/fd_file_test.cc \ + src/base/unix_file/mapped_file_test.cc \ + src/base/unix_file/null_file_test.cc \ + src/base/unix_file/random_access_file_utils_test.cc \ + src/base/unix_file/string_file_test.cc \ src/class_linker_test.cc \ src/compiler_test.cc \ src/dex_cache_test.cc \ src/dex_file_test.cc \ src/dex_instruction_visitor_test.cc \ src/exception_test.cc \ - src/file_test.cc \ src/gc/space_bitmap_test.cc \ src/gc/space_test.cc \ src/gtest_test.cc \ diff --git a/src/atomic.h b/src/atomic.h index c6c0f7d5ca..c69a9d1188 100644 --- a/src/atomic.h +++ b/src/atomic.h @@ -19,9 +19,9 @@ #include <stdint.h> +#include "base/macros.h" #include "cutils/atomic.h" #include "cutils/atomic-inline.h" -#include "macros.h" namespace art { diff --git a/src/macros.h b/src/base/macros.h index d63aed6dd2..d63aed6dd2 100644 --- a/src/macros.h +++ b/src/base/macros.h diff --git a/src/base/unix_file/README b/src/base/unix_file/README new file mode 100644 index 0000000000..e9aec22954 --- /dev/null +++ b/src/base/unix_file/README @@ -0,0 +1,15 @@ +A simple C++ wrapper for Unix file I/O. + +This is intended to be lightweight and easy to use, similar to Java's +RandomAccessFile and related classes. The usual C++ idioms of RAII and "you +don't pay for what you don't use" apply. + +In particular, the basic RandomAccessFile interface is kept small and simple so +it's trivial to add new implementations. + +This code will not log, because it can't know whether that's appropriate in +your application. + +This code will, in general, return -errno on failure. If an operation consisted +of multiple sub-operations, it will return the errno corresponding to the most +relevant operation. diff --git a/src/base/unix_file/fd_file.cc b/src/base/unix_file/fd_file.cc new file mode 100644 index 0000000000..73130a3238 --- /dev/null +++ b/src/base/unix_file/fd_file.cc @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2009 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 "base/unix_file/fd_file.h" +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include "logging.h" + +namespace unix_file { + +FdFile::FdFile() : fd_(-1), auto_close_(true) { +} + +FdFile::FdFile(int fd) : fd_(fd), auto_close_(true) { +} + +FdFile::FdFile(int fd, const std::string& path) : fd_(fd), file_path_(path), auto_close_(true) { +} + +FdFile::~FdFile() { + if (auto_close_ && fd_ != -1) { + Close(); + } +} + +void FdFile::DisableAutoClose() { + auto_close_ = false; +} + +bool FdFile::Open(const std::string& path, int flags) { + return Open(path, flags, 0640); +} + +bool FdFile::Open(const std::string& path, int flags, mode_t mode) { + CHECK_EQ(fd_, -1) << path; + fd_ = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)); + if (fd_ == -1) { + return false; + } + file_path_ = path; + return true; +} + +int FdFile::Close() { + int result = TEMP_FAILURE_RETRY(close(fd_)); + if (result == -1) { + return -errno; + } else { + fd_ = -1; + file_path_ = ""; + return 0; + } +} + +int FdFile::Flush() { + int rc = TEMP_FAILURE_RETRY(fdatasync(fd_)); + return (rc == -1) ? -errno : rc; +} + +int64_t FdFile::Read(char* buf, int64_t byte_count, int64_t offset) const { + int rc = TEMP_FAILURE_RETRY(pread64(fd_, buf, byte_count, offset)); + return (rc == -1) ? -errno : rc; +} + +int FdFile::SetLength(int64_t new_length) { + int rc = TEMP_FAILURE_RETRY(ftruncate64(fd_, new_length)); + return (rc == -1) ? -errno : rc; +} + +int64_t FdFile::GetLength() const { + struct stat s; + int rc = TEMP_FAILURE_RETRY(fstat(fd_, &s)); + return (rc == -1) ? -errno : s.st_size; +} + +int64_t FdFile::Write(const char* buf, int64_t byte_count, int64_t offset) { + int rc = TEMP_FAILURE_RETRY(pwrite64(fd_, buf, byte_count, offset)); + return (rc == -1) ? -errno : rc; +} + +int FdFile::Fd() const { + return fd_; +} + +bool FdFile::IsOpened() const { + return fd_ >= 0; +} + +std::string FdFile::GetPath() const { + return file_path_; +} + +bool FdFile::ReadFully(void* buffer, int64_t byte_count) { + char* ptr = static_cast<char*>(buffer); + while (byte_count > 0) { + int bytes_read = TEMP_FAILURE_RETRY(read(fd_, ptr, byte_count)); + if (bytes_read <= 0) { + return false; + } + byte_count -= bytes_read; // Reduce the number of remaining bytes. + ptr += bytes_read; // Move the buffer forward. + } + return true; +} + +bool FdFile::WriteFully(const void* buffer, int64_t byte_count) { + const char* ptr = static_cast<const char*>(buffer); + while (byte_count > 0) { + int bytes_read = TEMP_FAILURE_RETRY(write(fd_, ptr, byte_count)); + if (bytes_read < 0) { + return false; + } + byte_count -= bytes_read; // Reduce the number of remaining bytes. + ptr += bytes_read; // Move the buffer forward. + } + return true; +} + +} // namespace unix_file diff --git a/src/base/unix_file/fd_file.h b/src/base/unix_file/fd_file.h new file mode 100644 index 0000000000..2b339613ba --- /dev/null +++ b/src/base/unix_file/fd_file.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009 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 BASE_UNIX_FILE_FD_FILE_H_ +#define BASE_UNIX_FILE_FD_FILE_H_ + +#include <fcntl.h> +#include <string> +#include "base/unix_file/random_access_file.h" +#include "base/macros.h" + +namespace unix_file { + +// A RandomAccessFile implementation backed by a file descriptor. +// +// Not thread safe. +class FdFile : public RandomAccessFile { + public: + FdFile(); + // Creates an FdFile using the given file descriptor. Takes ownership of the + // file descriptor. (Use DisableAutoClose to retain ownership.) + explicit FdFile(int fd); + explicit FdFile(int fd, const std::string& path); + + // Destroys an FdFile, closing the file descriptor if Close hasn't already + // been called. (If you care about the return value of Close, call it + // yourself; this is meant to handle failure cases and read-only accesses. + // Note though that calling Close and checking its return value is still no + // guarantee that data actually made it to stable storage.) + virtual ~FdFile(); + + // Opens file 'file_path' using 'flags' and 'mode'. + bool Open(const std::string& file_path, int flags); + bool Open(const std::string& file_path, int flags, mode_t mode); + + // RandomAccessFile API. + virtual int Close(); + virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const; + virtual int SetLength(int64_t new_length); + virtual int64_t GetLength() const; + virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset); + virtual int Flush(); + + // Bonus API. + int Fd() const; + bool IsOpened() const; + std::string GetPath() const; + void DisableAutoClose(); + bool ReadFully(void* buffer, int64_t byte_count); + bool WriteFully(const void* buffer, int64_t byte_count); + + private: + int fd_; + std::string file_path_; + bool auto_close_; + + DISALLOW_COPY_AND_ASSIGN(FdFile); +}; + +} // namespace unix_file + +#endif // BASE_UNIX_FILE_FD_FILE_H_ diff --git a/src/base/unix_file/fd_file_test.cc b/src/base/unix_file/fd_file_test.cc new file mode 100644 index 0000000000..d620666747 --- /dev/null +++ b/src/base/unix_file/fd_file_test.cc @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2009 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 "base/unix_file/fd_file.h" +#include "base/unix_file/random_access_file_test.h" +#include "gtest/gtest.h" + +namespace unix_file { + +class FdFileTest : public RandomAccessFileTest { + protected: + virtual RandomAccessFile* MakeTestFile() { + return new FdFile(fileno(tmpfile())); + } +}; + +TEST_F(FdFileTest, Read) { + TestRead(); +} + +TEST_F(FdFileTest, SetLength) { + TestSetLength(); +} + +TEST_F(FdFileTest, Write) { + TestWrite(); +} + +TEST_F(FdFileTest, UnopenedFile) { + FdFile file; + EXPECT_EQ(-1, file.Fd()); + EXPECT_FALSE(file.IsOpened()); + EXPECT_TRUE(file.GetPath().empty()); +} + +TEST_F(FdFileTest, OpenClose) { + std::string good_path(GetTmpPath("some-file.txt")); + FdFile file; + ASSERT_TRUE(file.Open(good_path, O_CREAT | O_WRONLY)); + EXPECT_GE(file.Fd(), 0); + EXPECT_TRUE(file.IsOpened()); + EXPECT_EQ(0, file.Close()); + EXPECT_EQ(-1, file.Fd()); + EXPECT_FALSE(file.IsOpened()); + EXPECT_TRUE(file.Open(good_path, O_RDONLY)); + EXPECT_GE(file.Fd(), 0); + EXPECT_TRUE(file.IsOpened()); +} + +} // namespace unix_file diff --git a/src/base/unix_file/mapped_file.cc b/src/base/unix_file/mapped_file.cc new file mode 100644 index 0000000000..84629b34a3 --- /dev/null +++ b/src/base/unix_file/mapped_file.cc @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2008 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 "base/unix_file/mapped_file.h" +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <algorithm> +#include <string> +#include "logging.h" + +namespace unix_file { + +MappedFile::~MappedFile() { +} + +int MappedFile::Close() { + if (IsMapped()) { + Unmap(); + } + return FdFile::Close(); +} + +bool MappedFile::MapReadOnly() { + CHECK(IsOpened()); + CHECK(!IsMapped()); + struct stat st; + int result = TEMP_FAILURE_RETRY(fstat(Fd(), &st)); + if (result == -1) { + PLOG(WARNING) << "Failed to stat file '" << GetPath() << "'"; + return false; + } + file_size_ = st.st_size; + do { + mapped_file_ = mmap(NULL, file_size_, PROT_READ, MAP_PRIVATE, Fd(), 0); + } while (mapped_file_ == MAP_FAILED && errno == EINTR); + if (mapped_file_ == MAP_FAILED) { + PLOG(WARNING) << "Failed to mmap file '" << GetPath() << "' of size " + << file_size_ << " bytes to memory"; + return false; + } + map_mode_ = kMapReadOnly; + return true; +} + +bool MappedFile::MapReadWrite(int64_t file_size) { + CHECK(IsOpened()); + CHECK(!IsMapped()); + int result = TEMP_FAILURE_RETRY(ftruncate64(Fd(), file_size)); + if (result == -1) { + PLOG(ERROR) << "Failed to truncate file '" << GetPath() + << "' to size " << file_size; + return false; + } + file_size_ = file_size; + do { + mapped_file_ = + mmap(NULL, file_size_, PROT_READ | PROT_WRITE, MAP_SHARED, Fd(), 0); + } while (mapped_file_ == MAP_FAILED && errno == EINTR); + if (mapped_file_ == MAP_FAILED) { + PLOG(WARNING) << "Failed to mmap file '" << GetPath() << "' of size " + << file_size_ << " bytes to memory"; + return false; + } + map_mode_ = kMapReadWrite; + return true; +} + +bool MappedFile::Unmap() { + CHECK(IsMapped()); + int result = TEMP_FAILURE_RETRY(munmap(mapped_file_, file_size_)); + if (result == -1) { + PLOG(WARNING) << "Failed unmap file '" << GetPath() << "' of size " + << file_size_; + return false; + } else { + mapped_file_ = NULL; + file_size_ = -1; + return true; + } +} + +int64_t MappedFile::Read(char* buf, int64_t byte_count, int64_t offset) const { + if (IsMapped()) { + if (offset < 0) { + errno = EINVAL; + return -errno; + } + int64_t read_size = std::max(0LL, std::min(byte_count, file_size_ - offset)); + if (read_size > 0) { + memcpy(buf, data() + offset, read_size); + } + return read_size; + } else { + return FdFile::Read(buf, byte_count, offset); + } +} + +int MappedFile::SetLength(int64_t new_length) { + CHECK(!IsMapped()); + return FdFile::SetLength(new_length); +} + +int64_t MappedFile::GetLength() const { + if (IsMapped()) { + return file_size_; + } else { + return FdFile::GetLength(); + } +} + +int MappedFile::Flush() { + int rc = IsMapped() ? TEMP_FAILURE_RETRY(msync(mapped_file_, file_size_, 0)) : FdFile::Flush(); + return rc == -1 ? -errno : 0; +} + +int64_t MappedFile::Write(const char* buf, int64_t byte_count, int64_t offset) { + if (IsMapped()) { + CHECK_EQ(kMapReadWrite, map_mode_); + if (offset < 0) { + errno = EINVAL; + return -errno; + } + int64_t write_size = std::max(0LL, std::min(byte_count, file_size_ - offset)); + if (write_size > 0) { + memcpy(data() + offset, buf, write_size); + } + return write_size; + } else { + return FdFile::Write(buf, byte_count, offset); + } +} + +int64_t MappedFile::size() const { + return GetLength(); +} + +bool MappedFile::IsMapped() const { + return mapped_file_ != NULL && mapped_file_ != MAP_FAILED; +} + +char* MappedFile::data() const { + CHECK(IsMapped()); + return static_cast<char*>(mapped_file_); +} + +} // namespace unix_file diff --git a/src/base/unix_file/mapped_file.h b/src/base/unix_file/mapped_file.h new file mode 100644 index 0000000000..161100b0d5 --- /dev/null +++ b/src/base/unix_file/mapped_file.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2008 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 BASE_UNIX_FILE_MAPPED_FILE_H_ +#define BASE_UNIX_FILE_MAPPED_FILE_H_ + +#include <fcntl.h> +#include <string> +#include "base/unix_file/fd_file.h" + +namespace unix_file { + +// Random access file which handles an mmap(2), munmap(2) pair in C++ +// RAII style. When a file is mmapped, the random access file +// interface accesses the mmapped memory directly; otherwise, the +// standard file I/O is used. Whenever a function fails, it returns +// false and errno is set to the corresponding error code. +class MappedFile : public FdFile { + public: + // File modes used in Open(). + enum FileMode { + kReadOnlyMode = O_RDONLY | O_LARGEFILE, + kReadWriteMode = O_CREAT | O_RDWR | O_LARGEFILE, + }; + + MappedFile() : FdFile(), file_size_(-1), mapped_file_(NULL) { + } + // Creates a MappedFile using the given file descriptor. Takes ownership of + // the file descriptor. + explicit MappedFile(int fd) : FdFile(fd), file_size_(-1), mapped_file_(NULL) { + } + + // Unmaps and closes the file if needed. + virtual ~MappedFile(); + + // Maps an opened file to memory in the read-only mode. + bool MapReadOnly(); + + // Maps an opened file to memory in the read-write mode. Before the + // file is mapped, it is truncated to 'file_size' bytes. + bool MapReadWrite(int64_t file_size); + + // Unmaps a mapped file so that, e.g., SetLength() may be invoked. + bool Unmap(); + + // RandomAccessFile API. + // The functions below require that the file is open, but it doesn't + // have to be mapped. + virtual int Close(); + virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const; + // SetLength() requires that the file is not mmapped. + virtual int SetLength(int64_t new_length); + virtual int64_t GetLength() const; + virtual int Flush(); + // Write() requires that, if the file is mmapped, it is mmapped in + // the read-write mode. Writes past the end of file are discarded. + virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset); + + // A convenience method equivalent to GetLength(). + int64_t size() const; + + // Returns true if the file has been mmapped. + bool IsMapped() const; + + // Returns a pointer to the start of the memory mapping once the + // file is successfully mapped; crashes otherwise. + char* data() const; + + private: + enum MapMode { + kMapReadOnly = 1, + kMapReadWrite = 2, + }; + + mutable int64_t file_size_; // May be updated in GetLength(). + void* mapped_file_; + MapMode map_mode_; + + DISALLOW_COPY_AND_ASSIGN(MappedFile); +}; + +} // namespace unix_file + +#endif // BASE_UNIX_FILE_MAPPED_FILE_H_ diff --git a/src/base/unix_file/mapped_file_test.cc b/src/base/unix_file/mapped_file_test.cc new file mode 100644 index 0000000000..f61ed3b279 --- /dev/null +++ b/src/base/unix_file/mapped_file_test.cc @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2008 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 "base/unix_file/mapped_file.h" +#include "base/unix_file/fd_file.h" +#include "base/unix_file/random_access_file_test.h" +#include "base/unix_file/random_access_file_utils.h" +#include "base/unix_file/string_file.h" +#include "gtest/gtest.h" +#include "logging.h" + +namespace unix_file { + +class MappedFileTest : public RandomAccessFileTest { + protected: + MappedFileTest() : kContent("some content") { + } + + void SetUp() { + art::CommonTest::SetEnvironmentVariables(android_data_); + + good_path_ = GetTmpPath("some-file.txt"); + int fd = TEMP_FAILURE_RETRY(open(good_path_.c_str(), O_CREAT|O_RDWR, 0666)); + FdFile dst(fd); + + StringFile src; + src.Assign(kContent); + + ASSERT_TRUE(CopyFile(src, &dst)); + } + + virtual RandomAccessFile* MakeTestFile() { + TEMP_FAILURE_RETRY(truncate(good_path_.c_str(), 0)); + MappedFile* f = new MappedFile; + CHECK(f->Open(good_path_, MappedFile::kReadWriteMode)); + return f; + } + + const std::string kContent; + std::string good_path_; +}; + +TEST_F(MappedFileTest, OkayToNotUse) { + MappedFile file; + EXPECT_EQ(-1, file.Fd()); + EXPECT_FALSE(file.IsOpened()); + EXPECT_FALSE(file.IsMapped()); +} + +TEST_F(MappedFileTest, OpenClose) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_GE(file.Fd(), 0); + EXPECT_TRUE(file.IsOpened()); + EXPECT_EQ(kContent.size(), file.size()); + EXPECT_EQ(0, file.Close()); + EXPECT_EQ(-1, file.Fd()); + EXPECT_FALSE(file.IsOpened()); +} + +TEST_F(MappedFileTest, OpenFdClose) { + FILE* f = tmpfile(); + ASSERT_TRUE(f != NULL); + MappedFile file(fileno(f)); + EXPECT_GE(file.Fd(), 0); + EXPECT_TRUE(file.IsOpened()); + EXPECT_EQ(0, file.Close()); +} + +TEST_F(MappedFileTest, CanUseAfterMapReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_FALSE(file.IsMapped()); + EXPECT_TRUE(file.MapReadOnly()); + EXPECT_TRUE(file.IsMapped()); + EXPECT_EQ(kContent.size(), file.size()); + ASSERT_TRUE(file.data()); + EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), file.size())); + EXPECT_EQ(0, file.Flush()); +} + +TEST_F(MappedFileTest, CanUseAfterMapReadWrite) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + EXPECT_FALSE(file.IsMapped()); + EXPECT_TRUE(file.MapReadWrite(1)); + EXPECT_TRUE(file.IsMapped()); + EXPECT_EQ(1, file.size()); + ASSERT_TRUE(file.data()); + EXPECT_EQ(kContent[0], *file.data()); + EXPECT_EQ(0, file.Flush()); +} + +TEST_F(MappedFileTest, CanWriteNewData) { + const std::string new_path(GetTmpPath("new-file.txt")); + ASSERT_EQ(-1, unlink(new_path.c_str())); + ASSERT_EQ(ENOENT, errno); + + MappedFile file; + ASSERT_TRUE(file.Open(new_path, MappedFile::kReadWriteMode)); + EXPECT_TRUE(file.MapReadWrite(kContent.size())); + EXPECT_TRUE(file.IsMapped()); + EXPECT_EQ(kContent.size(), file.size()); + ASSERT_TRUE(file.data()); + memcpy(file.data(), kContent.c_str(), kContent.size()); + EXPECT_EQ(0, file.Close()); + EXPECT_FALSE(file.IsMapped()); + + FdFile new_file(TEMP_FAILURE_RETRY(open(new_path.c_str(), O_RDONLY))); + StringFile buffer; + ASSERT_TRUE(CopyFile(new_file, &buffer)); + EXPECT_EQ(kContent, buffer.ToStringPiece()); + EXPECT_EQ(0, unlink(new_path.c_str())); +} + +TEST_F(MappedFileTest, FileMustExist) { + const std::string bad_path(GetTmpPath("does-not-exist.txt")); + MappedFile file; + EXPECT_FALSE(file.Open(bad_path, MappedFile::kReadOnlyMode)); + EXPECT_EQ(-1, file.Fd()); +} + +TEST_F(MappedFileTest, FileMustBeWritable) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_FALSE(file.MapReadWrite(10)); +} + +TEST_F(MappedFileTest, RemappingAllowedUntilSuccess) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_FALSE(file.MapReadWrite(10)); + EXPECT_FALSE(file.MapReadWrite(10)); +} + +TEST_F(MappedFileTest, ResizeMappedFile) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(10)); + EXPECT_EQ(10, file.GetLength()); + EXPECT_TRUE(file.Unmap()); + EXPECT_TRUE(file.MapReadWrite(20)); + EXPECT_EQ(20, file.GetLength()); + EXPECT_EQ(0, file.Flush()); + EXPECT_TRUE(file.Unmap()); + EXPECT_EQ(0, file.Flush()); + EXPECT_EQ(0, file.SetLength(5)); + EXPECT_TRUE(file.MapReadOnly()); + EXPECT_EQ(5, file.GetLength()); +} + +TEST_F(MappedFileTest, ReadNotMapped) { + TestRead(); +} + +TEST_F(MappedFileTest, SetLengthNotMapped) { + TestSetLength(); +} + +TEST_F(MappedFileTest, WriteNotMapped) { + TestWrite(); +} + +TEST_F(MappedFileTest, ReadMappedReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + ASSERT_TRUE(file.MapReadOnly()); + TestReadContent(kContent, &file); +} + +TEST_F(MappedFileTest, ReadMappedReadWrite) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(kContent.size())); + TestReadContent(kContent, &file); +} + +TEST_F(MappedFileTest, WriteMappedReadWrite) { + TEMP_FAILURE_RETRY(unlink(good_path_.c_str())); + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(kContent.size())); + + // Can't write to a negative offset. + EXPECT_EQ(-EINVAL, file.Write(kContent.c_str(), 0, -123)); + + // A zero-length write is a no-op. + EXPECT_EQ(0, file.Write(kContent.c_str(), 0, 0)); + // But the file size is as given when mapped. + EXPECT_EQ(kContent.size(), file.GetLength()); + + // Data written past the end are discarded. + EXPECT_EQ(kContent.size() - 1, + file.Write(kContent.c_str(), kContent.size(), 1)); + EXPECT_EQ(0, memcmp(kContent.c_str(), file.data() + 1, kContent.size() - 1)); + + // Data can be overwritten. + EXPECT_EQ(kContent.size(), file.Write(kContent.c_str(), kContent.size(), 0)); + EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), kContent.size())); +} + +#if 0 // death tests don't work on android yet + +class MappedFileDeathTest : public MappedFileTest {}; + +TEST_F(MappedFileDeathTest, MustMapBeforeUse) { + MappedFile file; + EXPECT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + EXPECT_DEATH(file.data(), "mapped_"); +} + +TEST_F(MappedFileDeathTest, RemappingNotAllowedReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + ASSERT_TRUE(file.MapReadOnly()); + EXPECT_DEATH(file.MapReadOnly(), "mapped_"); +} + +TEST_F(MappedFileDeathTest, RemappingNotAllowedReadWrite) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(10)); + EXPECT_DEATH(file.MapReadWrite(10), "mapped_"); +} + +TEST_F(MappedFileDeathTest, SetLengthMappedReadWrite) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode)); + ASSERT_TRUE(file.MapReadWrite(10)); + EXPECT_EQ(10, file.GetLength()); + EXPECT_DEATH(file.SetLength(0), ".*"); +} + +TEST_F(MappedFileDeathTest, SetLengthMappedReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + ASSERT_TRUE(file.MapReadOnly()); + EXPECT_EQ(kContent.size(), file.GetLength()); + EXPECT_DEATH(file.SetLength(0), ".*"); +} + +TEST_F(MappedFileDeathTest, WriteMappedReadOnly) { + MappedFile file; + ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode)); + ASSERT_TRUE(file.MapReadOnly()); + char buf[10]; + EXPECT_DEATH(file.Write(buf, 0, 0), ".*"); +} + +#endif + +} // namespace unix_file diff --git a/src/base/unix_file/null_file.cc b/src/base/unix_file/null_file.cc new file mode 100644 index 0000000000..050decb6db --- /dev/null +++ b/src/base/unix_file/null_file.cc @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009 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 "base/unix_file/null_file.h" +#include <errno.h> + +namespace unix_file { + +NullFile::NullFile() { +} + +NullFile::~NullFile() { +} + +int NullFile::Close() { + return 0; +} + +int NullFile::Flush() { + return 0; +} + +int64_t NullFile::Read(char* buf, int64_t byte_count, int64_t offset) const { + if (offset < 0) { + return -EINVAL; + } + return 0; +} + +int NullFile::SetLength(int64_t new_length) { + if (new_length < 0) { + return -EINVAL; + } + return 0; +} + +int64_t NullFile::GetLength() const { + return 0; +} + +int64_t NullFile::Write(const char* buf, int64_t byte_count, int64_t offset) { + if (offset < 0) { + return -EINVAL; + } + return byte_count; +} + +} // namespace unix_file diff --git a/src/base/unix_file/null_file.h b/src/base/unix_file/null_file.h new file mode 100644 index 0000000000..e716603687 --- /dev/null +++ b/src/base/unix_file/null_file.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 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 BASE_UNIX_FILE_NULL_FILE_H_ +#define BASE_UNIX_FILE_NULL_FILE_H_ + +#include "base/unix_file/random_access_file.h" +#include "base/macros.h" + +namespace unix_file { + +// A RandomAccessFile implementation equivalent to /dev/null. Writes are +// discarded, and there's no data to be read. Callers could use FdFile in +// conjunction with /dev/null, but that's not portable and costs a file +// descriptor. NullFile is "free". +// +// Thread safe. +class NullFile : public RandomAccessFile { + public: + NullFile(); + virtual ~NullFile(); + + // RandomAccessFile API. + virtual int Close(); + virtual int Flush(); + virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const; + virtual int SetLength(int64_t new_length); + virtual int64_t GetLength() const; + virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset); + + private: + DISALLOW_COPY_AND_ASSIGN(NullFile); +}; + +} // namespace unix_file + +#endif // BASE_UNIX_FILE_NULL_FILE_H_ diff --git a/src/base/unix_file/null_file_test.cc b/src/base/unix_file/null_file_test.cc new file mode 100644 index 0000000000..0f20acd825 --- /dev/null +++ b/src/base/unix_file/null_file_test.cc @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 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 "base/unix_file/null_file.h" + +#include <errno.h> + +#include "gtest/gtest.h" + +namespace unix_file { + +class NullFileTest : public testing::Test { }; + +TEST_F(NullFileTest, Read) { + NullFile f; + char buf[256]; + // You can't read a negative number of bytes... + ASSERT_EQ(-EINVAL, f.Read(buf, 0, -1)); + // ...but everything else is fine (though you'll get no data). + ASSERT_EQ(0, f.Read(buf, 128, 0)); + ASSERT_EQ(0, f.Read(buf, 128, 128)); +} + +TEST_F(NullFileTest, SetLength) { + NullFile f; + // You can't set a negative length... + ASSERT_EQ(-EINVAL, f.SetLength(-1)); + // ...but everything else is fine. + ASSERT_EQ(0, f.SetLength(0)); + ASSERT_EQ(0, f.SetLength(128)); +} + +TEST_F(NullFileTest, GetLength) { + const std::string content("hello"); + NullFile f; + // The length is always 0. + ASSERT_EQ(0, f.GetLength()); + ASSERT_EQ(content.size(), f.Write(content.data(), content.size(), 0)); + ASSERT_EQ(0, f.GetLength()); +} + +TEST_F(NullFileTest, Write) { + const std::string content("hello"); + NullFile f; + // You can't write at a negative offset... + ASSERT_EQ(-EINVAL, f.Write(content.data(), content.size(), -128)); + // But you can write anywhere else... + ASSERT_EQ(content.size(), f.Write(content.data(), content.size(), 0)); + ASSERT_EQ(content.size(), f.Write(content.data(), content.size(), 128)); + // ...though the file will remain empty. + ASSERT_EQ(0, f.GetLength()); +} + +} // namespace unix_file diff --git a/src/base/unix_file/random_access_file.h b/src/base/unix_file/random_access_file.h new file mode 100644 index 0000000000..22da37f03e --- /dev/null +++ b/src/base/unix_file/random_access_file.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 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 BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ +#define BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ + +#include <stdint.h> + +namespace unix_file { + +// A file interface supporting random-access reading and writing of content, +// along with the ability to set the length of a file (smaller or greater than +// its current extent). +// +// This interface does not support a stream position (i.e. every read or write +// must specify an offset). This interface does not imply any buffering policy. +// +// All operations return >= 0 on success or -errno on failure. +// +// Implementations never return EINTR; callers are spared the need to manually +// retry interrupted operations. +// +// Any concurrent access to files should be externally synchronized. +class RandomAccessFile { + public: + virtual ~RandomAccessFile() { } + + virtual int Close() = 0; + + // Reads 'byte_count' bytes into 'buf' starting at offset 'offset' in the + // file. Returns the number of bytes actually read. + virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const = 0; + + // Sets the length of the file to 'new_length'. If this is smaller than the + // file's current extent, data is discarded. If this is greater than the + // file's current extent, it is as if a write of the relevant number of zero + // bytes occurred. Returns 0 on success. + virtual int SetLength(int64_t new_length) = 0; + + // Returns the current size of this file. + virtual int64_t GetLength() const = 0; + + // Writes 'byte_count' bytes from 'buf' starting at offset 'offset' in the + // file. Zero-byte writes are acceptable, and writes past the end are as if + // a write of the relevant number of zero bytes also occurred. Returns the + // number of bytes actually written. + virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset) = 0; + + // Flushes file data. + virtual int Flush() = 0; +}; + +} // namespace unix_file + +#endif // BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ diff --git a/src/base/unix_file/random_access_file_test.h b/src/base/unix_file/random_access_file_test.h new file mode 100644 index 0000000000..3baaeae8ac --- /dev/null +++ b/src/base/unix_file/random_access_file_test.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2009 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 BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ +#define BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ + +#include <errno.h> + +#include <string> + +#include "common_test.h" +#include "gtest/gtest.h" +#include "UniquePtr.h" + +namespace unix_file { + +class RandomAccessFileTest : public testing::Test { + protected: + virtual ~RandomAccessFileTest() { + } + + // Override this to return an instance of the subclass under test that's + // backed by a temporary file. + virtual RandomAccessFile* MakeTestFile() = 0; + + virtual void SetUp() { + art::CommonTest::SetEnvironmentVariables(android_data_); + } + + std::string GetTmpPath(const std::string& name) { + std::string path; + path = android_data_; + path += "/"; + path += name; + return path; + } + + // TODO(enh): ReadString (and WriteString) might be generally useful. + static bool ReadString(RandomAccessFile* f, std::string* s) { + s->clear(); + char buf[256]; + int64_t n = 0; + int64_t offset = 0; + while ((n = f->Read(buf, sizeof(buf), offset)) > 0) { + s->append(buf, n); + offset += n; + } + return n != -1; + } + + void TestRead() { + char buf[256]; + UniquePtr<RandomAccessFile> file(MakeTestFile()); + + // Reading from the start of an empty file gets you zero bytes, however many + // you ask for. + ASSERT_EQ(0, file->Read(buf, 0, 0)); + ASSERT_EQ(0, file->Read(buf, 123, 0)); + + const std::string content("hello"); + ASSERT_EQ(content.size(), file->Write(content.data(), content.size(), 0)); + + TestReadContent(content, file.get()); + } + + void TestReadContent(const std::string& content, RandomAccessFile* file) { + const int buf_size = content.size() + 10; + UniquePtr<char> buf(new char[buf_size]); + // Can't read from a negative offset. + ASSERT_EQ(-EINVAL, file->Read(buf.get(), 0, -123)); + + // Reading too much gets us just what's in the file. + ASSERT_EQ(content.size(), file->Read(buf.get(), buf_size, 0)); + ASSERT_EQ(std::string(buf.get(), content.size()), content); + + // We only get as much as we ask for. + const size_t short_request = 2; + ASSERT_LT(short_request, content.size()); + ASSERT_EQ(short_request, file->Read(buf.get(), short_request, 0)); + ASSERT_EQ(std::string(buf.get(), short_request), + content.substr(0, short_request)); + + // We don't have to start at the beginning. + const int non_zero_offset = 2; + ASSERT_GT(non_zero_offset, 0); + ASSERT_EQ(short_request, + file->Read(buf.get(), short_request, non_zero_offset)); + ASSERT_EQ(std::string(buf.get(), short_request), + content.substr(non_zero_offset, short_request)); + + // Reading past the end gets us nothing. + ASSERT_EQ(0, file->Read(buf.get(), buf_size, file->GetLength())); + ASSERT_EQ(0, file->Read(buf.get(), buf_size, file->GetLength() + 1)); + } + + void TestSetLength() { + const std::string content("hello"); + UniquePtr<RandomAccessFile> file(MakeTestFile()); + ASSERT_EQ(content.size(), file->Write(content.data(), content.size(), 0)); + ASSERT_EQ(content.size(), file->GetLength()); + + // Can't give a file a negative length. + ASSERT_EQ(-EINVAL, file->SetLength(-123)); + + // Can truncate the file. + int64_t new_length = 2; + ASSERT_EQ(0, file->SetLength(new_length)); + ASSERT_EQ(new_length, file->GetLength()); + std::string new_content; + ASSERT_TRUE(ReadString(file.get(), &new_content)); + ASSERT_EQ(content.substr(0, 2), new_content); + + // Expanding the file appends zero bytes. + new_length = file->GetLength() + 1; + ASSERT_EQ(0, file->SetLength(new_length)); + ASSERT_EQ(new_length, file->GetLength()); + ASSERT_TRUE(ReadString(file.get(), &new_content)); + ASSERT_EQ('\0', new_content[new_length - 1]); + } + + void TestWrite() { + const std::string content("hello"); + UniquePtr<RandomAccessFile> file(MakeTestFile()); + + // Can't write to a negative offset. + ASSERT_EQ(-EINVAL, file->Write(content.data(), 0, -123)); + + // Writing zero bytes of data is a no-op. + ASSERT_EQ(0, file->Write(content.data(), 0, 0)); + ASSERT_EQ(0, file->GetLength()); + + // We can write data. + ASSERT_EQ(content.size(), file->Write(content.data(), content.size(), 0)); + ASSERT_EQ(content.size(), file->GetLength()); + std::string new_content; + ASSERT_TRUE(ReadString(file.get(), &new_content)); + ASSERT_EQ(new_content, content); + + // We can read it back. + char buf[256]; + ASSERT_EQ(content.size(), file->Read(buf, sizeof(buf), 0)); + ASSERT_EQ(std::string(buf, content.size()), content); + + // We can append data past the end. + ASSERT_EQ(content.size(), + file->Write(content.data(), content.size(), file->GetLength() + 1)); + int64_t new_length = 2*content.size() + 1; + ASSERT_EQ(file->GetLength(), new_length); + ASSERT_TRUE(ReadString(file.get(), &new_content)); + ASSERT_EQ(std::string("hello\0hello", new_length), new_content); + } + + protected: + std::string android_data_; +}; + +} // namespace unix_file + +#endif // BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ diff --git a/src/base/unix_file/random_access_file_utils.cc b/src/base/unix_file/random_access_file_utils.cc new file mode 100644 index 0000000000..df3b308bb0 --- /dev/null +++ b/src/base/unix_file/random_access_file_utils.cc @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 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 <vector> +#include "base/unix_file/random_access_file_utils.h" +#include "base/unix_file/random_access_file.h" + +namespace unix_file { + +bool CopyFile(const RandomAccessFile& src, RandomAccessFile* dst) { + // We don't call src->GetLength because some files (those in /proc, say) + // don't know how long they are. We just read until there's nothing left. + std::vector<char> buf(4096); + int64_t offset = 0; + int64_t n; + while ((n = src.Read(&buf[0], buf.size(), offset)) > 0) { + if (dst->Write(&buf[0], n, offset) != n) { + return false; + } + offset += n; + } + return n >= 0; +} + +} // namespace unix_file diff --git a/src/base/unix_file/random_access_file_utils.h b/src/base/unix_file/random_access_file_utils.h new file mode 100644 index 0000000000..0535ead8c5 --- /dev/null +++ b/src/base/unix_file/random_access_file_utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 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 BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ +#define BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ + +namespace unix_file { + +class RandomAccessFile; + +// Copies from 'src' to 'dst'. Reads all the data from 'src', and writes it +// to 'dst'. Not thread-safe. Neither file will be closed. +bool CopyFile(const RandomAccessFile& src, RandomAccessFile* dst); + +} // namespace unix_file + +#endif // BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ diff --git a/src/base/unix_file/random_access_file_utils_test.cc b/src/base/unix_file/random_access_file_utils_test.cc new file mode 100644 index 0000000000..63179220a2 --- /dev/null +++ b/src/base/unix_file/random_access_file_utils_test.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 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 "base/unix_file/random_access_file_utils.h" +#include "base/unix_file/fd_file.h" +#include "base/unix_file/string_file.h" +#include "gtest/gtest.h" + +namespace unix_file { + +class RandomAccessFileUtilsTest : public testing::Test { }; + +TEST_F(RandomAccessFileUtilsTest, CopyFile) { + StringFile src; + StringFile dst; + + const std::string content("hello"); + src.Assign(content); + ASSERT_EQ(src.ToStringPiece(), content); + ASSERT_EQ(dst.ToStringPiece(), ""); + + ASSERT_TRUE(CopyFile(src, &dst)); + ASSERT_EQ(src.ToStringPiece(), dst.ToStringPiece()); +} + +TEST_F(RandomAccessFileUtilsTest, BadSrc) { + FdFile src(-1); + StringFile dst; + ASSERT_FALSE(CopyFile(src, &dst)); +} + +TEST_F(RandomAccessFileUtilsTest, BadDst) { + StringFile src; + FdFile dst(-1); + + // We need some source content to trigger a write. + // Copying an empty file is a no-op. + src.Assign("hello"); + + ASSERT_FALSE(CopyFile(src, &dst)); +} + +} // namespace unix_file diff --git a/src/base/unix_file/string_file.cc b/src/base/unix_file/string_file.cc new file mode 100644 index 0000000000..5d47b17b6f --- /dev/null +++ b/src/base/unix_file/string_file.cc @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2009 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 "base/unix_file/string_file.h" +#include <errno.h> +#include <algorithm> +#include "logging.h" + +namespace unix_file { + +StringFile::StringFile() { +} + +StringFile::~StringFile() { +} + +int StringFile::Close() { + return 0; +} + +int StringFile::Flush() { + return 0; +} + +int64_t StringFile::Read(char *buf, int64_t byte_count, int64_t offset) const { + CHECK(buf); + CHECK_GE(byte_count, 0); + + if (offset < 0) { + return -EINVAL; + } + + const int64_t available_bytes = std::min(byte_count, GetLength() - offset); + if (available_bytes < 0) { + return 0; // Not an error, but nothing for us to do, either. + } + memcpy(buf, data_.data() + offset, available_bytes); + return available_bytes; +} + +int StringFile::SetLength(int64_t new_length) { + if (new_length < 0) { + return -EINVAL; + } + data_.resize(new_length); + return 0; +} + +int64_t StringFile::GetLength() const { + return data_.size(); +} + +int64_t StringFile::Write(const char *buf, int64_t byte_count, int64_t offset) { + CHECK(buf); + CHECK_GE(byte_count, 0); + + if (offset < 0) { + return -EINVAL; + } + + if (byte_count == 0) { + return 0; + } + + // FUSE seems happy to allow writes past the end. (I'd guess it doesn't + // synthesize a write of zero bytes so that we're free to implement sparse + // files.) GNU as(1) seems to require such writes. Those files are small. + const int64_t bytes_past_end = offset - GetLength(); + if (bytes_past_end > 0) { + data_.append(bytes_past_end, '\0'); + } + + data_.replace(offset, byte_count, buf, byte_count); + return byte_count; +} + +void StringFile::Assign(const art::StringPiece &new_data) { + data_.assign(new_data.data(), new_data.size()); +} + +const art::StringPiece StringFile::ToStringPiece() const { + return data_; +} + +} // namespace unix_file diff --git a/src/base/unix_file/string_file.h b/src/base/unix_file/string_file.h new file mode 100644 index 0000000000..4277dc2ea7 --- /dev/null +++ b/src/base/unix_file/string_file.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009 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 BASE_UNIX_FILE_STRING_FILE_H_ +#define BASE_UNIX_FILE_STRING_FILE_H_ + +#include <stdint.h> + +#include <string> + +#include "base/macros.h" +#include "base/unix_file/random_access_file.h" +#include "stringpiece.h" + +namespace unix_file { + +// A RandomAccessFile implementation backed by a std::string. (That is, all data is +// kept in memory.) +// +// Not thread safe. +class StringFile : public RandomAccessFile { + public: + StringFile(); + virtual ~StringFile(); + + // RandomAccessFile API. + virtual int Close(); + virtual int Flush(); + virtual int64_t Read(char* buf, int64_t byte_count, int64_t offset) const; + virtual int SetLength(int64_t new_length); + virtual int64_t GetLength() const; + virtual int64_t Write(const char* buf, int64_t byte_count, int64_t offset); + + // Bonus API. + void Assign(const art::StringPiece& new_data); + const art::StringPiece ToStringPiece() const; + + private: + std::string data_; + + DISALLOW_COPY_AND_ASSIGN(StringFile); +}; + +} // namespace unix_file + +#endif // BASE_UNIX_FILE_STRING_FILE_H_ diff --git a/src/base/unix_file/string_file_test.cc b/src/base/unix_file/string_file_test.cc new file mode 100644 index 0000000000..88214610c4 --- /dev/null +++ b/src/base/unix_file/string_file_test.cc @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 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 "base/unix_file/string_file.h" +#include "base/unix_file/random_access_file_test.h" +#include "gtest/gtest.h" + +namespace unix_file { + +class StringFileTest : public RandomAccessFileTest { + protected: + virtual RandomAccessFile* MakeTestFile() { + return new StringFile; + } +}; + +TEST_F(StringFileTest, Read) { + TestRead(); +} + +TEST_F(StringFileTest, SetLength) { + TestSetLength(); +} + +TEST_F(StringFileTest, Write) { + TestWrite(); +} + +} // namespace unix_file diff --git a/src/casts.h b/src/casts.h index f5580ddadf..f996dcd6fd 100644 --- a/src/casts.h +++ b/src/casts.h @@ -19,7 +19,7 @@ #include <assert.h> #include <string.h> -#include "macros.h" +#include "base/macros.h" namespace art { diff --git a/src/class_linker.cc b/src/class_linker.cc index 9a354e1653..97b25ba8f2 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -27,6 +27,7 @@ #include <utility> #include <vector> +#include "base/unix_file/fd_file.h" #include "casts.h" #include "class_loader.h" #include "debugger.h" diff --git a/src/class_linker.h b/src/class_linker.h index 14c719e8fe..e85a7f9dc8 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -21,11 +21,11 @@ #include <utility> #include <vector> +#include "base/macros.h" #include "dex_cache.h" #include "dex_file.h" #include "gtest/gtest.h" #include "heap.h" -#include "macros.h" #include "mutex.h" #include "oat_file.h" #include "object.h" diff --git a/src/common_test.h b/src/common_test.h index f564bbdb14..9dbdbfc09d 100644 --- a/src/common_test.h +++ b/src/common_test.h @@ -20,15 +20,15 @@ #include <sys/stat.h> #include <sys/types.h> +#include "base/macros.h" +#include "base/unix_file/fd_file.h" #include "class_linker.h" #include "class_loader.h" #include "compiler.h" #include "dex_file.h" -#include "file.h" #include "gtest/gtest.h" #include "heap.h" #include "instruction_set.h" -#include "macros.h" #include "oat_file.h" #include "object_utils.h" #include "os.h" @@ -143,16 +143,14 @@ class ScratchFile { ScratchFile() { filename_ = getenv("ANDROID_DATA"); filename_ += "/TmpFile-XXXXXX"; - fd_ = mkstemp(&filename_[0]); - CHECK_NE(-1, fd_); - file_.reset(OS::FileFromFd(GetFilename().c_str(), fd_)); + int fd = mkstemp(&filename_[0]); + CHECK_NE(-1, fd); + file_.reset(new File(fd, GetFilename())); } ~ScratchFile() { int unlink_result = unlink(filename_.c_str()); CHECK_EQ(0, unlink_result); - int close_result = close(fd_); - CHECK_EQ(0, close_result); } const std::string& GetFilename() const { @@ -164,12 +162,11 @@ class ScratchFile { } int GetFd() const { - return fd_; + return file_->Fd(); } private: std::string filename_; - int fd_; UniquePtr<File> file_; }; @@ -289,11 +286,8 @@ class CommonTest : public testing::Test { #endif } - protected: - virtual void SetUp() { - is_host_ = getenv("ANDROID_BUILD_TOP") != NULL; - - if (is_host_) { + static void SetEnvironmentVariables(std::string& android_data) { + if (IsHost()) { // $ANDROID_ROOT is set on the device, but not on the host. // We need to set this so that icu4c can find its locale data. std::string root; @@ -310,11 +304,20 @@ class CommonTest : public testing::Test { } // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of art-cache - android_data_ = (is_host_ ? "/tmp/art-data-XXXXXX" : "/data/art-cache/art-data-XXXXXX"); - if (mkdtemp(&android_data_[0]) == NULL) { - PLOG(FATAL) << "mkdtemp(\"" << &android_data_[0] << "\") failed"; + android_data = (IsHost() ? "/tmp/art-data-XXXXXX" : "/data/art-cache/art-data-XXXXXX"); + if (mkdtemp(&android_data[0]) == NULL) { + PLOG(FATAL) << "mkdtemp(\"" << &android_data[0] << "\") failed"; } - setenv("ANDROID_DATA", android_data_.c_str(), 1); + setenv("ANDROID_DATA", android_data.c_str(), 1); + } + + protected: + static bool IsHost() { + return (getenv("ANDROID_BUILD_TOP") != NULL); + } + + virtual void SetUp() { + SetEnvironmentVariables(android_data_); art_cache_.append(android_data_.c_str()); art_cache_.append("/art-cache"); int mkdir_result = mkdir(art_cache_.c_str(), 0700); @@ -434,7 +437,7 @@ class CommonTest : public testing::Test { } std::string GetLibCoreDexFileName() { - if (is_host_) { + if (IsHost()) { const char* host_dir = getenv("ANDROID_HOST_OUT"); CHECK(host_dir != NULL); return StringPrintf("%s/framework/core-hostdex.jar", host_dir); @@ -445,7 +448,7 @@ class CommonTest : public testing::Test { const DexFile* OpenTestDexFile(const char* name) { CHECK(name != NULL); std::string filename; - if (is_host_) { + if (IsHost()) { filename += getenv("ANDROID_HOST_OUT"); filename += "/framework/"; } else { @@ -524,7 +527,6 @@ class CommonTest : public testing::Test { CompileMethod(method); } - bool is_host_; std::string android_data_; std::string art_cache_; const DexFile* java_lang_dex_file_; // owned by runtime_ diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc index 3524cddfbf..b482d0060e 100644 --- a/src/compiler_llvm/compilation_unit.cc +++ b/src/compiler_llvm/compilation_unit.cc @@ -18,7 +18,6 @@ #include "compiled_method.h" #include "compiler_llvm.h" -#include "file.h" #include "instruction_set.h" #include "ir_builder.h" #include "logging.h" diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h index 0867e566e9..9aa9791ee8 100644 --- a/src/compiler_llvm/compiler_llvm.h +++ b/src/compiler_llvm/compiler_llvm.h @@ -17,10 +17,10 @@ #ifndef ART_SRC_COMPILER_LLVM_COMPILER_LLVM_H_ #define ART_SRC_COMPILER_LLVM_COMPILER_LLVM_H_ +#include "base/macros.h" #include "compiler.h" #include "dex_file.h" #include "instruction_set.h" -#include "macros.h" #include "object.h" #include "procedure_linkage_table.h" diff --git a/src/constants_mips.h b/src/constants_mips.h index 08661e9cea..a03a0c5031 100644 --- a/src/constants_mips.h +++ b/src/constants_mips.h @@ -18,9 +18,9 @@ #define ART_SRC_CONSTANTS_MIPS_H_ #include <iosfwd> +#include "base/macros.h" #include "globals.h" #include "logging.h" -#include "macros.h" namespace art { namespace mips { diff --git a/src/constants_x86.h b/src/constants_x86.h index 7181f99096..e1ddd9a8f7 100644 --- a/src/constants_x86.h +++ b/src/constants_x86.h @@ -18,9 +18,9 @@ #define ART_SRC_CONSTANTS_X86_H_ #include <iosfwd> +#include "base/macros.h" #include "globals.h" #include "logging.h" -#include "macros.h" namespace art { namespace x86 { diff --git a/src/dex2oat.cc b/src/dex2oat.cc index 5739057cce..550f857c5d 100644 --- a/src/dex2oat.cc +++ b/src/dex2oat.cc @@ -23,10 +23,10 @@ #include <string> #include <vector> +#include "base/unix_file/fd_file.h" #include "class_linker.h" #include "class_loader.h" #include "compiler.h" -#include "file.h" #include "image_writer.h" #include "leb128.h" #include "oat_writer.h" @@ -274,7 +274,7 @@ class Dex2Oat { image_file_location_oat_begin, image_file_location, *compiler.get())) { - LOG(ERROR) << "Failed to create oat file " << oat_file->name(); + LOG(ERROR) << "Failed to create oat file " << oat_file->GetPath(); return NULL; } return compiler.release(); @@ -797,7 +797,8 @@ static int dex2oat(int argc, char** argv) { oat_location = oat_filename; } } else { - oat_file.reset(OS::FileFromFd(oat_location.c_str(), oat_fd)); + oat_file.reset(new File(oat_fd, oat_location)); + oat_file->DisableAutoClose(); } if (oat_file.get() == NULL) { PLOG(ERROR) << "Failed to create oat file: " << oat_location; diff --git a/src/dex_cache.h b/src/dex_cache.h index 8d88dc6ca4..ee44856a4d 100644 --- a/src/dex_cache.h +++ b/src/dex_cache.h @@ -17,9 +17,9 @@ #ifndef ART_SRC_DEX_CACHE_H_ #define ART_SRC_DEX_CACHE_H_ +#include "base/macros.h" #include "dex_file.h" #include "globals.h" -#include "macros.h" #include "object.h" namespace art { diff --git a/src/dex_instruction.h b/src/dex_instruction.h index 48dbb0c949..658e756776 100644 --- a/src/dex_instruction.h +++ b/src/dex_instruction.h @@ -17,9 +17,9 @@ #ifndef ART_SRC_DEX_INSTRUCTION_H_ #define ART_SRC_DEX_INSTRUCTION_H_ +#include "base/macros.h" #include "globals.h" #include "logging.h" -#include "macros.h" namespace art { diff --git a/src/dex_instruction_visitor.h b/src/dex_instruction_visitor.h index d625b64fa8..ff4620f8f0 100644 --- a/src/dex_instruction_visitor.h +++ b/src/dex_instruction_visitor.h @@ -17,8 +17,8 @@ #ifndef ART_SRC_DEX_INSTRUCTION_VISITOR_H_ #define ART_SRC_DEX_INSTRUCTION_VISITOR_H_ +#include "base/macros.h" #include "dex_instruction.h" -#include "macros.h" namespace art { diff --git a/src/disassembler.h b/src/disassembler.h index afff7f1abc..1f50bfc9c0 100644 --- a/src/disassembler.h +++ b/src/disassembler.h @@ -21,8 +21,8 @@ #include <iosfwd> +#include "base/macros.h" #include "instruction_set.h" -#include "macros.h" namespace art { diff --git a/src/file.cc b/src/file.cc deleted file mode 100644 index 310876b1cc..0000000000 --- a/src/file.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2009 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.h" - -namespace art { - -bool File::ReadFully(void* buffer, int64_t num_bytes) { - int64_t remaining = num_bytes; - char* current_buffer = reinterpret_cast<char*>(buffer); - while (remaining > 0) { - int bytes_read = Read(current_buffer, remaining); - if (bytes_read <= 0) { - return false; - } - remaining -= bytes_read; // Reduce the number of remaining bytes. - current_buffer += bytes_read; // Move the buffer forward. - } - return true; -} - - -bool File::WriteFully(const void* buffer, int64_t num_bytes) { - int64_t remaining = num_bytes; - const char* current_buffer = reinterpret_cast<const char*>(buffer); - while (remaining > 0) { - int bytes_read = Write(current_buffer, remaining); - if (bytes_read < 0) { - return false; - } - remaining -= bytes_read; // Reduce the number of remaining bytes. - current_buffer += bytes_read; // Move the buffer forward. - } - return true; -} - -} // namespace art diff --git a/src/file.h b/src/file.h deleted file mode 100644 index 7e3d72b562..0000000000 --- a/src/file.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2009 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_SRC_FILE_H_ -#define ART_SRC_FILE_H_ - -#include <stdint.h> -#include <sys/types.h> - -namespace art { - -class File { - public: - virtual ~File() { } - - virtual int64_t Read(void* buffer, int64_t num_bytes) = 0; - virtual int64_t Write(const void* buffer, int64_t num_bytes) = 0; - - // ReadFully and WriteFully do attempt to transfer all of the bytes to/from - // the buffer. In the event of short accesses they will loop internally until - // the whole buffer has been transferred or an error occurs. If an error - // occurred the result will be set to false. - virtual bool ReadFully(void* buffer, int64_t num_bytes); - virtual bool WriteFully(const void* buffer, int64_t num_bytes); - bool WriteByte(uint8_t byte) { - return WriteFully(&byte, 1); - } - - // Get the length of the file. Returns a negative value if the length cannot - // be determined (e.g. not seekable device). - virtual off_t Length() = 0; - - // Get the current position in the file. - // Returns a negative value if position cannot be determined. - virtual off_t Position() = 0; - - virtual int Fd() = 0; - - const char* name() const { return name_; } - - protected: - explicit File(const char* name) : name_(name) { } - virtual void Close() = 0; - virtual bool IsClosed() = 0; - - private: - const char* name_; -}; - -} // namespace art - -#endif // ART_SRC_FILE_H_ diff --git a/src/file_linux.cc b/src/file_linux.cc deleted file mode 100644 index cd272fb0bb..0000000000 --- a/src/file_linux.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 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_linux.h" - -#include <errno.h> -#include <unistd.h> - -#include "logging.h" - -namespace art { - -LinuxFile::~LinuxFile() { - // Close the file if necessary (unless it's a standard stream). - if (auto_close_ && fd_ > STDERR_FILENO) { - Close(); - } -} - -void LinuxFile::Close() { - DCHECK_GT(fd_, 0); - int err = close(fd_); - if (err != 0) { - PLOG(WARNING) << "Problem closing " << name(); - } - fd_ = kClosedFd; -} - - -bool LinuxFile::IsClosed() { - return fd_ == kClosedFd; -} - - -int64_t LinuxFile::Read(void* buffer, int64_t num_bytes) { - DCHECK_GE(fd_, 0); - return read(fd_, buffer, num_bytes); -} - - -int64_t LinuxFile::Write(const void* buffer, int64_t num_bytes) { - DCHECK_GE(fd_, 0); - return write(fd_, buffer, num_bytes); -} - - -off_t LinuxFile::Position() { - DCHECK_GE(fd_, 0); - return lseek(fd_, 0, SEEK_CUR); -} - - -off_t LinuxFile::Length() { - DCHECK_GE(fd_, 0); - off_t position = lseek(fd_, 0, SEEK_CUR); - if (position < 0) { - // The file is not capable of seeking. Return an error. - return -1; - } - off_t result = lseek(fd_, 0, SEEK_END); - lseek(fd_, position, SEEK_SET); - return result; -} - -} // namespace art diff --git a/src/file_linux.h b/src/file_linux.h deleted file mode 100644 index b5d6f3b4e0..0000000000 --- a/src/file_linux.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2010 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_SRC_FILE_LINUX_H_ -#define ART_SRC_FILE_LINUX_H_ - -#include "file.h" - -namespace art { - -class LinuxFile : public File { - public: - LinuxFile(const char* name, int fd, bool auto_close) - : File(name), fd_(fd), auto_close_(auto_close) {} - virtual ~LinuxFile(); - - virtual void Close(); - virtual bool IsClosed(); - - virtual int64_t Read(void* buffer, int64_t num_bytes); - virtual int64_t Write(const void* buffer, int64_t num_bytes); - - virtual off_t Length(); - virtual off_t Position(); - - virtual int Fd() { - return fd_; - } - - private: - static const int kClosedFd = -1; - - int fd_; - bool auto_close_; -}; - -} // namespace art - -#endif // ART_SRC_FILE_LINUX_H_ diff --git a/src/file_test.cc b/src/file_test.cc deleted file mode 100644 index 85c130e914..0000000000 --- a/src/file_test.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2009 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.h" - -#include "UniquePtr.h" -#include "common_test.h" -#include "os.h" - -namespace art { - -class FileTest : public CommonTest {}; - -TEST_F(FileTest, Read) { - std::string filename(GetLibCoreDexFileName()); - UniquePtr<File> file(OS::OpenFile(filename.c_str(), false)); - ASSERT_TRUE(file.get() != NULL); - EXPECT_STREQ(filename.c_str(), file->name()); - char buffer[3]; - buffer[0] = '\0'; - EXPECT_TRUE(file->ReadFully(buffer, 2)); // ReadFully returns true. - buffer[2] = '\0'; - EXPECT_STREQ("PK", buffer); // zip file magic - EXPECT_FALSE(file->WriteByte(1)); // Cannot write to a read-only file. -} - - -TEST_F(FileTest, FileLength) { - std::string filename(GetLibCoreDexFileName()); - UniquePtr<File> file(OS::OpenFile(filename.c_str(), false)); - ASSERT_TRUE(file.get() != NULL); - EXPECT_NE(0, file->Length()); -} - - -TEST_F(FileTest, FilePosition) { - std::string filename(GetLibCoreDexFileName()); - UniquePtr<File> file(OS::OpenFile(filename.c_str(), false)); - ASSERT_TRUE(file.get() != NULL); - char buf[4]; - EXPECT_TRUE(file->ReadFully(buf, 2)); - EXPECT_EQ(2, file->Position()); - EXPECT_TRUE(file->ReadFully(buf, 2)); - EXPECT_EQ(4, file->Position()); -} - - -TEST_F(FileTest, FileFd) { - std::string filename(GetLibCoreDexFileName()); - UniquePtr<File> file(OS::OpenFile(filename.c_str(), false)); - ASSERT_TRUE(file.get() != NULL); - EXPECT_NE(-1, file->Fd()); -} - - -} // namespace art diff --git a/src/gc/atomic_stack.h b/src/gc/atomic_stack.h index d67d2f2868..4a7920e080 100644 --- a/src/gc/atomic_stack.h +++ b/src/gc/atomic_stack.h @@ -20,9 +20,9 @@ #include <string> #include "atomic_integer.h" +#include "base/macros.h" #include "UniquePtr.h" #include "logging.h" -#include "macros.h" #include "mem_map.h" #include "utils.h" diff --git a/src/gc/large_object_space.cc b/src/gc/large_object_space.cc index b2e0d2fbb0..a994479f92 100644 --- a/src/gc/large_object_space.cc +++ b/src/gc/large_object_space.cc @@ -17,7 +17,6 @@ #include "large_object_space.h" #include "UniquePtr.h" #include "dlmalloc.h" -#include "file.h" #include "image.h" #include "logging.h" #include "os.h" diff --git a/src/gc/mark_sweep.cc b/src/gc/mark_sweep.cc index d5231ecca5..f57d6155de 100644 --- a/src/gc/mark_sweep.cc +++ b/src/gc/mark_sweep.cc @@ -22,6 +22,7 @@ #include <vector> #include "barrier.h" +#include "base/macros.h" #include "card_table.h" #include "class_loader.h" #include "dex_cache.h" @@ -31,7 +32,6 @@ #include "jni_internal.h" #include "large_object_space.h" #include "logging.h" -#include "macros.h" #include "monitor.h" #include "object.h" #include "runtime.h" diff --git a/src/gc/mark_sweep.h b/src/gc/mark_sweep.h index c740bb7303..3581d98772 100644 --- a/src/gc/mark_sweep.h +++ b/src/gc/mark_sweep.h @@ -18,8 +18,8 @@ #define ART_SRC_MARK_SWEEP_H_ #include "atomic_stack.h" +#include "base/macros.h" #include "garbage_collector.h" -#include "macros.h" #include "heap_bitmap.h" #include "object.h" #include "offsets.h" diff --git a/src/gc/space.cc b/src/gc/space.cc index 8595dd00ec..27f78ccdae 100644 --- a/src/gc/space.cc +++ b/src/gc/space.cc @@ -17,8 +17,8 @@ #include "space.h" #include "UniquePtr.h" +#include "base/unix_file/fd_file.h" #include "dlmalloc.h" -#include "file.h" #include "image.h" #include "logging.h" #include "os.h" @@ -485,7 +485,7 @@ ImageSpace* ImageSpace::Create(const std::string& image_file_name) { return NULL; } UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(), - file->Length(), + file->GetLength(), // TODO: selectively PROT_EXEC stubs PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_FIXED, diff --git a/src/gc/space.h b/src/gc/space.h index dfbc9d2a37..24427f148e 100644 --- a/src/gc/space.h +++ b/src/gc/space.h @@ -21,9 +21,9 @@ #include "../mutex.h" #include "UniquePtr.h" +#include "base/macros.h" #include "globals.h" #include "image.h" -#include "macros.h" #include "dlmalloc.h" #include "mem_map.h" diff --git a/src/gc/sticky_mark_sweep.h b/src/gc/sticky_mark_sweep.h index 9c3b6a4c77..8396bbe09a 100644 --- a/src/gc/sticky_mark_sweep.h +++ b/src/gc/sticky_mark_sweep.h @@ -17,8 +17,8 @@ #ifndef ART_SRC_STICKY_MARK_SWEEP_H_ #define ART_SRC_STICKY_MARK_SWEEP_H_ +#include "base/macros.h" #include "locks.h" -#include "macros.h" #include "partial_mark_sweep.h" #include "utils.h" diff --git a/src/gc_map.h b/src/gc_map.h index afccaa1e41..80810b03d8 100644 --- a/src/gc_map.h +++ b/src/gc_map.h @@ -17,8 +17,8 @@ #ifndef ART_SRC_GC_MAP_H_ #define ART_SRC_GC_MAP_H_ +#include "base/macros.h" #include "logging.h" -#include "macros.h" #include <stdint.h> namespace art { diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc index 696501520e..8838c29b6b 100644 --- a/src/hprof/hprof.cc +++ b/src/hprof/hprof.cc @@ -37,9 +37,9 @@ #include <set> +#include "base/unix_file/fd_file.h" #include "class_linker.h" #include "debugger.h" -#include "file.h" #include "globals.h" #include "heap.h" #include "logging.h" @@ -459,7 +459,7 @@ class Hprof { } } - UniquePtr<File> file(OS::FileFromFd(filename_.c_str(), out_fd)); + UniquePtr<File> file(new File(out_fd, filename_)); okay = file->WriteFully(header_data_ptr_, header_data_size_) && file->WriteFully(body_data_ptr_, body_data_size_); if (!okay) { @@ -468,7 +468,6 @@ class Hprof { self->ThrowNewException("Ljava/lang/RuntimeException;", msg.c_str()); LOG(ERROR) << msg; } - close(out_fd); } // Throw out a log message for the benefit of "runhat". diff --git a/src/image_test.cc b/src/image_test.cc index feb490c651..a250b13b5d 100644 --- a/src/image_test.cc +++ b/src/image_test.cc @@ -18,7 +18,6 @@ #include <vector> #include "common_test.h" -#include "file.h" #include "image.h" #include "image_writer.h" #include "oat_writer.h" @@ -71,7 +70,7 @@ TEST_F(ImageTest, WriteRead) { ASSERT_FALSE(space->IsImageSpace()); ASSERT_TRUE(space != NULL); ASSERT_TRUE(space->IsAllocSpace()); - ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length())); + ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->GetLength())); } // Need to delete the compiler since it has worker threads which are attached to runtime. diff --git a/src/image_writer.cc b/src/image_writer.cc index a9aa2e0adf..6065760ae0 100644 --- a/src/image_writer.cc +++ b/src/image_writer.cc @@ -20,12 +20,12 @@ #include <vector> +#include "base/unix_file/fd_file.h" #include "class_linker.h" #include "class_loader.h" #include "compiled_method.h" #include "compiler.h" #include "dex_cache.h" -#include "file.h" #include "gc/large_object_space.h" #include "gc/space.h" #include "globals.h" diff --git a/src/indenter.h b/src/indenter.h index f66df0897a..4ac0c01163 100644 --- a/src/indenter.h +++ b/src/indenter.h @@ -17,7 +17,7 @@ #ifndef ART_SRC_INDENTER_H_ #define ART_SRC_INDENTER_H_ -#include "macros.h" +#include "base/macros.h" #include <streambuf> const char kIndentChar =' '; diff --git a/src/instrumentation.cc b/src/instrumentation.cc index d796aef7f0..28f8cb24a2 100644 --- a/src/instrumentation.cc +++ b/src/instrumentation.cc @@ -18,6 +18,7 @@ #include <sys/uio.h> +#include "base/unix_file/fd_file.h" #include "class_linker.h" #include "debugger.h" #include "dex_cache.h" diff --git a/src/instrumentation.h b/src/instrumentation.h index a5ab650f88..b17e0206f9 100644 --- a/src/instrumentation.h +++ b/src/instrumentation.h @@ -21,9 +21,8 @@ #include <set> #include <string> -#include "file.h" +#include "base/macros.h" #include "globals.h" -#include "macros.h" #include "safe_map.h" #include "trace.h" #include "UniquePtr.h" diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc index 88677d5750..2a2bde28af 100644 --- a/src/jdwp/jdwp_handler.cc +++ b/src/jdwp/jdwp_handler.cc @@ -26,6 +26,7 @@ */ #include "atomic.h" +#include "base/macros.h" #include "debugger.h" #include "jdwp/jdwp_priv.h" #include "jdwp/jdwp_handler.h" @@ -33,7 +34,6 @@ #include "jdwp/jdwp_constants.h" #include "jdwp/jdwp_expand_buf.h" #include "logging.h" -#include "macros.h" #include "stringprintf.h" #include <stdlib.h> diff --git a/src/jni_internal.h b/src/jni_internal.h index 95bc281ca7..606887c90b 100644 --- a/src/jni_internal.h +++ b/src/jni_internal.h @@ -19,9 +19,9 @@ #include "jni.h" +#include "base/macros.h" #include "heap.h" #include "indirect_reference_table.h" -#include "macros.h" #include "mutex.h" #include "reference_table.h" #include "runtime.h" diff --git a/src/locks.h b/src/locks.h index 9da77110a2..6f8400dbfe 100644 --- a/src/locks.h +++ b/src/locks.h @@ -19,7 +19,7 @@ #include <ostream> -#include "macros.h" +#include "base/macros.h" namespace art { diff --git a/src/logging.h b/src/logging.h index 1c04b2cc2a..55dc710f0d 100644 --- a/src/logging.h +++ b/src/logging.h @@ -22,8 +22,8 @@ #include <iostream> // NOLINT #include <sstream> #include <signal.h> +#include "base/macros.h" #include "log_severity.h" -#include "macros.h" #define CHECK(x) \ if (UNLIKELY(!(x))) \ diff --git a/src/memory_region.h b/src/memory_region.h index 5a7eab61e2..bd1ae87aee 100644 --- a/src/memory_region.h +++ b/src/memory_region.h @@ -18,9 +18,10 @@ #define ART_SRC_MEMORY_REGION_H_ #include <stdint.h> + +#include "base/macros.h" #include "globals.h" #include "logging.h" -#include "macros.h" #include "memory_region.h" namespace art { diff --git a/src/mutex.h b/src/mutex.h index 9e337eca14..6cfd4b938d 100644 --- a/src/mutex.h +++ b/src/mutex.h @@ -23,10 +23,10 @@ #include <iosfwd> #include <string> +#include "base/macros.h" #include "globals.h" #include "locks.h" #include "logging.h" -#include "macros.h" #if defined(__APPLE__) #define ART_USE_FUTEXES 0 @@ -19,9 +19,9 @@ #include <vector> +#include "base/macros.h" #include "dex_file.h" #include "instruction_set.h" -#include "macros.h" namespace art { diff --git a/src/oat/jni/jni_compiler.cc b/src/oat/jni/jni_compiler.cc index 585d60e5d3..5a2243e311 100644 --- a/src/oat/jni/jni_compiler.cc +++ b/src/oat/jni/jni_compiler.cc @@ -17,6 +17,7 @@ #include <algorithm> #include <vector> +#include "base/macros.h" #include "calling_convention.h" #include "class_linker.h" #include "compiled_method.h" @@ -24,7 +25,6 @@ #include "disassembler.h" #include "jni_internal.h" #include "logging.h" -#include "macros.h" #include "oat/runtime/oat_support_entrypoints.h" #include "oat/utils/assembler.h" #include "oat/utils/managed_register.h" diff --git a/src/oat/utils/assembler.h b/src/oat/utils/assembler.h index 0880d573ea..c05309ae83 100644 --- a/src/oat/utils/assembler.h +++ b/src/oat/utils/assembler.h @@ -19,12 +19,12 @@ #include <vector> +#include "base/macros.h" #include "constants_arm.h" #include "constants_mips.h" #include "constants_x86.h" #include "instruction_set.h" #include "logging.h" -#include "macros.h" #include "managed_register.h" #include "memory_region.h" #include "offsets.h" diff --git a/src/oat/utils/mips/assembler_mips.h b/src/oat/utils/mips/assembler_mips.h index 73937aa4ef..02759e4efb 100644 --- a/src/oat/utils/mips/assembler_mips.h +++ b/src/oat/utils/mips/assembler_mips.h @@ -18,10 +18,11 @@ #define ART_SRC_OAT_UTILS_MIPS_ASSEMBLER_MIPS_H_ #include <vector> + +#include "base/macros.h" #include "constants_mips.h" #include "globals.h" #include "managed_register_mips.h" -#include "macros.h" #include "oat/utils/assembler.h" #include "offsets.h" #include "utils.h" diff --git a/src/oat/utils/x86/assembler_x86.h b/src/oat/utils/x86/assembler_x86.h index 5971fe8d1d..dddb9b1885 100644 --- a/src/oat/utils/x86/assembler_x86.h +++ b/src/oat/utils/x86/assembler_x86.h @@ -18,10 +18,10 @@ #define ART_SRC_OAT_UTILS_X86_ASSEMBLER_X86_H_ #include <vector> +#include "base/macros.h" #include "constants_x86.h" #include "globals.h" #include "managed_register_x86.h" -#include "macros.h" #include "oat/utils/assembler.h" #include "offsets.h" #include "utils.h" diff --git a/src/oat_file.cc b/src/oat_file.cc index 145d2e2d62..04ee545bb5 100644 --- a/src/oat_file.cc +++ b/src/oat_file.cc @@ -16,7 +16,7 @@ #include "oat_file.h" -#include "file.h" +#include "base/unix_file/fd_file.h" #include "os.h" #include "stl_util.h" @@ -92,33 +92,33 @@ bool OatFile::Map(File& file, flags |= MAP_FIXED; } UniquePtr<MemMap> map(MemMap::MapFileAtAddress(requested_base, - file.Length(), + file.GetLength(), prot, flags, file.Fd(), 0)); if (map.get() == NULL) { - LOG(WARNING) << "Failed to map oat file from " << file.name() << " for " << GetLocation(); + LOG(WARNING) << "Failed to map oat file from " << file.GetPath() << " for " << GetLocation(); return false; } CHECK(requested_base == 0 || requested_base == map->Begin()) - << file.name() << " for " << GetLocation() << " " << reinterpret_cast<void*>(map->Begin()); + << file.GetPath() << " for " << GetLocation() << " " << reinterpret_cast<void*>(map->Begin()); DCHECK_EQ(0, memcmp(&oat_header, map->Begin(), sizeof(OatHeader))) - << file.name() << " for " << GetLocation(); + << file.GetPath() << " for " << GetLocation(); off_t code_offset = oat_header.GetExecutableOffset(); - if (code_offset < file.Length()) { + if (code_offset < file.GetLength()) { byte* code_address = map->Begin() + code_offset; - size_t code_length = file.Length() - code_offset; + size_t code_length = file.GetLength() - code_offset; if (mprotect(code_address, code_length, prot | PROT_EXEC) != 0) { PLOG(ERROR) << "Failed to make oat code executable in " - << file.name() << " for " << GetLocation(); + << file.GetPath() << " for " << GetLocation(); return false; } } else { // its possible to have no code if all the methods were abstract, native, etc - DCHECK_EQ(code_offset, RoundUp(file.Length(), kPageSize)) - << file.name() << " for " << GetLocation(); + DCHECK_EQ(code_offset, RoundUp(file.GetLength(), kPageSize)) + << file.GetPath() << " for " << GetLocation(); } const byte* oat = map->Begin(); @@ -131,40 +131,40 @@ bool OatFile::Map(File& file, << "+" << sizeof(OatHeader) << "+" << oat_header.GetImageFileLocationSize() << "<=" << reinterpret_cast<void*>(map->End()) - << " " << file.name() << " for " << GetLocation(); + << " " << file.GetPath() << " for " << GetLocation(); for (size_t i = 0; i < oat_header.GetDexFileCount(); i++) { size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat); - CHECK_GT(dex_file_location_size, 0U) << file.name() << " for " << GetLocation(); + CHECK_GT(dex_file_location_size, 0U) << file.GetPath() << " for " << GetLocation(); oat += sizeof(dex_file_location_size); - CHECK_LT(oat, map->End()) << file.name() << " for " << GetLocation(); + CHECK_LT(oat, map->End()) << file.GetPath() << " for " << GetLocation(); const char* dex_file_location_data = reinterpret_cast<const char*>(oat); oat += dex_file_location_size; - CHECK_LT(oat, map->End()) << file.name() << " for " << GetLocation(); + CHECK_LT(oat, map->End()) << file.GetPath() << " for " << GetLocation(); std::string dex_file_location(dex_file_location_data, dex_file_location_size); uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat); oat += sizeof(dex_file_checksum); - CHECK_LT(oat, map->End()) << file.name() << " for " << GetLocation(); + CHECK_LT(oat, map->End()) << file.GetPath() << " for " << GetLocation(); uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat); - CHECK_GT(dex_file_offset, 0U) << file.name() << " for " << GetLocation(); - CHECK_LT(dex_file_offset, static_cast<uint32_t>(file.Length())) - << file.name() << " for " << GetLocation(); + CHECK_GT(dex_file_offset, 0U) << file.GetPath() << " for " << GetLocation(); + CHECK_LT(dex_file_offset, static_cast<uint32_t>(file.GetLength())) + << file.GetPath() << " for " << GetLocation(); oat += sizeof(dex_file_offset); - CHECK_LT(oat, map->End()) << file.name() << " for " << GetLocation(); + CHECK_LT(oat, map->End()) << file.GetPath() << " for " << GetLocation(); uint8_t* dex_file_pointer = map->Begin() + dex_file_offset; CHECK(DexFile::IsMagicValid(dex_file_pointer)) - << file.name() << " for " << GetLocation() << " " << dex_file_pointer; + << file.GetPath() << " for " << GetLocation() << " " << dex_file_pointer; CHECK(DexFile::IsVersionValid(dex_file_pointer)) - << file.name() << " for " << GetLocation() << " " << dex_file_pointer; + << file.GetPath() << " for " << GetLocation() << " " << dex_file_pointer; const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer); const uint32_t* methods_offsets_pointer = reinterpret_cast<const uint32_t*>(oat); oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_); - CHECK_LE(oat, map->End()) << file.name() << " for " << GetLocation(); + CHECK_LE(oat, map->End()) << file.GetPath() << " for " << GetLocation(); oat_dex_files_.Put(dex_file_location, new OatDexFile(this, dex_file_location, diff --git a/src/oat_writer.cc b/src/oat_writer.cc index a15c5cfbff..49d4e253bd 100644 --- a/src/oat_writer.cc +++ b/src/oat_writer.cc @@ -18,9 +18,9 @@ #include <zlib.h> +#include "base/unix_file/fd_file.h" #include "class_linker.h" #include "class_loader.h" -#include "file.h" #include "os.h" #include "safe_map.h" #include "scoped_thread_state_change.h" @@ -425,30 +425,30 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, bool OatWriter::Write(File* file) { if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) { - PLOG(ERROR) << "Failed to write oat header to " << file->name(); + PLOG(ERROR) << "Failed to write oat header to " << file->GetPath(); return false; } if (!file->WriteFully(image_file_location_.data(), image_file_location_.size())) { - PLOG(ERROR) << "Failed to write oat header image file location to " << file->name(); + PLOG(ERROR) << "Failed to write oat header image file location to " << file->GetPath(); return false; } if (!WriteTables(file)) { - LOG(ERROR) << "Failed to write oat tables to " << file->name(); + LOG(ERROR) << "Failed to write oat tables to " << file->GetPath(); return false; } size_t code_offset = WriteCode(file); if (code_offset == 0) { - LOG(ERROR) << "Failed to write oat code to " << file->name(); + LOG(ERROR) << "Failed to write oat code to " << file->GetPath(); return false; } code_offset = WriteCodeDexFiles(file, code_offset); if (code_offset == 0) { - LOG(ERROR) << "Failed to write oat code for dex files to " << file->name(); + LOG(ERROR) << "Failed to write oat code for dex files to " << file->GetPath(); return false; } @@ -458,7 +458,7 @@ bool OatWriter::Write(File* file) { bool OatWriter::WriteTables(File* file) { for (size_t i = 0; i != oat_dex_files_.size(); ++i) { if (!oat_dex_files_[i]->Write(file)) { - PLOG(ERROR) << "Failed to write oat dex information to " << file->name(); + PLOG(ERROR) << "Failed to write oat dex information to " << file->GetPath(); return false; } } @@ -473,13 +473,13 @@ bool OatWriter::WriteTables(File* file) { } const DexFile* dex_file = (*dex_files_)[i]; if (!file->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) { - PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << file->name(); + PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << file->GetPath(); return false; } } for (size_t i = 0; i != oat_classes_.size(); ++i) { if (!oat_classes_[i]->Write(file)) { - PLOG(ERROR) << "Failed to write oat methods information to " << file->name(); + PLOG(ERROR) << "Failed to write oat methods information to " << file->GetPath(); return false; } } @@ -491,7 +491,7 @@ size_t OatWriter::WriteCode(File* file) { off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR); if (static_cast<uint32_t>(new_offset) != code_offset) { PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset - << " Expected: " << code_offset << " File: " << file->name(); + << " Expected: " << code_offset << " File: " << file->GetPath(); return 0; } DCHECK_CODE_OFFSET(); @@ -527,7 +527,7 @@ size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, size_t& oat_c void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file, File* f) const { PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file) - << " to " << f->name(); + << " to " << f->GetPath(); } size_t OatWriter::WriteCodeClassDef(File* file, @@ -588,7 +588,7 @@ size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_cla off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR); if (static_cast<uint32_t>(new_offset) != aligned_code_offset) { PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset - << " Expected: " << aligned_code_offset << " File: " << file->name(); + << " Expected: " << aligned_code_offset << " File: " << file->GetPath(); return 0; } code_offset += aligned_code_delta; @@ -813,24 +813,24 @@ void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const { bool OatWriter::OatDexFile::Write(File* file) const { if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) { - PLOG(ERROR) << "Failed to write dex file location length to " << file->name(); + PLOG(ERROR) << "Failed to write dex file location length to " << file->GetPath(); return false; } if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) { - PLOG(ERROR) << "Failed to write dex file location data to " << file->name(); + PLOG(ERROR) << "Failed to write dex file location data to " << file->GetPath(); return false; } if (!file->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) { - PLOG(ERROR) << "Failed to write dex file location checksum to " << file->name(); + PLOG(ERROR) << "Failed to write dex file location checksum to " << file->GetPath(); return false; } if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) { - PLOG(ERROR) << "Failed to write dex file offset to " << file->name(); + PLOG(ERROR) << "Failed to write dex file offset to " << file->GetPath(); return false; } if (!file->WriteFully(&methods_offsets_[0], sizeof(methods_offsets_[0]) * methods_offsets_.size())) { - PLOG(ERROR) << "Failed to write methods offsets to " << file->name(); + PLOG(ERROR) << "Failed to write methods offsets to " << file->GetPath(); return false; } return true; @@ -854,12 +854,12 @@ void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const { bool OatWriter::OatClass::Write(File* file) const { if (!file->WriteFully(&status_, sizeof(status_))) { - PLOG(ERROR) << "Failed to write class status to " << file->name(); + PLOG(ERROR) << "Failed to write class status to " << file->GetPath(); return false; } if (!file->WriteFully(&method_offsets_[0], sizeof(method_offsets_[0]) * method_offsets_.size())) { - PLOG(ERROR) << "Failed to write method offsets to " << file->name(); + PLOG(ERROR) << "Failed to write method offsets to " << file->GetPath(); return false; } return true; diff --git a/src/oatdump.cc b/src/oatdump.cc index 45d936a0a3..cd8b4bb586 100644 --- a/src/oatdump.cc +++ b/src/oatdump.cc @@ -22,10 +22,10 @@ #include <string> #include <vector> +#include "base/unix_file/fd_file.h" #include "class_linker.h" #include "dex_instruction.h" #include "disassembler.h" -#include "file.h" #include "gc_map.h" #include "gc/large_object_space.h" #include "gc/space.h" @@ -792,7 +792,7 @@ class ImageDumper { } os << "STATS:\n" << std::flush; UniquePtr<File> file(OS::OpenFile(image_filename_.c_str(), false)); - stats_.file_bytes = file->Length(); + stats_.file_bytes = file->GetLength(); size_t header_bytes = sizeof(ImageHeader); stats_.header_bytes = header_bytes; size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes; diff --git a/src/object.h b/src/object.h index e9851c08f3..a3b808f7a5 100644 --- a/src/object.h +++ b/src/object.h @@ -22,12 +22,12 @@ #include "UniquePtr.h" #include "atomic.h" +#include "base/macros.h" #include "casts.h" #include "globals.h" #include "heap.h" #include "invoke_type.h" #include "logging.h" -#include "macros.h" #include "modifiers.h" #include "offsets.h" #include "primitive.h" @@ -17,20 +17,21 @@ #ifndef ART_SRC_OS_H_ #define ART_SRC_OS_H_ +namespace unix_file { +class FdFile; +} // namespace unix_file + namespace art { -// Interface to the underlying OS platform. +typedef ::unix_file::FdFile File; -class File; +// Interface to the underlying OS platform. class OS { public: - // Open a file. The returned file must be deleted by the caller. + // Open a file. The returned pointer must be deleted by the caller. static File* OpenFile(const char* name, bool writable, bool create = true); - // Create a file from an already open file descriptor - static File* FileFromFd(const char* name, int fd); - // Check if a file exists. static bool FileExists(const char* name); diff --git a/src/os_linux.cc b/src/os_linux.cc index b91f1ff116..ceda7dd51c 100644 --- a/src/os_linux.cc +++ b/src/os_linux.cc @@ -21,7 +21,8 @@ #include <sys/stat.h> #include <fcntl.h> -#include "file_linux.h" +#include "base/unix_file/fd_file.h" +#include "UniquePtr.h" namespace art { @@ -35,15 +36,11 @@ File* OS::OpenFile(const char* name, bool writable, bool create) { } else { flags |= O_RDONLY; } - int fd = open(name, flags, 0666); - if (fd < 0) { + UniquePtr<File> file(new File); + if (!file->Open(name, flags, 0666)) { return NULL; } - return new LinuxFile(name, fd, true); -} - -File* OS::FileFromFd(const char* name, int fd) { - return new LinuxFile(name, fd, false); + return file.release(); } bool OS::FileExists(const char* name) { diff --git a/src/primitive.h b/src/primitive.h index ae2e487a96..d0caecaa88 100644 --- a/src/primitive.h +++ b/src/primitive.h @@ -19,8 +19,8 @@ #include <sys/types.h> +#include "base/macros.h" #include "logging.h" -#include "macros.h" namespace art { diff --git a/src/runtime.h b/src/runtime.h index c596a17578..c8a520af4a 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -25,11 +25,11 @@ #include <utility> #include <vector> +#include "base/macros.h" #include "globals.h" #include "heap.h" #include "instruction_set.h" #include "jobject_comparator.h" -#include "macros.h" #include "locks.h" #include "runtime_stats.h" #include "safe_map.h" diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc index 72989a6c23..e2050d1205 100644 --- a/src/runtime_linux.cc +++ b/src/runtime_linux.cc @@ -34,7 +34,7 @@ struct Backtrace { } }; -struct OS { +struct OsInfo { void Dump(std::ostream& os) { utsname info; uname(&info); @@ -242,7 +242,7 @@ void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_contex bool has_address = (signal_number == SIGILL || signal_number == SIGBUS || signal_number == SIGFPE || signal_number == SIGSEGV); - OS os_info; + OsInfo os_info; const char* cmd_line = GetCmdLine(); if (cmd_line == NULL) { cmd_line = "<unset>"; // Because no-one called InitLogging. @@ -258,7 +258,7 @@ void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_contex info->si_code, GetSignalCodeName(signal_number, info->si_code)) << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "") << "\n" - << "OS: " << Dumpable<OS>(os_info) << "\n" + << "OS: " << Dumpable<OsInfo>(os_info) << "\n" << "Cmdline: " << cmd_line << "\n" << "Thread: " << tid << " \"" << thread_name << "\"\n" << "Registers:\n" << Dumpable<UContext>(thread_context) << "\n" diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc index db0d2c734b..9fdf4e9927 100644 --- a/src/signal_catcher.cc +++ b/src/signal_catcher.cc @@ -25,8 +25,8 @@ #include <sys/types.h> #include <unistd.h> +#include "base/unix_file/fd_file.h" #include "class_linker.h" -#include "file.h" #include "heap.h" #include "os.h" #include "runtime.h" @@ -106,13 +106,12 @@ void SignalCatcher::Output(const std::string& s) { PLOG(ERROR) << "Unable to open stack trace file '" << stack_trace_file_ << "'"; return; } - UniquePtr<File> file(OS::FileFromFd(stack_trace_file_.c_str(), fd)); + UniquePtr<File> file(new File(fd, stack_trace_file_)); if (!file->WriteFully(s.data(), s.size())) { PLOG(ERROR) << "Failed to write stack traces to '" << stack_trace_file_ << "'"; } else { LOG(INFO) << "Wrote stack traces to '" << stack_trace_file_ << "'"; } - close(fd); } void SignalCatcher::HandleSigQuit() { diff --git a/src/sirt_ref.h b/src/sirt_ref.h index ea0b9a360a..5e29214787 100644 --- a/src/sirt_ref.h +++ b/src/sirt_ref.h @@ -17,8 +17,8 @@ #ifndef ART_SRC_SIRT_REF_H_ #define ART_SRC_SIRT_REF_H_ +#include "base/macros.h" #include "logging.h" -#include "macros.h" #include "thread.h" namespace art { diff --git a/src/stack.h b/src/stack.h index ecfa8461c0..30de26daa0 100644 --- a/src/stack.h +++ b/src/stack.h @@ -17,11 +17,11 @@ #ifndef ART_SRC_STACK_H_ #define ART_SRC_STACK_H_ +#include "base/macros.h" #include "dex_file.h" #include "heap.h" #include "instrumentation.h" #include "jni.h" -#include "macros.h" #include "oat/runtime/context.h" #include <stdint.h> diff --git a/src/stack_indirect_reference_table.h b/src/stack_indirect_reference_table.h index 506f00ab4d..a9d305ad12 100644 --- a/src/stack_indirect_reference_table.h +++ b/src/stack_indirect_reference_table.h @@ -17,8 +17,8 @@ #ifndef ART_SRC_STACK_INDIRECT_REFERENCE_TABLE_H_ #define ART_SRC_STACK_INDIRECT_REFERENCE_TABLE_H_ +#include "base/macros.h" #include "logging.h" -#include "macros.h" namespace art { diff --git a/src/thread.h b/src/thread.h index 4d973159f1..29ae7c18e5 100644 --- a/src/thread.h +++ b/src/thread.h @@ -25,10 +25,10 @@ #include <string> #include <vector> +#include "base/macros.h" #include "closure.h" #include "globals.h" #include "instrumentation.h" -#include "macros.h" #include "oat/runtime/oat_support_entrypoints.h" #include "locks.h" #include "offsets.h" diff --git a/src/thread_android.cc b/src/thread_android.cc index f86d0f461d..7c4551fa24 100644 --- a/src/thread_android.cc +++ b/src/thread_android.cc @@ -24,7 +24,7 @@ #include <cutils/sched_policy.h> #include <utils/threads.h> -#include "macros.h" +#include "base/macros.h" namespace art { diff --git a/src/thread_arm.cc b/src/thread_arm.cc index bc343edae0..0ef26bff5e 100644 --- a/src/thread_arm.cc +++ b/src/thread_arm.cc @@ -17,7 +17,7 @@ #include "thread.h" #include "asm_support.h" -#include "macros.h" +#include "base/macros.h" namespace art { diff --git a/src/thread_mips.cc b/src/thread_mips.cc index bc343edae0..0ef26bff5e 100644 --- a/src/thread_mips.cc +++ b/src/thread_mips.cc @@ -17,7 +17,7 @@ #include "thread.h" #include "asm_support.h" -#include "macros.h" +#include "base/macros.h" namespace art { diff --git a/src/thread_x86.cc b/src/thread_x86.cc index c8412357de..959f317471 100644 --- a/src/thread_x86.cc +++ b/src/thread_x86.cc @@ -20,7 +20,7 @@ #include <sys/types.h> #include "asm_support.h" -#include "macros.h" +#include "base/macros.h" #include "thread.h" #include "thread_list.h" diff --git a/src/trace.cc b/src/trace.cc index f04b1db123..7b3cea8e3d 100644 --- a/src/trace.cc +++ b/src/trace.cc @@ -18,6 +18,7 @@ #include <sys/uio.h> +#include "base/unix_file/fd_file.h" #include "class_linker.h" #include "debugger.h" #include "dex_cache.h" @@ -179,7 +180,8 @@ void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int if (trace_fd < 0) { trace_file = OS::OpenFile(trace_filename, true); } else { - trace_file = OS::FileFromFd("tracefile", trace_fd); + trace_file = new File(trace_fd, "tracefile"); + trace_file->DisableAutoClose(); } if (trace_file == NULL) { PLOG(ERROR) << "Unable to open trace file '" << trace_filename << "'"; diff --git a/src/trace.h b/src/trace.h index 5dd29b9edb..e3f254ee7a 100644 --- a/src/trace.h +++ b/src/trace.h @@ -21,9 +21,9 @@ #include <set> #include <string> -#include "file.h" +#include "base/macros.h" #include "globals.h" -#include "macros.h" +#include "os.h" #include "safe_map.h" #include "UniquePtr.h" @@ -17,9 +17,10 @@ #ifndef ART_SRC_UTF_H_ #define ART_SRC_UTF_H_ +#include "base/macros.h" + #include <stddef.h> #include <stdint.h> -#include "macros.h" /* * All UTF-8 in art is actually modified UTF-8. Mostly, this distinction diff --git a/src/utils.cc b/src/utils.cc index 3cf69148b3..78d359921f 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -24,8 +24,8 @@ #include <unistd.h> #include "UniquePtr.h" +#include "base/unix_file/fd_file.h" #include "class_loader.h" -#include "file.h" #include "object.h" #include "object_utils.h" #include "os.h" @@ -95,14 +95,14 @@ void GetThreadStack(pthread_t thread, void*& stack_base, size_t& stack_size) { } bool ReadFileToString(const std::string& file_name, std::string* result) { - UniquePtr<File> file(OS::OpenFile(file_name.c_str(), false)); - if (file.get() == NULL) { + UniquePtr<File> file(new File); + if (!file->Open(file_name, O_RDONLY)) { return false; } std::vector<char> buf(8 * KB); while (true) { - int64_t n = file->Read(&buf[0], buf.size()); + int64_t n = TEMP_FAILURE_RETRY(read(file->Fd(), &buf[0], buf.size())); if (n == -1) { return false; } diff --git a/src/verifier/dex_gc_map.h b/src/verifier/dex_gc_map.h index d588cfd388..540dae8c55 100644 --- a/src/verifier/dex_gc_map.h +++ b/src/verifier/dex_gc_map.h @@ -17,8 +17,8 @@ #ifndef ART_SRC_VERIFIER_DEX_GC_MAP_H_ #define ART_SRC_VERIFIER_DEX_GC_MAP_H_ +#include "base/macros.h" #include "logging.h" -#include "macros.h" #include <stdint.h> namespace art { diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h index 95d79054fe..99801c6f5d 100644 --- a/src/verifier/method_verifier.h +++ b/src/verifier/method_verifier.h @@ -22,11 +22,11 @@ #include <set> #include <vector> +#include "base/macros.h" #include "casts.h" #include "compiler.h" #include "dex_file.h" #include "dex_instruction.h" -#include "macros.h" #include "object.h" #include "reg_type.h" #include "reg_type_cache.h" diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h index 79ff67425b..c610e06388 100644 --- a/src/verifier/reg_type.h +++ b/src/verifier/reg_type.h @@ -17,7 +17,7 @@ #ifndef ART_SRC_VERIFIER_REG_TYPE_H_ #define ART_SRC_VERIFIER_REG_TYPE_H_ -#include "macros.h" +#include "base/macros.h" #include "object.h" #include <stdint.h> diff --git a/src/verifier/reg_type_cache.h b/src/verifier/reg_type_cache.h index bf0c5b1cbb..c86f65b2de 100644 --- a/src/verifier/reg_type_cache.h +++ b/src/verifier/reg_type_cache.h @@ -17,7 +17,7 @@ #ifndef ART_SRC_VERIFIER_REG_TYPE_CACHE_H_ #define ART_SRC_VERIFIER_REG_TYPE_CACHE_H_ -#include "macros.h" +#include "base/macros.h" #include "reg_type.h" #include "stl_util.h" diff --git a/src/zip_archive.cc b/src/zip_archive.cc index 18a2f30cf6..c9e9c0a64a 100644 --- a/src/zip_archive.cc +++ b/src/zip_archive.cc @@ -23,6 +23,7 @@ #include <sys/types.h> #include <unistd.h> +#include "base/unix_file/fd_file.h" #include "UniquePtr.h" namespace art { @@ -243,13 +244,13 @@ bool ZipEntry::ExtractToFile(File& file) { uint32_t length = GetUncompressedLength(); int result = TEMP_FAILURE_RETRY(ftruncate(file.Fd(), length)); if (result == -1) { - PLOG(WARNING) << "Zip: failed to ftruncate " << file.name() << " to length " << length; + PLOG(WARNING) << "Zip: failed to ftruncate " << file.GetPath() << " to length " << length; return false; } UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0)); if (map.get() == NULL) { - LOG(WARNING) << "Zip: failed to mmap space for " << file.name(); + LOG(WARNING) << "Zip: failed to mmap space for " << file.GetPath(); return false; } diff --git a/src/zip_archive.h b/src/zip_archive.h index d7a8d80184..65fbdb873e 100644 --- a/src/zip_archive.h +++ b/src/zip_archive.h @@ -20,10 +20,11 @@ #include <stdint.h> #include <zlib.h> -#include "file.h" +#include "base/unix_file/random_access_file.h" #include "globals.h" #include "logging.h" #include "mem_map.h" +#include "os.h" #include "safe_map.h" #include "stringpiece.h" #include "UniquePtr.h" diff --git a/src/zip_archive_test.cc b/src/zip_archive_test.cc index 7409ec4700..9bdc24ba03 100644 --- a/src/zip_archive_test.cc +++ b/src/zip_archive_test.cc @@ -36,11 +36,11 @@ TEST_F(ZipArchiveTest, FindAndExtract) { ScratchFile tmp; ASSERT_NE(-1, tmp.GetFd()); - UniquePtr<File> file(OS::FileFromFd(tmp.GetFilename().c_str(), tmp.GetFd())); + UniquePtr<File> file(new File(tmp.GetFd(), tmp.GetFilename())); ASSERT_TRUE(file.get() != NULL); bool success = zip_entry->ExtractToFile(*file); ASSERT_TRUE(success); - close(tmp.GetFd()); + file.reset(NULL); uint32_t computed_crc = crc32(0L, Z_NULL, 0); int fd = open(tmp.GetFilename().c_str(), O_RDONLY); |