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 "trans_listener.h"
17
18 #include <dirent.h>
19 #include <filesystem>
20 #include <random>
21
22 #include "ipc_skeleton.h"
23 #include "sandbox_helper.h"
24 #include "uri.h"
25 #include "n_error.h"
26 #include "dfs_event_dfx.h"
27
28 namespace OHOS {
29 namespace FileManagement {
30 namespace ModuleFileIO {
31 using namespace OHOS::AppFileService;
32 using namespace AppFileService::ModuleFileUri;
33 const std::string NETWORK_PARA = "?networkid=";
34 const std::string FILE_MANAGER_AUTHORITY = "docs";
35 const std::string MEDIA_AUTHORITY = "media";
36 const std::string DISTRIBUTED_PATH = "/data/storage/el2/distributedfiles/";
37 std::atomic<uint32_t> TransListener::getSequenceId_ = 0;
38
RmDir(const std::string & path)39 void TransListener::RmDir(const std::string &path)
40 {
41 HILOGI("RmDirm path : %{public}s", path.c_str());
42 std::filesystem::path pathName(path);
43 std::error_code errCode;
44 if (std::filesystem::exists(pathName, errCode)) {
45 std::filesystem::remove_all(pathName, errCode);
46 if (errCode.value() != 0) {
47 HILOGE("Failed to remove directory, error code: %{public}d", errCode.value());
48 }
49 } else {
50 HILOGE("pathName is not exists, error code: %{public}d", errCode.value());
51 }
52 }
53
CreateDfsCopyPath()54 std::string TransListener::CreateDfsCopyPath()
55 {
56 std::random_device rd;
57 std::string random = std::to_string(rd());
58 while (std::filesystem::exists(DISTRIBUTED_PATH + random)) {
59 random = std::to_string(rd());
60 }
61 return random;
62 }
63
HandleCopyFailure(CopyEvent & copyEvent,const Storage::DistributedFile::HmdfsInfo & info,const std::string & disSandboxPath,const std::string & currentId)64 NError TransListener::HandleCopyFailure(CopyEvent ©Event, const Storage::DistributedFile::HmdfsInfo &info,
65 const std::string &disSandboxPath, const std::string ¤tId)
66 {
67 if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) {
68 RmDir(disSandboxPath);
69 }
70 auto it = softbusErr2ErrCodeTable.find(copyEvent.errorCode);
71 if (it == softbusErr2ErrCodeTable.end()) {
72 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED,
73 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE,
74 RadarReporter::SEND_FILE_ERROR, RadarReporter::CONCURRENT_ID, currentId,
75 RadarReporter::PACKAGE_NAME, to_string(copyEvent.errorCode));
76 return NError(EIO);
77 }
78 if (copyEvent.errorCode != DFS_CANCEL_SUCCESS) {
79 HILOGE("HandleCopyFailure failed, copyEvent.errorCode = %{public}d.", copyEvent.errorCode);
80 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED,
81 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE,
82 RadarReporter::SEND_FILE_ERROR, RadarReporter::CONCURRENT_ID, currentId,
83 RadarReporter::PACKAGE_NAME, to_string(copyEvent.errorCode));
84 }
85 return NError(it->second);
86 }
87
WaitForCopyResult(TransListener * transListener)88 int TransListener::WaitForCopyResult(TransListener* transListener)
89 {
90 if (transListener == nullptr) {
91 HILOGE("transListener is nullptr");
92 return FAILED;
93 }
94 std::unique_lock<std::mutex> lock(transListener->cvMutex_);
95 transListener->cv_.wait(lock, [&transListener]() {
96 return transListener->copyEvent_.copyResult == SUCCESS ||
97 transListener->copyEvent_.copyResult == FAILED;
98 });
99 return transListener->copyEvent_.copyResult;
100 }
101
CopyFileFromSoftBus(const std::string & srcUri,const std::string & destUri,std::shared_ptr<FileInfos> fileInfos,std::shared_ptr<JsCallbackObject> callback)102 NError TransListener::CopyFileFromSoftBus(const std::string &srcUri, const std::string &destUri,
103 std::shared_ptr<FileInfos> fileInfos, std::shared_ptr<JsCallbackObject> callback)
104 {
105 HILOGI("CopyFileFromSoftBus begin.");
106 std::string currentId = "CopyFile_" + std::to_string(getpid()) + "_" + std::to_string(getSequenceId_);
107 ++getSequenceId_;
108 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_SUCCESS,
109 RadarReporter::BIZ_STATE, RadarReporter::DFX_BEGIN, RadarReporter::PACKAGE_NAME, std::to_string(getpid()),
110 RadarReporter::CONCURRENT_ID, currentId);
111 sptr<TransListener> transListener = new (std::nothrow) TransListener();
112 if (transListener == nullptr) {
113 HILOGE("new trans listener failed");
114 return NError(ENOMEM);
115 }
116 transListener->callback_ = std::move(callback);
117
118 Storage::DistributedFile::HmdfsInfo info{};
119 Uri uri(destUri);
120 info.authority = uri.GetAuthority();
121 info.sandboxPath = SandboxHelper::Decode(uri.GetPath());
122 std::string disSandboxPath;
123 auto ret = PrepareCopySession(srcUri, destUri, transListener, info, disSandboxPath);
124 if (ret != ERRNO_NOERR) {
125 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED,
126 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE,
127 RadarReporter::PREPARE_COPY_SESSION_ERROR, RadarReporter::CONCURRENT_ID, currentId,
128 RadarReporter::PACKAGE_NAME, to_string(ret));
129 return NError(EIO);
130 }
131 if (fileInfos->taskSignal != nullptr) {
132 fileInfos->taskSignal->SetFileInfoOfRemoteTask(info.sessionName, fileInfos->srcPath);
133 }
134 auto copyResult = WaitForCopyResult(transListener);
135 if (copyResult == FAILED) {
136 return HandleCopyFailure(transListener->copyEvent_, info, disSandboxPath, currentId);
137 }
138 if (info.authority == FILE_MANAGER_AUTHORITY || info.authority == MEDIA_AUTHORITY) {
139 HILOGW("Public or media path not copy");
140 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_SUCCESS,
141 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::CONCURRENT_ID, currentId);
142 return NError(ERRNO_NOERR);
143 }
144
145 ret = CopyToSandBox(srcUri, disSandboxPath, info.sandboxPath, currentId);
146 RmDir(disSandboxPath);
147 if (ret != ERRNO_NOERR) {
148 HILOGE("CopyToSandBox failed, ret = %{public}d.", ret);
149 return NError(EIO);
150 }
151 return NError(ERRNO_NOERR);
152 }
153
PrepareCopySession(const std::string & srcUri,const std::string & destUri,TransListener * transListener,Storage::DistributedFile::HmdfsInfo & info,std::string & disSandboxPath)154 int32_t TransListener::PrepareCopySession(const std::string &srcUri,
155 const std::string &destUri,
156 TransListener* transListener,
157 Storage::DistributedFile::HmdfsInfo &info,
158 std::string &disSandboxPath)
159 {
160 std::string tmpDir;
161 if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) {
162 tmpDir = CreateDfsCopyPath();
163 disSandboxPath = DISTRIBUTED_PATH + tmpDir;
164 std::error_code errCode;
165 if (!std::filesystem::create_directory(disSandboxPath, errCode)) {
166 HILOGE("Create dir failed, error code: %{public}d", errCode.value());
167 return errCode.value();
168 }
169
170 auto pos = info.sandboxPath.rfind('/');
171 if (pos == std::string::npos) {
172 HILOGE("invalid file path");
173 return EIO;
174 }
175 auto sandboxDir = info.sandboxPath.substr(0, pos);
176 if (std::filesystem::exists(sandboxDir, errCode)) {
177 info.dirExistFlag = true;
178 }
179 }
180
181 info.copyPath = tmpDir;
182 auto networkId = GetNetworkIdFromUri(srcUri);
183 HILOGI("dfs PrepareSession begin.");
184 auto ret = Storage::DistributedFile::DistributedFileDaemonManager::GetInstance().PrepareSession(srcUri, destUri,
185 networkId, transListener, info);
186 if (ret != ERRNO_NOERR) {
187 HILOGE("PrepareSession failed, ret = %{public}d.", ret);
188 if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) {
189 RmDir(disSandboxPath);
190 }
191 return EIO;
192 }
193 return ERRNO_NOERR;
194 }
195
CopyToSandBox(const std::string & srcUri,const std::string & disSandboxPath,const std::string & sandboxPath,const std::string & currentId)196 int32_t TransListener::CopyToSandBox(const std::string &srcUri, const std::string &disSandboxPath,
197 const std::string &sandboxPath, const std::string ¤tId)
198 {
199 std::error_code errCode;
200 if (std::filesystem::exists(sandboxPath) && std::filesystem::is_directory(sandboxPath)) {
201 HILOGI("Copy dir");
202 std::filesystem::copy(disSandboxPath, sandboxPath,
203 std::filesystem::copy_options::recursive | std::filesystem::copy_options::update_existing, errCode);
204 if (errCode.value() != 0) {
205 HILOGE("Copy dir failed: errCode: %{public}d", errCode.value());
206 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED,
207 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE,
208 RadarReporter::COPY_TO_SANDBOX_ERROR, RadarReporter::CONCURRENT_ID, currentId,
209 RadarReporter::PACKAGE_NAME, to_string(errCode.value()));
210 return EIO;
211 }
212 } else {
213 HILOGI("Copy file.");
214 Uri uri(srcUri);
215 auto fileName = GetFileName(uri.GetPath());
216 if (fileName.empty()) {
217 HILOGE("Get filename failed");
218 RmDir(disSandboxPath);
219 return EIO;
220 }
221 std::filesystem::copy(disSandboxPath + fileName, sandboxPath, std::filesystem::copy_options::update_existing,
222 errCode);
223 if (errCode.value() != 0) {
224 HILOGE("Copy file failed: errCode: %{public}d", errCode.value());
225 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED,
226 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE,
227 RadarReporter::COPY_TO_SANDBOX_ERROR, RadarReporter::CONCURRENT_ID, currentId,
228 RadarReporter::PACKAGE_NAME, to_string(errCode.value()));
229 return EIO;
230 }
231 }
232 HILOGI("Copy file success.");
233 RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_SUCCESS,
234 RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::CONCURRENT_ID, currentId);
235 return ERRNO_NOERR;
236 }
237
GetFileName(const std::string & path)238 std::string TransListener::GetFileName(const std::string &path)
239 {
240 auto pos = path.find_last_of('/');
241 if (pos == std::string::npos) {
242 HILOGE("invalid path");
243 return "";
244 }
245 return SandboxHelper::Decode(path.substr(pos));
246 }
247
GetNetworkIdFromUri(const std::string & uri)248 std::string TransListener::GetNetworkIdFromUri(const std::string &uri)
249 {
250 return uri.substr(uri.find(NETWORK_PARA) + NETWORK_PARA.size(), uri.size());
251 }
252
CallbackComplete(uv_work_t * work,int stat)253 void TransListener::CallbackComplete(uv_work_t *work, int stat)
254 {
255 if (work == nullptr) {
256 HILOGE("Failed to get uv_queue_work pointer");
257 return;
258 }
259
260 std::shared_ptr<UvEntry> entry(static_cast<UvEntry *>(work->data), [work](UvEntry *data) {
261 delete data;
262 delete work;
263 });
264 if (entry == nullptr) {
265 HILOGE("entry pointer is nullptr.");
266 return;
267 }
268 napi_handle_scope scope = nullptr;
269 napi_env env = entry->callback->env;
270 napi_status status = napi_open_handle_scope(env, &scope);
271 if (status != napi_ok) {
272 HILOGE("Failed to open handle scope, status: %{public}d.", status);
273 return;
274 }
275 NVal obj = NVal::CreateObject(env);
276 if (entry->progressSize <= MAX_VALUE && entry->totalSize <= MAX_VALUE) {
277 obj.AddProp("processedSize", NVal::CreateInt64(env, entry->progressSize).val_);
278 obj.AddProp("totalSize", NVal::CreateInt64(env, entry->totalSize).val_);
279 }
280
281 napi_value result = nullptr;
282 napi_value jsCallback = entry->callback->nRef.Deref(env).val_;
283 status = napi_call_function(env, nullptr, jsCallback, 1, &(obj.val_), &result);
284 if (status != napi_ok) {
285 HILOGE("Failed to get result, status: %{public}d.", status);
286 }
287 status = napi_close_handle_scope(env, scope);
288 if (status != napi_ok) {
289 HILOGE("Failed to close scope, status: %{public}d.", status);
290 }
291 }
292
OnFileReceive(uint64_t totalBytes,uint64_t processedBytes)293 int32_t TransListener::OnFileReceive(uint64_t totalBytes, uint64_t processedBytes)
294 {
295 std::lock_guard<std::mutex> lock(callbackMutex_);
296 if (callback_ == nullptr) {
297 HILOGE("Failed to parse watcher callback");
298 return ENOMEM;
299 }
300
301 uv_loop_s *loop = nullptr;
302 napi_get_uv_event_loop(callback_->env, &loop);
303 if (loop == nullptr) {
304 HILOGE("Failed to get uv event loop");
305 return ENOMEM;
306 }
307
308 uv_work_t *work = new (std::nothrow) uv_work_t;
309 if (work == nullptr) {
310 HILOGE("Failed to create uv_work_t pointer");
311 return ENOMEM;
312 }
313
314 UvEntry *entry = new (std::nothrow) UvEntry(callback_);
315 if (entry == nullptr) {
316 HILOGE("entry ptr is nullptr");
317 delete work;
318 return ENOMEM;
319 }
320 entry->progressSize = processedBytes;
321 entry->totalSize = totalBytes;
322 work->data = entry;
323 int retVal = uv_queue_work(
324 loop, work, [](uv_work_t *work) {}, reinterpret_cast<uv_after_work_cb>(CallbackComplete));
325 if (retVal != 0) {
326 HILOGE("failed to get uv_queue_work");
327 delete (reinterpret_cast<UvEntry *>(work->data));
328 delete work;
329 return ENOMEM;
330 }
331 return ERRNO_NOERR;
332 }
333
OnFinished(const std::string & sessionName)334 int32_t TransListener::OnFinished(const std::string &sessionName)
335 {
336 HILOGI("OnFinished");
337 {
338 std::lock_guard<std::mutex> lock(callbackMutex_);
339 callback_ = nullptr;
340 }
341 {
342 std::lock_guard<std::mutex> lock(cvMutex_);
343 copyEvent_.copyResult = SUCCESS;
344 cv_.notify_all();
345 }
346 return ERRNO_NOERR;
347 }
348
OnFailed(const std::string & sessionName,int32_t errorCode)349 int32_t TransListener::OnFailed(const std::string &sessionName, int32_t errorCode)
350 {
351 HILOGI("OnFailed, errorCode is %{public}d", errorCode);
352 {
353 std::lock_guard<std::mutex> lock(callbackMutex_);
354 callback_ = nullptr;
355 }
356 {
357 std::lock_guard<std::mutex> lock(cvMutex_);
358 copyEvent_.copyResult = FAILED;
359 copyEvent_.errorCode = errorCode;
360 cv_.notify_all();
361 }
362 return ERRNO_NOERR;
363 }
364 } // namespace ModuleFileIO
365 } // namespace FileManagement
366 } // namespace OHOS