diff options
Diffstat (limited to 'runtime/base/unix_file/mapped_file.cc')
-rw-r--r-- | runtime/base/unix_file/mapped_file.cc | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/runtime/base/unix_file/mapped_file.cc b/runtime/base/unix_file/mapped_file.cc new file mode 100644 index 0000000000..b63fdd3bef --- /dev/null +++ b/runtime/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/logging.h" +#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> + +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 |