1 /*
2 * Copyright (c) 2021 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 "hks_storage_file_lock.h"
17
18 #include <stdbool.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "hks_lock.h"
23 #include "hks_mem.h"
24 #include "hks_mutex.h"
25 #include "hks_template.h"
26 #include "securec.h"
27
28 struct HksStorageFileLock {
29 char *path;
30 HksLock *lock;
31 uint32_t ref;
32 HksStorageFileLock *next;
33 };
34
35 static HksStorageFileLock *g_lockListFirst = NULL;
36 static HksStorageFileLock *g_lockListLast = NULL;
37 static HksMutex *g_lockListLock = NULL;
38
FreeFileLock(HksStorageFileLock * lock)39 static void FreeFileLock(HksStorageFileLock *lock)
40 {
41 if (lock == NULL) {
42 return;
43 }
44
45 if (lock->path) {
46 HKS_FREE(lock->path);
47 lock->path = NULL;
48 }
49
50 if (lock->lock) {
51 HksLockClose(lock->lock);
52 lock->lock = NULL;
53 }
54
55 HKS_FREE(lock);
56 }
57
ClearLockList(void)58 static void ClearLockList(void)
59 {
60 if (g_lockListFirst == NULL) {
61 return;
62 }
63
64 HksStorageFileLock *iter = g_lockListFirst;
65 HksStorageFileLock *temp = NULL;
66 while (iter != NULL) {
67 temp = iter->next;
68 FreeFileLock(iter);
69 iter = temp;
70 }
71
72 g_lockListFirst = NULL;
73 g_lockListLast = NULL;
74 }
75
FindFileLock(const char * path)76 static HksStorageFileLock *FindFileLock(const char *path)
77 {
78 HksStorageFileLock *iter = g_lockListFirst;
79 while (iter != NULL) {
80 if (strcmp(path, iter->path) == 0) {
81 return iter;
82 } else {
83 iter = iter->next;
84 }
85 }
86 return NULL;
87 }
88
AllocFileLock(const char * path)89 static HksStorageFileLock *AllocFileLock(const char *path)
90 {
91 HksStorageFileLock *lock = HksMalloc(sizeof(HksStorageFileLock));
92 HKS_IF_NULL_RETURN(lock, NULL)
93
94 size_t len = strlen(path);
95 lock->path = HksMalloc(len + 1);
96 if (lock->path == NULL) {
97 FreeFileLock(lock);
98 return NULL;
99 }
100 if (strcpy_s(lock->path, len + 1, path) != EOK) {
101 FreeFileLock(lock);
102 return NULL;
103 }
104 lock->lock = HksLockCreate();
105 lock->ref = 1;
106 lock->next = NULL;
107 if (lock->path == NULL || lock->lock == NULL) {
108 FreeFileLock(lock);
109 return NULL;
110 }
111 return lock;
112 }
113
AddRef(HksStorageFileLock * lock)114 static void AddRef(HksStorageFileLock *lock)
115 {
116 if (lock == NULL) {
117 return;
118 }
119
120 lock->ref++;
121 }
122
AppendFileLock(HksStorageFileLock * lock)123 static void AppendFileLock(HksStorageFileLock *lock)
124 {
125 if (g_lockListFirst == NULL) {
126 g_lockListFirst = lock;
127 g_lockListFirst->next = NULL;
128 g_lockListLast = lock;
129 return;
130 }
131
132 if (g_lockListLast != NULL) {
133 g_lockListLast->next = lock;
134 g_lockListLast = lock;
135 g_lockListLast->next = NULL;
136 }
137 }
138
HksStorageFileLockCreate(const char * path)139 HksStorageFileLock *HksStorageFileLockCreate(const char *path)
140 {
141 HKS_IF_NULL_RETURN(path, NULL)
142
143 HKS_IF_NULL_RETURN(g_lockListLock, NULL)
144
145 if (HksMutexLock(g_lockListLock) != 0) {
146 return NULL;
147 }
148 HksStorageFileLock *lock = FindFileLock(path);
149 if (lock == NULL) {
150 lock = AllocFileLock(path);
151 if (lock != NULL) {
152 AppendFileLock(lock);
153 }
154 } else {
155 AddRef(lock);
156 }
157 (void)HksMutexUnlock(g_lockListLock);
158
159 return lock;
160 }
161
HksStorageFileLockRead(HksStorageFileLock * lock)162 int32_t HksStorageFileLockRead(HksStorageFileLock *lock)
163 {
164 HKS_IF_NULL_RETURN(lock, -1)
165
166 return HksLockLockRead(lock->lock);
167 }
168
HksStorageFileUnlockRead(HksStorageFileLock * lock)169 int32_t HksStorageFileUnlockRead(HksStorageFileLock *lock)
170 {
171 HKS_IF_NULL_RETURN(lock, -1)
172
173 return HksLockUnlockRead(lock->lock);
174 }
175
HksStorageFileLockWrite(HksStorageFileLock * lock)176 int32_t HksStorageFileLockWrite(HksStorageFileLock *lock)
177 {
178 HKS_IF_NULL_RETURN(lock, -1)
179
180 return HksLockLockWrite(lock->lock);
181 }
182
HksStorageFileUnlockWrite(HksStorageFileLock * lock)183 int32_t HksStorageFileUnlockWrite(HksStorageFileLock *lock)
184 {
185 HKS_IF_NULL_RETURN(lock, -1)
186
187 return HksLockUnlockWrite(lock->lock);
188 }
189
IsLockInList(const HksStorageFileLock * lock)190 static bool IsLockInList(const HksStorageFileLock *lock)
191 {
192 HksStorageFileLock *iter = g_lockListFirst;
193 while (iter != NULL) {
194 if (lock == iter) {
195 return true;
196 } else {
197 iter = iter->next;
198 }
199 }
200 return false;
201 }
202
Release(HksStorageFileLock * lock)203 static uint32_t Release(HksStorageFileLock *lock)
204 {
205 uint32_t ref = 0;
206 HksStorageFileLock *iter = g_lockListFirst;
207 HksStorageFileLock *previous = NULL;
208 bool remove = false;
209 while (iter != NULL) {
210 if (lock == iter) {
211 lock->ref--;
212 ref = lock->ref;
213 if (ref == 0) {
214 remove = true;
215 }
216 break;
217 } else {
218 previous = iter;
219 iter = iter->next;
220 }
221 }
222
223 if (remove && iter != NULL) {
224 if (previous != NULL) {
225 previous->next = iter->next;
226 } else {
227 g_lockListFirst = iter->next;
228 }
229 if (g_lockListLast == lock) {
230 g_lockListLast = previous;
231 }
232 FreeFileLock(lock);
233 }
234
235 return ref;
236 }
237
HksStorageFileLockRelease(HksStorageFileLock * lock)238 void HksStorageFileLockRelease(HksStorageFileLock *lock)
239 {
240 if (lock == NULL) {
241 return;
242 }
243
244 if (g_lockListLock == NULL) {
245 return;
246 }
247
248 if (HksMutexLock(g_lockListLock) != 0) {
249 return;
250 }
251
252 if (IsLockInList(lock)) {
253 Release(lock);
254 }
255
256 (void)HksMutexUnlock(g_lockListLock);
257 }
258
OnLoad(void)259 __attribute__((constructor)) static void OnLoad(void)
260 {
261 g_lockListLock = HksMutexCreate();
262 g_lockListFirst = NULL;
263 g_lockListLast = NULL;
264 }
265
OnUnload(void)266 __attribute__((destructor)) static void OnUnload(void)
267 {
268 if (g_lockListLock != NULL) {
269 HksMutexClose(g_lockListLock);
270 g_lockListLock = NULL;
271 }
272
273 ClearLockList();
274 }
275