diff --git a/services/backup.cfg b/services/backup.cfg index 6fc61dab40f59ba0f92c43dd5987a4192987c80c..4c96571a37d175924f65a23ba4f728e6a0bd85e4 100644 --- a/services/backup.cfg +++ b/services/backup.cfg @@ -6,11 +6,14 @@ "uid" : "backup", "gid" : ["backup", "log"], "secon" : "u:r:backup_sa:s0", + "sandbox" : 0, + "caps" : ["DAC_READ_SEARCH", "SYS_ADMIN"], "permission" : [ "ohos.permission.STORAGE_MANAGER", "ohos.permission.GET_BUNDLE_INFO_PRIVILEGED", "ohos.permission.ACCESS_EXT_SYSTEM_ABILITY", - "ohos.permission.CONNECT_BACKUP_EXTENSION" + "ohos.permission.CONNECT_BACKUP_EXTENSION", + "ohos.permission.READ_MEDIA" ], "permission_acls" : ["ohos.permission.ACCESS_EXT_SYSTEM_ABILITY"] } diff --git a/services/backup_sa/BUILD.gn b/services/backup_sa/BUILD.gn index c5983d3a5949e2b2af453f1037ab73e93bc90df3..4f0cab5c413c9bc394c0ebd2e2d7a733ecf8199c 100644 --- a/services/backup_sa/BUILD.gn +++ b/services/backup_sa/BUILD.gn @@ -177,6 +177,7 @@ ohos_shared_library("backup_sa") { "src/module_ipc/svc_session_manager.cpp", "src/module_notify/notify_work_service.cpp", "src/module_sched/sched_scheduler.cpp", + "src/module_external/storage_manager_service.cpp", ] defines = [ @@ -194,6 +195,8 @@ ohos_shared_library("backup_sa") { ":backup_sa_ipc", "${path_backup}/interfaces/inner_api/native/backup_kit_inner:backup_kit_inner", "${path_backup}/utils:backup_utils", + "${path_backup}/interfaces/innerkits/native:sandbox_helper_native", + "${path_backup}/interfaces/innerkits/native:fileuri_native", ] external_deps = [ @@ -215,6 +218,8 @@ ohos_shared_library("backup_sa") { "safwk:system_ability_fwk", "samgr:samgr_proxy", "storage_service:storage_manager_sa_proxy", + "data_share:datashare_consumer", + "data_share:datashare_common", ] cflags_cc = [ diff --git a/services/backup_sa/include/module_external/storage_manager_service.h b/services/backup_sa/include/module_external/storage_manager_service.h new file mode 100644 index 0000000000000000000000000000000000000000..ac57da922303d90d6c21782eea4d793aabfe5945 --- /dev/null +++ b/services/backup_sa/include/module_external/storage_manager_service.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_FILEMGMT_BACKUP_STORAGE_MGR_SERVICE_H +#define OHOS_FILEMGMT_BACKUP_STORAGE_MGR_SERVICE_H + +#include +#include +#include + +#include "istorage_manager.h" +#include "datashare_abs_result_set.h" +#include "datashare_helper.h" +#include "datashare_predicates.h" + +namespace OHOS::FileManagement::Backup { +const uint64_t PATH_MAX_LEN = 4096; +const std::string PHY_APP = "/data/app/"; +const std::string WILDCARD_DEFAULT_INCLUDE = "*"; +constexpr char FILE_SEPARATOR_CHAR = '/'; +const std::string BASE_EL1 = "/data/storage/el1/base/"; +const std::string BASE_EL2 = "/data/storage/el2/base/"; +const std::string EL1 = "el1"; +const std::string EL2 = "el2"; +const std::string BASE = "/base/"; +const std::string BACKUP_INCLUDE = "INCLUDES"; +const std::string BACKUP_EXCLUDE = "EXCLUDES"; +const std::string BACKUP_PATH_PREFIX = "/data/service/el2/"; +const std::string BACKUP_PATH_SURFFIX = "/backup/backup_sa/"; +const std::string BACKUP_INCEXC_SYMBOL = "incExc_"; +const std::string BACKUP_STAT_SYMBOL = "stat_"; +const std::string DEFAULT_INCLUDE_PATH_IN_HAP_FILES = "files"; +const std::string DEFAULT_INCLUDE_PATH_IN_HAP_DATABASE = "database"; +const std::string DEFAULT_INCLUDE_PATH_IN_HAP_PREFERENCE = "preferences"; +const std::string MEDIA_CLOUD_SAND_PREFIX = "/storage/cloud"; +const std::string MEDIA_SAND_PREFIX = "/storage/media"; +const std::string URI_PREFIX = "file://"; +const std::string NORMAL_SAND_PREFIX = "/data/storage"; +const std::string FILE_SAND_PREFIX = "/storage/Users"; +const std::string FILE_AUTHORITY = "docs"; +const std::string DEFAULT_PATH_WITH_WILDCARD = "haps/*"; +const std::string FILE_CONTENT_SEPARATOR = ";"; +const char LINE_SEP = '\n'; +const std::string VER_10_LINE1 = "version=1.0&attrNum=8"; +const std::string VER_10_LINE2 = "path;mode;dir;size;mtime;hash;isIncremental;encodeFlag"; +const std::string MEDIALIBRARY_DATA_URI = "datashare:///media"; +const std::string MEDIA_QUERYOPRN_QUERYVOLUME = "query_media_volume"; +const std::string MEDIA_TYPE = "media"; +const std::string FILE_TYPE = "file"; +const std::int32_t E_OK = 0; +constexpr int32_t E_ERR = -1; +constexpr int32_t STORAGE_SERVICE_SYS_CAP_TAG = 13600000; +constexpr const char *QUOTA_DEVICE_DATA_PATH = "/data"; +constexpr const char *PROC_MOUNTS_PATH = "/proc/mounts"; +constexpr const char *DEV_BLOCK_PATH = "/dev/block/"; +const std::int32_t E_SA_IS_NULLPTR = STORAGE_SERVICE_SYS_CAP_TAG + 12; +const std::int32_t E_REMOTE_IS_NULLPTR = STORAGE_SERVICE_SYS_CAP_TAG + 13; +const std::int32_t E_MEDIALIBRARY_ERROR = STORAGE_SERVICE_SYS_CAP_TAG + 1202; +const std::int32_t E_QUERY = STORAGE_SERVICE_SYS_CAP_TAG + 1206; +const std::int32_t E_GETROWCOUNT = STORAGE_SERVICE_SYS_CAP_TAG + 1207; +const std::int32_t E_SYS_KERNEL_ERR = STORAGE_SERVICE_SYS_CAP_TAG + 8; +const int MEDIA_TYPE_IMAGE = 1; +const int MEDIA_TYPE_VIDEO = 2; +const int MEDIA_TYPE_AUDIO = 3; +const int32_t GET_DATA_SHARE_HELPER_TIMES = 5; +const int UID_FILE_MANAGER = 1006; +const int32_t USER_ID_BASE = 200000; +static std::map mQuotaReverseMounts; + + +struct FileStat { + std::string filePath; + int64_t fileSize; + int64_t lastUpdateTime; + int32_t mode; + bool isDir; + bool isIncre; +}; +struct BundleStatsParas { + uint32_t userId; + std::string &bundleName; + int64_t lastBackupTime; + int64_t fileSizeSum; + int64_t incFileSizeSum; +}; + +class StorageManagerService { +public: + static StorageManagerService &GetInstance() + { + static StorageManagerService instance {}; + return instance; + } + /** + * @brief Get the bundle stats object + * + * @param bundleName bundle name + */ + bool GetBundleStats(const std::string &bundleName, StorageManager::BundleStats &bundleStats); + + /** + * @brief Get the user storage stats object + * + * @param bundleName bundle name + * @param userId user id + */ + int32_t GetUserStorageStatsByType(int32_t userId, StorageManager::StorageStats &storageStats, std::string type); + + /** + * @brief update memory para + * + * @param size para data + */ + int32_t UpdateMemoryPara(int32_t size, int32_t oldSize); + + /** + * @brief Get the user storage stats object + * + * @param userId user id + * @param bundleNames + * @param incrementalBackTimes + * @param pkgFileSizes bundle backup file size + * @param incPkgFileSizes Incremental bundle backup file size + */ + int32_t GetBundleStatsForIncrease(uint32_t userId, const std::vector &bundleNames, + const std::vector &incrementalBackTimes, std::vector &pkgFileSizes, + std::vector &incPkgFileSizes); +private: + StorageManagerService() = default; + ~StorageManagerService() = default; + void GetBundleStatsForIncreaseEach(uint32_t userId, std::string &bundleName, int64_t lastBackupTime, + std::vector &pkgFileSizes, std::vector &incPkgFileSizes); + std::tuple, std::vector> ReadIncludesExcludesPath( + const std::string &bundleName, const int64_t lastBackupTime, const uint32_t userId); + void DealWithIncludeFiles(const BundleStatsParas ¶s, const std::vector &includes, + std::vector &phyIncludes, std::map& pathMap); + void ConvertSandboxRealPath(const uint32_t userId, const std::string &bundleName, + const std::string &sandboxPathStr, std::vector &realPaths, + std::map& pathMap); + void DeduplicationPath(std::vector &configPaths); + void ScanExtensionPath(BundleStatsParas ¶s, + const std::vector &includes, const std::vector &excludes, + std::map &pathMap, std::ofstream &statFile); + void RecognizeSandboxWildCard(const uint32_t userId, const std::string &bundleName, + const std::string &sandboxPathStr, std::vector &phyIncludes, + std::map& pathMap); + void SetExcludePathMap(std::string &excludePath, std::map &excludesMap); + std::tuple CheckIfDirForIncludes(const std::string &path, BundleStatsParas ¶s, + std::map &pathMap, std::ofstream &statFile, std::map &excludesMap); + bool GetIncludesFileStats(const std::string &dir, BundleStatsParas ¶s, + std::map &pathMap, + std::ofstream &statFile, std::map &excludesMap); + bool GetPathWildCard(uint32_t userId, const std::string &bundleName, const std::string &includeWildCard, + std::vector &includePathList, std::map &pathMap); + bool ExcludeFilter(std::map &excludesMap, const std::string &path); + void WriteFileList(std::ofstream &statFile, struct FileStat fileStat, BundleStatsParas ¶s); + bool AddOuterDirIntoFileStat(const std::string &dir, BundleStatsParas ¶s, const std::string &sandboxDir, + std::ofstream &statFile, std::map &excludesMap); + std::string PhysicalToSandboxPath(const std::string &dir, const std::string &sandboxDir, const std::string &path); + void InsertStatFile(const std::string &path, struct FileStat fileStat, + std::ofstream &statFile, std::map &excludesMap, BundleStatsParas ¶s); + bool AddPathMapForPathWildCard(uint32_t userId, const std::string &bundleName, const std::string &phyPath, + std::map &pathMap); + uint32_t CheckOverLongPath(const std::string &path); + int32_t GetMediaStorageStats(StorageManager::StorageStats &storageStats); + void GetMediaTypeAndSize(const std::shared_ptr &resultSet, + StorageManager::StorageStats &storageStats); + int32_t GetFileStorageStats(int32_t userId, StorageManager::StorageStats &storageStats); + bool InitialiseQuotaMounts(); +}; +} // namespace OHOS::FileManagement::Backup +#endif // OHOS_FILEMGMT_BACKUP_STORAGE_MGR_SERVICE_H \ No newline at end of file diff --git a/services/backup_sa/src/module_external/storage_manager_service.cpp b/services/backup_sa/src/module_external/storage_manager_service.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02af0ec49b1876104dd4403c806d7a556ca44a44 --- /dev/null +++ b/services/backup_sa/src/module_external/storage_manager_service.cpp @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module_external/storage_manager_service.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_resources/b_constants.h" +#include "filemgmt_libhilog.h" +#include "sandbox_helper.h" +#include "file_uri.h" + +#include +#include + +namespace OHOS::FileManagement::Backup { +using namespace std; +std::recursive_mutex mMountsLock; + +static bool PathSortFunc(const std::string &path1, const std::string &path2) +{ + return path1 < path2; +} + +static std::string GetQuotaSrcMountPath(const std::string &target) +{ + std::lock_guard lock(mMountsLock); + if (mQuotaReverseMounts.find(target) != mQuotaReverseMounts.end()) { + return mQuotaReverseMounts[target]; + } else { + return ""; + } +} + +bool StorageManagerService::GetBundleStats(const string &bundleName, + StorageManager::BundleStats &storageStats) +{ + return true; +} + +int32_t StorageManagerService::GetUserStorageStatsByType(int32_t userId, StorageManager::StorageStats &storageStats, + std::string type) +{ + storageStats.video_ = 0; + storageStats.image_ = 0; + storageStats.file_ = 0; + int32_t err = E_ERR; + if (type == MEDIA_TYPE) { + HILOGI("GetUserStorageStatsByType media"); + err = GetMediaStorageStats(storageStats); + } else if (type == FILE_TYPE) { + HILOGI("GetUserStorageStatsByType file"); + err = GetFileStorageStats(userId, storageStats); + } else { + HILOGI("GetUserStorageStatsByType type: %{public}s", type.c_str()); + } + return err; +} + +int32_t StorageManagerService::GetMediaStorageStats(StorageManager::StorageStats &storageStats) +{ + HILOGE("GetMediaStorageStats start"); + auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (sam == nullptr) { + HILOGE("StorageStatusService::GetMediaStorageStats samgr == nullptr"); + return E_SA_IS_NULLPTR; + } + auto remoteObj = sam->GetSystemAbility(FILEMANAGEMENT_BACKUP_SERVICE_SA_ID); + if (remoteObj == nullptr) { + HILOGE("StorageStatusService::GetMediaStorageStats remoteObj == nullptr"); + return E_REMOTE_IS_NULLPTR; + } + int32_t tryCount = 1; + HILOGE("GetMediaStorageStats start Creator"); + auto dataShareHelper = DataShare::DataShareHelper::Creator(remoteObj, MEDIALIBRARY_DATA_URI); + while (dataShareHelper == nullptr && tryCount < GET_DATA_SHARE_HELPER_TIMES) { + HILOGW("dataShareHelper is retrying, attempt %{public}d", tryCount); + dataShareHelper = DataShare::DataShareHelper::Creator(remoteObj, MEDIALIBRARY_DATA_URI); + tryCount++; + } + if (dataShareHelper == nullptr) { + HILOGE("dataShareHelper is null!"); + return E_MEDIALIBRARY_ERROR; + } + vector columns; + Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_QUERYOPRN_QUERYVOLUME + "/" + MEDIA_QUERYOPRN_QUERYVOLUME); + DataShare::DataSharePredicates predicates; + HILOGE("GetMediaStorageStats start Query"); + auto queryResultSet = dataShareHelper->Query(uri, predicates, columns); + if (queryResultSet == nullptr) { + HILOGE("queryResultSet is null!"); + return E_QUERY; + } + auto count = 0; + auto ret = queryResultSet->GetRowCount(count); + if ((ret != E_OK) || (count < 0)) { + HILOGE("get row count from rdb failed"); + return E_GETROWCOUNT; + } + GetMediaTypeAndSize(queryResultSet, storageStats); + dataShareHelper->Release(); + HILOGE("GetMediaStorageStats end"); + return E_OK; +} + +void StorageManagerService::GetMediaTypeAndSize(const std::shared_ptr &resultSet, + StorageManager::StorageStats &storageStats) +{ +} + +int32_t StorageManagerService::GetFileStorageStats(int32_t userId, StorageManager::StorageStats &storageStats) +{ + int32_t uid = userId * USER_ID_BASE + UID_FILE_MANAGER; + HILOGE("GetOccupiedSpaceForUid uid:%{public}d", uid); + if (InitialiseQuotaMounts() != true) { + HILOGE("Failed to initialise quota mounts"); + return E_SYS_KERNEL_ERR; + } + + std::string device = ""; + device = GetQuotaSrcMountPath(QUOTA_DEVICE_DATA_PATH); + if (device.empty()) { + HILOGE("skip when device no quotas present"); + return E_OK; + } + + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast(&dq)) != 0) { + HILOGE("Failed to get quotactl, errno : %{public}d", errno); + return E_SYS_KERNEL_ERR; + } + storageStats.file_ = static_cast(dq.dqb_curspace); + HILOGE("GetOccupiedSpaceForUid size:%{public}s", std::to_string(storageStats.file_).c_str()); + return E_OK; +} + +bool StorageManagerService::InitialiseQuotaMounts() +{ + std::lock_guard lock(mMountsLock); + mQuotaReverseMounts.clear(); + std::ifstream in(PROC_MOUNTS_PATH); + + if (!in.is_open()) { + HILOGE("Failed to open mounts file"); + return false; + } + std::string source; + std::string target; + std::string ignored; + + while (in.peek() != EOF) { + std::getline(in, source, ' '); + std::getline(in, target, ' '); + std::getline(in, ignored); + if (source.compare(0, strlen(DEV_BLOCK_PATH), DEV_BLOCK_PATH) == 0 + && target.compare(QUOTA_DEVICE_DATA_PATH) == 0) { + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, reinterpret_cast(&dq)) == 0) { + mQuotaReverseMounts[target] = source; + } + } + } + return true; +} + +int32_t StorageManagerService::UpdateMemoryPara(int32_t size, int32_t oldSize) +{ + return E_OK; +} + +int32_t StorageManagerService::GetBundleStatsForIncrease(uint32_t userId, const std::vector &bundleNames, + const std::vector &incrementalBackTimes, std::vector &pkgFileSizes, + std::vector &incPkgFileSizes) +{ + HILOGI("GetBundleStatsForIncrease start"); + if (bundleNames.size() != incrementalBackTimes.size()) { + HILOGE("Invalid paramters, size of bundleNames should match incrementalBackTimes."); + return E_ERR; + } + for (size_t i = 0; i < bundleNames.size(); i++) { + std::string bundleName = bundleNames[i]; + int64_t lastBackupTime = incrementalBackTimes[i]; + GetBundleStatsForIncreaseEach(userId, bundleName, lastBackupTime, pkgFileSizes, incPkgFileSizes); + } + return E_OK; +} + +void StorageManagerService::GetBundleStatsForIncreaseEach(uint32_t userId, std::string &bundleName, + int64_t lastBackupTime, std::vector &pkgFileSizes, std::vector &incPkgFileSizes) +{ +} + +std::tuple, std::vector> StorageManagerService::ReadIncludesExcludesPath( + const std::string &bundleName, const int64_t lastBackupTime, const uint32_t userId) +{ + if (bundleName.empty()) { + HILOGE("bundleName is empty"); + return { {}, {} }; + } + // 保存includeExclude的path + std::string filePath = BACKUP_PATH_PREFIX + std::to_string(userId) + BACKUP_PATH_SURFFIX + + bundleName + FILE_SEPARATOR_CHAR + BACKUP_INCEXC_SYMBOL + std::to_string(lastBackupTime); + std::ifstream incExcFile; + incExcFile.open(filePath.data()); + if (!incExcFile.is_open()) { + HILOGE("Cannot open include/exclude file, fail errno:%{public}d", errno); + return { {}, {} }; + } + + std::vector includes; + std::vector excludes; + bool incOrExt = true; + while (incExcFile) { + std::string line; + std::getline(incExcFile, line); + if (line.empty()) { + HILOGI("Read Complete"); + break; + } + if (line == BACKUP_INCLUDE) { + incOrExt = true; + } else if (line == BACKUP_EXCLUDE) { + incOrExt = false; + } + if (incOrExt && line != BACKUP_INCLUDE) { + includes.emplace_back(line); + } else if (!incOrExt && line != BACKUP_EXCLUDE) { + excludes.emplace_back(line); + } + } + incExcFile.close(); + return {includes, excludes}; +} + +void StorageManagerService::DealWithIncludeFiles(const BundleStatsParas ¶s, + const std::vector &includes, std::vector &phyIncludes, + std::map& pathMap) +{ +} + +void StorageManagerService::ConvertSandboxRealPath(const uint32_t userId, const std::string &bundleName, + const std::string &sandboxPathStr, std::vector &realPaths, + std::map& pathMap) +{ +} + +void StorageManagerService::DeduplicationPath(std::vector &configPaths) +{ +} + +void StorageManagerService::ScanExtensionPath(BundleStatsParas ¶s, + const std::vector &includes, const std::vector &excludes, + std::map &pathMap, std::ofstream &statFile) +{ +} + +void StorageManagerService::RecognizeSandboxWildCard(const uint32_t userId, const std::string &bundleName, + const std::string &sandboxPathStr, std::vector &phyIncludes, + std::map& pathMap) +{ +} + +void StorageManagerService::SetExcludePathMap(std::string &excludePath, std::map &excludesMap) +{ +} + +std::tuple StorageManagerService::CheckIfDirForIncludes(const std::string &path, BundleStatsParas ¶s, + std::map &pathMap, std::ofstream &statFile, std::map &excludesMap) +{ + if (!statFile.is_open() || path.empty()) { + HILOGE("CheckIfDirForIncludes Param failed"); + return {false, false}; + } + // check whether the path exists + struct stat fileStatInfo = {0}; + if (stat(path.c_str(), &fileStatInfo) != 0) { + HILOGE("CheckIfDirForIncludes call stat error %{public}s, fail errno:%{public}d", path.c_str(), errno); + return {false, false}; + } + if (S_ISDIR(fileStatInfo.st_mode)) { + HILOGI("%{public}s exists and is a directory", path.c_str()); + return {true, true}; + } else { + std::string sandboxPath = path; + auto it = pathMap.find(path); + if (it != pathMap.end()) { + sandboxPath = it->second; + } + + struct FileStat fileStat; + fileStat.filePath = sandboxPath; + fileStat.fileSize = fileStatInfo.st_size; + // mode + fileStat.mode = static_cast(fileStatInfo.st_mode); + fileStat.isDir = false; + int64_t lastUpdateTime = static_cast(fileStatInfo.st_mtime); + fileStat.lastUpdateTime = lastUpdateTime; + if (paras.lastBackupTime == 0 || lastUpdateTime > paras.lastBackupTime) { + fileStat.isIncre = true; + } + if (ExcludeFilter(excludesMap, path) == false) { + WriteFileList(statFile, fileStat, paras); + } + return {true, false}; + } +} + +bool StorageManagerService::GetIncludesFileStats(const std::string &dir, BundleStatsParas ¶s, + std::map &pathMap, + std::ofstream &statFile, std::map &excludesMap) +{ + std::string sandboxDir = dir; + auto it = pathMap.find(dir); + if (it != pathMap.end()) { + sandboxDir = it->second; + } + // stat current directory info + AddOuterDirIntoFileStat(dir, paras, sandboxDir, statFile, excludesMap); + + std::stack folderStack; + std::string filePath; + folderStack.push(dir); + // stat files and sub-directory in current directory info + while (!folderStack.empty()) { + filePath = folderStack.top(); + folderStack.pop(); + DIR *dirPtr = opendir(filePath.c_str()); + if (dirPtr == nullptr) { + HILOGE("GetIncludesFileStats open file dir:%{private}s fail, errno:%{public}d", filePath.c_str(), errno); + continue; + } + if (filePath.back() != FILE_SEPARATOR_CHAR) { + filePath.push_back(FILE_SEPARATOR_CHAR); + } + + struct dirent *entry = nullptr; + while ((entry = readdir(dirPtr)) != nullptr) { + if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) { + continue; + } + std::string path = filePath + entry->d_name; + struct stat fileInfo = {0}; + if (stat(path.c_str(), &fileInfo) != 0) { + HILOGE("GetIncludesFileStats call stat error %{private}s, errno:%{public}d", path.c_str(), errno); + fileInfo.st_size = 0; + } + struct FileStat fileStat = {}; + fileStat.filePath = PhysicalToSandboxPath(dir, sandboxDir, path); + fileStat.fileSize = fileInfo.st_size; + CheckOverLongPath(fileStat.filePath); + // mode + fileStat.mode = static_cast(fileInfo.st_mode); + int64_t lastUpdateTime = static_cast(fileInfo.st_mtime); + fileStat.lastUpdateTime = lastUpdateTime; + fileStat.isIncre = (paras.lastBackupTime == 0 || lastUpdateTime > paras.lastBackupTime) ? true : false; + if (entry->d_type == DT_DIR) { + fileStat.isDir = true; + folderStack.push(path); + } + InsertStatFile(path, fileStat, statFile, excludesMap, paras); + } + closedir(dirPtr); + } + return true; +} + +bool StorageManagerService::GetPathWildCard(uint32_t userId, const std::string &bundleName, + const std::string &includeWildCard, std::vector &includePathList, + std::map &pathMap) +{ + size_t pos = includeWildCard.rfind(WILDCARD_DEFAULT_INCLUDE); + if (pos == std::string::npos) { + HILOGE("GetPathWildCard: path should include *"); + return false; + } + std::string pathBeforeWildCard = includeWildCard.substr(0, pos); + DIR *dirPtr = opendir(pathBeforeWildCard.c_str()); + if (dirPtr == nullptr) { + HILOGE("GetPathWildCard open file dir:%{public}s fail, errno:%{public}d", pathBeforeWildCard.c_str(), errno); + return false; + } + struct dirent *entry = nullptr; + std::vector subDirs; + while ((entry = readdir(dirPtr)) != nullptr) { + if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) { + continue; + } + std::string path = pathBeforeWildCard + entry->d_name; + if (entry->d_type == DT_DIR) { + subDirs.emplace_back(path); + } + } + closedir(dirPtr); + for (auto &subDir : subDirs) { + DIR *subDirPtr = opendir(subDir.c_str()); + if (subDirPtr == nullptr) { + HILOGE("GetPathWildCard open file dir:%{private}s fail, errno:%{public}d", subDir.c_str(), errno); + return false; + } + while ((entry = readdir(subDirPtr)) != nullptr) { + if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) { + continue; + } + std::string dirName = std::string(entry->d_name); + + std::string path = subDir + FILE_SEPARATOR_CHAR + entry->d_name; + if (entry->d_type == DT_DIR && (dirName == DEFAULT_INCLUDE_PATH_IN_HAP_FILES || + dirName == DEFAULT_INCLUDE_PATH_IN_HAP_DATABASE || + dirName == DEFAULT_INCLUDE_PATH_IN_HAP_PREFERENCE)) { + includePathList.emplace_back(path); + AddPathMapForPathWildCard(userId, bundleName, path, pathMap); + } + } + closedir(subDirPtr); + } + return true; +} + +bool StorageManagerService::ExcludeFilter(std::map &excludesMap, const std::string &path) +{ + if (path.empty()) { + HILOGE("ExcludeFilter Param failed"); + return true; + } + std::string formatPath = path; + for (auto exclude = excludesMap.begin(); exclude != excludesMap.end(); exclude++) { + if (exclude->second != true) { + if (formatPath.compare(exclude->first) == 0) { + return true; + } + } else { + if (formatPath.compare(0, exclude->first.size(), exclude->first) == 0 && + (formatPath.size() == exclude->first.size() || formatPath[exclude->first.size()] == '/')) { + return true; + } + } + } + return false; +} + +void StorageManagerService::WriteFileList(std::ofstream &statFile, struct FileStat fileStat, BundleStatsParas ¶s) +{ +} + +bool StorageManagerService::AddOuterDirIntoFileStat(const std::string &dir, BundleStatsParas ¶s, + const std::string &sandboxDir, std::ofstream &statFile, std::map &excludesMap) +{ + if (!statFile.is_open() || dir.empty()) { + HILOGE("AddOuterDirIntoFileStat Param failed"); + return false; + } + struct stat fileInfo = {0}; + if (stat(dir.c_str(), &fileInfo) != 0) { + HILOGE("AddOuterDirIntoFileStat call stat error %{private}s, fail errno:%{public}d", dir.c_str(), errno); + return false; + } + struct FileStat fileStat = {}; + fileStat.filePath = PhysicalToSandboxPath(dir, sandboxDir, dir); + fileStat.fileSize = fileInfo.st_size; + // mode + fileStat.mode = static_cast(fileInfo.st_mode); + int64_t lastUpdateTime = static_cast(fileInfo.st_mtime); + fileStat.lastUpdateTime = lastUpdateTime; + fileStat.isIncre = (paras.lastBackupTime == 0 || lastUpdateTime > paras.lastBackupTime) ? true : false; + fileStat.isDir = true; + std::string formatPath = dir; + if (formatPath.back() != FILE_SEPARATOR_CHAR) { + formatPath.push_back(FILE_SEPARATOR_CHAR); + } + if (ExcludeFilter(excludesMap, formatPath) == false) { + WriteFileList(statFile, fileStat, paras); + } + return true; +} + +std::string StorageManagerService::PhysicalToSandboxPath(const std::string &dir, const std::string &sandboxDir, + const std::string &path) +{ + std::size_t dirPos = dir.size(); + std::string pathSurffix = path.substr(dirPos); + return sandboxDir + pathSurffix; +} + +void StorageManagerService::InsertStatFile(const std::string &path, struct FileStat fileStat, + std::ofstream &statFile, std::map &excludesMap, BundleStatsParas ¶s) +{ +} + +bool StorageManagerService::AddPathMapForPathWildCard(uint32_t userId, const std::string &bundleName, + const std::string &phyPath, std::map &pathMap) +{ + std::string physicalPrefixEl1 = PHY_APP + EL1 + FILE_SEPARATOR_CHAR + std::to_string(userId) + BASE + + bundleName + FILE_SEPARATOR_CHAR; + std::string physicalPrefixEl2 = PHY_APP + EL2 + FILE_SEPARATOR_CHAR + std::to_string(userId) + BASE + + bundleName + FILE_SEPARATOR_CHAR; + if (phyPath.find(physicalPrefixEl1) == 0) { + std::string relatePath = phyPath.substr(physicalPrefixEl1.size()); + pathMap.insert({phyPath, BASE_EL1 + relatePath}); + } else if (phyPath.find(physicalPrefixEl2) == 0) { + std::string relatePath = phyPath.substr(physicalPrefixEl2.size()); + pathMap.insert({phyPath, BASE_EL2 + relatePath}); + } else { + HILOGE("Invalid phyiscal path"); + return false; + } + return true; +} + +uint32_t StorageManagerService::CheckOverLongPath(const std::string &path) +{ + uint32_t len = path.length(); + if (len >= PATH_MAX_LEN) { + size_t found = path.find_last_of('/'); + std::string sub = path.substr(found + 1); + HILOGE("Path over long, length:%{public}d, fileName:%{public}s.", len, sub.c_str()); + } + return len; +} + +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_sa/module_external/BUILD.gn b/tests/unittests/backup_sa/module_external/BUILD.gn index a161cb53634b29ab841663d03231c403e9703cbe..f0f63b4d4ccd47830d0f5c50b8c6d90a4cf82022 100644 --- a/tests/unittests/backup_sa/module_external/BUILD.gn +++ b/tests/unittests/backup_sa/module_external/BUILD.gn @@ -62,7 +62,70 @@ ohos_unittest("bms_adapter_test") { use_exceptions = true } +ohos_unittest("storage_manager_service_test") { + module_out_path = path_module_out_tests + + include_dirs = [ + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + "${path_backup}/services/backup_sa/include", + "${path_backup}/services/backup_sa/src", + "${path_backup}/utils/include", + "${path_backup}/utils/include/b_hilog", + "${path_backup_mock}/utils_mock/include", + ] + + sources = [ + "${path_backup_mock}/utils_mock/src/b_jsonutil_mock.cpp", + "${path_backup_mock}/utils_mock/src/b_sa_utils_mock.cpp", + "storage_manager_service_test.cpp", + ] + + deps = [ + "${path_backup}/interfaces/inner_api/native/backup_kit_inner:backup_kit_inner", + "${path_backup}/utils:backup_utils", + "${path_backup}/interfaces/innerkits/native:sandbox_helper_native", + "${path_backup}/interfaces/innerkits/native:fileuri_native", + "${path_backup}/services/backup_sa:backup_sa" + ] + + defines = [ + "LOG_TAG=\"app_file_service\"", + "LOG_DOMAIN=0xD200000", + "private = public", + "protected = public", + ] + + external_deps = [ + "ability_base:want", + "ability_runtime:ability_connect_callback_stub", + "ability_runtime:ability_manager", + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "init:libbegetutil", + "ipc:ipc_core", + "jsoncpp:jsoncpp", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + "storage_service:storage_manager_sa_proxy", + "data_share:datashare_consumer", + "data_share:datashare_common", + "googletest:gmock_main", + "googletest:gtest_main", + ] + + use_exceptions = true +} + group("adapter_test") { testonly = true - deps = [ ":bms_adapter_test" ] + deps = [ + ":bms_adapter_test", + ":storage_manager_service_test" ] } diff --git a/tests/unittests/backup_sa/module_external/storage_manager_service_test.cpp b/tests/unittests/backup_sa/module_external/storage_manager_service_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b1a34425b92ef1ce3d9b6b7630f048851fa909c --- /dev/null +++ b/tests/unittests/backup_sa/module_external/storage_manager_service_test.cpp @@ -0,0 +1,141 @@ +/*) + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "b_jsonutil_mock.h" +#include "b_sa_utils_mock.h" + +#include +#include +#include +#include "file_uri.h" +#include "sandbox_helper.h" +#include "module_external/storage_manager_service.h" +#include "module_external/storage_manager_service.cpp" + +namespace OHOS { +const std::string CAMERA_BUNDLENAME = "file"; +using namespace std; +using namespace testing; +using namespace FileManagement::Backup; +namespace fs = std::filesystem; +class StorageManagerServiceTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; + +void StorageManagerServiceTest::SetUpTestCase(void) {} +void StorageManagerServiceTest::TearDownTestCase(void) {} +void StorageManagerServiceTest::SetUp(void) {} +void StorageManagerServiceTest::TearDown(void) {} + +/** + * @tc.name: Storage_Manager_ServiceTest_GetBundleStatsForIncrease_001 + * @tc.desc: check the GetBundleStatsForIncrease function + * @tc.type: FUNC + * @tc.require: AR000IGCR7 + */ +HWTEST_F(StorageManagerServiceTest, Storage_Manager_ServiceTest_GetBundleStatsForIncrease_001, + testing::ext::TestSize.Level1) +{ + uint32_t userId = 100; + std::vector bundleNames = {"com.example.app1", "com.example.app2"}; + std::vector incrementalBackTimes = {123456789}; + std::vector pkgFileSizes; + std::vector incPkgFileSizes; + int32_t result = StorageManagerService::GetInstance().GetBundleStatsForIncrease(userId, bundleNames, + incrementalBackTimes, pkgFileSizes, incPkgFileSizes); + EXPECT_EQ(result, E_ERR); +} + +/** + * @tc.name: Storage_Manager_ServiceTest_GetBundleStatsForIncrease_002 + * @tc.desc: check the GetBundleStatsForIncrease function + * @tc.type: FUNC + * @tc.require: AR000IGCR7 + */ +HWTEST_F(StorageManagerServiceTest, Storage_Manager_ServiceTest_GetBundleStatsForIncrease_002, + testing::ext::TestSize.Level1) +{ + uint32_t userId = 100; + std::vector bundleNames = {"com.example.app1", "com.example.app2"}; + std::vector incrementalBackTimes = {123456789, 987654321}; + std::vector pkgFileSizes; + std::vector incPkgFileSizes; + int32_t result = StorageManagerService::GetInstance().GetBundleStatsForIncrease(userId, bundleNames, + incrementalBackTimes, pkgFileSizes, incPkgFileSizes); + EXPECT_EQ(result, 0); +} + +/** + * @tc.name: Storage_Manager_ServiceTest_GetBundleStatsForIncreaseEach_001 + * @tc.desc: check the GetBundleStatsForIncreaseEach function + * @tc.type: FUNC + * @tc.require: AR000IGCR7 + */ +HWTEST_F(StorageManagerServiceTest, Storage_Manager_ServiceTest_GetBundleStatsForIncreaseEach_001, + testing::ext::TestSize.Level1) +{ + uint32_t userId = 100; + std::string bundleName = "testBundle"; + int64_t lastBackupTime = 123456789; + std::vector pkgFileSizes; + std::vector incPkgFileSizes; + StorageManagerService::GetInstance().GetBundleStatsForIncreaseEach(userId, bundleName, lastBackupTime, + pkgFileSizes, incPkgFileSizes); + EXPECT_EQ(pkgFileSizes.size(), 1); + EXPECT_EQ(pkgFileSizes[0], 0); + EXPECT_EQ(incPkgFileSizes.size(), 1); + EXPECT_EQ(incPkgFileSizes[0], 0); +} + +/** + * @tc.name: Storage_Manager_ServiceTest_ReadIncludesExcludesPath_001 + * @tc.desc: check the ReadIncludesExcludesPath function + * @tc.type: FUNC + * @tc.require: AR000IGCR7 + */ +HWTEST_F(StorageManagerServiceTest, Storage_Manager_ServiceTest_ReadIncludesExcludesPath_001, + testing::ext::TestSize.Level1) +{ + std::string bundleName = ""; + int64_t lastBackupTime = 123456789; + uint32_t userId = 100; + auto result = StorageManagerService::GetInstance().ReadIncludesExcludesPath(bundleName, lastBackupTime, userId); + EXPECT_TRUE(std::get<0>(result).empty()); + EXPECT_TRUE(std::get<1>(result).empty()); +} + +/** + * @tc.name: Storage_Manager_ServiceTest_ReadIncludesExcludesPath_002 + * @tc.desc: check the ReadIncludesExcludesPath function + * @tc.type: FUNC + * @tc.require: AR000IGCR7 + */ +HWTEST_F(StorageManagerServiceTest, Storage_Manager_ServiceTest_ReadIncludesExcludesPath_002, + testing::ext::TestSize.Level1) +{ + std::string bundleName = "testBundle"; + int64_t lastBackupTime = 123456789; + uint32_t userId = 100; + // Assuming the file does not exist or cannot be opened + auto result = StorageManagerService::GetInstance().ReadIncludesExcludesPath(bundleName, lastBackupTime, userId); + EXPECT_TRUE(std::get<0>(result).empty()); + EXPECT_TRUE(std::get<1>(result).empty()); +} +}