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