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 "network/softbus/softbus_asset_recv_listener.h"
17 
18 #include <filesystem>
19 #include <memory>
20 
21 #include "accesstoken_kit.h"
22 #include "asset_callback_manager.h"
23 #include "dfs_error.h"
24 #include "ipc_skeleton.h"
25 #include "network/softbus/softbus_handler_asset.h"
26 #include "os_account_manager.h"
27 #include "refbase.h"
28 #include "utils_log.h"
29 
30 namespace OHOS {
31 namespace Storage {
32 namespace DistributedFile {
33 const std::string HMDFS_PATH = "/mnt/hmdfs/{userId}/account/device_view/local/data/";
34 const std::string USRT_ID_FLAG = "{userId}";
35 const std::string TEMP_DIR = "ASSET_TEMP/";
36 const std::string ASSET_FLAG_SINGLE = ".asset_single?";
37 const std::string ASSET_FLAG_ZIP = ".asset_zip?";
OnFile(int32_t socket,FileEvent * event)38 void SoftbusAssetRecvListener::OnFile(int32_t socket, FileEvent *event)
39 {
40     if (event == nullptr) {
41         LOGE("invalid parameter");
42         return;
43     }
44     switch (event->type) {
45         case FILE_EVENT_RECV_UPDATE_PATH:
46             event->UpdateRecvPath = GetRecvPath;
47             break;
48         case FILE_EVENT_RECV_START:
49             OnRecvAssetStart(socket, event->files, event->fileCnt);
50             break;
51         case FILE_EVENT_RECV_FINISH:
52             OnRecvAssetFinished(socket, event->files, event->fileCnt);
53             break;
54         case FILE_EVENT_RECV_ERROR:
55             OnRecvAssetError(socket, event->errorCode);
56             break;
57         default:
58             LOGI("Other situations");
59             break;
60     }
61 }
62 
GetRecvPath()63 const char* SoftbusAssetRecvListener::GetRecvPath()
64 {
65     int32_t userId = GetCurrentUserId();
66 
67     std::string path = HMDFS_PATH;
68     auto pos = path.find(USRT_ID_FLAG);
69     if (pos == std::string::npos) {
70         return "";
71     }
72 
73     path_ = path.replace(pos, USRT_ID_FLAG.length(), std::to_string(userId));
74     const char* recvPath = path_.c_str();
75     LOGI("SoftbusAssetRecvListener GetRecvPath: %{public}s", recvPath);
76     return recvPath;
77 }
78 
OnRecvAssetStart(int32_t socketId,const char ** fileList,int32_t fileCnt)79 void SoftbusAssetRecvListener::OnRecvAssetStart(int32_t socketId, const char **fileList, int32_t fileCnt)
80 {
81     LOGI("OnRecvFileStart, sessionId = %{public}d, fileCnt = %{public}d", socketId, fileCnt);
82     if (fileCnt == 0) {
83         LOGE("fileList has no file");
84         return;
85     }
86     auto srcNetworkId = SoftBusHandlerAsset::GetInstance().GetClientInfo(socketId);
87     if (srcNetworkId.empty()) {
88         LOGE("get srcNetworkId fail");
89         return;
90     }
91     std::string filePath(path_ + fileList[0]);
92     sptr<AssetObj> assetObj (new (std::nothrow) AssetObj());
93     int32_t ret = SoftBusHandlerAsset::GetInstance().GenerateAssetObjInfo(socketId, filePath, assetObj);
94     if (ret != FileManagement::ERR_OK) {
95         LOGE("Generate assetObjInfo fail");
96         return;
97     }
98     AssetCallbackManager::GetInstance().NotifyAssetRecvStart(srcNetworkId,
99                                                              assetObj->dstNetworkId_,
100                                                              assetObj->sessionId_,
101                                                              assetObj->dstBundleName_);
102 }
103 
OnRecvAssetFinished(int32_t socketId,const char ** fileList,int32_t fileCnt)104 void SoftbusAssetRecvListener::OnRecvAssetFinished(int32_t socketId, const char **fileList, int32_t fileCnt)
105 {
106     LOGI("OnRecvFileFinished, sessionId = %{public}d, fileCnt = %{public}d", socketId, fileCnt);
107     if (fileCnt == 0) {
108         LOGE("fileList has no file");
109         return;
110     }
111     auto srcNetworkId = SoftBusHandlerAsset::GetInstance().GetClientInfo(socketId);
112     if (srcNetworkId.empty()) {
113         LOGE("get srcNetworkId fail");
114         return;
115     }
116     std::string firstFilePath(path_ + fileList[0]);
117     sptr<AssetObj> assetObj (new (std::nothrow) AssetObj());
118     int32_t ret = SoftBusHandlerAsset::GetInstance().GenerateAssetObjInfo(socketId, firstFilePath, assetObj);
119     if (ret != FileManagement::ERR_OK) {
120         LOGE("Generate assetObjInfo fail");
121         return;
122     }
123     for (int32_t i = 0; i < fileCnt; i++) {
124         std::string filePath(path_ + fileList[i]);
125         if (JudgeSingleFile(filePath)) {
126             ret = HandleSingleFile(socketId, filePath, assetObj);
127         } else {
128             ret = HandleZipFile(socketId, filePath, assetObj);
129         }
130 
131         if (ret != FileManagement::ERR_OK) {
132             LOGE("MoveAsset fail, socket %{public}d", socketId);
133             AssetCallbackManager::GetInstance().NotifyAssetRecvFinished(srcNetworkId, assetObj,
134                                                                         FileManagement::ERR_BAD_VALUE);
135             SoftBusHandlerAsset::GetInstance().RemoveClientInfo(socketId);
136             return;
137         }
138     }
139     RemoveAsset(firstFilePath);
140     AssetCallbackManager::GetInstance().NotifyAssetRecvFinished(srcNetworkId, assetObj, FileManagement::ERR_OK);
141     SoftBusHandlerAsset::GetInstance().RemoveClientInfo(socketId);
142 }
143 
OnRecvAssetError(int32_t socketId,int32_t errorCode)144 void SoftbusAssetRecvListener::OnRecvAssetError(int32_t socketId, int32_t errorCode)
145 {
146     LOGE("OnRecvAssetError, sessionId = %{public}d, errorCode = %{public}d", socketId, errorCode);
147     auto srcNetworkId = SoftBusHandlerAsset::GetInstance().GetClientInfo(socketId);
148     if (srcNetworkId.empty()) {
149         LOGE("get srcNetworkId fail");
150         return;
151     }
152     sptr<AssetObj> nullAssetObj (new (std::nothrow) AssetObj());
153 
154     AssetCallbackManager::GetInstance().NotifyAssetRecvFinished(srcNetworkId, nullAssetObj,
155                                                                 FileManagement::ERR_BAD_VALUE);
156     SoftBusHandlerAsset::GetInstance().RemoveClientInfo(socketId);
157 }
158 
OnAssetRecvBind(int32_t sessionId,PeerSocketInfo info)159 void SoftbusAssetRecvListener::OnAssetRecvBind(int32_t sessionId, PeerSocketInfo info)
160 {
161     LOGI("OnAssetRecvBind begin, sessionId %{public}d", sessionId);
162     SoftBusHandlerAsset::GetInstance().OnAssetRecvBind(sessionId, info.networkId);
163 }
164 
GetCurrentUserId()165 int32_t SoftbusAssetRecvListener::GetCurrentUserId()
166 {
167     std::vector<int32_t> userIds{};
168     auto ret = AccountSA::OsAccountManager::QueryActiveOsAccountIds(userIds);
169     if (ret != NO_ERROR || userIds.empty()) {
170         LOGE("query active os account id failed, ret = %{public}d", ret);
171         return FileManagement::E_GET_USER_ID;
172     }
173     LOGI("GetCurrentUserId end.");
174     return userIds[0];
175 }
176 
MoveAsset(const std::vector<std::string> & fileList,bool isSingleFile)177 bool SoftbusAssetRecvListener::MoveAsset(const std::vector<std::string> &fileList, bool isSingleFile)
178 {
179     if (isSingleFile) {
180         std::string oldPath = fileList[0];
181         std::string newPath = oldPath;
182         size_t pos = newPath.find(TEMP_DIR);
183         if (pos == std::string::npos) {
184             LOGE("get asset temp dir fail, file name is %{public}s", GetAnonyString(oldPath).c_str());
185             return false;
186         }
187         newPath.replace(pos, TEMP_DIR.length(), "");
188         pos = newPath.find(ASSET_FLAG_SINGLE);
189         if (pos == std::string::npos) {
190             LOGE("get asset flag fail, file name is %{public}s", GetAnonyString(oldPath).c_str());
191             return false;
192         }
193         newPath.resize(pos);
194         try {
195             SoftBusHandlerAsset::GetInstance().MkDirRecurse(newPath, S_IRWXU | S_IRWXG | S_IXOTH);
196             std::filesystem::rename(oldPath.c_str(), newPath.c_str());
197         } catch (const std::filesystem::filesystem_error &e) {
198             LOGE("rename file fail, file name is %{public}s", e.what());
199             return false;
200         }
201         return true;
202     }
203 
204     for (auto oldPath : fileList) {
205         std::string newPath = oldPath;
206         size_t pos = newPath.find(TEMP_DIR);
207         if (pos == std::string::npos) {
208             LOGE("get asset temp dir fail, file name is %{public}s", GetAnonyString(oldPath).c_str());
209             return false;
210         }
211         newPath.replace(pos, TEMP_DIR.length(), "");
212         try {
213             SoftBusHandlerAsset::GetInstance().MkDirRecurse(newPath, S_IRWXU | S_IRWXG | S_IXOTH);
214             std::filesystem::rename(oldPath.c_str(), newPath.c_str());
215         } catch (const std::filesystem::filesystem_error &e) {
216             LOGE("rename file fail, file name is %{public}s", e.what());
217             return false;
218         }
219     }
220     return true;
221 }
222 
RemoveAsset(const std::string & file)223 bool SoftbusAssetRecvListener::RemoveAsset(const std::string &file)
224 {
225     size_t pos = file.find(TEMP_DIR);
226     if (pos == std::string::npos) {
227         LOGE("get asset temp dir fail, file name is %{public}s", GetAnonyString(file).c_str());
228         return false;
229     }
230     std::string removePath = file.substr(0, pos + TEMP_DIR.length() - 1);
231     bool ret = std::filesystem::remove_all(removePath.c_str());
232     if (!ret) {
233         LOGE("remove file fail, remove path is %{public}s", GetAnonyString(removePath).c_str());
234         return false;
235     }
236     return true;
237 }
238 
HandleSingleFile(int32_t socketId,const std::string & filePath,const sptr<AssetObj> & assetObj)239 int32_t SoftbusAssetRecvListener::HandleSingleFile(int32_t socketId,
240                                                    const std::string &filePath,
241                                                    const sptr<AssetObj> &assetObj)
242 {
243     LOGI("HandleSingleFile begin.");
244     std::vector<std::string> fileList = {filePath};
245     auto uris = SoftBusHandlerAsset::GetInstance().GenerateUris(fileList, assetObj->dstBundleName_, true);
246     if (uris.size() == 0) {
247         LOGE("Generate uris fail");
248         return FileManagement::ERR_BAD_VALUE;
249     }
250     assetObj->uris_.emplace_back(uris[0]);
251 
252     bool moveRet = MoveAsset(fileList, true);
253     if (!moveRet) {
254         LOGE("MoveAsset fail, socket %{public}d", socketId);
255         return FileManagement::ERR_BAD_VALUE;
256     }
257     LOGI("HandleOneFile end.");
258     return FileManagement::ERR_OK;
259 }
260 
HandleZipFile(int32_t socketId,const std::string & filePath,const sptr<AssetObj> & assetObj)261 int32_t SoftbusAssetRecvListener::HandleZipFile(int32_t socketId,
262                                                 const std::string &filePath,
263                                                 const sptr<AssetObj> &assetObj)
264 {
265     LOGI("HandleZipFile begin.");
266     size_t pos = filePath.find(ASSET_FLAG_ZIP);
267     if (pos == std::string::npos) {
268         LOGE("filePath is not a zip file : %{public}s", GetAnonyString(filePath).c_str());
269         return FileManagement::ERR_BAD_VALUE;
270     }
271     std::string zipfilePath = filePath.substr(0, pos);
272     try {
273         std::filesystem::rename(filePath.c_str(), zipfilePath.c_str());
274     } catch (const std::filesystem::filesystem_error &e) {
275         LOGE("rename file fail, file name is %{public}s", e.what());
276         return FileManagement::ERR_BAD_VALUE;
277     }
278     pos = zipfilePath.rfind("/");
279     if (pos == std::string::npos) {
280         LOGE("filePath is not a zip file : %{public}s", GetAnonyString(filePath).c_str());
281         return FileManagement::ERR_BAD_VALUE;
282     }
283     std::string relativePath = zipfilePath.substr(0, pos + 1);
284     std::vector<std::string> fileList = SoftBusHandlerAsset::GetInstance().DecompressFile(zipfilePath, relativePath);
285     if (fileList.empty()) {
286         LOGE("unzip fail");
287         return FileManagement::ERR_BAD_VALUE;
288     }
289 
290     auto uris = SoftBusHandlerAsset::GetInstance().GenerateUris(fileList, assetObj->dstBundleName_, false);
291     if (uris.size() == 0) {
292         LOGE("Generate uris fail");
293         return FileManagement::ERR_BAD_VALUE;
294     }
295     assetObj->uris_.insert(assetObj->uris_.end(), uris.begin(), uris.end());
296 
297     bool moveRet = MoveAsset(fileList, false);
298     if (!moveRet) {
299         LOGE("MoveAsset fail, socket %{public}d", socketId);
300         return FileManagement::ERR_BAD_VALUE;
301     }
302     LOGI("HandleMoreFile end.");
303     return FileManagement::ERR_OK;
304 }
305 
JudgeSingleFile(const std::string & filePath)306 bool SoftbusAssetRecvListener::JudgeSingleFile(const std::string &filePath)
307 {
308     size_t pos = filePath.find(ASSET_FLAG_SINGLE);
309     if (pos == std::string::npos) {
310         LOGI("this file is zip file");
311         return false;
312     }
313     return true;
314 }
315 
OnRecvShutdown(int32_t sessionId,ShutdownReason reason)316 void SoftbusAssetRecvListener::OnRecvShutdown(int32_t sessionId, ShutdownReason reason)
317 {
318     LOGI("OnSessionClosed, sessionId = %{public}d, reason = %{public}d", sessionId, reason);
319 }
320 } // namespace DistributedFile
321 } // namespace Storage
322 } // namespace OHOS