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