14f94c520f8d699a5973956a1716272146be17128Zonr Chang/*
24f94c520f8d699a5973956a1716272146be17128Zonr Chang * Copyright 2012, The Android Open Source Project
34f94c520f8d699a5973956a1716272146be17128Zonr Chang *
44f94c520f8d699a5973956a1716272146be17128Zonr Chang * Licensed under the Apache License, Version 2.0 (the "License");
54f94c520f8d699a5973956a1716272146be17128Zonr Chang * you may not use this file except in compliance with the License.
64f94c520f8d699a5973956a1716272146be17128Zonr Chang * You may obtain a copy of the License at
74f94c520f8d699a5973956a1716272146be17128Zonr Chang *
84f94c520f8d699a5973956a1716272146be17128Zonr Chang *     http://www.apache.org/licenses/LICENSE-2.0
94f94c520f8d699a5973956a1716272146be17128Zonr Chang *
104f94c520f8d699a5973956a1716272146be17128Zonr Chang * Unless required by applicable law or agreed to in writing, software
114f94c520f8d699a5973956a1716272146be17128Zonr Chang * distributed under the License is distributed on an "AS IS" BASIS,
124f94c520f8d699a5973956a1716272146be17128Zonr Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134f94c520f8d699a5973956a1716272146be17128Zonr Chang * See the License for the specific language governing permissions and
144f94c520f8d699a5973956a1716272146be17128Zonr Chang * limitations under the License.
154f94c520f8d699a5973956a1716272146be17128Zonr Chang */
164f94c520f8d699a5973956a1716272146be17128Zonr Chang
17a2dd52f0710c214e00c1a13e25116e1af5eec77aJean-Luc Brouillet#include "FileBase.h"
18a2dd52f0710c214e00c1a13e25116e1af5eec77aJean-Luc Brouillet#include "Log.h"
19331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines
204f94c520f8d699a5973956a1716272146be17128Zonr Chang#include <sys/file.h>
214f94c520f8d699a5973956a1716272146be17128Zonr Chang#include <sys/stat.h>
224f94c520f8d699a5973956a1716272146be17128Zonr Chang#include <unistd.h>
234f94c520f8d699a5973956a1716272146be17128Zonr Chang
244f94c520f8d699a5973956a1716272146be17128Zonr Chang#include <cerrno>
25331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines#include <cstring>
264f94c520f8d699a5973956a1716272146be17128Zonr Chang#include <new>
274f94c520f8d699a5973956a1716272146be17128Zonr Chang
284f94c520f8d699a5973956a1716272146be17128Zonr Changusing namespace bcc;
294f94c520f8d699a5973956a1716272146be17128Zonr Chang
3048cd745480738c026312931877ecb8ebecb1c64eStephen Hines#ifdef _WIN32
3148cd745480738c026312931877ecb8ebecb1c64eStephen Hines// TODO: Fix flock usage under windows
3248cd745480738c026312931877ecb8ebecb1c64eStephen Hines#define LOCK_SH 0
3348cd745480738c026312931877ecb8ebecb1c64eStephen Hines#define LOCK_EX 0
3448cd745480738c026312931877ecb8ebecb1c64eStephen Hines#define LOCK_NB 0
3548cd745480738c026312931877ecb8ebecb1c64eStephen Hines#define LOCK_UN 0
3648cd745480738c026312931877ecb8ebecb1c64eStephen Hines
3748cd745480738c026312931877ecb8ebecb1c64eStephen Hinesint flock(int fd, int operation) {
3848cd745480738c026312931877ecb8ebecb1c64eStephen Hines  return 0;
3948cd745480738c026312931877ecb8ebecb1c64eStephen Hines}
4048cd745480738c026312931877ecb8ebecb1c64eStephen Hines#endif  // _WIN32
4148cd745480738c026312931877ecb8ebecb1c64eStephen Hines
424f94c520f8d699a5973956a1716272146be17128Zonr ChangFileBase::FileBase(const std::string &pFilename,
434f94c520f8d699a5973956a1716272146be17128Zonr Chang                   unsigned pOpenFlags,
444f94c520f8d699a5973956a1716272146be17128Zonr Chang                   unsigned pFlags)
454f94c520f8d699a5973956a1716272146be17128Zonr Chang  : mFD(-1),
464f94c520f8d699a5973956a1716272146be17128Zonr Chang    mError(),
474f94c520f8d699a5973956a1716272146be17128Zonr Chang    mName(pFilename), mOpenFlags(pOpenFlags),
48331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines    mShouldUnlock(false),
49331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines    mShouldDelete(false) {
504f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Process pFlags
514f94c520f8d699a5973956a1716272146be17128Zonr Chang#ifdef O_BINARY
524f94c520f8d699a5973956a1716272146be17128Zonr Chang  if (pFlags & kBinary) {
534f94c520f8d699a5973956a1716272146be17128Zonr Chang    mOpenFlags |= O_BINARY;
544f94c520f8d699a5973956a1716272146be17128Zonr Chang  }
554f94c520f8d699a5973956a1716272146be17128Zonr Chang#endif
56c02eae6f35de7dfd92233d591b27c05f15c2a6a1Shih-wei Liao  if (pFlags & kTruncate) {
57c02eae6f35de7dfd92233d591b27c05f15c2a6a1Shih-wei Liao    mOpenFlags |= O_TRUNC;
58c02eae6f35de7dfd92233d591b27c05f15c2a6a1Shih-wei Liao  }
594f94c520f8d699a5973956a1716272146be17128Zonr Chang
60b2b8c64cd0524f9210218df4738f40409631ea26Shih-wei Liao  if (pFlags & kAppend) {
61b2b8c64cd0524f9210218df4738f40409631ea26Shih-wei Liao    mOpenFlags |= O_APPEND;
62b2b8c64cd0524f9210218df4738f40409631ea26Shih-wei Liao  }
63b2b8c64cd0524f9210218df4738f40409631ea26Shih-wei Liao
64331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines  if (pFlags & kDeleteOnClose) {
65331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines    mShouldDelete = true;
66331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines  }
67331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines
684f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Open the file.
694f94c520f8d699a5973956a1716272146be17128Zonr Chang  open();
704f94c520f8d699a5973956a1716272146be17128Zonr Chang
714f94c520f8d699a5973956a1716272146be17128Zonr Chang  return;
724f94c520f8d699a5973956a1716272146be17128Zonr Chang}
734f94c520f8d699a5973956a1716272146be17128Zonr Chang
744f94c520f8d699a5973956a1716272146be17128Zonr ChangFileBase::~FileBase() {
754f94c520f8d699a5973956a1716272146be17128Zonr Chang  close();
764f94c520f8d699a5973956a1716272146be17128Zonr Chang}
774f94c520f8d699a5973956a1716272146be17128Zonr Chang
784f94c520f8d699a5973956a1716272146be17128Zonr Changbool FileBase::open() {
794f94c520f8d699a5973956a1716272146be17128Zonr Chang  do {
804f94c520f8d699a5973956a1716272146be17128Zonr Chang    // FIXME: Hard-coded permissions (0644) for newly created file should be
814f94c520f8d699a5973956a1716272146be17128Zonr Chang    //        removed and provide a way to let the user configure the value.
824f94c520f8d699a5973956a1716272146be17128Zonr Chang    mFD = ::open(mName.c_str(), mOpenFlags, 0644);
834f94c520f8d699a5973956a1716272146be17128Zonr Chang    if (mFD > 0) {
844f94c520f8d699a5973956a1716272146be17128Zonr Chang      return true;
854f94c520f8d699a5973956a1716272146be17128Zonr Chang    }
864f94c520f8d699a5973956a1716272146be17128Zonr Chang
874f94c520f8d699a5973956a1716272146be17128Zonr Chang    // Some errors occurred ...
884f94c520f8d699a5973956a1716272146be17128Zonr Chang    if (errno != EINTR) {
894f94c520f8d699a5973956a1716272146be17128Zonr Chang      detectError();
904f94c520f8d699a5973956a1716272146be17128Zonr Chang      return false;
914f94c520f8d699a5973956a1716272146be17128Zonr Chang    }
924f94c520f8d699a5973956a1716272146be17128Zonr Chang  } while (true);
934f94c520f8d699a5973956a1716272146be17128Zonr Chang  // unreachable
944f94c520f8d699a5973956a1716272146be17128Zonr Chang}
954f94c520f8d699a5973956a1716272146be17128Zonr Chang
964f94c520f8d699a5973956a1716272146be17128Zonr Chang
974f94c520f8d699a5973956a1716272146be17128Zonr Changbool FileBase::checkFileIntegrity() {
984f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Check the file integrity by examining whether the inode referring to the mFD
994f94c520f8d699a5973956a1716272146be17128Zonr Chang  // and to the file mName are the same.
1004f94c520f8d699a5973956a1716272146be17128Zonr Chang  struct stat fd_stat, file_stat;
1014f94c520f8d699a5973956a1716272146be17128Zonr Chang
1024f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Get the file status of file descriptor mFD.
1034f94c520f8d699a5973956a1716272146be17128Zonr Chang  do {
1044f94c520f8d699a5973956a1716272146be17128Zonr Chang    if (::fstat(mFD, &fd_stat) == 0) {
1054f94c520f8d699a5973956a1716272146be17128Zonr Chang      break;
1064f94c520f8d699a5973956a1716272146be17128Zonr Chang    } else if (errno != EINTR) {
1074f94c520f8d699a5973956a1716272146be17128Zonr Chang      detectError();
1084f94c520f8d699a5973956a1716272146be17128Zonr Chang      return false;
1094f94c520f8d699a5973956a1716272146be17128Zonr Chang    }
1104f94c520f8d699a5973956a1716272146be17128Zonr Chang  } while (true);
1114f94c520f8d699a5973956a1716272146be17128Zonr Chang
1124f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Get the file status of file mName.
1134f94c520f8d699a5973956a1716272146be17128Zonr Chang  do {
1144f94c520f8d699a5973956a1716272146be17128Zonr Chang    if (::stat(mName.c_str(), &file_stat) == 0) {
1154f94c520f8d699a5973956a1716272146be17128Zonr Chang      break;
1164f94c520f8d699a5973956a1716272146be17128Zonr Chang    } else if (errno != EINTR) {
1174f94c520f8d699a5973956a1716272146be17128Zonr Chang      detectError();
1184f94c520f8d699a5973956a1716272146be17128Zonr Chang      return false;
1194f94c520f8d699a5973956a1716272146be17128Zonr Chang    }
1204f94c520f8d699a5973956a1716272146be17128Zonr Chang  } while (true);
1214f94c520f8d699a5973956a1716272146be17128Zonr Chang
1224f94c520f8d699a5973956a1716272146be17128Zonr Chang  return ((fd_stat.st_dev == file_stat.st_dev) &&
1234f94c520f8d699a5973956a1716272146be17128Zonr Chang          (fd_stat.st_ino == file_stat.st_ino));
1244f94c520f8d699a5973956a1716272146be17128Zonr Chang}
1254f94c520f8d699a5973956a1716272146be17128Zonr Chang
1264f94c520f8d699a5973956a1716272146be17128Zonr Changvoid FileBase::detectError() {
1274f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Read error from errno.
128d0993af5b1337f8186dd9aedea2e138a919e02e9Stephen Hines  mError.assign(errno, std::generic_category());
1294f94c520f8d699a5973956a1716272146be17128Zonr Chang}
1304f94c520f8d699a5973956a1716272146be17128Zonr Chang
1314f94c520f8d699a5973956a1716272146be17128Zonr Changbool FileBase::lock(enum LockModeEnum pMode,
1324f94c520f8d699a5973956a1716272146be17128Zonr Chang                    bool pNonblocking,
1334f94c520f8d699a5973956a1716272146be17128Zonr Chang                    unsigned pMaxRetry,
1344f94c520f8d699a5973956a1716272146be17128Zonr Chang                    useconds_t pRetryInterval) {
1354f94c520f8d699a5973956a1716272146be17128Zonr Chang  int lock_operation;
1364f94c520f8d699a5973956a1716272146be17128Zonr Chang  unsigned retry = 0;
1374f94c520f8d699a5973956a1716272146be17128Zonr Chang
1384f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Check the state.
1394f94c520f8d699a5973956a1716272146be17128Zonr Chang  if ((mFD < 0) || hasError()) {
1404f94c520f8d699a5973956a1716272146be17128Zonr Chang    return false;
1414f94c520f8d699a5973956a1716272146be17128Zonr Chang  }
1424f94c520f8d699a5973956a1716272146be17128Zonr Chang
1434f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Return immediately if it's already locked.
1444f94c520f8d699a5973956a1716272146be17128Zonr Chang  if (mShouldUnlock) {
1454f94c520f8d699a5973956a1716272146be17128Zonr Chang    return true;
1464f94c520f8d699a5973956a1716272146be17128Zonr Chang  }
1474f94c520f8d699a5973956a1716272146be17128Zonr Chang
1484f94c520f8d699a5973956a1716272146be17128Zonr Chang  // Determine the lock operation (2nd argument) to the flock().
1494f94c520f8d699a5973956a1716272146be17128Zonr Chang  if (pMode == kReadLock) {
1504f94c520f8d699a5973956a1716272146be17128Zonr Chang    lock_operation = LOCK_SH;
1514f94c520f8d699a5973956a1716272146be17128Zonr Chang  } else if (pMode == kWriteLock) {
1524f94c520f8d699a5973956a1716272146be17128Zonr Chang    lock_operation = LOCK_EX;
1534f94c520f8d699a5973956a1716272146be17128Zonr Chang  } else {
154d0993af5b1337f8186dd9aedea2e138a919e02e9Stephen Hines    mError = std::make_error_code(std::errc::invalid_argument);
1554f94c520f8d699a5973956a1716272146be17128Zonr Chang    return false;
1564f94c520f8d699a5973956a1716272146be17128Zonr Chang  }
1574f94c520f8d699a5973956a1716272146be17128Zonr Chang
1584f94c520f8d699a5973956a1716272146be17128Zonr Chang  if (pNonblocking) {
1594f94c520f8d699a5973956a1716272146be17128Zonr Chang    lock_operation |= LOCK_NB;
1604f94c520f8d699a5973956a1716272146be17128Zonr Chang  }
1614f94c520f8d699a5973956a1716272146be17128Zonr Chang
1624f94c520f8d699a5973956a1716272146be17128Zonr Chang  do {
1634f94c520f8d699a5973956a1716272146be17128Zonr Chang    if (::flock(mFD, lock_operation) == 0) {
1644f94c520f8d699a5973956a1716272146be17128Zonr Chang      mShouldUnlock = true;
1654f94c520f8d699a5973956a1716272146be17128Zonr Chang      // Here we got a lock but we need to check whether the mFD still
1664f94c520f8d699a5973956a1716272146be17128Zonr Chang      // "represents" the filename (mName) we opened in the contructor. This
1674f94c520f8d699a5973956a1716272146be17128Zonr Chang      // check may failed when another process deleted the original file mFD
1684f94c520f8d699a5973956a1716272146be17128Zonr Chang      // mapped when we were trying to obtain the lock on the file.
1694f94c520f8d699a5973956a1716272146be17128Zonr Chang      if (!checkFileIntegrity()) {
1704f94c520f8d699a5973956a1716272146be17128Zonr Chang        if (hasError() || !reopen()) {
1714f94c520f8d699a5973956a1716272146be17128Zonr Chang          // Error occurred when check the file integrity or re-open the file.
1724f94c520f8d699a5973956a1716272146be17128Zonr Chang          return false;
1734f94c520f8d699a5973956a1716272146be17128Zonr Chang        } else {
1744f94c520f8d699a5973956a1716272146be17128Zonr Chang          // Wait a while before the next try.
1754f94c520f8d699a5973956a1716272146be17128Zonr Chang          ::usleep(pRetryInterval);
1764f94c520f8d699a5973956a1716272146be17128Zonr Chang          retry++;
1774f94c520f8d699a5973956a1716272146be17128Zonr Chang          continue;
1784f94c520f8d699a5973956a1716272146be17128Zonr Chang        }
1794f94c520f8d699a5973956a1716272146be17128Zonr Chang      }
1804f94c520f8d699a5973956a1716272146be17128Zonr Chang
1814f94c520f8d699a5973956a1716272146be17128Zonr Chang      return true;
1824f94c520f8d699a5973956a1716272146be17128Zonr Chang    }
1834f94c520f8d699a5973956a1716272146be17128Zonr Chang
1844f94c520f8d699a5973956a1716272146be17128Zonr Chang    // flock() was not performed successfully. Check the errno to see whether
1854f94c520f8d699a5973956a1716272146be17128Zonr Chang    // it's retry-able.
1864f94c520f8d699a5973956a1716272146be17128Zonr Chang    if (errno == EINTR) {
1874f94c520f8d699a5973956a1716272146be17128Zonr Chang      // flock() was interrupted by delivery of a signal. Restart without
1884f94c520f8d699a5973956a1716272146be17128Zonr Chang      // decrement the retry counter.
1894f94c520f8d699a5973956a1716272146be17128Zonr Chang      continue;
1904f94c520f8d699a5973956a1716272146be17128Zonr Chang    } else if (errno == EWOULDBLOCK) {
1914f94c520f8d699a5973956a1716272146be17128Zonr Chang      // The file descriptor was locked by others, wait for a while before next
1924f94c520f8d699a5973956a1716272146be17128Zonr Chang      // retry.
1934f94c520f8d699a5973956a1716272146be17128Zonr Chang      retry++;
1944f94c520f8d699a5973956a1716272146be17128Zonr Chang      ::usleep(pRetryInterval);
1954f94c520f8d699a5973956a1716272146be17128Zonr Chang    } else {
1964f94c520f8d699a5973956a1716272146be17128Zonr Chang      // There's a fatal error occurs when perform flock(). Return immediately
1974f94c520f8d699a5973956a1716272146be17128Zonr Chang      // without further retry.
1984f94c520f8d699a5973956a1716272146be17128Zonr Chang      detectError();
1994f94c520f8d699a5973956a1716272146be17128Zonr Chang      return false;
2004f94c520f8d699a5973956a1716272146be17128Zonr Chang    }
2014f94c520f8d699a5973956a1716272146be17128Zonr Chang  } while (retry <= pMaxRetry);
2024f94c520f8d699a5973956a1716272146be17128Zonr Chang
2034f94c520f8d699a5973956a1716272146be17128Zonr Chang  return false;
2044f94c520f8d699a5973956a1716272146be17128Zonr Chang}
2054f94c520f8d699a5973956a1716272146be17128Zonr Chang
2064f94c520f8d699a5973956a1716272146be17128Zonr Changvoid FileBase::unlock() {
2074f94c520f8d699a5973956a1716272146be17128Zonr Chang  if (mFD < 0) {
2084f94c520f8d699a5973956a1716272146be17128Zonr Chang    return;
2094f94c520f8d699a5973956a1716272146be17128Zonr Chang  }
2104f94c520f8d699a5973956a1716272146be17128Zonr Chang
2114f94c520f8d699a5973956a1716272146be17128Zonr Chang  do {
2124f94c520f8d699a5973956a1716272146be17128Zonr Chang    if (::flock(mFD, LOCK_UN) == 0) {
2134f94c520f8d699a5973956a1716272146be17128Zonr Chang      mShouldUnlock = false;
2144f94c520f8d699a5973956a1716272146be17128Zonr Chang      return;
2154f94c520f8d699a5973956a1716272146be17128Zonr Chang    }
2164f94c520f8d699a5973956a1716272146be17128Zonr Chang  } while (errno == EINTR);
2174f94c520f8d699a5973956a1716272146be17128Zonr Chang
2184f94c520f8d699a5973956a1716272146be17128Zonr Chang  detectError();
2194f94c520f8d699a5973956a1716272146be17128Zonr Chang  return;
2204f94c520f8d699a5973956a1716272146be17128Zonr Chang}
2214f94c520f8d699a5973956a1716272146be17128Zonr Chang
2224f94c520f8d699a5973956a1716272146be17128Zonr Changvoid FileBase::close() {
2234f94c520f8d699a5973956a1716272146be17128Zonr Chang  if (mShouldUnlock) {
2244f94c520f8d699a5973956a1716272146be17128Zonr Chang    unlock();
2254f94c520f8d699a5973956a1716272146be17128Zonr Chang    mShouldUnlock = false;
2264f94c520f8d699a5973956a1716272146be17128Zonr Chang  }
2274f94c520f8d699a5973956a1716272146be17128Zonr Chang  if (mFD > 0) {
2284f94c520f8d699a5973956a1716272146be17128Zonr Chang    ::close(mFD);
2294f94c520f8d699a5973956a1716272146be17128Zonr Chang    mFD = -1;
2304f94c520f8d699a5973956a1716272146be17128Zonr Chang  }
231331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines  if (mShouldDelete) {
232331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines    int res = ::remove(mName.c_str());
233331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines    if (res != 0) {
234331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines      ALOGE("Failed to remove file: %s - %s", mName.c_str(), ::strerror(res));
235331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines    }
236331310e1f3f86a795f78e42b3f03558a43829f09Stephen Hines  }
2374f94c520f8d699a5973956a1716272146be17128Zonr Chang  return;
2384f94c520f8d699a5973956a1716272146be17128Zonr Chang}
239