| // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by the GPL v2 license that can |
| // be found in the LICENSE file. |
| // |
| // Implementation of simple_file::File |
| #include "verity/simple_file/file.h" |
| |
| namespace simple_file { |
| |
| const Env* File::env() const { |
| if (env_) { |
| return env_; |
| } |
| return default_env_; |
| } |
| |
| bool File::Initialize(const char* path, int flags, const Env* new_env) { |
| if (fd_ >= 0) { |
| LOG(ERROR) << "Attempted to Initialize while in use"; |
| return false; |
| } |
| |
| if (!new_env) { |
| DLOG(INFO) << "Using the default Env"; |
| } else { |
| env_ = new_env; |
| } |
| |
| if (flags & O_CREAT) { |
| // TODO(wad) less hacky |
| fd_ = env()->Create(path, flags, S_IRUSR | S_IWUSR); |
| } else { |
| fd_ = env()->Open(path, flags); |
| } |
| if (fd_ < 0) { |
| PLOG(ERROR) << "Failed to open the specified file"; |
| return false; |
| } |
| return true; |
| } |
| |
| void File::Reset() { |
| if (fd_ >= 0) { |
| env()->Close(fd_); |
| fd_ = -1; |
| } |
| env_ = NULL; |
| offset_ = 0; |
| delete default_env_; |
| default_env_ = new Env; |
| } |
| |
| bool File::Seek(off_t location, bool absolute) { |
| int64_t size = Size(); |
| if (absolute) { |
| if (location > size || location < 0) |
| return false; |
| offset_ = location; |
| return true; |
| } |
| off_t result = location + offset_; |
| if (result < 0 || result > size) { |
| return false; |
| } |
| offset_ = result; |
| return true; |
| } |
| |
| off_t File::Whence() const { |
| return offset_; |
| } |
| |
| bool File::Read(int bytes, uint8_t* buf) { |
| if (!ReadAt(bytes, buf, offset_)) { |
| return false; |
| } |
| offset_ += bytes; |
| return true; |
| } |
| |
| bool File::ReadAt(int bytes, uint8_t* buf, off_t offset) { |
| if (fd_ < 0) { |
| LOG(ERROR) << "Read called with an invalid fd"; |
| return false; |
| } |
| if (bytes <= 0) { |
| LOG(ERROR) << "Negative or 0 sized read requested"; |
| return false; |
| } |
| ssize_t in_bytes = env()->Pread(fd_, buf, bytes, offset); |
| if (in_bytes == bytes) { |
| return true; |
| } |
| if (in_bytes < 0) { |
| // TODO(wad) Roll PLOG into the Env so that errno logging is encapsulated. |
| PLOG(ERROR) << "An error occurred reading from the file"; |
| return false; |
| } |
| DLOG(INFO) << "Failed to read the total number of bytes requested."; |
| return false; |
| } |
| |
| int64_t File::Size() const { |
| if (fd_ < 0) { |
| LOG(ERROR) << "Size called with an invalid fd"; |
| return false; |
| } |
| struct stat buf; |
| if (env()->Fstat(fd_, &buf)) { |
| PLOG(ERROR) << "Failed to fstat() the file"; |
| return -1; |
| } |
| if (!S_ISBLK(buf.st_mode)) { |
| return static_cast<int64_t>(buf.st_size); |
| } |
| // Handle use on block devices. |
| int64_t size = -1; |
| if (env()->BlockDevSize(fd_, &size)) { |
| PLOG(ERROR) << "Failed to get the block device size"; |
| return -1; |
| } |
| return size; |
| } |
| |
| bool File::WriteAt(int bytes, const uint8_t* buf, off_t offset) { |
| if (fd_ < 0) { |
| LOG(ERROR) << "Write called with an invalid fd"; |
| return false; |
| } |
| if (bytes <= 0) { |
| LOG(ERROR) << "Negative or 0 sized write requested"; |
| return false; |
| } |
| ssize_t out_bytes = env()->Pwrite(fd_, buf, bytes, offset); |
| if (out_bytes == bytes) { |
| return true; |
| } |
| if (out_bytes < 0) { |
| PLOG(ERROR) << "An error occurred writing to the file at " << offset; |
| return false; |
| } |
| DLOG(INFO) << "Failed to write the total number of bytes requested."; |
| return false; |
| } |
| |
| bool File::Write(int bytes, const uint8_t* buf) { |
| if (!WriteAt(bytes, buf, offset_)) { |
| return false; |
| } |
| offset_ += bytes; |
| return true; |
| } |
| |
| } // namespace simple_file |