1d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath/* 2d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * Copyright (C) 2011 The Android Open Source Project 3d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * 4d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 5d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * you may not use this file except in compliance with the License. 6d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * You may obtain a copy of the License at 7d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * 8d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 9d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * 10d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * Unless required by applicable law or agreed to in writing, software 11d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 12d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * See the License for the specific language governing permissions and 14d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath * limitations under the License. 15d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath */ 16d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 17d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath#include "scoped_flock.h" 18d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 19d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath#include <sys/file.h> 20d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath#include <sys/stat.h> 21d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 22d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath#include "base/logging.h" 23d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath#include "base/stringprintf.h" 24d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath#include "base/unix_file/fd_file.h" 25d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 26d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamathnamespace art { 27d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 28d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamathbool ScopedFlock::Init(const char* filename, std::string* error_msg) { 29877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle return Init(filename, O_CREAT | O_RDWR, true, error_msg); 30877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle} 31877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle 32877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravlebool ScopedFlock::Init(const char* filename, int flags, bool block, std::string* error_msg) { 33d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath while (true) { 344303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe if (file_.get() != nullptr) { 354303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe UNUSED(file_->FlushCloseOrErase()); // Ignore result. 364303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 37877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle file_.reset(OS::OpenFileWithFlags(filename, flags)); 382cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier if (file_.get() == nullptr) { 39d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath *error_msg = StringPrintf("Failed to open file '%s': %s", filename, strerror(errno)); 40d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath return false; 41d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath } 42877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle int operation = block ? LOCK_EX : (LOCK_EX | LOCK_NB); 43877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), operation)); 44877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle if (flock_result == EWOULDBLOCK) { 45877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle // File is locked by someone else and we are required not to block; 46877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle return false; 47877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle } 48d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath if (flock_result != 0) { 49d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath *error_msg = StringPrintf("Failed to lock file '%s': %s", filename, strerror(errno)); 50d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath return false; 51d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath } 52d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath struct stat fstat_stat; 53d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath int fstat_result = TEMP_FAILURE_RETRY(fstat(file_->Fd(), &fstat_stat)); 54d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath if (fstat_result != 0) { 55d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath *error_msg = StringPrintf("Failed to fstat file '%s': %s", filename, strerror(errno)); 56d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath return false; 57d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath } 58d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath struct stat stat_stat; 59d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath int stat_result = TEMP_FAILURE_RETRY(stat(filename, &stat_stat)); 60d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath if (stat_result != 0) { 61d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath PLOG(WARNING) << "Failed to stat, will retry: " << filename; 62d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath // ENOENT can happen if someone racing with us unlinks the file we created so just retry. 63877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle if (block) { 64877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle continue; 65877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle } else { 66877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle // Note that in theory we could race with someone here for a long time and end up retrying 67877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle // over and over again. This potential behavior does not fit well in the non-blocking 68877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle // semantics. Thus, if we are not require to block return failure when racing. 69877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle return false; 70877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle } 71d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath } 72d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath if (fstat_stat.st_dev != stat_stat.st_dev || fstat_stat.st_ino != stat_stat.st_ino) { 73d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath LOG(WARNING) << "File changed while locking, will retry: " << filename; 74877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle if (block) { 75877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle continue; 76877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle } else { 77877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle // See comment above. 78877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle return false; 79877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle } 80d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath } 81d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath return true; 82d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath } 83d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath} 84d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 85a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Lightbool ScopedFlock::Init(File* file, std::string* error_msg) { 86024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle file_.reset(new File(dup(file->Fd()), file->GetPath(), file->CheckUsage(), file->ReadOnlyMode())); 87a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light if (file_->Fd() == -1) { 88a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light file_.reset(); 89a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light *error_msg = StringPrintf("Failed to duplicate open file '%s': %s", 90a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light file->GetPath().c_str(), strerror(errno)); 91a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light return false; 92a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light } 93a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light if (0 != TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_EX))) { 94a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light file_.reset(); 952cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier *error_msg = StringPrintf( 962cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier "Failed to lock file '%s': %s", file->GetPath().c_str(), strerror(errno)); 97a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light return false; 98a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light } 99a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light return true; 100a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light} 101a59dd80f9f48cb750d329d4d4af2d99d72b484d1Alex Light 102877fd963548a3175665bfef25b0d24bc0e5a0135Calin JuravleFile* ScopedFlock::GetFile() const { 1032cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier CHECK(file_.get() != nullptr); 104d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath return file_.get(); 105d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath} 106d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 107833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampebool ScopedFlock::HasFile() { 108833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe return file_.get() != nullptr; 109833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe} 110833a48501d560c9fa7fc78ef619888138c2d374fAndreas Gampe 111d1c606f280797be81e2592c483869a6ec836a9f3Narayan KamathScopedFlock::ScopedFlock() { } 112d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 113d1c606f280797be81e2592c483869a6ec836a9f3Narayan KamathScopedFlock::~ScopedFlock() { 1142cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier if (file_.get() != nullptr) { 115d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath int flock_result = TEMP_FAILURE_RETRY(flock(file_->Fd(), LOCK_UN)); 116d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath CHECK_EQ(0, flock_result); 117024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle int close_result = -1; 118024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle if (file_->ReadOnlyMode()) { 119024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle close_result = file_->Close(); 120024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle } else { 121024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle close_result = file_->FlushCloseOrErase(); 122024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle } 123024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle if (close_result != 0) { 1244303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe PLOG(WARNING) << "Could not close scoped file lock file."; 1254303ba97313458491e038d78efa041d41cf7bb43Andreas Gampe } 126d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath } 127d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath} 128d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath 129d1c606f280797be81e2592c483869a6ec836a9f3Narayan Kamath} // namespace art 130