405 lines
10 KiB
C
405 lines
10 KiB
C
/*
|
|
* Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include "vfs_mount.h"
|
|
#include "vfs_files.h"
|
|
#include "vfs_maps.h"
|
|
#include "vfs_config.h"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
#include "limits.h"
|
|
#include "errno.h"
|
|
#include "securec.h"
|
|
#include "vfs_operations.h"
|
|
#include "los_compiler.h"
|
|
#include "los_debug.h"
|
|
#include "los_fs.h"
|
|
#include "los_mux.h"
|
|
|
|
struct MountPoint *g_mountPoints = NULL;
|
|
|
|
static void MpDeleteFromList(struct MountPoint *mp)
|
|
{
|
|
struct MountPoint *prev = NULL;
|
|
|
|
/* delete mp from mount list */
|
|
if (g_mountPoints == mp) {
|
|
g_mountPoints = mp->mNext;
|
|
} else {
|
|
for (prev = g_mountPoints; prev != NULL; prev = prev->mNext) {
|
|
if (prev->mNext != mp) {
|
|
continue;
|
|
}
|
|
|
|
prev->mNext = mp->mNext;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if (LOSCFG_FS_SUPPORT_MOUNT_TARGET_RECURSIVE == 1)
|
|
struct MountPoint *VfsMpFind(const char *path, const char **pathInMp)
|
|
{
|
|
struct MountPoint *mp = g_mountPoints;
|
|
struct MountPoint *bestMp = NULL;
|
|
int bestMatches = 0;
|
|
|
|
if (pathInMp != NULL) {
|
|
*pathInMp = NULL;
|
|
}
|
|
while ((mp != NULL) && (mp->mPath != NULL)) {
|
|
const char *mPath = mp->mPath;
|
|
const char *iPath = path;
|
|
const char *t = NULL;
|
|
int matches = 0;
|
|
do {
|
|
while ((*mPath == '/') && (*(mPath + 1) != '/')) {
|
|
mPath++;
|
|
}
|
|
while ((*iPath == '/') && (*(iPath + 1) != '/')) {
|
|
iPath++;
|
|
}
|
|
|
|
t = strchr(mPath, '/');
|
|
if (t == NULL) {
|
|
t = strchr(mPath, '\0');
|
|
}
|
|
if ((t == mPath) || (t == NULL)) {
|
|
break;
|
|
}
|
|
if (strncmp(mPath, iPath, (size_t)(t - mPath)) != 0) {
|
|
goto next; /* this mount point do not match, check next */
|
|
}
|
|
|
|
iPath += (t - mPath);
|
|
if ((*iPath != '\0') && (*iPath != '/')) {
|
|
goto next;
|
|
}
|
|
|
|
matches += (t - mPath);
|
|
mPath += (t - mPath);
|
|
} while (*mPath != '\0');
|
|
|
|
if (matches > bestMatches) {
|
|
bestMatches = matches;
|
|
bestMp = mp;
|
|
|
|
while ((*iPath == '/') && (*(iPath + 1) != '/')) {
|
|
iPath++;
|
|
}
|
|
|
|
if (pathInMp != NULL) {
|
|
*pathInMp = path;
|
|
}
|
|
}
|
|
next:
|
|
mp = mp->mNext;
|
|
}
|
|
|
|
return bestMp;
|
|
}
|
|
#else
|
|
struct MountPoint *VfsMpFind(const char *path, const char **pathInMp)
|
|
{
|
|
struct MountPoint *mp = g_mountPoints;
|
|
const char *iPath = path;
|
|
const char *mPath = NULL;
|
|
const char *target = NULL;
|
|
|
|
if (pathInMp != NULL) {
|
|
*pathInMp = NULL;
|
|
}
|
|
while (*iPath == '/') {
|
|
++iPath;
|
|
}
|
|
|
|
while ((mp != NULL) && (mp->mPath != NULL)) {
|
|
mPath = mp->mPath;
|
|
target = iPath;
|
|
|
|
while (*mPath == '/') {
|
|
++mPath;
|
|
}
|
|
|
|
while ((*mPath != '\0') && (*mPath != '/') &&
|
|
(*target != '\0') && (*target != '/')) {
|
|
if (*mPath != *target) {
|
|
break;
|
|
}
|
|
++mPath;
|
|
++target;
|
|
}
|
|
if (((*mPath == '\0') || (*mPath == '/')) &&
|
|
((*target == '\0') || (*target == '/'))) {
|
|
if (pathInMp != NULL) {
|
|
*pathInMp = path;
|
|
}
|
|
return mp;
|
|
}
|
|
mp = mp->mNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
STATIC struct MountPoint *VfsMountPointInit(const char *source, const char *target,
|
|
const char *fsType, unsigned long mountflags)
|
|
{
|
|
struct MountPoint *mp = NULL;
|
|
const char *pathInMp = NULL;
|
|
struct FsMap *mFs = NULL;
|
|
size_t ssize = 0;
|
|
size_t tsize;
|
|
|
|
/* find mp by target, to see if it was mounted */
|
|
mp = VfsMpFind(target, &pathInMp);
|
|
if (mp != NULL && pathInMp != NULL) {
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
/* Find fsMap corresponding to the fsType */
|
|
mFs = VfsFsMapGet(fsType);
|
|
if ((mFs == NULL) || (mFs->fsMops == NULL) || (mFs->fsMops->mount == NULL)) {
|
|
errno = ENODEV;
|
|
return NULL;
|
|
}
|
|
|
|
if (source != NULL) {
|
|
ssize = strlen(source) + 1;
|
|
}
|
|
|
|
tsize = strlen(target) + 1;
|
|
|
|
mp = (struct MountPoint *)LOSCFG_FS_MALLOC_HOOK(sizeof(struct MountPoint) + ssize + tsize);
|
|
if (mp == NULL) {
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
|
|
mp->mFs = mFs;
|
|
mp->mDev = NULL;
|
|
mp->mRefs = 0;
|
|
mp->mWriteEnable = (mountflags & MS_RDONLY) ? FALSE : TRUE;
|
|
mp->mFs->fsRefs++;
|
|
|
|
if (source != NULL && strcpy_s((char *)mp + sizeof(struct MountPoint), ssize, source) != EOK) {
|
|
LOSCFG_FS_FREE_HOOK(mp);
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
|
|
if (strcpy_s((char *)mp + sizeof(struct MountPoint) + ssize, tsize, target) != EOK) {
|
|
LOSCFG_FS_FREE_HOOK(mp);
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
mp->mDev = source ? (char *)mp + sizeof(struct MountPoint) : NULL;
|
|
mp->mPath = (char *)mp + sizeof(struct MountPoint) + ssize;
|
|
|
|
return mp;
|
|
}
|
|
|
|
STATIC int VfsRemount(const char *source, const char *target,
|
|
const char *fsType, unsigned long mountflags,
|
|
const void *data)
|
|
{
|
|
(VOID)source;
|
|
(VOID)fsType;
|
|
struct MountPoint *mp;
|
|
|
|
mp = VfsMpFind(target, NULL);
|
|
if (mp == NULL) {
|
|
errno = EINVAL;
|
|
return (int)LOS_NOK;
|
|
}
|
|
|
|
LOS_ASSERT(mp->mFs != NULL);
|
|
LOS_ASSERT(mp->mFs->fsMops != NULL);
|
|
LOS_ASSERT(mp->mFs->fsMops->mount != NULL);
|
|
|
|
return mp->mFs->fsMops->mount(mp, mountflags, data);
|
|
}
|
|
|
|
STATIC int VfsMountPathCheck(const char *target)
|
|
{
|
|
/* target must begin with '/', for example /system, /data, etc. */
|
|
if ((target == NULL) || (target[0] != '/')) {
|
|
errno = EINVAL;
|
|
return (int)LOS_NOK;
|
|
}
|
|
|
|
if (strlen(target) >= PATH_MAX) {
|
|
errno = ENAMETOOLONG;
|
|
return (int)LOS_NOK;
|
|
}
|
|
|
|
return LOS_OK;
|
|
}
|
|
|
|
int mount(const char *source, const char *target,
|
|
const char *fsType, unsigned long mountflags,
|
|
const void *data)
|
|
{
|
|
int ret;
|
|
struct MountPoint *mp = NULL;
|
|
|
|
if (VfsMountPathCheck(target) != LOS_OK) {
|
|
return (int)LOS_NOK;
|
|
}
|
|
|
|
(void)LOS_FsLock();
|
|
|
|
if (mountflags & MS_REMOUNT) {
|
|
ret = VfsRemount(source, target, fsType, mountflags, data);
|
|
LOS_FsUnlock();
|
|
return ret;
|
|
}
|
|
|
|
mp = VfsMountPointInit(source, target, fsType, mountflags);
|
|
if (mp == NULL) {
|
|
LOS_FsUnlock();
|
|
return (int)LOS_NOK;
|
|
}
|
|
|
|
ret = mp->mFs->fsMops->mount(mp, mountflags, data);
|
|
if (ret != 0) {
|
|
/* errno is set */
|
|
PRINT_ERR("mount failed, target %s.\n", target);
|
|
goto errout;
|
|
}
|
|
|
|
mp->mNext = g_mountPoints;
|
|
g_mountPoints = mp;
|
|
LOS_FsUnlock();
|
|
return LOS_OK;
|
|
|
|
errout:
|
|
LOSCFG_FS_FREE_HOOK(mp);
|
|
LOS_FsUnlock();
|
|
return (int)LOS_NOK;
|
|
}
|
|
|
|
int umount(const char *target)
|
|
{
|
|
struct MountPoint *mp = NULL;
|
|
int ret = (int)LOS_NOK;
|
|
|
|
(void)LOS_FsLock();
|
|
if (VfsMountPathCheck(target) != LOS_OK) {
|
|
goto errout;
|
|
}
|
|
|
|
mp = VfsMpFind(target, NULL);
|
|
if ((mp == NULL) || (mp->mRefs != 0)) {
|
|
goto errout;
|
|
}
|
|
|
|
if ((mp->mFs == NULL) || (mp->mFs->fsMops == NULL) ||
|
|
(mp->mFs->fsMops->umount == NULL)) {
|
|
goto errout;
|
|
}
|
|
|
|
ret = mp->mFs->fsMops->umount(mp);
|
|
if (ret != 0) {
|
|
/* errno is set */
|
|
goto errout;
|
|
}
|
|
|
|
/* delete mp from mount list */
|
|
MpDeleteFromList(mp);
|
|
mp->mFs->fsRefs--;
|
|
LOSCFG_FS_FREE_HOOK(mp);
|
|
|
|
LOS_FsUnlock();
|
|
return LOS_OK;
|
|
|
|
errout:
|
|
PRINT_ERR("umount2 failed, target %s.\n", target);
|
|
LOS_FsUnlock();
|
|
return (int)LOS_NOK;
|
|
}
|
|
|
|
static void CloseFdsInMp(const struct MountPoint *mp)
|
|
{
|
|
for (int fd = 0; fd < NR_OPEN_DEFAULT; fd++) {
|
|
struct File *f = FdToFile(fd);
|
|
if (f == NULL) {
|
|
continue;
|
|
}
|
|
if ((f->fMp == mp) &&
|
|
(f->fFops != NULL) &&
|
|
(f->fFops->close != NULL)) {
|
|
(void)f->fFops->close(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
int umount2(const char *target, int flag)
|
|
{
|
|
struct MountPoint *mp = NULL;
|
|
int ret = (int)LOS_NOK;
|
|
|
|
(void)LOS_FsLock();
|
|
if (VfsMountPathCheck(target) != LOS_OK) {
|
|
goto errout;
|
|
}
|
|
|
|
mp = VfsMpFind(target, NULL);
|
|
if ((mp == NULL) || (mp->mRefs != 0) ||
|
|
(mp->mFs == NULL) || (mp->mFs->fsMops == NULL) ||
|
|
(mp->mFs->fsMops->umount2 == NULL)) {
|
|
goto errout;
|
|
}
|
|
|
|
/* Close all files under the mount point */
|
|
if ((UINT32)flag & MNT_FORCE) {
|
|
CloseFdsInMp(mp);
|
|
}
|
|
|
|
ret = mp->mFs->fsMops->umount2(mp, flag);
|
|
if (ret != 0) {
|
|
/* errno is set */
|
|
goto errout;
|
|
}
|
|
|
|
/* delete mp from mount list */
|
|
MpDeleteFromList(mp);
|
|
mp->mFs->fsRefs--;
|
|
LOSCFG_FS_FREE_HOOK(mp);
|
|
|
|
LOS_FsUnlock();
|
|
return LOS_OK;
|
|
|
|
errout:
|
|
PRINT_ERR("umount2 failed, target %s.\n", target);
|
|
LOS_FsUnlock();
|
|
return (int)LOS_NOK;
|
|
}
|