openharmony_kernel_liteos_m/components/fs/vfs/vfs_mount.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;
}