1761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes/* 2761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * Copyright (C) 2009 The Android Open Source Project 3761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * 4761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 5761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * you may not use this file except in compliance with the License. 6761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * You may obtain a copy of the License at 7761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * 8761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 9761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * 10761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * Unless required by applicable law or agreed to in writing, software 11761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 12761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * See the License for the specific language governing permissions and 14761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes * limitations under the License. 15761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes */ 16761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 17761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes#include "base/unix_file/fd_file.h" 184303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 19761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes#include <errno.h> 205096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#include <limits> 21761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes#include <sys/stat.h> 22761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes#include <sys/types.h> 23761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes#include <unistd.h> 24761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 254303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe#include "base/logging.h" 264303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 275096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko// Includes needed for FdFile::Copy(). 285096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#ifdef __linux__ 295096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#include <sys/sendfile.h> 305096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#else 315096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#include <algorithm> 325096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#include "base/stl_util.h" 335096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#include "globals.h" 345096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#endif 355096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko 36761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesnamespace unix_file { 37761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 382e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin JuravleFdFile::FdFile() 392e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle : guard_state_(GuardState::kClosed), fd_(-1), auto_close_(true), read_only_mode_(false) { 40761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 41761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 424303ba97313458491e038d78efa041d41cf7bb43Andreas GampeFdFile::FdFile(int fd, bool check_usage) 434303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe : guard_state_(check_usage ? GuardState::kBase : GuardState::kNoCheck), 442e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle fd_(fd), auto_close_(true), read_only_mode_(false) { 45761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 46761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 474303ba97313458491e038d78efa041d41cf7bb43Andreas GampeFdFile::FdFile(int fd, const std::string& path, bool check_usage) 482e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle : FdFile(fd, path, check_usage, false) { 492e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle} 502e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle 512e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin JuravleFdFile::FdFile(int fd, const std::string& path, bool check_usage, bool read_only_mode) 524303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe : guard_state_(check_usage ? GuardState::kBase : GuardState::kNoCheck), 532e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle fd_(fd), file_path_(path), auto_close_(true), read_only_mode_(read_only_mode) { 54761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 55761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 56df8789252252c77660daf5d602d425b60b344b08Andreas GampeFdFile::FdFile(const std::string& path, int flags, mode_t mode, bool check_usage) 57df8789252252c77660daf5d602d425b60b344b08Andreas Gampe : fd_(-1), auto_close_(true) { 58df8789252252c77660daf5d602d425b60b344b08Andreas Gampe Open(path, flags, mode); 59df8789252252c77660daf5d602d425b60b344b08Andreas Gampe if (!check_usage || !IsOpened()) { 60df8789252252c77660daf5d602d425b60b344b08Andreas Gampe guard_state_ = GuardState::kNoCheck; 61df8789252252c77660daf5d602d425b60b344b08Andreas Gampe } 62df8789252252c77660daf5d602d425b60b344b08Andreas Gampe} 63df8789252252c77660daf5d602d425b60b344b08Andreas Gampe 64df8789252252c77660daf5d602d425b60b344b08Andreas Gampevoid FdFile::Destroy() { 654303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (kCheckSafeUsage && (guard_state_ < GuardState::kNoCheck)) { 664303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (guard_state_ < GuardState::kFlushed) { 673fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe LOG(ERROR) << "File " << file_path_ << " wasn't explicitly flushed before destruction."; 684303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 694303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (guard_state_ < GuardState::kClosed) { 703fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe LOG(ERROR) << "File " << file_path_ << " wasn't explicitly closed before destruction."; 714303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 724303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe CHECK_GE(guard_state_, GuardState::kClosed); 734303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 74761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes if (auto_close_ && fd_ != -1) { 754303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (Close() != 0) { 76497d5266380934ac78574a2a471d3dc0d8862708Mathieu Chartier PLOG(WARNING) << "Failed to close file with fd=" << fd_ << " path=" << file_path_; 774303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 784303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 794303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe} 804303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 81df8789252252c77660daf5d602d425b60b344b08Andreas GampeFdFile& FdFile::operator=(FdFile&& other) { 82df8789252252c77660daf5d602d425b60b344b08Andreas Gampe if (this == &other) { 83df8789252252c77660daf5d602d425b60b344b08Andreas Gampe return *this; 84df8789252252c77660daf5d602d425b60b344b08Andreas Gampe } 85df8789252252c77660daf5d602d425b60b344b08Andreas Gampe 86df8789252252c77660daf5d602d425b60b344b08Andreas Gampe if (this->fd_ != other.fd_) { 87df8789252252c77660daf5d602d425b60b344b08Andreas Gampe Destroy(); // Free old state. 88df8789252252c77660daf5d602d425b60b344b08Andreas Gampe } 89df8789252252c77660daf5d602d425b60b344b08Andreas Gampe 90df8789252252c77660daf5d602d425b60b344b08Andreas Gampe guard_state_ = other.guard_state_; 91df8789252252c77660daf5d602d425b60b344b08Andreas Gampe fd_ = other.fd_; 92df8789252252c77660daf5d602d425b60b344b08Andreas Gampe file_path_ = std::move(other.file_path_); 93df8789252252c77660daf5d602d425b60b344b08Andreas Gampe auto_close_ = other.auto_close_; 94df8789252252c77660daf5d602d425b60b344b08Andreas Gampe other.Release(); // Release other. 95df8789252252c77660daf5d602d425b60b344b08Andreas Gampe 96df8789252252c77660daf5d602d425b60b344b08Andreas Gampe return *this; 97df8789252252c77660daf5d602d425b60b344b08Andreas Gampe} 98df8789252252c77660daf5d602d425b60b344b08Andreas Gampe 99df8789252252c77660daf5d602d425b60b344b08Andreas GampeFdFile::~FdFile() { 100df8789252252c77660daf5d602d425b60b344b08Andreas Gampe Destroy(); 101df8789252252c77660daf5d602d425b60b344b08Andreas Gampe} 102df8789252252c77660daf5d602d425b60b344b08Andreas Gampe 1034303ba97313458491e038d78efa041d41cf7bb43Andreas Gampevoid FdFile::moveTo(GuardState target, GuardState warn_threshold, const char* warning) { 1044303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (kCheckSafeUsage) { 1054303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (guard_state_ < GuardState::kNoCheck) { 1064303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (warn_threshold < GuardState::kNoCheck && guard_state_ >= warn_threshold) { 1073fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe LOG(ERROR) << warning; 1084303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 1094303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe guard_state_ = target; 1104303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 1114303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 1124303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe} 1134303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 1144303ba97313458491e038d78efa041d41cf7bb43Andreas Gampevoid FdFile::moveUp(GuardState target, const char* warning) { 1154303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (kCheckSafeUsage) { 1164303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (guard_state_ < GuardState::kNoCheck) { 1174303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (guard_state_ < target) { 1184303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe guard_state_ = target; 1194303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } else if (target < guard_state_) { 1203fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe LOG(ERROR) << warning; 1214303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 1224303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 123761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes } 124761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 125761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 126761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesvoid FdFile::DisableAutoClose() { 127761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes auto_close_ = false; 128761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 129761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 130761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesbool FdFile::Open(const std::string& path, int flags) { 131761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return Open(path, flags, 0640); 132761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 133761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 134761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesbool FdFile::Open(const std::string& path, int flags, mode_t mode) { 135b64decdc7361c6c93bd91fdd016a50971c8e537aDavid Brazdil static_assert(O_RDONLY == 0, "Readonly flag has unexpected value."); 136761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes CHECK_EQ(fd_, -1) << path; 137b64decdc7361c6c93bd91fdd016a50971c8e537aDavid Brazdil read_only_mode_ = ((flags & O_ACCMODE) == O_RDONLY); 138761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes fd_ = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)); 139761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes if (fd_ == -1) { 140761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return false; 141761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes } 142761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes file_path_ = path; 1434303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (kCheckSafeUsage && (flags & (O_RDWR | O_CREAT | O_WRONLY)) != 0) { 1444303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe // Start in the base state (not flushed, not closed). 1454303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe guard_state_ = GuardState::kBase; 1464303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } else { 1474303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe // We are not concerned with read-only files. In that case, proper flushing and closing is 1484303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe // not important. 1494303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe guard_state_ = GuardState::kNoCheck; 1504303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 151761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return true; 152761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 153761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 154761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesint FdFile::Close() { 1556a887d6a1d1ca089b48663a5ae11f973b98785a9Elliott Hughes int result = close(fd_); 1564303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 1574303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe // Test here, so the file is closed and not leaked. 1584303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (kCheckSafeUsage) { 1594303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe CHECK_GE(guard_state_, GuardState::kFlushed) << "File " << file_path_ 1604303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe << " has not been flushed before closing."; 1614303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe moveUp(GuardState::kClosed, nullptr); 1624303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 1634303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 164761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes if (result == -1) { 165761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return -errno; 166761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes } else { 167761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes fd_ = -1; 168761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes file_path_ = ""; 169761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return 0; 170761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes } 171761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 172761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 173761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesint FdFile::Flush() { 1742e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 175c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#ifdef __linux__ 176761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes int rc = TEMP_FAILURE_RETRY(fdatasync(fd_)); 177c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#else 178c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers int rc = TEMP_FAILURE_RETRY(fsync(fd_)); 179c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#endif 1804303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe moveUp(GuardState::kFlushed, "Flushing closed file."); 181761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return (rc == -1) ? -errno : rc; 182761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 183761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 184761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesint64_t FdFile::Read(char* buf, int64_t byte_count, int64_t offset) const { 185c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#ifdef __linux__ 186761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes int rc = TEMP_FAILURE_RETRY(pread64(fd_, buf, byte_count, offset)); 187c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#else 188c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers int rc = TEMP_FAILURE_RETRY(pread(fd_, buf, byte_count, offset)); 189c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#endif 190761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return (rc == -1) ? -errno : rc; 191761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 192761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 193761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesint FdFile::SetLength(int64_t new_length) { 1942e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 195c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#ifdef __linux__ 196761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes int rc = TEMP_FAILURE_RETRY(ftruncate64(fd_, new_length)); 197c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#else 198c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers int rc = TEMP_FAILURE_RETRY(ftruncate(fd_, new_length)); 199c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#endif 2004303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe moveTo(GuardState::kBase, GuardState::kClosed, "Truncating closed file."); 201761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return (rc == -1) ? -errno : rc; 202761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 203761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 204761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesint64_t FdFile::GetLength() const { 205761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes struct stat s; 206761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes int rc = TEMP_FAILURE_RETRY(fstat(fd_, &s)); 207761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return (rc == -1) ? -errno : s.st_size; 208761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 209761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 210761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesint64_t FdFile::Write(const char* buf, int64_t byte_count, int64_t offset) { 2112e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 212c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#ifdef __linux__ 213761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes int rc = TEMP_FAILURE_RETRY(pwrite64(fd_, buf, byte_count, offset)); 214c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#else 215c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers int rc = TEMP_FAILURE_RETRY(pwrite(fd_, buf, byte_count, offset)); 216c5f17732d8144491c642776b6b48c85dfadf4b52Ian Rogers#endif 2174303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe moveTo(GuardState::kBase, GuardState::kClosed, "Writing into closed file."); 218761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return (rc == -1) ? -errno : rc; 219761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 220761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 221761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesint FdFile::Fd() const { 222761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return fd_; 223761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 224761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 2252e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravlebool FdFile::ReadOnlyMode() const { 2262e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle return read_only_mode_; 2272e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle} 2282e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle 2292e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravlebool FdFile::CheckUsage() const { 2302e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle return guard_state_ != GuardState::kNoCheck; 2312e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle} 2322e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle 233761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughesbool FdFile::IsOpened() const { 234761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return fd_ >= 0; 235761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 236761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 2373774335b08076117d6950cd472cdd59a167470b5Igor Murashkinstatic ssize_t ReadIgnoreOffset(int fd, void *buf, size_t count, off_t offset) { 2383774335b08076117d6950cd472cdd59a167470b5Igor Murashkin DCHECK_EQ(offset, 0); 2393774335b08076117d6950cd472cdd59a167470b5Igor Murashkin return read(fd, buf, count); 2403774335b08076117d6950cd472cdd59a167470b5Igor Murashkin} 2413774335b08076117d6950cd472cdd59a167470b5Igor Murashkin 2423774335b08076117d6950cd472cdd59a167470b5Igor Murashkintemplate <ssize_t (*read_func)(int, void*, size_t, off_t)> 2433774335b08076117d6950cd472cdd59a167470b5Igor Murashkinstatic bool ReadFullyGeneric(int fd, void* buffer, size_t byte_count, size_t offset) { 244761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes char* ptr = static_cast<char*>(buffer); 245761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes while (byte_count > 0) { 2463774335b08076117d6950cd472cdd59a167470b5Igor Murashkin ssize_t bytes_read = TEMP_FAILURE_RETRY(read_func(fd, ptr, byte_count, offset)); 247825201e9a7e718470e2dac222dffdee729050ac5Andreas Gampe if (bytes_read <= 0) { 248825201e9a7e718470e2dac222dffdee729050ac5Andreas Gampe // 0: end of file 249825201e9a7e718470e2dac222dffdee729050ac5Andreas Gampe // -1: error 250761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return false; 251761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes } 252761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes byte_count -= bytes_read; // Reduce the number of remaining bytes. 253761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes ptr += bytes_read; // Move the buffer forward. 2543774335b08076117d6950cd472cdd59a167470b5Igor Murashkin offset += static_cast<size_t>(bytes_read); // Move the offset forward. 255761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes } 256761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return true; 257761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 258761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 2593774335b08076117d6950cd472cdd59a167470b5Igor Murashkinbool FdFile::ReadFully(void* buffer, size_t byte_count) { 2603774335b08076117d6950cd472cdd59a167470b5Igor Murashkin return ReadFullyGeneric<ReadIgnoreOffset>(fd_, buffer, byte_count, 0); 2613774335b08076117d6950cd472cdd59a167470b5Igor Murashkin} 2623774335b08076117d6950cd472cdd59a167470b5Igor Murashkin 2633774335b08076117d6950cd472cdd59a167470b5Igor Murashkinbool FdFile::PreadFully(void* buffer, size_t byte_count, size_t offset) { 2643774335b08076117d6950cd472cdd59a167470b5Igor Murashkin return ReadFullyGeneric<pread>(fd_, buffer, byte_count, offset); 2653774335b08076117d6950cd472cdd59a167470b5Igor Murashkin} 2663774335b08076117d6950cd472cdd59a167470b5Igor Murashkin 2676f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartiertemplate <bool kUseOffset> 2686f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartierbool FdFile::WriteFullyGeneric(const void* buffer, size_t byte_count, size_t offset) { 2692e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 2704303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe moveTo(GuardState::kBase, GuardState::kClosed, "Writing into closed file."); 2716f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier DCHECK(kUseOffset || offset == 0u); 2726f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier const char* ptr = static_cast<const char*>(buffer); 273761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes while (byte_count > 0) { 2746f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier ssize_t bytes_written = kUseOffset 2756f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier ? TEMP_FAILURE_RETRY(pwrite(fd_, ptr, byte_count, offset)) 2766f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier : TEMP_FAILURE_RETRY(write(fd_, ptr, byte_count)); 277ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers if (bytes_written == -1) { 278761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return false; 279761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes } 280ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers byte_count -= bytes_written; // Reduce the number of remaining bytes. 281ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers ptr += bytes_written; // Move the buffer forward. 2826f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier offset += static_cast<size_t>(bytes_written); 283761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes } 284761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes return true; 285761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} 286761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes 2876f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartierbool FdFile::PwriteFully(const void* buffer, size_t byte_count, size_t offset) { 2886f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier return WriteFullyGeneric<true>(buffer, byte_count, offset); 2896f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier} 2906f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier 2916f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartierbool FdFile::WriteFully(const void* buffer, size_t byte_count) { 2926f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier return WriteFullyGeneric<false>(buffer, byte_count, 0u); 2936f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier} 2946f6b134e39e7f01cf6c029ce1f95fcadb642cbc3Mathieu Chartier 2955096e66d07db8041589518f8c5b0281d859d0817Vladimir Markobool FdFile::Copy(FdFile* input_file, int64_t offset, int64_t size) { 2962e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 2975096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko off_t off = static_cast<off_t>(offset); 2985096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko off_t sz = static_cast<off_t>(size); 2995096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko if (offset < 0 || static_cast<int64_t>(off) != offset || 3005096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko size < 0 || static_cast<int64_t>(sz) != size || 3015096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko sz > std::numeric_limits<off_t>::max() - off) { 3025096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko errno = EINVAL; 3035096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko return false; 3045096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko } 3055096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko if (size == 0) { 3065096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko return true; 3075096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko } 3085096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#ifdef __linux__ 3095096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko // Use sendfile(), available for files since linux kernel 2.6.33. 3105096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko off_t end = off + sz; 3115096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko while (off != end) { 3125096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko int result = TEMP_FAILURE_RETRY( 3135096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko sendfile(Fd(), input_file->Fd(), &off, end - off)); 3145096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko if (result == -1) { 3155096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko return false; 3165096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko } 3175096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko // Ignore the number of bytes in `result`, sendfile() already updated `off`. 3185096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko } 3195096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#else 3205096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko if (lseek(input_file->Fd(), off, SEEK_SET) != off) { 3215096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko return false; 3225096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko } 3235096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko constexpr size_t kMaxBufferSize = 4 * ::art::kPageSize; 3245096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko const size_t buffer_size = std::min<uint64_t>(size, kMaxBufferSize); 3255096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko art::UniqueCPtr<void> buffer(malloc(buffer_size)); 3265096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko if (buffer == nullptr) { 3275096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko errno = ENOMEM; 3285096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko return false; 3295096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko } 3305096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko while (size != 0) { 3315096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko size_t chunk_size = std::min<uint64_t>(buffer_size, size); 3325096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko if (!input_file->ReadFully(buffer.get(), chunk_size) || 3335096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko !WriteFully(buffer.get(), chunk_size)) { 3345096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko return false; 3355096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko } 3365096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko size -= chunk_size; 3375096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko } 3385096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko#endif 3395096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko return true; 3405096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko} 3415096e66d07db8041589518f8c5b0281d859d0817Vladimir Marko 342550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampebool FdFile::Unlink() { 343550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe if (file_path_.empty()) { 344550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe return false; 345550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe } 346550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe 347550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe // Try to figure out whether this file is still referring to the one on disk. 348550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe bool is_current = false; 349550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe { 350550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe struct stat this_stat, current_stat; 351550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe int cur_fd = TEMP_FAILURE_RETRY(open(file_path_.c_str(), O_RDONLY)); 352550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe if (cur_fd > 0) { 353550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe // File still exists. 354550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe if (fstat(fd_, &this_stat) == 0 && fstat(cur_fd, ¤t_stat) == 0) { 355550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe is_current = (this_stat.st_dev == current_stat.st_dev) && 356550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe (this_stat.st_ino == current_stat.st_ino); 357550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe } 358550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe close(cur_fd); 359550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe } 360550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe } 361550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe 362550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe if (is_current) { 363550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe unlink(file_path_.c_str()); 364550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe } 365550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe 366550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe return is_current; 367550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe} 368550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe 369550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampebool FdFile::Erase(bool unlink) { 3702e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 371550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe 372550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe bool ret_result = true; 373550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe if (unlink) { 374550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe ret_result = Unlink(); 375550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe } 376550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe 377550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe int result; 378550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe result = SetLength(0); 379550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe result = Flush(); 380550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe result = Close(); 381550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe // Ignore the errors. 382550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe 383550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe return ret_result; 3844303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe} 3854303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 3864303ba97313458491e038d78efa041d41cf7bb43Andreas Gampeint FdFile::FlushCloseOrErase() { 3872e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 388550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe int flush_result = Flush(); 3894303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (flush_result != 0) { 3903fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe LOG(ERROR) << "CloseOrErase failed while flushing a file."; 3914303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe Erase(); 3924303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe return flush_result; 3934303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 394550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe int close_result = Close(); 3954303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (close_result != 0) { 3963fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe LOG(ERROR) << "CloseOrErase failed while closing a file."; 3974303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe Erase(); 3984303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe return close_result; 3994303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 4004303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe return 0; 4014303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe} 4024303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 4034303ba97313458491e038d78efa041d41cf7bb43Andreas Gampeint FdFile::FlushClose() { 4042e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 405550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe int flush_result = Flush(); 4064303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (flush_result != 0) { 4073fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe LOG(ERROR) << "FlushClose failed while flushing a file."; 4084303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 409550c589938ef7cd7c4287ba4e52ddc4853598af7Andreas Gampe int close_result = Close(); 4104303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (close_result != 0) { 4113fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe LOG(ERROR) << "FlushClose failed while closing a file."; 4124303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 4134303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe return (flush_result != 0) ? flush_result : close_result; 4144303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe} 4154303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe 416e21dc3db191df04c100620965bee4617b3b24397Andreas Gampevoid FdFile::MarkUnchecked() { 417e21dc3db191df04c100620965bee4617b3b24397Andreas Gampe guard_state_ = GuardState::kNoCheck; 418e21dc3db191df04c100620965bee4617b3b24397Andreas Gampe} 419e21dc3db191df04c100620965bee4617b3b24397Andreas Gampe 420877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravlebool FdFile::ClearContent() { 4212e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 422877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle if (SetLength(0) < 0) { 4233fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe PLOG(ERROR) << "Failed to reset the length"; 424877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle return false; 425877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle } 426877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle return ResetOffset(); 427877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle} 428877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle 429877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravlebool FdFile::ResetOffset() { 4302e2db786b8fbaa4dceb37603a4296b0b2aea4e9eCalin Juravle DCHECK(!read_only_mode_); 431877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle off_t rc = TEMP_FAILURE_RETRY(lseek(fd_, 0, SEEK_SET)); 432877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle if (rc == static_cast<off_t>(-1)) { 4333fec9ac0d5af1358d216eb2fdc2000ec0205f3f0Andreas Gampe PLOG(ERROR) << "Failed to reset the offset"; 434877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle return false; 435877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle } 436877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle return true; 437877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle} 438877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle 439761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes} // namespace unix_file 440