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