1 /*
2 * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "vfs_mount.h"
31 #include "vfs_files.h"
32 #include "vfs_maps.h"
33 #include "vfs_config.h"
34 #include "stdlib.h"
35 #include "string.h"
36 #include "limits.h"
37 #include "errno.h"
38 #include "securec.h"
39 #include "vfs_operations.h"
40 #include "los_compiler.h"
41 #include "los_debug.h"
42 #include "los_fs.h"
43 #include "los_mux.h"
44
45 struct MountPoint *g_mountPoints = NULL;
46
MpDeleteFromList(struct MountPoint * mp)47 static void MpDeleteFromList(struct MountPoint *mp)
48 {
49 struct MountPoint *prev = NULL;
50
51 /* delete mp from mount list */
52 if (g_mountPoints == mp) {
53 g_mountPoints = mp->mNext;
54 } else {
55 for (prev = g_mountPoints; prev != NULL; prev = prev->mNext) {
56 if (prev->mNext != mp) {
57 continue;
58 }
59
60 prev->mNext = mp->mNext;
61 break;
62 }
63 }
64 }
65
66 #if (LOSCFG_FS_SUPPORT_MOUNT_TARGET_RECURSIVE == 1)
VfsMpFind(const char * path,const char ** pathInMp)67 struct MountPoint *VfsMpFind(const char *path, const char **pathInMp)
68 {
69 struct MountPoint *mp = g_mountPoints;
70 struct MountPoint *bestMp = NULL;
71 int bestMatches = 0;
72
73 if (pathInMp != NULL) {
74 *pathInMp = NULL;
75 }
76 while ((mp != NULL) && (mp->mPath != NULL)) {
77 const char *mPath = mp->mPath;
78 const char *iPath = path;
79 const char *t = NULL;
80 int matches = 0;
81 do {
82 while ((*mPath == '/') && (*(mPath + 1) != '/')) {
83 mPath++;
84 }
85 while ((*iPath == '/') && (*(iPath + 1) != '/')) {
86 iPath++;
87 }
88
89 t = strchr(mPath, '/');
90 if (t == NULL) {
91 t = strchr(mPath, '\0');
92 }
93 if ((t == mPath) || (t == NULL)) {
94 break;
95 }
96 if (strncmp(mPath, iPath, (size_t)(t - mPath)) != 0) {
97 goto next; /* this mount point do not match, check next */
98 }
99
100 iPath += (t - mPath);
101 if ((*iPath != '\0') && (*iPath != '/')) {
102 goto next;
103 }
104
105 matches += (t - mPath);
106 mPath += (t - mPath);
107 } while (*mPath != '\0');
108
109 if (matches > bestMatches) {
110 bestMatches = matches;
111 bestMp = mp;
112
113 while ((*iPath == '/') && (*(iPath + 1) != '/')) {
114 iPath++;
115 }
116
117 if (pathInMp != NULL) {
118 *pathInMp = path;
119 }
120 }
121 next:
122 mp = mp->mNext;
123 }
124
125 return bestMp;
126 }
127 #else
VfsMpFind(const char * path,const char ** pathInMp)128 struct MountPoint *VfsMpFind(const char *path, const char **pathInMp)
129 {
130 struct MountPoint *mp = g_mountPoints;
131 const char *iPath = path;
132 const char *mPath = NULL;
133 const char *target = NULL;
134
135 if (pathInMp != NULL) {
136 *pathInMp = NULL;
137 }
138 while (*iPath == '/') {
139 ++iPath;
140 }
141
142 while ((mp != NULL) && (mp->mPath != NULL)) {
143 mPath = mp->mPath;
144 target = iPath;
145
146 while (*mPath == '/') {
147 ++mPath;
148 }
149
150 while ((*mPath != '\0') && (*mPath != '/') &&
151 (*target != '\0') && (*target != '/')) {
152 if (*mPath != *target) {
153 break;
154 }
155 ++mPath;
156 ++target;
157 }
158 if (((*mPath == '\0') || (*mPath == '/')) &&
159 ((*target == '\0') || (*target == '/'))) {
160 if (pathInMp != NULL) {
161 *pathInMp = path;
162 }
163 return mp;
164 }
165 mp = mp->mNext;
166 }
167 return NULL;
168 }
169 #endif
170
VfsMountPointInit(const char * source,const char * target,const char * fsType,unsigned long mountflags)171 STATIC struct MountPoint *VfsMountPointInit(const char *source, const char *target,
172 const char *fsType, unsigned long mountflags)
173 {
174 struct MountPoint *mp = NULL;
175 const char *pathInMp = NULL;
176 struct FsMap *mFs = NULL;
177 size_t ssize = 0;
178 size_t tsize;
179
180 /* find mp by target, to see if it was mounted */
181 mp = VfsMpFind(target, &pathInMp);
182 if (mp != NULL && pathInMp != NULL) {
183 errno = EINVAL;
184 return NULL;
185 }
186
187 /* Find fsMap coresponding to the fsType */
188 mFs = VfsFsMapGet(fsType);
189 if ((mFs == NULL) || (mFs->fsMops == NULL) || (mFs->fsMops->mount == NULL)) {
190 errno = ENODEV;
191 return NULL;
192 }
193
194 if (source != NULL) {
195 ssize = strlen(source) + 1;
196 }
197
198 tsize = strlen(target) + 1;
199
200 mp = (struct MountPoint *)LOSCFG_FS_MALLOC_HOOK(sizeof(struct MountPoint) + ssize + tsize);
201 if (mp == NULL) {
202 errno = ENOMEM;
203 return NULL;
204 }
205
206 mp->mFs = mFs;
207 mp->mDev = NULL;
208 mp->mRefs = 0;
209 mp->mWriteEnable = (mountflags & MS_RDONLY) ? FALSE : TRUE;
210 mp->mFs->fsRefs++;
211
212 if (source != NULL && strcpy_s((char *)mp + sizeof(struct MountPoint), ssize, source) != EOK) {
213 LOSCFG_FS_FREE_HOOK(mp);
214 errno = ENOMEM;
215 return NULL;
216 }
217
218 if (strcpy_s((char *)mp + sizeof(struct MountPoint) + ssize, tsize, target) != EOK) {
219 LOSCFG_FS_FREE_HOOK(mp);
220 errno = ENOMEM;
221 return NULL;
222 }
223 mp->mDev = source ? (char *)mp + sizeof(struct MountPoint) : NULL;
224 mp->mPath = (char *)mp + sizeof(struct MountPoint) + ssize;
225
226 return mp;
227 }
228
VfsRemount(const char * source,const char * target,const char * fsType,unsigned long mountflags,const void * data)229 STATIC int VfsRemount(const char *source, const char *target,
230 const char *fsType, unsigned long mountflags,
231 const void *data)
232 {
233 (VOID)source;
234 (VOID)fsType;
235 struct MountPoint *mp;
236
237 mp = VfsMpFind(target, NULL);
238 if (mp == NULL) {
239 errno = EINVAL;
240 return (int)LOS_NOK;
241 }
242
243 LOS_ASSERT(mp->mFs != NULL);
244 LOS_ASSERT(mp->mFs->fsMops != NULL);
245 LOS_ASSERT(mp->mFs->fsMops->mount != NULL);
246
247 return mp->mFs->fsMops->mount(mp, mountflags, data);
248 }
249
VfsMountPathCheck(const char * target)250 STATIC int VfsMountPathCheck(const char *target)
251 {
252 /* target must begin with '/', for example /system, /data, etc. */
253 if ((target == NULL) || (target[0] != '/')) {
254 errno = EINVAL;
255 return (int)LOS_NOK;
256 }
257
258 if (strlen(target) >= PATH_MAX) {
259 errno = ENAMETOOLONG;
260 return (int)LOS_NOK;
261 }
262
263 return LOS_OK;
264 }
265
mount(const char * source,const char * target,const char * fsType,unsigned long mountflags,const void * data)266 int mount(const char *source, const char *target,
267 const char *fsType, unsigned long mountflags,
268 const void *data)
269 {
270 int ret;
271 struct MountPoint *mp = NULL;
272
273 if (VfsMountPathCheck(target) != LOS_OK) {
274 return (int)LOS_NOK;
275 }
276
277 (void)LOS_FsLock();
278
279 if (mountflags & MS_REMOUNT) {
280 ret = VfsRemount(source, target, fsType, mountflags, data);
281 LOS_FsUnlock();
282 return ret;
283 }
284
285 mp = VfsMountPointInit(source, target, fsType, mountflags);
286 if (mp == NULL) {
287 LOS_FsUnlock();
288 return (int)LOS_NOK;
289 }
290
291 ret = mp->mFs->fsMops->mount(mp, mountflags, data);
292 if (ret != 0) {
293 /* errno is set */
294 PRINT_ERR("mount failed, target %s.\n", target);
295 goto errout;
296 }
297
298 mp->mNext = g_mountPoints;
299 g_mountPoints = mp;
300 LOS_FsUnlock();
301 return LOS_OK;
302
303 errout:
304 LOSCFG_FS_FREE_HOOK(mp);
305 LOS_FsUnlock();
306 return (int)LOS_NOK;
307 }
308
umount(const char * target)309 int umount(const char *target)
310 {
311 struct MountPoint *mp = NULL;
312 int ret = (int)LOS_NOK;
313
314 (void)LOS_FsLock();
315 if (VfsMountPathCheck(target) != LOS_OK) {
316 goto errout;
317 }
318
319 mp = VfsMpFind(target, NULL);
320 if ((mp == NULL) || (mp->mRefs != 0)) {
321 goto errout;
322 }
323
324 if ((mp->mFs == NULL) || (mp->mFs->fsMops == NULL) ||
325 (mp->mFs->fsMops->umount == NULL)) {
326 goto errout;
327 }
328
329 ret = mp->mFs->fsMops->umount(mp);
330 if (ret != 0) {
331 /* errno is set */
332 goto errout;
333 }
334
335 /* delete mp from mount list */
336 MpDeleteFromList(mp);
337 mp->mFs->fsRefs--;
338 LOSCFG_FS_FREE_HOOK(mp);
339
340 LOS_FsUnlock();
341 return LOS_OK;
342
343 errout:
344 PRINT_ERR("umount2 failed, target %s.\n", target);
345 LOS_FsUnlock();
346 return (int)LOS_NOK;
347 }
348
CloseFdsInMp(const struct MountPoint * mp)349 static void CloseFdsInMp(const struct MountPoint *mp)
350 {
351 for (int fd = 0; fd < NR_OPEN_DEFAULT; fd++) {
352 struct File *f = FdToFile(fd);
353 if (f == NULL) {
354 continue;
355 }
356 if ((f->fMp == mp) &&
357 (f->fFops != NULL) &&
358 (f->fFops->close != NULL)) {
359 (void)f->fFops->close(f);
360 }
361 }
362 }
363
umount2(const char * target,int flag)364 int umount2(const char *target, int flag)
365 {
366 struct MountPoint *mp = NULL;
367 int ret = (int)LOS_NOK;
368
369 (void)LOS_FsLock();
370 if (VfsMountPathCheck(target) != LOS_OK) {
371 goto errout;
372 }
373
374 mp = VfsMpFind(target, NULL);
375 if ((mp == NULL) || (mp->mRefs != 0) ||
376 (mp->mFs == NULL) || (mp->mFs->fsMops == NULL) ||
377 (mp->mFs->fsMops->umount2 == NULL)) {
378 goto errout;
379 }
380
381 /* Close all files under the mount point */
382 if ((UINT32)flag & MNT_FORCE) {
383 CloseFdsInMp(mp);
384 }
385
386 ret = mp->mFs->fsMops->umount2(mp, flag);
387 if (ret != 0) {
388 /* errno is set */
389 goto errout;
390 }
391
392 /* delete mp from mount list */
393 MpDeleteFromList(mp);
394 mp->mFs->fsRefs--;
395 LOSCFG_FS_FREE_HOOK(mp);
396
397 LOS_FsUnlock();
398 return LOS_OK;
399
400 errout:
401 PRINT_ERR("umount2 failed, target %s.\n", target);
402 LOS_FsUnlock();
403 return (int)LOS_NOK;
404 }
405