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 "translistener.h"
17 #include <filesystem>
18 #include <random>
19 #include <thread>
20 #include "sandbox_helper.h"
21 #include "uri.h"
22 #include "uni_error.h"
23
24 using Uri = OHOS::Uri;
25 namespace OHOS {
26 namespace CJSystemapi {
27 using namespace FileFs;
28 const std::string NETWORK_PARA = "?networkid=";
29 const std::string FILE_MANAGER_AUTHORITY = "docs";
30 const std::string MEDIA_AUTHORITY = "media";
31 const std::string DISTRIBUTED_PATH = "/data/storage/el2/distributedfiles/";
32
RmDir(const std::string & path)33 void TransListener::RmDir(const std::string &path)
34 {
35 LOGI("RmDirm path : %{public}s", path.c_str());
36 std::filesystem::path pathName(path);
37 std::error_code errCode;
38 if (std::filesystem::exists(pathName, errCode)) {
39 std::filesystem::remove_all(pathName, errCode);
40 if (errCode.value() != 0) {
41 LOGE("Failed to remove directory, error code: %{public}d", errCode.value());
42 }
43 } else {
44 LOGE("pathName is not exists, error code: %{public}d", errCode.value());
45 }
46 }
47
CreateDfsCopyPath()48 std::string TransListener::CreateDfsCopyPath()
49 {
50 std::random_device rd;
51 std::string random = std::to_string(rd());
52 while (std::filesystem::exists(DISTRIBUTED_PATH + random)) {
53 random = std::to_string(rd());
54 }
55 return random;
56 }
57
CopyFileFromSoftBus(const std::string & srcUri,const std::string & destUri,std::shared_ptr<FileInfos> fileInfos,std::shared_ptr<CjCallbackObject> callback)58 int32_t TransListener::CopyFileFromSoftBus(const std::string& srcUri, const std::string& destUri,
59 std::shared_ptr<FileInfos> fileInfos, std::shared_ptr<CjCallbackObject> callback)
60 {
61 LOGI("CopyFileFromSoftBus begin.");
62 sptr<TransListener> transListener = new (std::nothrow) TransListener();
63 if (transListener == nullptr) {
64 LOGE("new trans listener failed");
65 return ENOMEM;
66 }
67 transListener->callback_ = std::move(callback);
68 Storage::DistributedFile::HmdfsInfo info{};
69 Uri uri(destUri);
70 info.authority = uri.GetAuthority();
71 info.sandboxPath = AppFileService::SandboxHelper::Decode(uri.GetPath());
72 std::string disSandboxPath;
73 auto ret = PrepareCopySession(srcUri, destUri, transListener, info, disSandboxPath);
74 if (ret != 0) {
75 LOGE("PrepareCopySession failed, ret = %{public}d.", ret);
76 return EIO;
77 }
78 if (fileInfos->taskSignal != nullptr) {
79 fileInfos->taskSignal->SetFileInfoOfRemoteTask(info.sessionName, fileInfos->srcPath);
80 }
81 std::unique_lock<std::mutex> lock(transListener->cvMutex_);
82 transListener->cv_.wait(lock, [&transListener]() {
83 return transListener->copyEvent_.copyResult == SUCCESS ||
84 transListener->copyEvent_.copyResult == FAILED;
85 });
86 LOGI("dfs PrepareSession Finish, result is %{public}d", transListener->copyEvent_.copyResult);
87 if (transListener->copyEvent_.copyResult == FAILED) {
88 if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) {
89 RmDir(disSandboxPath);
90 }
91 auto it = softbusErr2ErrCodeTable.find(transListener->copyEvent_.errorCode);
92 if (it == softbusErr2ErrCodeTable.end()) {
93 return EIO;
94 }
95 return it->second;
96 }
97 if (info.authority == FILE_MANAGER_AUTHORITY || info.authority == MEDIA_AUTHORITY) {
98 LOGE("Public or media path not copy");
99 return 0;
100 }
101 ret = CopyToSandBox(srcUri, disSandboxPath, info.sandboxPath);
102 RmDir(disSandboxPath);
103 if (ret != 0) {
104 LOGE("CopyToSandBox failed, ret = %{public}d.", ret);
105 return EIO;
106 }
107 return 0;
108 }
109
PrepareCopySession(const std::string & srcUri,const std::string & destUri,TransListener * transListener,Storage::DistributedFile::HmdfsInfo & info,std::string & disSandboxPath)110 int32_t TransListener::PrepareCopySession(const std::string &srcUri,
111 const std::string &destUri,
112 TransListener* transListener,
113 Storage::DistributedFile::HmdfsInfo &info,
114 std::string &disSandboxPath)
115 {
116 std::string tmpDir;
117 if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) {
118 tmpDir = CreateDfsCopyPath();
119 disSandboxPath = DISTRIBUTED_PATH + tmpDir;
120 std::error_code errCode;
121 if (!std::filesystem::create_directory(disSandboxPath, errCode)) {
122 LOGE("Create dir failed, error code: %{public}d", errCode.value());
123 return errCode.value();
124 }
125
126 auto pos = info.sandboxPath.rfind('/');
127 if (pos == std::string::npos) {
128 LOGE("invalid file path");
129 return EIO;
130 }
131 auto sandboxDir = info.sandboxPath.substr(0, pos);
132 if (std::filesystem::exists(sandboxDir, errCode)) {
133 info.dirExistFlag = true;
134 }
135 }
136
137 info.copyPath = tmpDir;
138 auto networkId = GetNetworkIdFromUri(srcUri);
139 LOGI("dfs PrepareSession begin.");
140 auto ret = Storage::DistributedFile::DistributedFileDaemonManager::GetInstance().PrepareSession(srcUri, destUri,
141 networkId, transListener, info);
142 if (ret != ERRNO_NOERR) {
143 LOGE("PrepareSession failed, ret = %{public}d.", ret);
144 if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) {
145 RmDir(disSandboxPath);
146 }
147 return EIO;
148 }
149 return ERRNO_NOERR;
150 }
151
CopyToSandBox(const std::string & srcUri,const std::string & disSandboxPath,const std::string & sandboxPath)152 int32_t TransListener::CopyToSandBox(const std::string &srcUri, const std::string &disSandboxPath,
153 const std::string &sandboxPath)
154 {
155 std::error_code errCode;
156 if (std::filesystem::exists(sandboxPath) && std::filesystem::is_directory(sandboxPath)) {
157 LOGI("Copy dir");
158 std::filesystem::copy(disSandboxPath, sandboxPath,
159 std::filesystem::copy_options::recursive | std::filesystem::copy_options::update_existing, errCode);
160 if (errCode.value() != 0) {
161 LOGE("Copy dir failed: errCode: %{public}d", errCode.value());
162 return EIO;
163 }
164 } else {
165 LOGI("Copy file.");
166 Uri uri(srcUri);
167 auto fileName = GetFileName(uri.GetPath());
168 if (fileName.empty()) {
169 LOGE("Get filename failed");
170 RmDir(disSandboxPath);
171 return EIO;
172 }
173 std::filesystem::copy(disSandboxPath + fileName, sandboxPath, std::filesystem::copy_options::update_existing,
174 errCode);
175 if (errCode.value() != 0) {
176 LOGE("Copy file failed: errCode: %{public}d", errCode.value());
177 return EIO;
178 }
179 }
180 LOGI("Copy file success.");
181 return ERRNO_NOERR;
182 }
183
GetFileName(const std::string & path)184 std::string TransListener::GetFileName(const std::string &path)
185 {
186 auto pos = path.find_last_of('/');
187 if (pos == std::string::npos) {
188 LOGE("invalid path");
189 return "";
190 }
191 return AppFileService::SandboxHelper::Decode(path.substr(pos));
192 }
193
GetNetworkIdFromUri(const std::string & uri)194 std::string TransListener::GetNetworkIdFromUri(const std::string &uri)
195 {
196 return uri.substr(uri.find(NETWORK_PARA) + NETWORK_PARA.size(), uri.size());
197 }
198
CallbackComplete(TransListener * transListener,CProgress progress)199 void TransListener::CallbackComplete(TransListener* transListener, CProgress progress)
200 {
201 if (transListener == nullptr ||
202 transListener->callback_ == nullptr ||
203 transListener->callback_->callback == nullptr) {
204 LOGE("Failed to get copy progress callback.");
205 return;
206 }
207 transListener->callback_->callback(progress);
208 }
209
OnFileReceive(uint64_t totalBytes,uint64_t processedBytes)210 int32_t TransListener::OnFileReceive(uint64_t totalBytes, uint64_t processedBytes)
211 {
212 std::lock_guard<std::mutex> lock(callbackMutex_);
213 if (callback_ == nullptr) {
214 LOGE("Failed to parse watcher callback");
215 return ENOMEM;
216 }
217 CProgress progress = { .processedSize = processedBytes, .totalSize = totalBytes };
218 std::thread([this, progress]() {
219 CallbackComplete(this, progress);
220 }).detach();
221 return ERRNO_NOERR;
222 }
223
OnFinished(const std::string & sessionName)224 int32_t TransListener::OnFinished(const std::string &sessionName)
225 {
226 LOGI("OnFinished");
227 {
228 std::lock_guard<std::mutex> lock(callbackMutex_);
229 callback_ = nullptr;
230 }
231 copyEvent_.copyResult = SUCCESS;
232 cv_.notify_all();
233 return ERRNO_NOERR;
234 }
235
OnFailed(const std::string & sessionName,int32_t errorCode)236 int32_t TransListener::OnFailed(const std::string &sessionName, int32_t errorCode)
237 {
238 LOGI("OnFailed, errorCode is %{public}d", errorCode);
239 {
240 std::lock_guard<std::mutex> lock(callbackMutex_);
241 callback_ = nullptr;
242 }
243 copyEvent_.copyResult = FAILED;
244 copyEvent_.errorCode = errorCode;
245 cv_.notify_all();
246 return ERRNO_NOERR;
247 }
248 }
249 }
250