1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "preferences_utils.h"
17 #include "preferences_file_lock.h"
18 #include "preferences_file_operation.h"
19
20 #include <fcntl.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23
24 #include <cerrno>
25 #include <cstdio>
26 #include <thread>
27
28 #include "log_print.h"
29 #include "visibility.h"
30 namespace OHOS {
31 namespace NativePreferences {
32 std::map<std::string, std::shared_ptr<std::mutex>> PreferencesLockManager::inProcessMutexs_;
33 std::mutex PreferencesLockManager::mapMutex_;
34
Get(const std::string fileName)35 std::shared_ptr<std::mutex> PreferencesLockManager::Get(const std::string fileName)
36 {
37 std::lock_guard<std::mutex> lockMutex(mapMutex_);
38 auto iter = inProcessMutexs_.find(fileName);
39 if (iter != inProcessMutexs_.end()) {
40 return iter->second;
41 }
42 auto res = inProcessMutexs_.insert_or_assign(fileName, std::make_shared<std::mutex>());
43 return res.first->second;
44 }
45
46 #if !defined(WINDOWS_PLATFORM)
47 static const std::chrono::milliseconds WAIT_CONNECT_TIMEOUT(20);
48 static const int ATTEMPTS = 50;
PreferencesFileLock(const std::string & path)49 PreferencesFileLock::PreferencesFileLock(const std::string &path)
50 {
51 filePath_ = PreferencesUtils::MakeFilePath(path, PreferencesUtils::STR_LOCK);
52 inProcessMutex_ = PreferencesLockManager::Get(filePath_);
53 inProcessMutex_->lock();
54 }
55
~PreferencesFileLock()56 PreferencesFileLock::~PreferencesFileLock()
57 {
58 inProcessMutex_->unlock();
59 if (fd_ > 0) {
60 struct flock fileLockInfo = { 0 };
61 fileLockInfo.l_type = F_UNLCK;
62 fileLockInfo.l_whence = SEEK_SET;
63 fileLockInfo.l_start = 0;
64 fileLockInfo.l_len = 0;
65 if (fcntl(fd_, F_SETLK, &fileLockInfo) == -1) {
66 LOG_ERROR("failed to release file lock error %{public}d.", errno);
67 }
68 close(fd_);
69 fd_ = -1;
70 }
71 }
72
ReadLock(bool & isMultiProcessing)73 void PreferencesFileLock::ReadLock(bool &isMultiProcessing)
74 {
75 if (Access(filePath_) != 0) {
76 return;
77 }
78 Lock(F_RDLCK, isMultiProcessing);
79 }
80
WriteLock(bool & isMultiProcessing)81 void PreferencesFileLock::WriteLock(bool &isMultiProcessing)
82 {
83 Lock(F_WRLCK, isMultiProcessing);
84 }
85
Lock(short lockType,bool & isMultiProcessing)86 void PreferencesFileLock::Lock(short lockType, bool &isMultiProcessing)
87 {
88 fd_ = open(filePath_.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
89 if (fd_ == -1) {
90 LOG_ERROR("Couldn't open file %{public}s errno %{public}d.", ExtractFileName(filePath_).c_str(), errno);
91 return;
92 }
93 struct flock fileLockInfo = { 0 };
94 fileLockInfo.l_type = lockType;
95 fileLockInfo.l_whence = SEEK_SET;
96 fileLockInfo.l_start = 0;
97 fileLockInfo.l_len = 0;
98
99 for (size_t i = 0; i < ATTEMPTS; ++i) {
100 if (fcntl(fd_, F_SETLK, &fileLockInfo) != -1) {
101 LOG_DEBUG("successfully obtained file lock");
102 return;
103 }
104 LOG_DEBUG("Attempt to obtain file lock again %{public}d", errno);
105 isMultiProcessing = true;
106 std::this_thread::sleep_for(WAIT_CONNECT_TIMEOUT);
107 }
108 LOG_ERROR("attempt to lock file %{public}s failed.", ExtractFileName(filePath_).c_str());
109 }
110
111 #else
112
PreferencesFileLock(const std::string & path)113 PreferencesFileLock::PreferencesFileLock(const std::string &path)
114 {
115 fd_ = -1;
116 inProcessMutex_.reset();
117 }
118
~PreferencesFileLock()119 PreferencesFileLock::~PreferencesFileLock()
120 {
121 }
122
ReadLock(bool & isMultiProcessing)123 void PreferencesFileLock::ReadLock(bool &isMultiProcessing)
124 {
125 }
126
WriteLock(bool & isMultiProcessing)127 void PreferencesFileLock::WriteLock(bool &isMultiProcessing)
128 {
129 }
130
Lock(short lockType,bool & isMultiProcessing)131 void PreferencesFileLock::Lock(short lockType, bool &isMultiProcessing)
132 {
133 }
134
135 #endif
136 } // End of namespace NativePreferences
137 } // End of namespace OHOS