1 /*
2 * Copyright (c) 2023 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 "ipc/cloud_daemon.h"
17
18 #include <exception>
19 #include <stdexcept>
20 #include <thread>
21 #include <malloc.h>
22 #include <sys/stat.h>
23 #include <sys/utsname.h>
24
25 #include "iremote_object.h"
26 #include "system_ability_definition.h"
27 #include "parameters.h"
28 #include "plugin_loader.h"
29 #include "dfs_error.h"
30 #include "fuse_manager/fuse_manager.h"
31 #include "utils_directory.h"
32 #include "utils_log.h"
33
34 namespace OHOS {
35 namespace FileManagement {
36 namespace CloudFile {
37 using namespace std;
38 using namespace CloudDisk;
39
40 namespace {
41 static const string LOCAL_PATH_DATA_SERVICE_EL2 = "/data/service/el2/";
42 static const string LOCAL_PATH_HMDFS_DENTRY_CACHE = "/hmdfs/cache/account_cache/dentry_cache/";
43 static const string LOCAL_PATH_HMDFS_CACHE_CLOUD = "/hmdfs/cache/account_cache/dentry_cache/cloud";
44 static const int32_t STAT_MODE_DIR = 0771;
45 static const int32_t STAT_MODE_DIR_DENTRY_CACHE = 02771;
46 static const int32_t OID_DFS = 1009;
47 }
48 REGISTER_SYSTEM_ABILITY_BY_ID(CloudDaemon, FILEMANAGEMENT_CLOUD_DAEMON_SERVICE_SA_ID, true);
49
CloudDaemon(int32_t saID,bool runOnCreate)50 CloudDaemon::CloudDaemon(int32_t saID, bool runOnCreate) : SystemAbility(saID, runOnCreate)
51 {
52 accountStatusListener_ = make_shared<AccountStatusListener>();
53 }
54
PublishSA()55 void CloudDaemon::PublishSA()
56 {
57 LOGI("Begin to init");
58 if (!registerToService_) {
59 bool ret = SystemAbility::Publish(this);
60 if (!ret) {
61 throw runtime_error("Failed to publish the daemon");
62 }
63 registerToService_ = true;
64 }
65 LOGI("Init finished successfully");
66 }
67
CheckDeviceInLinux()68 static bool CheckDeviceInLinux()
69 {
70 struct utsname uts;
71 if (uname(&uts) == -1) {
72 LOGE("uname get failed.");
73 return false;
74 }
75 if (strcmp(uts.sysname, "Linux") == 0) {
76 LOGI("uname system is linux.");
77 return true;
78 }
79 return false;
80 }
81
ModSysParam()82 static void ModSysParam()
83 {
84 if (CheckDeviceInLinux()) {
85 const string photos = "persist.kernel.bundle_name.photos";
86 const string clouddrive = "persist.kernel.bundle_name.clouddrive";
87 system::SetParameter(photos, "");
88 system::SetParameter(clouddrive, "");
89 }
90 }
91
OnStart()92 void CloudDaemon::OnStart()
93 {
94 LOGI("Begin to start service");
95 if (state_ == ServiceRunningState::STATE_RUNNING) {
96 LOGI("Daemon has already started");
97 return;
98 }
99
100 try {
101 PublishSA();
102 AddSystemAbilityListener(COMMON_EVENT_SERVICE_ID);
103 mode_t mode = 002;
104 umask(mode);
105 ModSysParam();
106 } catch (const exception &e) {
107 LOGE("%{public}s", e.what());
108 }
109
110 state_ = ServiceRunningState::STATE_RUNNING;
111 /* load cloud file ext plugin */
112 CloudFile::PluginLoader::GetInstance().LoadCloudKitPlugin();
113 LOGI("Start service successfully");
114 }
115
HandleStartMove(int32_t userId)116 void HandleStartMove(int32_t userId)
117 {
118 const string moveFile = "persist.kernel.move.finish";
119 system::SetParameter(moveFile, "false");
120 const std::string filemanagerKey = "persist.kernel.bundle_name.filemanager";
121 string subList[] = {"com.ohos.photos", system::GetParameter(filemanagerKey, "")};
122 string srcBase = "/data/service/el1/public/cloudfile/" + to_string(userId);
123 string dstBase = "/data/service/el2/" + to_string(userId) + "/hmdfs/cloudfile_manager";
124 const auto copyOptions = filesystem::copy_options::overwrite_existing | filesystem::copy_options::recursive;
125 for (auto sub : subList) {
126 string srcPath = srcBase + '/' + sub;
127 string dstPath = dstBase + '/' + sub;
128 if (access(srcPath.c_str(), F_OK) != 0) {
129 LOGI("srcPath %{public}s not found", GetAnonyString(srcPath).c_str());
130 continue;
131 }
132 LOGI("Begin to move path: %{public}s", GetAnonyString(srcPath).c_str());
133 error_code errCode;
134 filesystem::copy(srcPath, dstPath, copyOptions, errCode);
135 if (errCode.value() != 0) {
136 LOGE("copy failed path: %{public}s, errCode: %{public}d",
137 GetAnonyString(srcPath).c_str(), errCode.value());
138 }
139 LOGI("End move path: %{public}s", GetAnonyString(srcPath).c_str());
140 bool ret = Storage::DistributedFile::Utils::ForceRemoveDirectoryDeepFirst(srcPath);
141 if (!ret) {
142 LOGE("remove failed path: %{public}s", GetAnonyString(srcPath).c_str());
143 }
144 }
145 system::SetParameter(moveFile, "true");
146 }
147
OnStop()148 void CloudDaemon::OnStop()
149 {
150 LOGI("Begin to stop");
151 state_ = ServiceRunningState::STATE_NOT_START;
152 registerToService_ = false;
153 LOGI("Stop finished successfully");
154 }
155
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)156 void CloudDaemon::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
157 {
158 LOGI("OnAddSystemAbility systemAbilityId:%{public}d added!", systemAbilityId);
159 accountStatusListener_->Start();
160 }
161
StartFuse(int32_t userId,int32_t devFd,const string & path)162 int32_t CloudDaemon::StartFuse(int32_t userId, int32_t devFd, const string &path)
163 {
164 LOGI("Start Fuse");
165 std::thread([=]() {
166 int32_t ret = FuseManager::GetInstance().StartFuse(userId, devFd, path);
167 LOGI("start fuse result %d", ret);
168 }).detach();
169
170 string dentryPath = LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) + LOCAL_PATH_HMDFS_CACHE_CLOUD;
171 if (access(dentryPath.c_str(), F_OK) != 0) {
172 string cachePath = LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) + LOCAL_PATH_HMDFS_DENTRY_CACHE;
173 if (mkdir(cachePath.c_str(), STAT_MODE_DIR) != 0 && errno != EEXIST) {
174 LOGE("create accout_cache path error %{public}d", errno);
175 return E_PATH;
176 }
177 if (chmod(cachePath.c_str(), STAT_MODE_DIR_DENTRY_CACHE) != 0) {
178 LOGE("chmod cachepath error %{public}d", errno);
179 }
180 if (chown(cachePath.c_str(), OID_DFS, OID_DFS) != 0) {
181 LOGE("chown cachepath error %{public}d", errno);
182 }
183 if (mkdir(dentryPath.c_str(), STAT_MODE_DIR) != 0 && errno != EEXIST) {
184 LOGE("create dentrypath %{public}d", errno);
185 return E_PATH;
186 }
187 if (chown(dentryPath.c_str(), OID_DFS, OID_DFS) != 0) {
188 LOGE("chown cachepath error %{public}d", errno);
189 }
190 }
191 if (path.find("cloud_fuse") != string::npos) {
192 std::thread([userId]() {
193 HandleStartMove(userId);
194 }).detach();
195 }
196 return E_OK;
197 }
198 } // namespace CloudFile
199 } // namespace FileManagement
200 } // namespace OHOS
201