1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "user/mount_manager.h"
17
18 #include <unistd.h>
19
20 #include "parameter.h"
21 #include "utils/mount_argument_utils.h"
22 #include "utils/storage_radar.h"
23 #include "storage_service_constant.h"
24 #include "storage_service_errno.h"
25 #include "storage_service_log.h"
26
27 namespace OHOS {
28 namespace StorageDaemon {
29 using namespace std;
30 using namespace OHOS::StorageService;
31 const string PROC_MOUNTS = "/proc/mounts";
32 static constexpr int SHARE_FILE_0771 = 0771;
33 constexpr int32_t PATH_MAX_FOR_LINK = 4096;
34
CheckSymlinkForMulti(const std::string & fdPath,const std::string & path,std::set<std::string> & occupyFiles)35 void MountManager::CheckSymlinkForMulti(const std::string &fdPath, const std::string &path,
36 std::set<std::string> &occupyFiles)
37 {
38 char realPath[PATH_MAX_FOR_LINK];
39 int res = readlink(fdPath.c_str(), realPath, sizeof(realPath) - 1);
40 if (res < 0) {
41 LOGE("readlink failed for multi, errno is %{public}d.", errno);
42 return;
43 }
44 realPath[res] = '\0';
45 std::string realPathStr(realPath);
46 if (realPathStr.find(UN_REACHABLE) == 0) {
47 realPathStr = realPathStr.substr(UN_REACHABLE.size()) + FILE_SEPARATOR_CHAR;
48 }
49 if (realPathStr.find(path) == 0) {
50 LOGE("find a fd from link, %{public}s", realPathStr.c_str());
51 realPathStr = realPathStr.substr(path.size());
52 if (realPathStr.empty()) {
53 return;
54 }
55 if (path == FILE_MGR_ROOT_PATH) {
56 occupyFiles.insert(realPathStr);
57 return;
58 }
59 std::string::size_type point = realPathStr.find(FILE_SEPARATOR_CHAR);
60 if (point != std::string::npos) {
61 realPathStr = realPathStr.substr(0, point);
62 }
63 occupyFiles.insert(realPathStr);
64 }
65 }
66
MountDisShareFile(int32_t userId,const std::map<std::string,std::string> & shareFiles)67 int32_t MountManager::MountDisShareFile(int32_t userId, const std::map<std::string, std::string> &shareFiles)
68 {
69 LOGI("mount share file start.");
70 std::map<std::string, std::string> notMountPaths = shareFiles;
71 FilterNotMountedPath(notMountPaths);
72 for (const auto &item: notMountPaths) {
73 std::string dstPath = item.first;
74 std::string srcPath = item.second;
75 if (!IsDir(srcPath)) {
76 LOGE("mount share file, src path invalid, errno is %{public}d", errno);
77 return E_NON_EXIST;
78 }
79 if (!IsDir(dstPath) && !MkDirRecurse(dstPath, SHARE_FILE_0771)) {
80 LOGE("mount share file, dst path mkdir failed, errno is %{public}d", errno);
81 return E_NON_EXIST;
82 }
83 int32_t ret = Mount(srcPath, dstPath, nullptr, MS_BIND, nullptr);
84 if (ret != 0) {
85 LOGE("mount share file failed, errno is %{public}d", errno);
86 std::string extraData = "src=" + srcPath + ",dst=" + dstPath + ",kernelCode=" + to_string(errno);
87 StorageRadar::ReportUserManager("MountDisShareFile", userId, E_MOUNT_SHARE_FILE, extraData);
88 return E_MOUNT_SHARE_FILE;
89 }
90 }
91 LOGI("mount share file success.");
92 return E_OK;
93 }
94
UMountDisShareFile(int32_t userId,const std::string & networkId)95 int32_t MountManager::UMountDisShareFile(int32_t userId, const std::string &networkId)
96 {
97 LOGI("umount share file, userId is %{public}d, networkId is %{private}s.", userId, networkId.c_str());
98 std::list<std::string> mounts;
99 FindMountsByNetworkId(networkId, mounts);
100 for (const std::string &item: mounts) {
101 int32_t ret = UMount2(item, MNT_DETACH);
102 if (ret != E_OK && errno != ENOENT && errno != EINVAL) {
103 LOGE("umount share file failed, errno is %{public}d.", errno);
104 std::string extraData = "networkId=" + networkId + ",kernelCode=" + to_string(errno);
105 StorageRadar::ReportUserManager("UMountDisShareFile", userId, E_UMOUNT_SHARE_FILE, extraData);
106 }
107 std::string path = item.substr(0, item.find(networkId) + networkId.size());
108 RmDirRecurse(path);
109 }
110 LOGI("umount share file end.");
111 return E_OK;
112 }
113
FindMountsByNetworkId(const std::string & networkId,std::list<std::string> & mounts)114 int32_t MountManager::FindMountsByNetworkId(const std::string &networkId, std::list<std::string> &mounts)
115 {
116 std::ifstream inputStream(PROC_MOUNTS.c_str(), std::ios::in);
117 if (!inputStream.is_open()) {
118 LOGE("unable to open /proc/mounts, errno is %{public}d", errno);
119 return E_UMOUNT_PROC_MOUNTS_OPEN;
120 }
121 std::string tmpLine;
122 while (std::getline(inputStream, tmpLine)) {
123 if (tmpLine.empty()) {
124 continue;
125 }
126 std::stringstream ss(tmpLine);
127 std::string dst;
128 if ((ss >> dst >> dst) && dst.find(networkId) != std::string::npos) {
129 mounts.push_front(dst);
130 }
131 }
132 return E_OK;
133 }
134
FilterNotMountedPath(std::map<std::string,std::string> & notMountPaths)135 int32_t MountManager::FilterNotMountedPath(std::map<std::string, std::string> ¬MountPaths)
136 {
137 std::ifstream inputStream(PROC_MOUNTS.c_str(), std::ios::in);
138 if (!inputStream.is_open()) {
139 LOGE("unable to open /proc/mounts, errno is %{public}d", errno);
140 return E_UMOUNT_PROC_MOUNTS_OPEN;
141 }
142 std::string tmpLine;
143 while (std::getline(inputStream, tmpLine)) {
144 if (tmpLine.empty()) {
145 continue;
146 }
147 std::stringstream ss(tmpLine);
148 std::string dst;
149 if ((ss >> dst >> dst) && notMountPaths.find(dst) != notMountPaths.end()) {
150 notMountPaths.erase(dst);
151 }
152 }
153 return E_OK;
154 }
155 } // namespace StorageDaemon
156 } // namespace OHOS