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 &copyEvent, const Storage::DistributedFile::HmdfsInfo &info,
65     const std::string &disSandboxPath, const std::string &currentId)
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 &currentId)
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