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