• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_handler_asset.h"
17 
18 #include <filesystem>
19 #include <fstream>
20 #include <memory>
21 #include <regex>
22 #include <sstream>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 
26 #include "all_connect/all_connect_manager.h"
27 #include "asset_callback_manager.h"
28 #include "device_manager.h"
29 #include "dfs_error.h"
30 #include "dm_device_info.h"
31 #include "ipc_skeleton.h"
32 #include "network/softbus/softbus_asset_recv_listener.h"
33 #include "network/softbus/softbus_asset_send_listener.h"
34 #include "network/softbus/softbus_session_listener.h"
35 #include "network/softbus/softbus_session_pool.h"
36 #include "refbase.h"
37 #include "softbus_bus_center.h"
38 #include "utils_log.h"
39 
40 #ifdef SUPPORT_SAME_ACCOUNT
41 #include "inner_socket.h"
42 #include "trans_type_enhanced.h"
43 #endif
44 
45 namespace OHOS {
46 namespace Storage {
47 namespace DistributedFile {
48 using namespace OHOS::FileManagement;
49 constexpr size_t MAX_SIZE = 500;
50 constexpr size_t BUFFER_SIZE = 512;
51 const int32_t DFS_QOS_TYPE_MIN_BW = 90 * 1024 * 1024;
52 const int32_t DFS_QOS_TYPE_MAX_LATENCY = 10000;
53 const int32_t DFS_QOS_TYPE_MIN_LATENCY = 2000;
54 const uint32_t MAX_ONLINE_DEVICE_SIZE = 10000;
55 const std::string RELATIVE_PATH_FLAG = "/account/device_view/local/data/";
56 const std::string DST_BUNDLE_NAME_FLAG = "/";
57 const std::string TEMP_DIR = "ASSET_TEMP";
58 const std::string ASSET_POSTFIX_SINGLE = ".asset_single?";
59 const std::string ASSET_POSTFIX_ZIP = ".asset_zip?";
SoftBusHandlerAsset()60 SoftBusHandlerAsset::SoftBusHandlerAsset()
61 {
62     ISocketListener fileSendListener;
63     fileSendListener.OnBind = nullptr;
64     fileSendListener.OnShutdown = SoftBusAssetSendListener::OnSendShutdown;
65     fileSendListener.OnFile = SoftBusAssetSendListener::OnFile;
66     fileSendListener.OnBytes = nullptr;
67     fileSendListener.OnMessage = nullptr;
68     fileSendListener.OnQos = nullptr;
69     sessionListener_[DFS_ASSET_ROLE_SEND] = fileSendListener;
70 
71     ISocketListener fileReceiveListener;
72     fileReceiveListener.OnBind = SoftbusAssetRecvListener::OnAssetRecvBind;
73     fileReceiveListener.OnShutdown = SoftbusAssetRecvListener::OnRecvShutdown;
74     fileReceiveListener.OnFile = SoftbusAssetRecvListener::OnFile;
75     fileReceiveListener.OnBytes = nullptr;
76     fileReceiveListener.OnMessage = nullptr;
77     fileReceiveListener.OnQos = nullptr;
78     sessionListener_[DFS_ASSET_ROLE_RECV] = fileReceiveListener;
79 }
80 
81 SoftBusHandlerAsset::~SoftBusHandlerAsset() = default;
82 
GetInstance()83 SoftBusHandlerAsset &SoftBusHandlerAsset::GetInstance()
84 {
85     LOGD("SoftBusHandlerAsset::GetInstance");
86     static SoftBusHandlerAsset assetHandle;
87     return assetHandle;
88 }
89 
CreateAssetLocalSessionServer()90 void SoftBusHandlerAsset::CreateAssetLocalSessionServer()
91 {
92     LOGI("CreateAssetLocalSessionServer Enter.");
93     {
94         std::lock_guard<std::mutex> lock(serverIdMapMutex_);
95         if (serverIdMap_.find(ASSET_LOCAL_SESSION_NAME) != serverIdMap_.end()) {
96             LOGI("%s: Session already create.", ASSET_LOCAL_SESSION_NAME.c_str());
97             return;
98         }
99     }
100 
101     SocketInfo serverInfo = {
102         .name = const_cast<char*>(ASSET_LOCAL_SESSION_NAME.c_str()),
103         .pkgName = const_cast<char*>(SERVICE_NAME.c_str()),
104         .dataType = DATA_TYPE_FILE,
105     };
106     int32_t socketId = Socket(serverInfo);
107     if (socketId < E_OK) {
108         LOGE("Create Socket fail socketId, socketId = %{public}d", socketId);
109         return;
110     }
111     QosTV qos[] = {
112         {.qos = QOS_TYPE_MIN_BW,        .value = DFS_QOS_TYPE_MIN_BW},
113         {.qos = QOS_TYPE_MAX_LATENCY,        .value = DFS_QOS_TYPE_MAX_LATENCY},
114         {.qos = QOS_TYPE_MIN_LATENCY,        .value = DFS_QOS_TYPE_MIN_LATENCY},
115     };
116     int32_t ret = Listen(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessionListener_[DFS_ASSET_ROLE_RECV]);
117     if (ret != E_OK) {
118         LOGE("Listen SocketClient error");
119         Shutdown(socketId);
120         return;
121     }
122     SoftBusSessionPool::SessionInfo sessionInfo{.uid = IPCSkeleton::GetCallingUid()};
123     SoftBusSessionPool::GetInstance().AddSessionInfo(ASSET_LOCAL_SESSION_NAME, sessionInfo);
124     {
125         std::lock_guard<std::mutex> lock(serverIdMapMutex_);
126         serverIdMap_.insert(std::make_pair(ASSET_LOCAL_SESSION_NAME, socketId));
127     }
128     LOGI("CreateAssetLocalSessionServer Success.");
129 }
130 
DeleteAssetLocalSessionServer()131 void SoftBusHandlerAsset::DeleteAssetLocalSessionServer()
132 {
133     LOGI("DeleteAssetLocalSessionServer Enter.");
134     std::lock_guard<std::mutex> lock(serverIdMapMutex_);
135     if (!serverIdMap_.empty()) {
136         auto it = serverIdMap_.find(ASSET_LOCAL_SESSION_NAME);
137         if (it == serverIdMap_.end()) {
138             LOGI("%s: Session already delete.", ASSET_LOCAL_SESSION_NAME.c_str());
139             return;
140         }
141         int32_t socketId = it->second;
142         serverIdMap_.erase(it);
143         Shutdown(socketId);
144         LOGI("RemoveSessionServer success.");
145     }
146     SoftBusSessionPool::GetInstance().DeleteSessionInfo(ASSET_LOCAL_SESSION_NAME);
147 }
148 
AssetBind(const std::string & dstNetworkId,int32_t & socketId)149 int32_t SoftBusHandlerAsset::AssetBind(const std::string &dstNetworkId, int32_t &socketId)
150 {
151     if (dstNetworkId.empty()) {
152         LOGI("The parameter is empty");
153         return E_OPEN_SESSION;
154     }
155     LOGI("AssetBind Enter.");
156     if (!IsSameAccount(dstNetworkId)) {
157         LOGI("The source and sink device is not same account, not support.");
158         return E_OPEN_SESSION;
159     }
160     QosTV qos[] = {
161         {.qos = QOS_TYPE_MIN_BW,        .value = DFS_QOS_TYPE_MIN_BW},
162         {.qos = QOS_TYPE_MAX_LATENCY,        .value = DFS_QOS_TYPE_MAX_LATENCY},
163         {.qos = QOS_TYPE_MIN_LATENCY,        .value = DFS_QOS_TYPE_MIN_LATENCY},
164     };
165     SocketInfo clientInfo = {
166         .name = const_cast<char*>((ASSET_LOCAL_SESSION_NAME.c_str())),
167         .peerName = const_cast<char*>(ASSET_LOCAL_SESSION_NAME.c_str()),
168         .peerNetworkId = const_cast<char*>(dstNetworkId.c_str()),
169         .pkgName = const_cast<char*>(SERVICE_NAME.c_str()),
170         .dataType = DATA_TYPE_FILE,
171     };
172 
173     socketId = Socket(clientInfo);
174     if (socketId < E_OK) {
175         LOGE("Create OpenSoftbusChannel Socket error");
176         return E_OPEN_SESSION;
177     }
178 
179     int32_t ret = Bind(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessionListener_[DFS_ASSET_ROLE_SEND]);
180     if (ret != E_OK) {
181         LOGE("Bind SocketClient error");
182         Shutdown(socketId);
183         return ret;
184     }
185     AllConnectManager::GetInstance().PublishServiceState(DfsConnectCode::PUSH_ASSET, dstNetworkId,
186         ServiceCollaborationManagerBussinessStatus::SCM_CONNECTED);
187     LOGI("OpenSession success.");
188     return E_OK;
189 }
190 
SetSocketOpt(int32_t socketId,const char ** src,uint32_t srcLen)191 void SoftBusHandlerAsset::SetSocketOpt(int32_t socketId, const char **src, uint32_t srcLen)
192 {
193 #ifdef SUPPORT_SAME_ACCOUNT
194     uint64_t totalSize = 0;
195     for (uint32_t i = 0; i < srcLen; ++i) {
196         const char *file = src[i];
197         struct stat buf {};
198         if (stat(file, &buf) == -1) {
199             return;
200         }
201         totalSize += static_cast<uint64_t>(buf.st_size);
202     }
203 
204     TransFlowInfo flowInfo;
205     flowInfo.sessionType = SHORT_DURATION_SESSION;
206     flowInfo.flowQosType = HIGH_THROUGHPUT;
207     flowInfo.flowSize = totalSize;
208     ::SetSocketOpt(socketId, OPT_LEVEL_SOFTBUS, (OptType)OPT_TYPE_FLOW_INFO, (void *)&flowInfo, sizeof(TransFlowInfo));
209 #endif
210 }
211 
AssetSendFile(int32_t socketId,const std::string & sendFile,bool isSingleFile)212 int32_t SoftBusHandlerAsset::AssetSendFile(int32_t socketId, const std::string& sendFile, bool isSingleFile)
213 {
214     auto assetObj = GetAssetObj(socketId);
215     if (assetObj == nullptr) {
216         LOGE("get assetObj fail.");
217         return ERR_BAD_VALUE;
218     }
219     if (!IsSameAccount(assetObj->dstNetworkId_)) {
220         LOGI("The source and sink device is not same account, not support.");
221         return ERR_BAD_VALUE;
222     }
223 
224     const char *src[MAX_SIZE] = {};
225     src[0] = sendFile.c_str();
226 
227     auto dstFile = GetDstFile(sendFile, assetObj->srcBundleName_,
228                               assetObj->dstBundleName_, assetObj->sessionId_, isSingleFile);
229     if (dstFile.empty()) {
230         LOGE("GetFileName failed or file is empty");
231         return ERR_BAD_VALUE;
232     }
233     const char *dst[MAX_SIZE] = {};
234     dst[0] = dstFile.c_str();
235 
236     LOGI("AssetSendFile Enter.");
237     SetSocketOpt(socketId, src, 1);
238     int32_t ret = ::SendFile(socketId, src, dst, 1);
239     if (ret != E_OK) {
240         LOGE("SendFile failed, sessionId = %{public}d", socketId);
241         return ret;
242     }
243     return E_OK;
244 }
245 
closeAssetBind(int32_t socketId)246 void SoftBusHandlerAsset::closeAssetBind(int32_t socketId)
247 {
248     LOGI("closeAssetBind Enter.");
249     Shutdown(socketId);
250     auto assetObj = GetAssetObj(socketId);
251     if (assetObj == nullptr) {
252         return;
253     }
254     RemoveAssetObj(socketId);
255     AllConnectManager::GetInstance().PublishServiceState(DfsConnectCode::PUSH_ASSET, assetObj->dstNetworkId_,
256         ServiceCollaborationManagerBussinessStatus::SCM_IDLE);
257 }
258 
OnAssetRecvBind(int32_t socketId,const std::string & srcNetWorkId)259 void SoftBusHandlerAsset::OnAssetRecvBind(int32_t socketId, const std::string &srcNetWorkId)
260 {
261     std::lock_guard<std::mutex> lock(clientInfoMutex_);
262     if (!IsSameAccount(srcNetWorkId)) {
263         LOGE("The source and sink device is not same account, not support.");
264         Shutdown(socketId);
265         return;
266     }
267     clientInfoMap_.insert(std::make_pair(socketId, srcNetWorkId));
268     AllConnectManager::GetInstance().PublishServiceState(DfsConnectCode::PUSH_ASSET, srcNetWorkId,
269         ServiceCollaborationManagerBussinessStatus::SCM_CONNECTED);
270 }
271 
GetClientInfo(int32_t socketId)272 std::string SoftBusHandlerAsset::GetClientInfo(int32_t socketId)
273 {
274     std::lock_guard<std::mutex> lock(clientInfoMutex_);
275     auto iter = clientInfoMap_.find(socketId);
276     if (iter == clientInfoMap_.end()) {
277         LOGE("ClientInfo not registered");
278         return "";
279     }
280     return iter->second;
281 }
282 
GetSocketIdFromClientInfo(const std::string & peerNetworkId)283 std::vector<int32_t> SoftBusHandlerAsset::GetSocketIdFromClientInfo(const std::string &peerNetworkId)
284 {
285     std::vector<int32_t> socketIdVec;
286     std::lock_guard<std::mutex> lock(clientInfoMutex_);
287     for (auto iter = clientInfoMap_.begin(); iter != clientInfoMap_.end(); ++iter) {
288         if (iter->second == peerNetworkId) {
289             socketIdVec.push_back(iter->first);
290         }
291     }
292     return socketIdVec;
293 }
294 
GetSocketIdFromAssetObj(const std::string & peerNetworkId)295 std::vector<int32_t> SoftBusHandlerAsset::GetSocketIdFromAssetObj(const std::string &peerNetworkId)
296 {
297     std::vector<int32_t> socketIdVec;
298     std::lock_guard<std::mutex> lock(assetObjMapMutex_);
299     for (auto iter = assetObjMap_.begin(); iter != assetObjMap_.end(); ++iter) {
300         if (iter->second->dstNetworkId_ == peerNetworkId) {
301             socketIdVec.push_back(iter->first);
302         }
303     }
304     return socketIdVec;
305 }
306 
RemoveClientInfo(int32_t socketId)307 void SoftBusHandlerAsset::RemoveClientInfo(int32_t socketId)
308 {
309     auto peerNetworkId = GetClientInfo(socketId);
310     if (!peerNetworkId.empty()) {
311         AllConnectManager::GetInstance().PublishServiceState(DfsConnectCode::PUSH_ASSET, peerNetworkId,
312             ServiceCollaborationManagerBussinessStatus::SCM_IDLE);
313     }
314     RemoveAssetObj(socketId);
315     std::lock_guard<std::mutex> lock(clientInfoMutex_);
316     auto it = clientInfoMap_.find(socketId);
317     if (it != clientInfoMap_.end()) {
318         clientInfoMap_.erase(it->first);
319     }
320 }
321 
AddAssetObj(int32_t socketId,const sptr<AssetObj> & assetObj)322 void SoftBusHandlerAsset::AddAssetObj(int32_t socketId, const sptr<AssetObj> &assetObj)
323 {
324     std::lock_guard<std::mutex> lock(assetObjMapMutex_);
325     auto iter = assetObjMap_.find(socketId);
326     if (iter != assetObjMap_.end()) {
327         LOGI("assetObj exist.");
328         return;
329     }
330     assetObjMap_.insert(std::pair<int32_t, sptr<AssetObj>>(socketId, assetObj));
331 }
332 
GetAssetObj(int32_t socketId)333 sptr<AssetObj> SoftBusHandlerAsset::GetAssetObj(int32_t socketId)
334 {
335     std::lock_guard<std::mutex> lock(assetObjMapMutex_);
336     auto iter = assetObjMap_.find(socketId);
337     if (iter == assetObjMap_.end()) {
338         LOGE("AssetObj not exist");
339         return nullptr;
340     }
341 
342     return iter->second;
343 }
344 
RemoveAssetObj(int32_t socketId)345 void SoftBusHandlerAsset::RemoveAssetObj(int32_t socketId)
346 {
347     std::lock_guard<std::mutex> lock(assetObjMapMutex_);
348     auto iter = assetObjMap_.find(socketId);
349     if (iter != assetObjMap_.end()) {
350         assetObjMap_.erase(iter);
351     }
352 }
353 
GenerateAssetObjInfo(int32_t socketId,const std::string & fileName,const sptr<AssetObj> & assetObj)354 int32_t SoftBusHandlerAsset::GenerateAssetObjInfo(int32_t socketId,
355                                                   const std::string &fileName,
356                                                   const sptr<AssetObj> &assetObj)
357 {
358     if (assetObj == nullptr) {
359         LOGE("assetObj is nullptr!");
360         return FileManagement::ERR_BAD_VALUE;
361     }
362 
363     size_t pos = fileName.find(RELATIVE_PATH_FLAG);
364     if (pos == std::string::npos) {
365         LOGE("Generate dstBundleName fail, firstFile is %{public}s", GetAnonyString(fileName).c_str());
366         return FileManagement::ERR_BAD_VALUE;
367     }
368     std::string relativeFileName = fileName.substr(pos + RELATIVE_PATH_FLAG.length());
369 
370     pos = relativeFileName.find(DST_BUNDLE_NAME_FLAG);
371     if (pos == std::string::npos) {
372         LOGE("Generate dstBundleName fail, relativeFirstFile is %{public}s", GetAnonyString(fileName).c_str());
373         return FileManagement::ERR_BAD_VALUE;
374     }
375     auto dstBundleName = relativeFileName.substr(0, pos);
376     assetObj->dstBundleName_ = dstBundleName;
377 
378     std::smatch match;
379     std::regex sessionIdRegex("sessionId=([^&]+)");
380     if (!std::regex_search(fileName, match, sessionIdRegex)) {
381         LOGE("Generate sessionId fail, relativeFirstFile is %{public}s", GetAnonyString(fileName).c_str());
382         return FileManagement::ERR_BAD_VALUE;
383     }
384     assetObj->sessionId_ = match[1].str();
385 
386     std::regex srcBundleNameRegex("srcBundleName=([^&]+)");
387     if (!std::regex_search(fileName, match, srcBundleNameRegex)) {
388         LOGE("Generate srcBundleName fail, relativeFirstFile is %{public}s", GetAnonyString(fileName).c_str());
389         return FileManagement::ERR_BAD_VALUE;
390     }
391     assetObj->srcBundleName_ = match[1].str();
392 
393     assetObj->dstNetworkId_ = GetLocalNetworkId();
394     if (assetObj->dstNetworkId_.empty()) {
395         LOGE("Failed to get info of local devices");
396         return FileManagement::ERR_BAD_VALUE;
397     }
398     return FileManagement::ERR_OK;
399 }
400 
IsSameAccount(const std::string & networkId)401 bool SoftBusHandlerAsset::IsSameAccount(const std::string &networkId)
402 {
403     std::vector<DistributedHardware::DmDeviceInfo> deviceList;
404     DistributedHardware::DeviceManager::GetInstance().GetTrustedDeviceList(SERVICE_NAME, "", deviceList);
405     if (deviceList.size() == 0 || deviceList.size() > MAX_ONLINE_DEVICE_SIZE) {
406         LOGE("trust device list size is invalid, size=%zu", deviceList.size());
407         return false;
408     }
409     for (const auto &deviceInfo : deviceList) {
410         if (std::string(deviceInfo.networkId) == networkId) {
411             return (deviceInfo.authForm == DistributedHardware::DmAuthForm::IDENTICAL_ACCOUNT);
412         }
413     }
414     return false;
415 }
416 
GetDstFile(const std::string & file,const std::string & srcBundleName,const std::string & dstBundleName,const std::string & sessionId,bool isSingleFile)417 std::string SoftBusHandlerAsset::GetDstFile(const std::string &file,
418                                             const std::string &srcBundleName,
419                                             const std::string &dstBundleName,
420                                             const std::string &sessionId,
421                                             bool isSingleFile)
422 {
423     std::stringstream dstFile;
424     size_t pos = file.find(srcBundleName);
425     if (pos == std::string::npos) {
426         return "";
427     }
428     std::string tempDir;
429     if (isSingleFile) {
430         tempDir = ASSET_POSTFIX_SINGLE;
431     } else {
432         tempDir = ASSET_POSTFIX_ZIP;
433     }
434     dstFile << dstBundleName << "/" << TEMP_DIR << file.substr(pos + srcBundleName.length())
435             << tempDir << "srcBundleName=" << srcBundleName << "&sessionId=" << sessionId;
436 
437     return dstFile.str();
438 }
439 
GenerateUris(const std::vector<std::string> & fileList,const std::string & dstBundleName,bool isSingleFile)440 std::vector<std::string> SoftBusHandlerAsset::GenerateUris(const std::vector<std::string> &fileList,
441                                                            const std::string &dstBundleName,
442                                                            bool isSingleFile)
443 {
444     auto tempDir = dstBundleName + "/" + TEMP_DIR;
445     std::vector<std::string> uris;
446     if (isSingleFile) {
447         std::stringstream uri;
448         std::string file = fileList[0];
449         size_t posPrefix = file.find(tempDir);
450         if (posPrefix == std::string::npos) {
451             LOGE("not find tempDir in fileList.");
452             return {};
453         }
454         size_t posPostfix = file.find(ASSET_POSTFIX_SINGLE);
455         if (posPostfix == std::string::npos) {
456             LOGE("not find asset postfix in fileList.");
457             return {};
458         }
459         uri <<"file://" << dstBundleName << "/data/storage/el2/distributedfiles"
460             << file.substr(posPrefix + tempDir.length(), posPostfix - posPrefix - tempDir.length());
461         uris.emplace_back(uri.str());
462         return uris;
463     }
464     for (auto file : fileList) {
465         std::stringstream uri;
466         size_t posPrefix = file.find(tempDir);
467         if (posPrefix == std::string::npos) {
468             LOGE("not find tempDir in fileList.");
469             return {};
470         }
471         uri <<"file://" << dstBundleName << "/data/storage/el2/distributedfiles"
472             << file.substr(posPrefix + tempDir.length());
473         uris.emplace_back(uri.str());
474     }
475     return uris;
476 }
477 
CompressFile(const std::vector<std::string> & fileList,const std::string & relativePath,const std::string & zipFileName)478 int32_t SoftBusHandlerAsset::CompressFile(const std::vector<std::string> &fileList,
479                                           const std::string &relativePath,
480                                           const std::string &zipFileName)
481 {
482     LOGI("CompressFile begin.");
483     zipFile outputFile = zipOpen64(zipFileName.c_str(), APPEND_STATUS_CREATE);
484     if (!outputFile) {
485         LOGE("Minizip failed to zipOpen, zipFileName = %{public}s", GetAnonyString(zipFileName).c_str());
486         return E_ZIP;
487     }
488 
489     for (const std::string& rootFile : fileList) {
490         size_t pos = rootFile.find(relativePath);
491         if (pos == std::string::npos) {
492             LOGE("rootFile not have relativePath");
493             return E_ZIP;
494         }
495         auto file = rootFile.substr(pos + relativePath.length());
496 
497         int err = zipOpenNewFileInZip3_64(outputFile, file.c_str(), NULL, NULL, 0, NULL, 0, NULL,
498                                           Z_DEFLATED, 0, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, 0);
499         if (err != ZIP_OK) {
500             LOGE("Minizip failed to zipOpenNewFileInZip, file = %{public}s", GetAnonyString(file).c_str());
501             zipClose(outputFile, NULL);
502             return E_ZIP;
503         }
504 
505         FILE* f = fopen(rootFile.c_str(), "rb");
506         if (f == NULL) {
507             LOGE("open file fail, path is %{public}s", GetAnonyString(rootFile).c_str());
508             return E_ZIP;
509         }
510         const size_t pageSize { getpagesize() };
511         auto buf = std::make_unique<char[]>(pageSize);
512         size_t actLen;
513         do {
514             actLen = fread(buf.get(), 1, pageSize, f);
515             if (actLen > 0) {
516                 zipWriteInFileInZip(outputFile, buf.get(), actLen);
517             }
518         } while (actLen == pageSize);
519         if (fclose(f) != 0) {
520             LOGE("Minizip failed to fclose");
521         }
522         zipCloseFileInZip(outputFile);
523     }
524     zipClose(outputFile, NULL);
525     LOGI("CompressFile end.");
526     return E_OK;
527 }
528 
DecompressFile(const std::string & unZipFileName,const std::string & relativePath)529 std::vector<std::string> SoftBusHandlerAsset::DecompressFile(const std::string &unZipFileName,
530                                                              const std::string &relativePath)
531 {
532     LOGI("DecompressFile begin.");
533     if (!IsDir(relativePath)) {
534         MkDirRecurse(relativePath, S_IRWXU | S_IRWXG | S_IXOTH);
535     }
536 
537     unzFile zipFile = unzOpen64(unZipFileName.c_str());
538     if (!zipFile) {
539         LOGE("Minizip failed to unzOpen, zipFileName = %{public}s", GetAnonyString(unZipFileName).c_str());
540         return {};
541     }
542 
543     unz_global_info64 globalInfo;
544     if (unzGetGlobalInfo64(zipFile, &globalInfo) != UNZ_OK) {
545         unzClose(zipFile);
546         LOGE("Minizip failed to unzGetGlobalInfo");
547         return {};
548     }
549 
550     std::vector<std::string> fileList;
551 
552     for (size_t i = 0; i < globalInfo.number_entry; ++i) {
553         std::string filePath = ExtractFile(zipFile, relativePath.c_str());
554         if (!filePath.empty()) {
555             fileList.push_back(filePath);
556         }
557         unzCloseCurrentFile(zipFile);
558         unzGoToNextFile(zipFile);
559     }
560     unzClose(zipFile);
561     LOGI("DecompressFile end.");
562     return fileList;
563 }
564 
GetLocalNetworkId()565 std::string SoftBusHandlerAsset::GetLocalNetworkId()
566 {
567     NodeBasicInfo tmpNodeInfo;
568     int errCode = GetLocalNodeDeviceInfo(SERVICE_NAME.c_str(), &tmpNodeInfo);
569     if (errCode != 0) {
570         LOGE("Failed to get info of local devices");
571         return "";
572     }
573     return tmpNodeInfo.networkId;
574 }
575 
MkDir(const std::string & path,mode_t mode)576 int32_t SoftBusHandlerAsset::MkDir(const std::string &path, mode_t mode)
577 {
578     return TEMP_FAILURE_RETRY(mkdir(path.c_str(), mode));
579 }
580 
MkDirRecurse(const std::string & path,mode_t mode)581 bool SoftBusHandlerAsset::MkDirRecurse(const std::string& path, mode_t mode)
582 {
583     size_t pos = path.rfind("/");
584     if (pos == std::string::npos) {
585         LOGE("is not a dir, path : %{public}s", GetAnonyString(path).c_str());
586     }
587     auto dirPath = path.substr(0, pos);
588 
589     std::string::size_type index = 0;
590     do {
591         std::string subPath = dirPath;
592         index = path.find('/', index + 1);
593         if (index != std::string::npos) {
594             subPath = path.substr(0, index);
595         }
596 
597         if (TEMP_FAILURE_RETRY(access(subPath.c_str(), F_OK)) != 0) {
598             if (MkDir(subPath, mode) != 0 && errno != EEXIST) {
599                 return false;
600             }
601         }
602     } while (index != std::string::npos);
603 
604     return TEMP_FAILURE_RETRY(access(path.c_str(), F_OK)) == 0;
605 }
606 
IsDir(const std::string & path)607 bool SoftBusHandlerAsset::IsDir(const std::string &path)
608 {
609     // check whether the path exists
610     struct stat st;
611     int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
612     if (ret) {
613         return false;
614     }
615     return S_ISDIR(st.st_mode);
616 }
617 
ExtractFile(unzFile unZipFile,const std::string & dir)618 std::string SoftBusHandlerAsset::ExtractFile(unzFile unZipFile, const std::string &dir)
619 {
620     auto filename = std::make_unique<char[]>(BUFFER_SIZE);
621     unz_file_info64 fileInfo;
622     if (unzGetCurrentFileInfo64(unZipFile, &fileInfo, filename.get(), BUFFER_SIZE, NULL, 0, NULL, 0) != UNZ_OK) {
623         LOGE("Minizip failed to unzGetCurrentFileInfo64");
624         return "";
625     }
626     std::string filenameWithPath(filename.get());
627     filenameWithPath = dir + filenameWithPath;
628     size_t pos = filenameWithPath.rfind('/');
629     if (pos == std::string::npos) {
630         LOGE("file path error, %{public}s", GetAnonyString(filenameWithPath).c_str());
631         return "";
632     }
633     std::string filenameWithoutPath = filenameWithPath.substr(pos + 1);
634 
635     if (!IsDir(filenameWithPath)) {
636         MkDirRecurse(filenameWithPath, S_IRWXU | S_IRWXG | S_IXOTH);
637     }
638     if (unzOpenCurrentFile(unZipFile) != UNZ_OK) {
639         LOGE("Minizip failed to unzOpenCurrentFile, filepath is %{public}s", GetAnonyString(filenameWithPath).c_str());
640     }
641     std::fstream file;
642     file.open(filenameWithPath, std::ios_base::out | std::ios_base::binary);
643     if (!file.is_open()) {
644         LOGE("open zip file fail, path is %{public}s", GetAnonyString(filenameWithPath).c_str());
645         return "";
646     }
647     const size_t pageSize =  { getpagesize() };
648     auto fileData = std::make_unique<char[]>(pageSize);
649     int32_t bytesRead;
650     do {
651         bytesRead = unzReadCurrentFile(unZipFile, (voidp)fileData.get(), pageSize);
652         if (bytesRead < 0) {
653             LOGE("Minizip failed to unzReadCurrentFile, filepath is %{public}s",
654                  GetAnonyString(filenameWithPath).c_str());
655             file.close();
656             return "";
657         }
658         file.write(fileData.get(), bytesRead);
659     } while (bytesRead > 0);
660     file.close();
661     return filenameWithPath;
662 }
663 
RemoveFile(const std::string & path,bool isRemove)664 void SoftBusHandlerAsset::RemoveFile(const std::string &path, bool isRemove)
665 {
666     LOGI("RemoveFile path is %{public}s", GetAnonyString(path).c_str());
667     if (!isRemove) {
668         LOGI("this file is not need remove");
669         return;
670     }
671     bool ret = std::filesystem::remove(path.c_str());
672     if (!ret) {
673         LOGE("remove file fail, remove path is %{public}s", GetAnonyString(path).c_str());
674     }
675 }
676 } // namespace DistributedFile
677 } // namespace Storage
678 } // namespace OHOS