• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2025 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 "module_external/storage_manager_service.h"
17 
18 #include <dirent.h>
19 #include <fstream>
20 #include <stack>
21 #include <sys/quota.h>
22 #include <sys/stat.h>
23 #include <sys/statvfs.h>
24 #include <refbase.h>
25 #include <linux/fs.h>
26 #include <linux/quota.h>
27 
28 #include "b_error/b_error.h"
29 #include "b_resources/b_constants.h"
30 #include "filemgmt_libhilog.h"
31 #include "sandbox_helper.h"
32 #include "file_uri.h"
33 
34 #include <iservice_registry.h>
35 #include <system_ability_definition.h>
36 
37 namespace OHOS::FileManagement::Backup {
38 using namespace std;
39 std::recursive_mutex mMountsLock;
40 
PathSortFunc(const std::string & path1,const std::string & path2)41 static bool PathSortFunc(const std::string &path1, const std::string &path2)
42 {
43     return path1 < path2;
44 }
45 
GetQuotaSrcMountPath(const std::string & target)46 static std::string GetQuotaSrcMountPath(const std::string &target)
47 {
48     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
49     if (mQuotaReverseMounts.find(target) != mQuotaReverseMounts.end()) {
50         return mQuotaReverseMounts[target];
51     } else {
52         return "";
53     }
54 }
55 
GetBundleStats(const string & bundleName,StorageManager::BundleStats & storageStats)56 bool StorageManagerService::GetBundleStats(const string &bundleName,
57     StorageManager::BundleStats &storageStats)
58 {
59     return true;
60 }
61 
GetUserStorageStatsByType(int32_t userId,StorageManager::StorageStats & storageStats,std::string type)62 int32_t StorageManagerService::GetUserStorageStatsByType(int32_t userId, StorageManager::StorageStats &storageStats,
63     std::string type)
64 {
65     storageStats.video_ = 0;
66     storageStats.image_ = 0;
67     storageStats.file_ = 0;
68     int32_t err = E_ERR;
69     if (type == MEDIA_TYPE) {
70         HILOGI("GetUserStorageStatsByType media");
71         err = GetMediaStorageStats(storageStats);
72     } else if (type == FILE_TYPE) {
73         HILOGI("GetUserStorageStatsByType file");
74         err = GetFileStorageStats(userId, storageStats);
75     } else {
76         HILOGI("GetUserStorageStatsByType type: %{public}s", type.c_str());
77     }
78     return err;
79 }
80 
GetMediaStorageStats(StorageManager::StorageStats & storageStats)81 int32_t StorageManagerService::GetMediaStorageStats(StorageManager::StorageStats &storageStats)
82 {
83     HILOGE("GetMediaStorageStats start");
84     auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
85     if (sam == nullptr) {
86         HILOGE("StorageStatusService::GetMediaStorageStats samgr == nullptr");
87         return E_SA_IS_NULLPTR;
88     }
89     auto remoteObj = sam->GetSystemAbility(FILEMANAGEMENT_BACKUP_SERVICE_SA_ID);
90     if (remoteObj == nullptr) {
91         HILOGE("StorageStatusService::GetMediaStorageStats remoteObj == nullptr");
92         return E_REMOTE_IS_NULLPTR;
93     }
94     int32_t tryCount = 1;
95     HILOGE("GetMediaStorageStats start Creator");
96     auto dataShareHelper = DataShare::DataShareHelper::Creator(remoteObj, MEDIALIBRARY_DATA_URI);
97     while (dataShareHelper == nullptr && tryCount < GET_DATA_SHARE_HELPER_TIMES) {
98         HILOGW("dataShareHelper is retrying, attempt %{public}d", tryCount);
99         dataShareHelper = DataShare::DataShareHelper::Creator(remoteObj, MEDIALIBRARY_DATA_URI);
100         tryCount++;
101     }
102     if (dataShareHelper == nullptr) {
103         HILOGE("dataShareHelper is null!");
104         return E_MEDIALIBRARY_ERROR;
105     }
106     vector<string> columns;
107     Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_QUERYOPRN_QUERYVOLUME + "/" + MEDIA_QUERYOPRN_QUERYVOLUME);
108     DataShare::DataSharePredicates predicates;
109     HILOGE("GetMediaStorageStats start Query");
110     auto queryResultSet = dataShareHelper->Query(uri, predicates, columns);
111     if (queryResultSet == nullptr) {
112         HILOGE("queryResultSet is null!");
113         return E_QUERY;
114     }
115     auto count = 0;
116     auto ret = queryResultSet->GetRowCount(count);
117     if ((ret != E_OK) || (count < 0)) {
118         HILOGE("get row count from rdb failed");
119         return E_GETROWCOUNT;
120     }
121     GetMediaTypeAndSize(queryResultSet, storageStats);
122     dataShareHelper->Release();
123     HILOGE("GetMediaStorageStats end");
124     return E_OK;
125 }
126 
GetMediaTypeAndSize(const std::shared_ptr<DataShare::DataShareResultSet> & resultSet,StorageManager::StorageStats & storageStats)127 void StorageManagerService::GetMediaTypeAndSize(const std::shared_ptr<DataShare::DataShareResultSet> &resultSet,
128     StorageManager::StorageStats &storageStats)
129 {
130     if (resultSet == nullptr) {
131         HILOGE("StorageStatusService::GetMediaTypeAndSize, input resultSet is nullptr.");
132         return;
133     }
134     int thumbnailType = -1;
135     while (resultSet->GoToNextRow() == E_OK) {
136         int32_t index = 0;
137         int mediatype = 0;
138         int64_t size = 0;
139         if (resultSet->GetColumnIndex("media_type", index) || resultSet->GetInt(index, mediatype)) {
140             HILOGE("get media_type column index or int value err.");
141             continue;
142         }
143         if (resultSet->GetColumnIndex("size", index) || resultSet->GetLong(index, size)) {
144             HILOGE("get size column index or long value err.");
145             continue;
146         }
147         HILOGI("media type: %{public}d, size: %{public}lld", mediatype, static_cast<long long>(size));
148         if (mediatype == MEDIA_TYPE_IMAGE || mediatype == thumbnailType) {
149             storageStats.image_ += size;
150         } else if (mediatype == MEDIA_TYPE_AUDIO) {
151             storageStats.audio_ = size;
152         } else if (mediatype == MEDIA_TYPE_VIDEO) {
153             storageStats.video_ = size;
154         } else {
155             HILOGW("unsupprted media_type: %{public}d", mediatype);
156         }
157     }
158 }
159 
GetFileStorageStats(int32_t userId,StorageManager::StorageStats & storageStats)160 int32_t StorageManagerService::GetFileStorageStats(int32_t userId, StorageManager::StorageStats &storageStats)
161 {
162     int32_t uid = userId * USER_ID_BASE + UID_FILE_MANAGER;
163     HILOGE("GetOccupiedSpaceForUid uid:%{public}d", uid);
164     if (InitialiseQuotaMounts() != true) {
165         HILOGE("Failed to initialise quota mounts");
166         return E_SYS_KERNEL_ERR;
167     }
168 
169     std::string device = "";
170     device = GetQuotaSrcMountPath(QUOTA_DEVICE_DATA_PATH);
171     if (device.empty()) {
172         HILOGE("skip when device no quotas present");
173         return E_OK;
174     }
175 
176     struct dqblk dq;
177     if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) {
178         HILOGE("Failed to get quotactl, errno : %{public}d", errno);
179         return E_SYS_KERNEL_ERR;
180     }
181     storageStats.file_ = static_cast<int64_t>(dq.dqb_curspace);
182     HILOGE("GetOccupiedSpaceForUid size:%{public}s", std::to_string(storageStats.file_).c_str());
183     return E_OK;
184 }
185 
InitialiseQuotaMounts()186 bool StorageManagerService::InitialiseQuotaMounts()
187 {
188     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
189     mQuotaReverseMounts.clear();
190     std::ifstream in(PROC_MOUNTS_PATH);
191 
192     if (!in.is_open()) {
193         HILOGE("Failed to open mounts file");
194         return false;
195     }
196     std::string source;
197     std::string target;
198     std::string ignored;
199 
200     while (in.peek() != EOF) {
201         std::getline(in, source, ' ');
202         std::getline(in, target, ' ');
203         std::getline(in, ignored);
204         if (source.compare(0, strlen(DEV_BLOCK_PATH), DEV_BLOCK_PATH) == 0
205             && target.compare(QUOTA_DEVICE_DATA_PATH) == 0) {
206             struct dqblk dq;
207             if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, reinterpret_cast<char*>(&dq)) == 0) {
208                 mQuotaReverseMounts[target] = source;
209             }
210         }
211     }
212     return true;
213 }
214 
UpdateMemoryPara(int32_t size,int32_t oldSize)215 int32_t StorageManagerService::UpdateMemoryPara(int32_t size, int32_t oldSize)
216 {
217     return E_OK;
218 }
219 
GetBundleStatsForIncrease(uint32_t userId,const std::vector<std::string> & bundleNames,const std::vector<int64_t> & incrementalBackTimes,std::vector<int64_t> & pkgFileSizes,std::vector<int64_t> & incPkgFileSizes)220 int32_t StorageManagerService::GetBundleStatsForIncrease(uint32_t userId, const std::vector<std::string> &bundleNames,
221     const std::vector<int64_t> &incrementalBackTimes, std::vector<int64_t> &pkgFileSizes,
222     std::vector<int64_t> &incPkgFileSizes)
223 {
224     HILOGI("GetBundleStatsForIncrease start");
225     if (bundleNames.size() != incrementalBackTimes.size()) {
226         HILOGE("Invalid paramters, size of bundleNames should match incrementalBackTimes.");
227         return E_ERR;
228     }
229     for (size_t i = 0; i < bundleNames.size(); i++) {
230         std::string bundleName = bundleNames[i];
231         int64_t lastBackupTime = incrementalBackTimes[i];
232         GetBundleStatsForIncreaseEach(userId, bundleName, lastBackupTime, pkgFileSizes, incPkgFileSizes);
233     }
234     return E_OK;
235 }
236 
GetBundleStatsForIncreaseEach(uint32_t userId,std::string & bundleName,int64_t lastBackupTime,std::vector<int64_t> & pkgFileSizes,std::vector<int64_t> & incPkgFileSizes)237 void StorageManagerService::GetBundleStatsForIncreaseEach(uint32_t userId, std::string &bundleName,
238     int64_t lastBackupTime, std::vector<int64_t> &pkgFileSizes, std::vector<int64_t> &incPkgFileSizes)
239 {
240     // input parameters
241     BundleStatsParas paras = {.userId = userId, .bundleName = bundleName,
242                               .lastBackupTime = lastBackupTime, .fileSizeSum = 0, .incFileSizeSum = 0};
243 
244     // obtain includes, excludes in backup extension config
245     auto [includes, excludes] = ReadIncludesExcludesPath(bundleName, lastBackupTime, userId);
246     if (includes.empty()) {
247         pkgFileSizes.emplace_back(0);
248         incPkgFileSizes.emplace_back(0);
249         return;
250     }
251     // physical paths
252     std::vector<std::string> phyIncludes;
253     // map about sandbox path to physical path
254     std::map<std::string, std::string> pathMap;
255 
256     // recognize physical path for include directory
257     DealWithIncludeFiles(paras, includes, phyIncludes, pathMap);
258     if (phyIncludes.empty()) {
259         HILOGE("Incorrect convert for include sandbox path for %{private}s", bundleName.c_str());
260         pkgFileSizes.emplace_back(0);
261         incPkgFileSizes.emplace_back(0);
262         return;
263     }
264 
265     // recognize physical path for exclude directory
266     std::vector<std::string> phyExcludes;
267     for (const auto &exclude : excludes) {
268         std::string excludeStr = exclude;
269         if (excludeStr.front() != FILE_SEPARATOR_CHAR) {
270             excludeStr = FILE_SEPARATOR_CHAR + excludeStr;
271         }
272         // convert sandbox to physical path
273         ConvertSandboxRealPath(userId, bundleName, excludeStr, phyExcludes, pathMap);
274     }
275 
276     std::string filePath = BACKUP_PATH_PREFIX + std::to_string(userId) + BACKUP_PATH_SURFFIX +
277         bundleName + FILE_SEPARATOR_CHAR + BACKUP_STAT_SYMBOL + std::to_string(lastBackupTime);
278     std::ofstream statFile;
279     statFile.open(filePath.data(), std::ios::out | std::ios::trunc);
280     if (!statFile.is_open()) {
281         HILOGE("creat file fail, errno:%{public}d.", errno);
282         pkgFileSizes.emplace_back(0);
283         incPkgFileSizes.emplace_back(0);
284         return;
285     }
286     statFile << VER_10_LINE1 << std::endl;
287     statFile << VER_10_LINE2 << std::endl;
288 
289     DeduplicationPath(phyIncludes);
290     ScanExtensionPath(paras, phyIncludes, phyExcludes, pathMap, statFile);
291     // calculate summary file sizes
292     pkgFileSizes.emplace_back(paras.fileSizeSum);
293     incPkgFileSizes.emplace_back(paras.incFileSizeSum);
294     HILOGI("bundleName: %{public}s, size: %{public}lld", bundleName.c_str(), static_cast<long long>(paras.fileSizeSum));
295     statFile.close();
296 }
297 
ReadIncludesExcludesPath(const std::string & bundleName,const int64_t lastBackupTime,const uint32_t userId)298 std::tuple<std::vector<std::string>, std::vector<std::string>> StorageManagerService::ReadIncludesExcludesPath(
299     const std::string &bundleName, const int64_t lastBackupTime, const uint32_t userId)
300 {
301     if (bundleName.empty()) {
302         HILOGE("bundleName is empty");
303         return { {}, {} };
304     }
305     // 保存includeExclude的path
306     std::string filePath = BACKUP_PATH_PREFIX + std::to_string(userId) + BACKUP_PATH_SURFFIX +
307         bundleName + FILE_SEPARATOR_CHAR + BACKUP_INCEXC_SYMBOL + std::to_string(lastBackupTime);
308     std::ifstream incExcFile;
309     incExcFile.open(filePath.data());
310     if (!incExcFile.is_open()) {
311         HILOGE("Cannot open include/exclude file, fail errno:%{public}d", errno);
312         return { {}, {} };
313     }
314 
315     std::vector<std::string> includes;
316     std::vector<std::string> excludes;
317     bool incOrExt = true;
318     while (incExcFile) {
319         std::string line;
320         std::getline(incExcFile, line);
321         if (line.empty()) {
322             HILOGI("Read Complete");
323             break;
324         }
325         if (line == BACKUP_INCLUDE) {
326             incOrExt = true;
327         } else if (line == BACKUP_EXCLUDE) {
328             incOrExt = false;
329         }
330         if (incOrExt && line != BACKUP_INCLUDE) {
331             includes.emplace_back(line);
332         } else if (!incOrExt && line != BACKUP_EXCLUDE) {
333             excludes.emplace_back(line);
334         }
335     }
336     incExcFile.close();
337     return {includes, excludes};
338 }
339 
DealWithIncludeFiles(const BundleStatsParas & paras,const std::vector<std::string> & includes,std::vector<std::string> & phyIncludes,std::map<std::string,std::string> & pathMap)340 void StorageManagerService::DealWithIncludeFiles(const BundleStatsParas &paras,
341     const std::vector<std::string> &includes, std::vector<std::string> &phyIncludes,
342     std::map<std::string, std::string>& pathMap)
343 {
344     uint32_t userId = paras.userId;
345     std::string bundleName = paras.bundleName;
346     for (const auto &include : includes) {
347         std::string includeStr = include;
348         if (includeStr.front() != FILE_SEPARATOR_CHAR) {
349             includeStr = FILE_SEPARATOR_CHAR + includeStr;
350         }
351         if (includeStr.find(BASE_EL1 + DEFAULT_PATH_WITH_WILDCARD) == 0 ||
352             includeStr.find(BASE_EL2 + DEFAULT_PATH_WITH_WILDCARD) == 0) {
353             // recognize sandbox path to physical path with wild card
354             RecognizeSandboxWildCard(userId, bundleName, includeStr, phyIncludes, pathMap);
355             if (phyIncludes.empty()) {
356                 HILOGE("DealWithIncludeFiles failed to recognize path with wildcard %{private}s", bundleName.c_str());
357                 continue;
358             }
359         } else {
360             // convert sandbox to physical path
361             ConvertSandboxRealPath(userId, bundleName, includeStr, phyIncludes, pathMap);
362         }
363     }
364 }
365 
ConvertSandboxRealPath(const uint32_t userId,const std::string & bundleName,const std::string & sandboxPathStr,std::vector<std::string> & realPaths,std::map<std::string,std::string> & pathMap)366 void StorageManagerService::ConvertSandboxRealPath(const uint32_t userId, const std::string &bundleName,
367     const std::string &sandboxPathStr, std::vector<std::string> &realPaths,
368     std::map<std::string, std::string>& pathMap)
369 {
370     std::string uriString;
371     if (sandboxPathStr.find(NORMAL_SAND_PREFIX) == 0) {
372         // for normal hap, start with file://bundleName
373         uriString = URI_PREFIX + bundleName;
374     } else if (sandboxPathStr.find(FILE_SAND_PREFIX) == 0) {
375         // for public files, start with file://docs
376         uriString = URI_PREFIX + FILE_AUTHORITY;
377     } else if (sandboxPathStr.find(MEDIA_SAND_PREFIX) == 0) {
378         std::string physicalPath = sandboxPathStr;
379         physicalPath.insert(MEDIA_SAND_PREFIX.length(), FILE_SEPARATOR_CHAR + std::to_string(userId));
380         realPaths.emplace_back(physicalPath);
381         pathMap.insert({physicalPath, sandboxPathStr});
382         return;
383     } else if (sandboxPathStr.find(MEDIA_CLOUD_SAND_PREFIX) == 0) {
384         std::string physicalPath = sandboxPathStr;
385         physicalPath.insert(MEDIA_CLOUD_SAND_PREFIX.length(), FILE_SEPARATOR_CHAR + std::to_string(userId));
386         realPaths.emplace_back(physicalPath);
387         pathMap.insert({physicalPath, sandboxPathStr});
388         return;
389     }
390 
391     if (!uriString.empty()) {
392         std::string sandboxPathUriStr = AppFileService::SandboxHelper::Encode(sandboxPathStr);
393         uriString += sandboxPathUriStr;
394         AppFileService::ModuleFileUri::FileUri uri(uriString);
395         // files
396         std::string physicalPath;
397         int ret = AppFileService::SandboxHelper::GetBackupPhysicalPath(uri.ToString(), std::to_string(userId),
398             physicalPath);
399         if (ret != 0) {
400             HILOGE("Get physical path failed with %{public}d", ret);
401             return;
402         }
403         realPaths.emplace_back(physicalPath);
404         pathMap.insert({physicalPath, sandboxPathStr});
405     }
406 }
407 
DeduplicationPath(std::vector<std::string> & configPaths)408 void StorageManagerService::DeduplicationPath(std::vector<std::string> &configPaths)
409 {
410     sort(configPaths.begin(), configPaths.end(), PathSortFunc);
411     auto it = unique(configPaths.begin(), configPaths.end(), [](const std::string &path1, const std::string &path2) {
412         return path1 == path2;
413     });
414     configPaths.erase(it, configPaths.end());
415 }
416 
ScanExtensionPath(BundleStatsParas & paras,const std::vector<std::string> & includes,const std::vector<std::string> & excludes,std::map<std::string,std::string> & pathMap,std::ofstream & statFile)417 void StorageManagerService::ScanExtensionPath(BundleStatsParas &paras,
418     const std::vector<std::string> &includes, const std::vector<std::string> &excludes,
419     std::map<std::string, std::string> &pathMap, std::ofstream &statFile)
420 {
421     std::map<std::string, bool> excludesMap;
422     for (auto exclude : excludes) {
423         SetExcludePathMap(exclude, excludesMap);
424     }
425     // all file with stats in include directory
426     for (const auto &includeDir : includes) {
427         // Check if includeDir is a file path
428         auto [isSucc, isDir] = CheckIfDirForIncludes(includeDir, paras, pathMap, statFile, excludesMap);
429         if (!isSucc) {
430             continue;
431         }
432         // recognize all file in include directory
433         if (isDir && !GetIncludesFileStats(includeDir, paras, pathMap, statFile, excludesMap)) {
434             HILOGE("Faied to get include files for includeDir");
435         }
436     }
437 }
438 
RecognizeSandboxWildCard(const uint32_t userId,const std::string & bundleName,const std::string & sandboxPathStr,std::vector<std::string> & phyIncludes,std::map<std::string,std::string> & pathMap)439 void StorageManagerService::RecognizeSandboxWildCard(const uint32_t userId, const std::string &bundleName,
440     const std::string &sandboxPathStr, std::vector<std::string> &phyIncludes,
441     std::map<std::string, std::string>& pathMap)
442 {
443     if (sandboxPathStr.find(BASE_EL1 + DEFAULT_PATH_WITH_WILDCARD) == 0) {
444         std::string physicalPrefix = PHY_APP + EL1 + FILE_SEPARATOR_CHAR + std::to_string(userId) + BASE +
445             bundleName + FILE_SEPARATOR_CHAR;
446         std::string relatePath = sandboxPathStr.substr(BASE_EL1.size());
447         if (!GetPathWildCard(userId, bundleName, physicalPrefix + relatePath, phyIncludes, pathMap)) {
448             HILOGE("el1 GetPathWildCard dir path invaild");
449         }
450     } else if (sandboxPathStr.find(BASE_EL2 + DEFAULT_PATH_WITH_WILDCARD) == 0) {
451         std::string physicalPrefix = PHY_APP + EL2 + FILE_SEPARATOR_CHAR + std::to_string(userId) + BASE +
452             bundleName + FILE_SEPARATOR_CHAR;
453         std::string relatePath = sandboxPathStr.substr(BASE_EL2.size());
454         if (!GetPathWildCard(userId, bundleName, physicalPrefix + relatePath, phyIncludes, pathMap)) {
455             HILOGE("el2 GetPathWildCard dir path invaild");
456         }
457     }
458 }
459 
SetExcludePathMap(std::string & excludePath,std::map<std::string,bool> & excludesMap)460 void StorageManagerService::SetExcludePathMap(std::string &excludePath, std::map<std::string, bool> &excludesMap)
461 {
462     if (excludePath.empty()) {
463         HILOGE("SetExcludePathMap Param failed");
464         return;
465     }
466     struct stat fileStatInfo = {0};
467     if (stat(excludePath.c_str(), &fileStatInfo) != 0) {
468         HILOGE("SetExcludePathMap call stat error %{private}s, errno:%{public}d", excludePath.c_str(), errno);
469         return;
470     }
471     if (S_ISDIR(fileStatInfo.st_mode)) {
472         if (excludePath.back() != FILE_SEPARATOR_CHAR) {
473             excludePath.push_back(FILE_SEPARATOR_CHAR);
474         }
475         excludesMap.insert({excludePath, true});
476     } else {
477         excludesMap.insert({excludePath, false});
478     }
479 }
480 
CheckIfDirForIncludes(const std::string & path,BundleStatsParas & paras,std::map<std::string,std::string> & pathMap,std::ofstream & statFile,std::map<std::string,bool> & excludesMap)481 std::tuple<bool, bool> StorageManagerService::CheckIfDirForIncludes(const std::string &path, BundleStatsParas &paras,
482     std::map<std::string, std::string> &pathMap, std::ofstream &statFile, std::map<std::string, bool> &excludesMap)
483 {
484     if (!statFile.is_open() || path.empty()) {
485         HILOGE("CheckIfDirForIncludes Param failed");
486         return {false, false};
487     }
488     // check whether the path exists
489     struct stat fileStatInfo = {0};
490     if (stat(path.c_str(), &fileStatInfo) != 0) {
491         HILOGE("CheckIfDirForIncludes call stat error %{public}s, fail errno:%{public}d", path.c_str(), errno);
492         return {false, false};
493     }
494     if (S_ISDIR(fileStatInfo.st_mode)) {
495         HILOGI("%{public}s exists and is a directory", path.c_str());
496         return {true, true};
497     } else {
498         std::string sandboxPath = path;
499         auto it = pathMap.find(path);
500         if (it != pathMap.end()) {
501             sandboxPath = it->second;
502         }
503 
504         struct FileStat fileStat;
505         fileStat.filePath = sandboxPath;
506         fileStat.fileSize = fileStatInfo.st_size;
507         // mode
508         fileStat.mode = static_cast<int32_t>(fileStatInfo.st_mode);
509         fileStat.isDir = false;
510         int64_t lastUpdateTime = static_cast<int64_t>(fileStatInfo.st_mtime);
511         fileStat.lastUpdateTime = lastUpdateTime;
512         if (paras.lastBackupTime == 0 || lastUpdateTime > paras.lastBackupTime) {
513             fileStat.isIncre = true;
514         }
515         if (ExcludeFilter(excludesMap, path) == false) {
516             WriteFileList(statFile, fileStat, paras);
517         }
518         return {true, false};
519     }
520 }
521 
GetIncludesFileStats(const std::string & dir,BundleStatsParas & paras,std::map<std::string,std::string> & pathMap,std::ofstream & statFile,std::map<std::string,bool> & excludesMap)522 bool StorageManagerService::GetIncludesFileStats(const std::string &dir, BundleStatsParas &paras,
523     std::map<std::string, std::string> &pathMap,
524     std::ofstream &statFile, std::map<std::string, bool> &excludesMap)
525 {
526     std::string sandboxDir = dir;
527     auto it = pathMap.find(dir);
528     if (it != pathMap.end()) {
529         sandboxDir = it->second;
530     }
531     // stat current directory info
532     AddOuterDirIntoFileStat(dir, paras, sandboxDir, statFile, excludesMap);
533 
534     std::stack<std::string> folderStack;
535     std::string filePath;
536     folderStack.push(dir);
537     // stat files and sub-directory in current directory info
538     while (!folderStack.empty()) {
539         filePath = folderStack.top();
540         folderStack.pop();
541         DIR *dirPtr = opendir(filePath.c_str());
542         if (dirPtr == nullptr) {
543             HILOGE("GetIncludesFileStats open file dir:%{private}s fail, errno:%{public}d", filePath.c_str(), errno);
544             continue;
545         }
546         if (filePath.back() != FILE_SEPARATOR_CHAR) {
547             filePath.push_back(FILE_SEPARATOR_CHAR);
548         }
549 
550         struct dirent *entry = nullptr;
551         while ((entry = readdir(dirPtr)) != nullptr) {
552             if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
553                 continue;
554             }
555             std::string path = filePath + entry->d_name;
556             struct stat fileInfo = {0};
557             if (stat(path.c_str(), &fileInfo) != 0) {
558                 HILOGE("GetIncludesFileStats call stat error %{private}s, errno:%{public}d", path.c_str(), errno);
559                 fileInfo.st_size = 0;
560             }
561             struct FileStat fileStat = {};
562             fileStat.filePath = PhysicalToSandboxPath(dir, sandboxDir, path);
563             fileStat.fileSize = fileInfo.st_size;
564             CheckOverLongPath(fileStat.filePath);
565             // mode
566             fileStat.mode = static_cast<int32_t>(fileInfo.st_mode);
567             int64_t lastUpdateTime = static_cast<int64_t>(fileInfo.st_mtime);
568             fileStat.lastUpdateTime = lastUpdateTime;
569             fileStat.isIncre = (paras.lastBackupTime == 0 || lastUpdateTime > paras.lastBackupTime) ? true : false;
570             if (entry->d_type == DT_DIR) {
571                 fileStat.isDir = true;
572                 folderStack.push(path);
573             }
574             InsertStatFile(path, fileStat, statFile, excludesMap, paras);
575         }
576         closedir(dirPtr);
577     }
578     return true;
579 }
580 
GetPathWildCard(uint32_t userId,const std::string & bundleName,const std::string & includeWildCard,std::vector<std::string> & includePathList,std::map<std::string,std::string> & pathMap)581 bool StorageManagerService::GetPathWildCard(uint32_t userId, const std::string &bundleName,
582     const std::string &includeWildCard, std::vector<std::string> &includePathList,
583     std::map<std::string, std::string> &pathMap)
584 {
585     size_t pos = includeWildCard.rfind(WILDCARD_DEFAULT_INCLUDE);
586     if (pos == std::string::npos) {
587         HILOGE("GetPathWildCard: path should include *");
588         return false;
589     }
590     std::string pathBeforeWildCard = includeWildCard.substr(0, pos);
591     DIR *dirPtr = opendir(pathBeforeWildCard.c_str());
592     if (dirPtr == nullptr) {
593         HILOGE("GetPathWildCard open file dir:%{public}s fail, errno:%{public}d", pathBeforeWildCard.c_str(), errno);
594         return false;
595     }
596     struct dirent *entry = nullptr;
597     std::vector<std::string> subDirs;
598     while ((entry = readdir(dirPtr)) != nullptr) {
599         if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
600             continue;
601         }
602         std::string path = pathBeforeWildCard + entry->d_name;
603         if (entry->d_type == DT_DIR) {
604             subDirs.emplace_back(path);
605         }
606     }
607     closedir(dirPtr);
608     for (auto &subDir : subDirs) {
609         DIR *subDirPtr = opendir(subDir.c_str());
610         if (subDirPtr == nullptr) {
611             HILOGE("GetPathWildCard open file dir:%{private}s fail, errno:%{public}d", subDir.c_str(), errno);
612             return false;
613         }
614         while ((entry = readdir(subDirPtr)) != nullptr) {
615             if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
616                 continue;
617             }
618             std::string dirName = std::string(entry->d_name);
619 
620             std::string path = subDir + FILE_SEPARATOR_CHAR + entry->d_name;
621             if (entry->d_type == DT_DIR && (dirName == DEFAULT_INCLUDE_PATH_IN_HAP_FILES ||
622                 dirName == DEFAULT_INCLUDE_PATH_IN_HAP_DATABASE ||
623                 dirName == DEFAULT_INCLUDE_PATH_IN_HAP_PREFERENCE)) {
624                 includePathList.emplace_back(path);
625                 AddPathMapForPathWildCard(userId, bundleName, path, pathMap);
626             }
627         }
628         closedir(subDirPtr);
629     }
630     return true;
631 }
632 
ExcludeFilter(std::map<std::string,bool> & excludesMap,const std::string & path)633 bool StorageManagerService::ExcludeFilter(std::map<std::string, bool> &excludesMap, const std::string &path)
634 {
635     if (path.empty()) {
636         HILOGE("ExcludeFilter Param failed");
637         return true;
638     }
639     std::string formatPath = path;
640     for (auto exclude = excludesMap.begin(); exclude != excludesMap.end(); exclude++) {
641         if (exclude->second != true) {
642             if (formatPath.compare(exclude->first) == 0) {
643                 return true;
644             }
645         } else {
646             if (formatPath.compare(0, exclude->first.size(), exclude->first) == 0 &&
647                 (formatPath.size() == exclude->first.size() || formatPath[exclude->first.size()] == '/')) {
648                 return true;
649             }
650         }
651     }
652     return false;
653 }
654 
WriteFileList(std::ofstream & statFile,struct FileStat fileStat,BundleStatsParas & paras)655 void StorageManagerService::WriteFileList(std::ofstream &statFile, struct FileStat fileStat, BundleStatsParas &paras)
656 {
657     if (!statFile.is_open() || fileStat.filePath.empty()) {
658         HILOGE("WriteFileList Param failed");
659         return;
660     }
661     std::string fileLine = "";
662     bool encodeFlag = false;
663     if (fileStat.filePath.find(LINE_SEP) != std::string::npos) {
664         fileLine += AppFileService::SandboxHelper::Encode(fileStat.filePath) + FILE_CONTENT_SEPARATOR;
665         encodeFlag = true;
666     } else {
667         fileLine += fileStat.filePath + FILE_CONTENT_SEPARATOR;
668     }
669     fileLine += std::to_string(fileStat.mode) + FILE_CONTENT_SEPARATOR;
670     if (fileStat.isDir) {
671         fileLine += std::to_string(1) + FILE_CONTENT_SEPARATOR;
672     } else {
673         fileLine += std::to_string(0) + FILE_CONTENT_SEPARATOR;
674     }
675     fileLine += std::to_string(fileStat.fileSize) + FILE_CONTENT_SEPARATOR;
676     fileLine += std::to_string(fileStat.lastUpdateTime) + FILE_CONTENT_SEPARATOR;
677     fileLine += FILE_CONTENT_SEPARATOR;
678     if (fileStat.isIncre) {
679         fileLine += std::to_string(1);
680     } else {
681         fileLine += std::to_string(0);
682     }
683     fileLine += FILE_CONTENT_SEPARATOR;
684     if (encodeFlag) {
685         fileLine += std::to_string(1);
686     } else {
687         fileLine += std::to_string(0);
688     }
689     // te file line
690     statFile << fileLine << std::endl;
691     if (fileStat.isIncre) {
692         paras.incFileSizeSum += fileStat.fileSize;
693     }
694     paras.fileSizeSum += fileStat.fileSize;
695 }
696 
AddOuterDirIntoFileStat(const std::string & dir,BundleStatsParas & paras,const std::string & sandboxDir,std::ofstream & statFile,std::map<std::string,bool> & excludesMap)697 bool StorageManagerService::AddOuterDirIntoFileStat(const std::string &dir, BundleStatsParas &paras,
698     const std::string &sandboxDir, std::ofstream &statFile, std::map<std::string, bool> &excludesMap)
699 {
700     if (!statFile.is_open() || dir.empty()) {
701         HILOGE("AddOuterDirIntoFileStat Param failed");
702         return false;
703     }
704     struct stat fileInfo = {0};
705     if (stat(dir.c_str(), &fileInfo) != 0) {
706         HILOGE("AddOuterDirIntoFileStat call stat error %{private}s, fail errno:%{public}d", dir.c_str(), errno);
707         return false;
708     }
709     struct FileStat fileStat = {};
710     fileStat.filePath = PhysicalToSandboxPath(dir, sandboxDir, dir);
711     fileStat.fileSize = fileInfo.st_size;
712     // mode
713     fileStat.mode = static_cast<int32_t>(fileInfo.st_mode);
714     int64_t lastUpdateTime = static_cast<int64_t>(fileInfo.st_mtime);
715     fileStat.lastUpdateTime = lastUpdateTime;
716     fileStat.isIncre = (paras.lastBackupTime == 0 || lastUpdateTime > paras.lastBackupTime) ? true : false;
717     fileStat.isDir = true;
718     std::string formatPath = dir;
719     if (formatPath.back() != FILE_SEPARATOR_CHAR) {
720         formatPath.push_back(FILE_SEPARATOR_CHAR);
721     }
722     if (ExcludeFilter(excludesMap, formatPath) == false) {
723         WriteFileList(statFile, fileStat, paras);
724     }
725     return true;
726 }
727 
PhysicalToSandboxPath(const std::string & dir,const std::string & sandboxDir,const std::string & path)728 std::string StorageManagerService::PhysicalToSandboxPath(const std::string &dir, const std::string &sandboxDir,
729     const std::string &path)
730 {
731     std::size_t dirPos = dir.size();
732     std::string pathSurffix = path.substr(dirPos);
733     return sandboxDir + pathSurffix;
734 }
735 
InsertStatFile(const std::string & path,struct FileStat fileStat,std::ofstream & statFile,std::map<std::string,bool> & excludesMap,BundleStatsParas & paras)736 void StorageManagerService::InsertStatFile(const std::string &path, struct FileStat fileStat,
737     std::ofstream &statFile, std::map<std::string, bool> &excludesMap, BundleStatsParas &paras)
738 {
739     if (!statFile.is_open() || path.empty()) {
740         HILOGE("InsertStatFile Param failed");
741         return;
742     }
743     std::string formatPath = path;
744     if (fileStat.isDir == true && formatPath.back() != FILE_SEPARATOR_CHAR) {
745         formatPath.push_back(FILE_SEPARATOR_CHAR);
746     }
747     if (!ExcludeFilter(excludesMap, formatPath)) {
748         WriteFileList(statFile, fileStat, paras);
749     }
750 }
751 
AddPathMapForPathWildCard(uint32_t userId,const std::string & bundleName,const std::string & phyPath,std::map<std::string,std::string> & pathMap)752 bool StorageManagerService::AddPathMapForPathWildCard(uint32_t userId, const std::string &bundleName,
753     const std::string &phyPath, std::map<std::string, std::string> &pathMap)
754 {
755     std::string physicalPrefixEl1 = PHY_APP + EL1 + FILE_SEPARATOR_CHAR + std::to_string(userId) + BASE +
756         bundleName + FILE_SEPARATOR_CHAR;
757     std::string physicalPrefixEl2 = PHY_APP + EL2 + FILE_SEPARATOR_CHAR + std::to_string(userId) + BASE +
758         bundleName + FILE_SEPARATOR_CHAR;
759     if (phyPath.find(physicalPrefixEl1) == 0) {
760         std::string relatePath = phyPath.substr(physicalPrefixEl1.size());
761         pathMap.insert({phyPath, BASE_EL1 + relatePath});
762     } else if (phyPath.find(physicalPrefixEl2) == 0) {
763         std::string relatePath = phyPath.substr(physicalPrefixEl2.size());
764         pathMap.insert({phyPath, BASE_EL2 + relatePath});
765     } else {
766         HILOGE("Invalid phyiscal path");
767         return false;
768     }
769     return true;
770 }
771 
CheckOverLongPath(const std::string & path)772 uint32_t StorageManagerService::CheckOverLongPath(const std::string &path)
773 {
774     uint32_t len = path.length();
775     if (len >= PATH_MAX_LEN) {
776         size_t found = path.find_last_of('/');
777         std::string sub = path.substr(found + 1);
778         HILOGE("Path over long, length:%{public}d, fileName:%{public}s.", len, sub.c_str());
779     }
780     return len;
781 }
782 
783 } // namespace OHOS::FileManagement::Backup