1 /*
2 * Copyright (c) 2021 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 #include <cstdlib>
18 #include <fcntl.h>
19 #include <sys/mount.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #include "ipc/istorage_daemon.h"
23 #include "parameter.h"
24 #include "storage_service_errno.h"
25 #include "storage_service_log.h"
26 #include "utils/file_utils.h"
27 #include "utils/mount_argument_utils.h"
28 #include "utils/string_utils.h"
29 #include "system_ability_definition.h"
30 #include "cloud_daemon_manager.h"
31
32
33 namespace OHOS {
34 namespace StorageDaemon {
35 using namespace std;
36 using namespace OHOS::FileManagement::CloudFile;
37 constexpr int32_t UMOUNT_RETRY_TIMES = 3;
38 std::shared_ptr<MountManager> MountManager::instance_ = nullptr;
39
40 const std::string HMDFS_SYS_CAP = "const.distributed_file_property.enabled";
41 const int32_t HMDFS_VAL_LEN = 6;
42 const int32_t HMDFS_TRUE_LEN = 5;
MountManager()43 MountManager::MountManager()
44 : hmdfsDirVec_{{"/data/service/el2/%d/share", 0711, OID_SYSTEM, OID_SYSTEM},
45 {"/data/service/el2/%d/hmdfs", 0711, OID_SYSTEM, OID_SYSTEM},
46 {"/data/service/el2/%d/hmdfs/fuse", 0771, OID_DFS, OID_DFS},
47 {"/data/service/el2/%d/hmdfs/account", 0711, OID_SYSTEM, OID_SYSTEM},
48 {"/data/service/el2/%d/hmdfs/account/files", 02771, OID_USER_DATA_RW, OID_USER_DATA_RW},
49 {"/data/service/el2/%d/hmdfs/account/data", 0711, OID_SYSTEM, OID_SYSTEM},
50 {"/data/service/el2/%d/hmdfs/non_account", 0711, OID_SYSTEM, OID_SYSTEM},
51 {"/data/service/el2/%d/hmdfs/non_account/files", 0711, OID_USER_DATA_RW, OID_USER_DATA_RW},
52 {"/data/service/el2/%d/hmdfs/non_account/data", 0711, OID_SYSTEM, OID_SYSTEM},
53 {"/data/service/el2/%d/hmdfs/cache", 0711, OID_DFS, OID_DFS},
54 {"/data/service/el2/%d/hmdfs/cache/account_cache", 0711, OID_DFS, OID_DFS},
55 {"/data/service/el2/%d/hmdfs/cache/non_account_cache", 0711, OID_DFS, OID_DFS},
56 {"/data/service/el2/%d/hmdfs/account/services", 0771, OID_DFS_SHARE, OID_DFS_SHARE}},
57 virtualDir_{{"/storage/media/%d", 0711, OID_USER_DATA_RW, OID_USER_DATA_RW},
58 {"/storage/media/%d/local", 0711, OID_USER_DATA_RW, OID_USER_DATA_RW},
59 {"/storage/cloud", 0711, OID_ROOT, OID_ROOT},
60 {"/storage/cloud/%d", 0711, OID_USER_DATA_RW, OID_USER_DATA_RW},
61 {"/mnt/share/", 0711, OID_ROOT, OID_ROOT},
62 {"/mnt/share/%d/", 0711, OID_ROOT, OID_ROOT},
63 {"/mnt/data/%d/", 0711, OID_ROOT, OID_ROOT},
64 {"/mnt/hmdfs/", 0711, OID_ROOT, OID_ROOT},
65 {"/mnt/hmdfs/%d/", 0711, OID_ROOT, OID_ROOT},
66 {"/mnt/hmdfs/%d/account", 0711, OID_ROOT, OID_ROOT},
67 {"/mnt/hmdfs/%d/non_account", 0711, OID_ROOT, OID_ROOT},
68 {"/mnt/hmdfs/%d/cloud", 0711, OID_ROOT, OID_ROOT}},
69 fileManagerDir_{{"/data/service/el2/%d/hmdfs/account/files/Documents", 02771, OID_FILE_MANAGER, OID_FILE_MANAGER},
70 {"/data/service/el2/%d/hmdfs/account/files/Download", 02771, OID_FILE_MANAGER, OID_FILE_MANAGER},
71 {"/data/service/el2/%d/hmdfs/account/files/Desktop", 02771, OID_FILE_MANAGER, OID_FILE_MANAGER},
72 {"/data/service/el2/%d/hmdfs/account/files/Docs", 02771, OID_FILE_MANAGER, OID_FILE_MANAGER},
73 {"/data/service/el2/%d/hmdfs/account/files/.Recent", 02771, OID_FILE_MANAGER, OID_FILE_MANAGER},
74 {"/data/service/el2/%d/hmdfs/account/files/.Trash", 02771, OID_FILE_MANAGER, OID_FILE_MANAGER}}
75 {
76 }
77
GetInstance()78 std::shared_ptr<MountManager> MountManager::GetInstance()
79 {
80 static std::once_flag onceFlag;
81 std::call_once(onceFlag, [&]() { instance_ = std::make_shared<MountManager>(); });
82
83 return instance_;
84 }
85
HmdfsTwiceMount(int32_t userId,std::string relativePath)86 int32_t MountManager::HmdfsTwiceMount(int32_t userId, std::string relativePath)
87 {
88 int32_t ret = HmdfsMount(userId, relativePath);
89
90 // bind mount
91 Utils::MountArgument hmdfsMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, relativePath));
92 ret += Mount(hmdfsMntArgs.GetFullDst() + "/device_view/", hmdfsMntArgs.GetCommFullPath(),
93 nullptr, MS_BIND, nullptr);
94 if (ret != 0 && errno != EEXIST && errno != EBUSY) {
95 LOGE("failed to bind mount device_view, err %{public}d", errno);
96 return E_MOUNT;
97 }
98 ret += Mount(hmdfsMntArgs.GetFullDst() + "/cloud_merge_view/", hmdfsMntArgs.GetCloudFullPath(),
99 nullptr, MS_BIND, nullptr);
100 if (ret != 0 && errno != EEXIST && errno != EBUSY) {
101 LOGE("failed to bind mount cloud_merge_view, err %{public}d", errno);
102 return E_MOUNT;
103 }
104 return E_OK;
105 }
106
SharefsMount(int32_t userId)107 int32_t MountManager::SharefsMount(int32_t userId)
108 {
109 Utils::MountArgument sharefsMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, ""));
110 int ret = Mount(sharefsMntArgs.GetShareSrc(), sharefsMntArgs.GetShareDst(), "sharefs",
111 sharefsMntArgs.GetFlags(), sharefsMntArgs.GetUserIdPara().c_str());
112 if (ret != 0 && errno != EEXIST && errno != EBUSY) {
113 LOGE("failed to mount sharefs, err %{public}d", errno);
114 return E_MOUNT;
115 }
116 return E_OK;
117 }
118
SharefsUMount(int32_t userId)119 int32_t MountManager::SharefsUMount(int32_t userId)
120 {
121 Utils::MountArgument sharefsMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, ""));
122 int32_t ret = UMount2(sharefsMntArgs.GetShareDst().c_str(), MNT_DETACH);
123 if (ret != E_OK) {
124 LOGE("umount sharefs, errno %{public}d, sharefs dst %{public}s", errno,
125 sharefsMntArgs.GetShareDst().c_str());
126 return E_UMOUNT;
127 }
128 return E_OK;
129 }
130
HmdfsMount(int32_t userId,std::string relativePath)131 int32_t MountManager::HmdfsMount(int32_t userId, std::string relativePath)
132 {
133 Utils::MountArgument hmdfsMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, relativePath));
134 int ret = Mount(hmdfsMntArgs.GetFullSrc(), hmdfsMntArgs.GetFullDst(), "hmdfs",
135 hmdfsMntArgs.GetFlags(), hmdfsMntArgs.OptionsToString().c_str());
136 if (ret != 0 && errno != EEXIST && errno != EBUSY) {
137 LOGE("failed to mount hmdfs, err %{public}d", errno);
138 return E_MOUNT;
139 }
140
141 ret = chown(hmdfsMntArgs.GetCtrlPath().c_str(), OID_DFS, OID_SYSTEM);
142 if (ret != 0) {
143 LOGE("failed to chown hmdfs sysfs node, err %{public}d", errno);
144 }
145
146 return E_OK;
147 }
148
149
CloudMount(int32_t userId)150 int32_t MountManager::CloudMount(int32_t userId)
151 {
152 int fd = -1;
153 string opt;
154 int ret;
155 Utils::MountArgument cloudMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, ""));
156 const string path = cloudMntArgs.GetFullCloud();
157 if (!cloudReady_) {
158 LOGI("Cloud Service has not started");
159 return E_MOUNT;
160 }
161
162 fd = open("/dev/fuse", O_RDWR);
163 if (fd < 0) {
164 LOGE("open /dev/fuse fail");
165 return E_MOUNT;
166 }
167
168 opt = StringPrintf("fd=%i,"
169 "rootmode=40000,"
170 "default_permissions,"
171 "allow_other,"
172 "user_id=0,group_id=0,"
173 "context=\"u:object_r:hmdfs:s0\","
174 "fscontext=u:object_r:hmdfs:s0",
175 fd);
176 ret = Mount("/dev/fuse", path.c_str(), "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opt.c_str());
177 if (ret) {
178 LOGE("failed to mount fuse, err %{public}d %{public}d %{public}s", errno, ret, path.c_str());
179 close(fd);
180 return ret;
181 }
182
183 ret = CloudDaemonManager::GetInstance().StartFuse(userId, fd, path);
184 if (ret) {
185 LOGE("failed to connect fuse, err %{public}d %{public}d %{public}s", errno, ret, path.c_str());
186 UMount(path.c_str());
187 }
188 LOGI("mount %{public}s success", path.c_str());
189 close(fd);
190 return ret;
191 }
192
HmdfsMount(int32_t userId)193 int32_t MountManager::HmdfsMount(int32_t userId)
194 {
195 int32_t ret = HmdfsTwiceMount(userId, "account");
196
197 ret += HmdfsMount(userId, "non_account");
198 if (ret != E_OK) {
199 return E_MOUNT;
200 }
201
202 mountMutex_.lock();
203 ret = CloudMount(userId);
204 if (ret == E_OK) {
205 fuseMountedUsers_.push_back(userId);
206 } else {
207 fuseToMountUsers_.push_back(userId);
208 }
209 mountMutex_.unlock();
210
211 return E_OK;
212 }
213
MountCloudForUsers(void)214 void MountManager::MountCloudForUsers(void)
215 {
216 for (auto it = fuseToMountUsers_.begin(); it != fuseToMountUsers_.end();) {
217 int32_t res = CloudMount(*it);
218 if (res == E_OK) {
219 fuseMountedUsers_.push_back(*it);
220 it = fuseToMountUsers_.erase(it);
221 } else {
222 it++;
223 }
224 }
225 }
226
UMountCloudForUsers(void)227 void MountManager::UMountCloudForUsers(void)
228 {
229 for (auto it = fuseMountedUsers_.begin(); it != fuseMountedUsers_.end();) {
230 int32_t res = CloudUMount(*it);
231 if (res == E_OK) {
232 fuseToMountUsers_.push_back(*it);
233 it = fuseMountedUsers_.erase(it);
234 } else {
235 it++;
236 }
237 }
238 }
239
SetCloudState(bool active)240 void MountManager::SetCloudState(bool active)
241 {
242 mountMutex_.lock();
243 cloudReady_ = active;
244 if (cloudReady_) {
245 MountCloudForUsers();
246 } else {
247 UMountCloudForUsers();
248 }
249 mountMutex_.unlock();
250 }
251
HmdfsTwiceUMount(int32_t userId,std::string relativePath)252 int32_t MountManager::HmdfsTwiceUMount(int32_t userId, std::string relativePath)
253 {
254 int32_t err = E_OK;
255 // un bind mount
256 Utils::MountArgument hmdfsMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, relativePath));
257 err = UMount(hmdfsMntArgs.GetCommFullPath());
258 if (err != E_OK) {
259 LOGE("failed to un bind mount, errno %{public}d, ComDataDir_ dst %{public}s", errno,
260 hmdfsMntArgs.GetCommFullPath().c_str());
261 }
262 err = UMount(hmdfsMntArgs.GetCloudFullPath());
263 if (err != E_OK) {
264 LOGE("failed to un bind mount, errno %{public}d, CloudDataDir dst %{public}s", errno,
265 hmdfsMntArgs.GetCloudFullPath().c_str());
266 }
267
268 err = UMount2(hmdfsMntArgs.GetFullDst().c_str(), MNT_DETACH);
269 if (err != E_OK) {
270 LOGE("identical account hmdfs umount failed, errno %{public}d, hmdfs dst %{public}s", errno,
271 hmdfsMntArgs.GetFullDst().c_str());
272 return E_UMOUNT;
273 }
274 return E_OK;
275 }
276
HmdfsUMount(int32_t userId,std::string relativePath)277 int32_t MountManager::HmdfsUMount(int32_t userId, std::string relativePath)
278 {
279 Utils::MountArgument hmdfsAuthMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, relativePath));
280 int32_t ret = UMount2(hmdfsAuthMntArgs.GetFullDst().c_str(), MNT_DETACH);
281 if (ret != E_OK) {
282 LOGE("umount auth hmdfs, errno %{public}d, auth hmdfs dst %{public}s", errno,
283 hmdfsAuthMntArgs.GetFullDst().c_str());
284 return E_UMOUNT;
285 }
286 return E_OK;
287 }
288
CloudUMount(int32_t userId)289 int32_t MountManager::CloudUMount(int32_t userId)
290 {
291 int32_t err = E_OK;
292 Utils::MountArgument cloudMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, ""));
293 const string path = cloudMntArgs.GetFullCloud();
294
295 err = UMount(path);
296 if (err != E_OK) {
297 LOGE("fuse umount failed, errno %{public}d, fuse dst %{public}s", errno, path.c_str());
298 return E_UMOUNT;
299 }
300 LOGI("umount %{public}s success", path.c_str());
301 return E_OK;
302 }
303
HmdfsUMount(int32_t userId)304 int32_t MountManager::HmdfsUMount(int32_t userId)
305 {
306 int32_t ret = HmdfsTwiceUMount(userId, "account");
307 ret += HmdfsUMount(userId, "non_account");
308 if (ret != E_OK) {
309 return E_UMOUNT;
310 }
311 CloudUMount(userId);
312 return E_OK;
313 }
314
SupportHmdfs()315 bool MountManager::SupportHmdfs()
316 {
317 char hmdfsEnable[HMDFS_VAL_LEN + 1] = {"false"};
318 int ret = GetParameter(HMDFS_SYS_CAP.c_str(), "", hmdfsEnable, HMDFS_VAL_LEN);
319 LOGI("GetParameter hmdfsEnable %{public}s, ret %{public}d", hmdfsEnable, ret);
320 if (strncmp(hmdfsEnable, "true", HMDFS_TRUE_LEN) == 0) {
321 return true;
322 }
323 return false;
324 }
325
LocalMount(int32_t userId)326 int32_t MountManager::LocalMount(int32_t userId)
327 {
328 Utils::MountArgument LocalMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, "account"));
329 if (Mount(LocalMntArgs.GetFullSrc(), LocalMntArgs.GetCommFullPath() + "local/",
330 nullptr, MS_BIND, nullptr)) {
331 LOGE("failed to bind mount, err %{public}d", errno);
332 return E_MOUNT;
333 }
334 if (Mount(LocalMntArgs.GetFullSrc(), LocalMntArgs.GetCloudFullPath(),
335 nullptr, MS_BIND, nullptr)) {
336 LOGE("failed to bind mount, err %{public}d", errno);
337 return E_MOUNT;
338 }
339 return E_OK;
340 }
341
MountByUser(int32_t userId)342 int32_t MountManager::MountByUser(int32_t userId)
343 {
344 int ret = E_OK;
345 // The Documnets and Download directories are managed by the File access framework,
346 // and the UID GID is changed to filemanager
347 PrepareFileManagerDir(userId);
348 if (CreateVirtualDirs(userId) != E_OK) {
349 LOGE("create hmdfs virtual dir error");
350 return E_PREPARE_DIR;
351 }
352
353 if (!SupportHmdfs()) {
354 ret = LocalMount(userId);
355 } else {
356 ret = HmdfsMount(userId);
357 }
358
359 if (ret != E_OK) {
360 LOGE("hmdfs mount error");
361 return ret;
362 }
363
364 ret = SharefsMount(userId);
365 if (ret != E_OK) {
366 LOGE("sharefs mount error");
367 return ret;
368 }
369 return E_OK;
370 }
371
PrepareFileManagerDir(int32_t userId)372 void MountManager::PrepareFileManagerDir(int32_t userId)
373 {
374 for (const DirInfo &dir : fileManagerDir_) {
375 std::string path = StringPrintf(dir.path.c_str(), userId);
376 int ret = IsSameGidUid(path, dir.uid, dir.gid);
377 LOGE("prepareDir %{public}s ret %{public}d", path.c_str(), ret);
378 // Dir exist and same uid, gid
379 if (ret == E_OK) {
380 continue;
381 }
382 // system error
383 if (ret == E_SYS_ERR) {
384 LOGE("system err %{public}s ", path.c_str());
385 continue;
386 }
387 // Dir exist and different uid, gid
388 if (ret == E_DIFF_UID_GID) {
389 ChownRecursion(path, OID_FILE_MANAGER, OID_FILE_MANAGER);
390 continue;
391 }
392 // Dir not exist
393 if (ret == E_NON_EXIST && !PrepareDir(path, dir.mode, dir.uid, dir.gid)) {
394 LOGE("failed to prepareDir %{public}s ", path.c_str());
395 }
396 }
397 }
398
LocalUMount(int32_t userId)399 int32_t MountManager::LocalUMount(int32_t userId)
400 {
401 Utils::MountArgument LocalMntArgs(Utils::MountArgumentDescriptors::Alpha(userId, "account"));
402 int err = UMount(LocalMntArgs.GetCommFullPath() + "local/");
403 if (err != E_OK) {
404 LOGE("failed to un bind mount, errno %{public}d, ComDataDir dst %{public}s", errno,
405 LocalMntArgs.GetCommFullPath().c_str());
406 }
407 err = UMount(LocalMntArgs.GetCloudFullPath());
408 if (err != E_OK) {
409 LOGE("failed to un bind mount, errno %{public}d, CloudDataDir dst %{public}s", errno,
410 LocalMntArgs.GetCloudFullPath().c_str());
411 }
412 return err;
413 }
414
UmountByUser(int32_t userId)415 int32_t MountManager::UmountByUser(int32_t userId)
416 {
417 int32_t count = 0;
418 while (count < UMOUNT_RETRY_TIMES) {
419 int32_t err = E_OK;
420 err = SharefsUMount(userId);
421 if (err != E_OK) {
422 LOGE("failed to umount sharefs, errno %{public}d", errno);
423 }
424 if (!SupportHmdfs()) {
425 err = LocalUMount(userId);
426 } else {
427 err = HmdfsUMount(userId);
428 }
429 if (err == E_OK) {
430 break;
431 } else if (errno == EBUSY) {
432 count++;
433 continue;
434 }
435 LOGE("failed to umount hmdfs, errno %{public}d", errno);
436 return E_UMOUNT;
437 }
438 return E_OK;
439 }
440
PrepareHmdfsDirs(int32_t userId)441 int32_t MountManager::PrepareHmdfsDirs(int32_t userId)
442 {
443 for (const DirInfo &dir : hmdfsDirVec_) {
444 if (!PrepareDir(StringPrintf(dir.path.c_str(), userId), dir.mode, dir.uid, dir.gid)) {
445 return E_PREPARE_DIR;
446 }
447 }
448
449 return E_OK;
450 }
451
PrepareFileManagerDirs(int32_t userId)452 int32_t MountManager::PrepareFileManagerDirs(int32_t userId)
453 {
454 for (const DirInfo &dir : fileManagerDir_) {
455 if (!PrepareDir(StringPrintf(dir.path.c_str(), userId), dir.mode, dir.uid, dir.gid)) {
456 return E_PREPARE_DIR;
457 }
458 }
459
460 return E_OK;
461 }
462
CreateVirtualDirs(int32_t userId)463 int32_t MountManager::CreateVirtualDirs(int32_t userId)
464 {
465 for (const DirInfo &dir : virtualDir_) {
466 if (!PrepareDir(StringPrintf(dir.path.c_str(), userId), dir.mode, dir.uid, dir.gid)) {
467 return E_PREPARE_DIR;
468 }
469 }
470
471 return E_OK;
472 }
473
DestroyHmdfsDirs(int32_t userId)474 int32_t MountManager::DestroyHmdfsDirs(int32_t userId)
475 {
476 bool err = true;
477
478 for (const DirInfo &dir : hmdfsDirVec_) {
479 if (IsEndWith(dir.path.c_str(), "%d")) {
480 err = RmDirRecurse(StringPrintf(dir.path.c_str(), userId));
481 }
482 }
483
484 return err ? E_OK : E_DESTROY_DIR;
485 }
486
487
DestroyFileManagerDirs(int32_t userId)488 int32_t MountManager::DestroyFileManagerDirs(int32_t userId)
489 {
490 bool err = true;
491
492 for (const DirInfo &dir : fileManagerDir_) {
493 if (IsEndWith(dir.path.c_str(), "%d")) {
494 err = RmDirRecurse(StringPrintf(dir.path.c_str(), userId));
495 }
496 }
497
498 return err ? E_OK : E_DESTROY_DIR;
499 }
500
501 } // namespace StorageDaemon
502 } // namespace OHOS
503