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, &current_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