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