• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_ = MakeFilePath(path, STR_LOCK);
52     inProcessMutex_ = PreferencesLockManager::Get(filePath_);
53     inProcessMutex_->lock();
54 }
55 
~PreferencesFileLock()56 PreferencesFileLock::~PreferencesFileLock()
57 {
58     inProcessMutex_->unlock();
59     if (Access(filePath_) != 0 && Access(MakeFilePath(filePath_, STR_BACKUP)) != 0) {
60         return;
61     }
62     if (fd_ > 0) {
63         struct flock fileLockInfo = { 0 };
64         fileLockInfo.l_type = F_UNLCK;
65         fileLockInfo.l_whence = SEEK_SET;
66         fileLockInfo.l_start = 0;
67         fileLockInfo.l_len = 0;
68         if (fcntl(fd_, F_SETLK, &fileLockInfo) == -1) {
69             LOG_ERROR("failed to release file lock error %{public}d.", errno);
70         }
71         close(fd_);
72         fd_ = -1;
73     }
74 }
75 
ReadLock(bool & isMultiProcessing)76 void PreferencesFileLock::ReadLock(bool &isMultiProcessing)
77 {
78     if (Access(filePath_) != 0 && Access(MakeFilePath(filePath_, STR_BACKUP)) != 0) {
79         return;
80     }
81     Lock(F_RDLCK, isMultiProcessing);
82 }
83 
WriteLock(bool & isMultiProcessing)84 void PreferencesFileLock::WriteLock(bool &isMultiProcessing)
85 {
86     Lock(F_WRLCK, isMultiProcessing);
87 }
88 
Lock(short lockType,bool & isMultiProcessing)89 void PreferencesFileLock::Lock(short lockType, bool &isMultiProcessing)
90 {
91     fd_ = open(filePath_.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
92     if (fd_ == -1) {
93         LOG_ERROR("Couldn't open file %{public}s errno %{public}d.", ExtractFileName(filePath_).c_str(), errno);
94         return;
95     }
96     struct flock fileLockInfo = { 0 };
97     fileLockInfo.l_type = lockType;
98     fileLockInfo.l_whence = SEEK_SET;
99     fileLockInfo.l_start = 0;
100     fileLockInfo.l_len = 0;
101 
102     for (size_t i = 0; i < ATTEMPTS; ++i) {
103         if (fcntl(fd_, F_SETLK, &fileLockInfo) != -1) {
104             LOG_DEBUG("successfully obtained file lock");
105             return;
106         }
107         LOG_DEBUG("Attempt to obtain file lock again %{public}d", errno);
108         isMultiProcessing = true;
109         std::this_thread::sleep_for(WAIT_CONNECT_TIMEOUT);
110     }
111     LOG_ERROR("attempt to lock file %{public}s failed.", ExtractFileName(filePath_).c_str());
112 }
113 
114 #else
115 
PreferencesFileLock(const std::string & path)116 PreferencesFileLock::PreferencesFileLock(const std::string &path)
117 {
118     fd_ = -1;
119     inProcessMutex_.reset();
120 }
121 
~PreferencesFileLock()122 PreferencesFileLock::~PreferencesFileLock()
123 {
124 }
125 
ReadLock(bool & isMultiProcessing)126 void PreferencesFileLock::ReadLock(bool &isMultiProcessing)
127 {
128 }
129 
WriteLock(bool & isMultiProcessing)130 void PreferencesFileLock::WriteLock(bool &isMultiProcessing)
131 {
132 }
133 
Lock(short lockType,bool & isMultiProcessing)134 void PreferencesFileLock::Lock(short lockType, bool &isMultiProcessing)
135 {
136 }
137 
138 #endif
139 } // End of namespace NativePreferences
140 } // End of namespace OHOS