• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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