1/*
2* Copyright (c) 2024 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 "daemon_execute.h"
17
18#include <chrono>
19#include <ctime>
20#include <filesystem>
21#include <memory>
22#include <random>
23#include <regex>
24
25#include "asset_callback_manager.h"
26#include "dfs_error.h"
27#include "network/softbus/softbus_asset_send_listener.h"
28#include "network/softbus/softbus_handler_asset.h"
29#include "network/softbus/softbus_session_pool.h"
30#include "refbase.h"
31#include "sandbox_helper.h"
32#include "utils_directory.h"
33#include "utils_log.h"
34
35#include "all_connect/all_connect_manager.h"
36#include "network/softbus/softbus_handler.h"
37
38namespace OHOS {
39namespace Storage {
40namespace DistributedFile {
41using namespace OHOS::AppFileService;
42using namespace OHOS::FileManagement;
43DaemonExecute::DaemonExecute()
44{
45    LOGI("DaemonExecute begin.");
46    executeFuncMap_[DEAMON_EXECUTE_PUSH_ASSET] = &DaemonExecute::ExecutePushAsset;
47    executeFuncMap_[DEAMON_EXECUTE_REQUEST_SEND_FILE] = &DaemonExecute::ExecuteRequestSendFile;
48}
49
50void DaemonExecute::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
51{
52    if (event == nullptr) {
53        LOGE("event is nullptr.");
54        return;
55    }
56    std::lock_guard<std::mutex> lock(executeFuncMapMutex_);
57    auto itFunc = executeFuncMap_.find(event->GetInnerEventId());
58    if (itFunc == executeFuncMap_.end()) {
59        LOGE("not find execute func.");
60        return;
61    }
62
63    auto executeFunc = itFunc->second;
64    (this->*executeFunc)(event);
65}
66
67void DaemonExecute::ExecutePushAsset(const AppExecFwk::InnerEvent::Pointer &event)
68{
69    if (event == nullptr) {
70        LOGI("eventhandler fail.");
71        return;
72    }
73    auto pushData = event->GetSharedObject<PushAssetData>();
74    if (pushData == nullptr) {
75        LOGE("pushData is nullptr.");
76        return;
77    }
78    int32_t userId = pushData->userId_;
79    auto assetObj = pushData->assetObj_;
80    if (assetObj == nullptr) {
81        LOGE("assetObj is nullptr.");
82        return;
83    }
84    int32_t socketId;
85    auto ret = SoftBusHandlerAsset::GetInstance().AssetBind(assetObj->dstNetworkId_, socketId);
86    if (ret != E_OK) {
87        LOGE("ExecutePushAsset AssetBind failed, ret %{public}d", ret);
88        auto taskId = assetObj->srcBundleName_ + assetObj->sessionId_;
89        AssetCallbackManager::GetInstance().NotifyAssetSendResult(taskId, assetObj, FileManagement::E_EVENT_HANDLER);
90        AssetCallbackManager::GetInstance().RemoveSendCallback(taskId);
91        return;
92    }
93    SoftBusHandlerAsset::GetInstance().AddAssetObj(socketId, assetObj);
94
95    auto fileList = GetFileList(assetObj->uris_, userId, assetObj->srcBundleName_);
96    if (fileList.empty()) {
97        LOGE("get fileList is empty.");
98        HandlePushAssetFail(socketId, assetObj);
99        return;
100    }
101
102    std::string sendFileName;
103    bool isSingleFile;
104    ret = HandleZip(fileList, assetObj, sendFileName, isSingleFile);
105    if (ret != E_OK) {
106        LOGE("zip files fail. socketId is %{public}d", socketId);
107        HandlePushAssetFail(socketId, assetObj);
108        SoftBusHandlerAsset::GetInstance().RemoveFile(sendFileName, !isSingleFile);
109        return;
110    }
111
112    ret = SoftBusHandlerAsset::GetInstance().AssetSendFile(socketId, sendFileName, isSingleFile);
113    if (ret != E_OK) {
114        LOGE("ExecutePushAsset send file fail, ret %{public}d", ret);
115        HandlePushAssetFail(socketId, assetObj);
116        SoftBusHandlerAsset::GetInstance().RemoveFile(sendFileName, !isSingleFile);
117        return;
118    }
119}
120
121void DaemonExecute::ExecuteRequestSendFile(const AppExecFwk::InnerEvent::Pointer &event)
122{
123    if (event == nullptr) {
124        LOGI("eventhandler fail.");
125        return;
126    }
127    auto requestSendFileData = event->GetSharedObject<RequestSendFileData>();
128    if (requestSendFileData == nullptr) {
129        LOGE("requestSendFileData is nullptr.");
130        return;
131    }
132
133    auto requestSendFileBlock  = requestSendFileData->requestSendFileBlock_;
134    if (requestSendFileBlock == nullptr) {
135        LOGE("requestSendFileBlock is nullptr.");
136        return;
137    }
138    std::string srcUri = requestSendFileData->srcUri_;
139    std::string dstPath  = requestSendFileData->dstPath_;
140    std::string dstDeviceId  = requestSendFileData->dstDeviceId_;
141    std::string sessionName  = requestSendFileData->sessionName_;
142    if (srcUri.empty() || dstDeviceId.empty() || sessionName.empty()) {
143        LOGE("params empty. %{public}s, %{public}s", sessionName.c_str(), Utils::GetAnonyString(dstDeviceId).c_str());
144        requestSendFileBlock->SetValue(ERR_BAD_VALUE);
145        return;
146    }
147
148    requestSendFileBlock->SetValue(RequestSendFileInner(srcUri, dstPath, dstDeviceId, sessionName));
149}
150
151int32_t DaemonExecute::RequestSendFileInner(const std::string &srcUri,
152                                            const std::string &dstPath,
153                                            const std::string &dstDeviceId,
154                                            const std::string &sessionName)
155{
156    LOGI("RequestSendFile begin dstDeviceId: %{public}s", Utils::GetAnonyString(dstDeviceId).c_str());
157    auto resourceReq = AllConnectManager::GetInstance().BuildResourceRequest();
158    int32_t ret = AllConnectManager::GetInstance().ApplyAdvancedResource(dstDeviceId, resourceReq.get());
159    if (ret != E_OK) {
160        LOGE("ApplyAdvancedResource fail, ret is %{public}d", ret);
161        return ERR_APPLY_RESULT;
162    }
163
164    int32_t socketId;
165    ret = SoftBusHandler::GetInstance().OpenSession(sessionName, sessionName, dstDeviceId, socketId);
166    if (ret != E_OK) {
167        LOGE("OpenSession failed, ret is %{public}d", ret);
168        return ret;
169    }
170    AllConnectManager::GetInstance().PublishServiceState(dstDeviceId,
171                                                         ServiceCollaborationManagerBussinessStatus::SCM_CONNECTED);
172    LOGI("RequestSendFile OpenSession success");
173
174    ret = SoftBusHandler::GetInstance().CopySendFile(socketId, sessionName, srcUri, dstPath);
175    if (ret != E_OK) {
176        LOGE("CopySendFile failed, ret is %{public}d", ret);
177        SoftBusHandler::GetInstance().CloseSession(socketId, sessionName);
178        return ret;
179    }
180    return E_OK;
181}
182
183std::string DaemonExecute::GetZipName(const std::string &relativePath)
184{
185    auto cppnow = std::chrono::system_clock::now();
186    auto cppnow_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(cppnow);
187    auto value = std::to_string(cppnow_ms.time_since_epoch().count());
188
189    std::random_device rd;
190    std::string random = std::to_string(rd());
191    std::string zipName = value + "_" + random + ".zip";
192
193    while (std::filesystem::exists(relativePath + zipName)) {
194        random = std::to_string(rd());
195        zipName = value + "_" + random + ".zip";
196    }
197    LOGI("zipName is %{public}s", zipName.c_str());
198    return zipName;
199}
200
201std::vector<std::string> DaemonExecute::GetFileList(const std::vector<std::string> &uris,
202                                                    int32_t userId,
203                                                    const std::string &srcBundleName)
204{
205    std::vector<std::string> fileList;
206    std::regex pattern("/mnt/hmdfs/\\d{3,}/account/device_view/local/data/.*");
207    for (const auto &uri : uris) {
208        size_t pos = uri.find(srcBundleName);
209        if (pos == std::string::npos) {
210            LOGE("srcBundleName not find in uri.");
211            return {};
212        }
213
214        std::string physicalPath;
215        int32_t ret = SandboxHelper::GetPhysicalPath(uri, std::to_string(userId), physicalPath);
216        if (ret != E_OK) {
217            LOGE("invalid uri, ret = %{public}d", ret);
218            return {};
219        }
220        if (!SandboxHelper::CheckValidPath(physicalPath)) {
221            LOGE("invalid path : %{public}s", GetAnonyString(physicalPath).c_str());
222            return {};
223        }
224        if (OHOS::Storage::DistributedFile::Utils::IsFolder(physicalPath)) {
225            LOGE("uri is folder are not supported now.");
226            return {};
227        }
228        if (!std::regex_match(physicalPath, pattern)) {
229            LOGE("physicalPath is not hmdfs path.");
230        }
231        fileList.emplace_back(physicalPath);
232    }
233    LOGI("GetFileList success, file num is %{public}s", std::to_string(fileList.size()).c_str());
234    return fileList;
235}
236
237int32_t DaemonExecute::HandleZip(const std::vector<std::string> &fileList,
238                                 const sptr<AssetObj> &assetObj,
239                                 std::string &sendFileName,
240                                 bool &isSingleFile)
241{
242    if (fileList.size() > 1) {
243        size_t pos = fileList[0].find(assetObj->srcBundleName_);
244        if (pos == std::string::npos) {
245            LOGE("srcBundleName not find in uri.");
246            return E_ZIP;
247        }
248        std::string relativePath = fileList[0].substr(0, pos + assetObj->srcBundleName_.length()) + "/";
249        sendFileName = relativePath + GetZipName(relativePath);
250        int32_t ret = SoftBusHandlerAsset::GetInstance().CompressFile(fileList, relativePath, sendFileName);
251        if (ret != E_OK) {
252            LOGE("zip ffiles fail.");
253            return E_ZIP;
254        }
255        isSingleFile = false;
256        SoftBusAssetSendListener::AddFileMap(assetObj->srcBundleName_ + assetObj->sessionId_, false);
257        return E_OK;
258    } else {
259        sendFileName = fileList[0];
260        isSingleFile = true;
261        SoftBusAssetSendListener::AddFileMap(assetObj->srcBundleName_ + assetObj->sessionId_, true);
262        return E_OK;
263    }
264}
265
266void DaemonExecute::HandlePushAssetFail(int32_t socketId, const sptr<AssetObj> &assetObj)
267{
268    auto taskId = assetObj->srcBundleName_ + assetObj->sessionId_;
269    AssetCallbackManager::GetInstance().NotifyAssetSendResult(taskId, assetObj, FileManagement::E_EVENT_HANDLER);
270    SoftBusHandlerAsset::GetInstance().closeAssetBind(socketId);
271    AssetCallbackManager::GetInstance().RemoveSendCallback(taskId);
272    SoftBusAssetSendListener::RemoveFileMap(taskId);
273}
274} // namespace DistributedFile
275} // namespace Storage
276} // namespace OHOS
277