xref: /kernel/liteos_m/components/fs/vfs/vfs_mount.c (revision 3d8536b4)
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
45struct MountPoint *g_mountPoints = NULL;
46
47static 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)
67struct 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
128struct 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
171STATIC 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 corresponding 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
229STATIC 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
250STATIC 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
266int 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
303errout:
304    LOSCFG_FS_FREE_HOOK(mp);
305    LOS_FsUnlock();
306    return (int)LOS_NOK;
307}
308
309int 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
343errout:
344    PRINT_ERR("umount2 failed, target %s.\n", target);
345    LOS_FsUnlock();
346    return (int)LOS_NOK;
347}
348
349static 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
364int 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
400errout:
401    PRINT_ERR("umount2 failed, target %s.\n", target);
402    LOS_FsUnlock();
403    return (int)LOS_NOK;
404}
405