diff --git a/frameworks/native/backup_ext/include/ext_extension.h b/frameworks/native/backup_ext/include/ext_extension.h index c39e05fcd9dbdfcc9d29cc48be36a806f5c75ec2..77151d99f99cc747b1eb5cbc01b1d1814d591f25 100644 --- a/frameworks/native/backup_ext/include/ext_extension.h +++ b/frameworks/native/backup_ext/include/ext_extension.h @@ -21,6 +21,7 @@ #include #include "b_json/b_json_entity_extension_config.h" +#include "b_json/b_json_entity_ext_manage.h" #include "b_resources/b_constants.h" #include "ext_backup_js.h" #include "ext_extension_stub.h" @@ -95,9 +96,15 @@ private: void AsyncTaskOnBackup(); + bool isIndexReadyForRestore(std::vector indexInfos_); + + bool getInfoFromIndexFile(std::vector indexInfos_); + private: std::shared_mutex lock_; std::shared_ptr extension_; + std::vector indexInfos_; + std::vector waitedFiles_; std::vector tars_; OHOS::ThreadPool threadPool_; }; diff --git a/frameworks/native/backup_ext/src/ext_extension.cpp b/frameworks/native/backup_ext/src/ext_extension.cpp index 987333bb3086a03a12a291bfe6004b1c08dbf85c..a4e7bda090e78dfefaac5d5e91371c4d46eb0aa6 100644 --- a/frameworks/native/backup_ext/src/ext_extension.cpp +++ b/frameworks/native/backup_ext/src/ext_extension.cpp @@ -55,6 +55,8 @@ const string INDEX_FILE_RESTORE = string(BConstants::PATH_BUNDLE_BACKUP_HOME). append(BConstants::EXT_BACKUP_MANAGE); using namespace std; +static set indexFileInfos; + void BackupExtExtension::VerifyCaller() { HILOGI("begin"); @@ -70,6 +72,87 @@ void BackupExtExtension::VerifyCaller() } } +static void createDirectory(const string &path) +{ + string::size_type index = 0; + do { + string subPath; + index = path.find('/', index + 1); + if (index == string::npos) { + subPath = path; + } else { + subPath = path.substr(0, index); + } + if (access(subPath.c_str(), F_OK) != 0) { + if (mkdir(subPath.c_str(), (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) != 0 && errno != EEXIST) { + string str = string("Failed to create folder. ").append(std::generic_category().message(errno)); + throw BError(BError::Codes::EXT_INVAL_ARG, str); + } + } + } while (index != string::npos); +} + +bool BackupExtExtension::isIndexReadyForRestore(std::vector indexInfos_) +{ + shared_lock lock(lock_); + if (indexInfos_.empty()) { + return false; + } + return true; +} + +bool BackupExtExtension::getInfoFromIndexFile(std::vector indexInfos_) +{ + if (access(INDEX_FILE_RESTORE.data(), F_OK) != 0) { + HILOGE("Index file does not exist"); + return false; + } + + // 获取索引文件内容 + BJsonCachedEntity cachedEntity(UniqueFd(open(INDEX_FILE_RESTORE.data(), O_RDONLY))); + auto cache = cachedEntity.Structuralize(); + // 写入索引信息加锁 + unique_lock lock(lock_); + indexInfos_ = cache.GetExtManageInfo(); + return true; +} + +static UniqueFd createFileFromIndexFile(ExtManageInfo& manageInfo) +{ + string filePath = manageInfo.fileName; + struct stat sta = manageInfo.sta; + + // 创建目录 + createDirectory(filePath.data()); + + // 创建FD + auto fd = UniqueFd(open(filePath.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)); + struct timespec tv[2] = {sta.st_atim, sta.st_mtim}; + if (futimens(fd.Get(), tv) != 0) { + HILOGE("failed to change the file time. %{public}s , %{public}d", filePath.c_str(), errno); + } + + return fd; +} + +static bool IsUserTar(const string &tarFile, const string &indexFile) +{ + if (tarFile.empty()) { + return false; + } + BJsonCachedEntity cachedEntity(UniqueFd(open(indexFile.data(), O_RDONLY))); + auto cache = cachedEntity.Structuralize(); + auto info = cache.GetExtManageInfo(); + for (auto &item : info) { + if (item.hashName == tarFile) { + HILOGI("tarFile:%{public}s isUserTar:%{public}d", tarFile.data(), item.isUserTar); + return item.isUserTar; + } + } + HILOGE("Can not find tarFile %{public}s", tarFile.data()); + return false; +} + UniqueFd BackupExtExtension::GetFileHandle(const string &fileName) { try { @@ -78,10 +161,41 @@ UniqueFd BackupExtExtension::GetFileHandle(const string &fileName) throw BError(BError::Codes::EXT_INVAL_ARG, "Action is invalid"); } + // 如果是manage.json + if (strcmp(fileName.data(), BConstants::EXT_BACKUP_MANAGE.data()) == 0) { + HILOGI("Index file is published before receive getFileHandle. "); + return UniqueFd(-1); + } + VerifyCaller(); - if (fileName.find('/') != string::npos) { - throw BError(BError::Codes::EXT_INVAL_ARG, "Filename is not valid"); + // 查看manage.json信息是否已经获取 + if (!isIndexReadyForRestore(indexInfos_)) { + HILOGI("Index file is not ready for restore"); + waitedFiles_.emplace_back(fileName); + return UniqueFd(-1); + } + + // 从Manage.json中获取对应的文件信息 + ExtManageInfo manageInfo; + bool isFind = false; + for (auto &item : indexInfos_) { + if (strcmp(item.hashName.data(), fileName.data()) == 0) { + manageInfo = item; + isFind = true; + break; + } + } + + if (!isFind) { + throw BError(BError::Codes::EXT_INVAL_ARG, "failed to get the fileName from manage.json"); + return UniqueFd(-1); + } + + // 普通大文件或者userTar + if (ExtractFileExt(fileName) != "tar" || IsUserTar(fileName, INDEX_FILE_RESTORE)) { + HILOGI("FileName contains path symbol."); + return createFileFromIndexFile(manageInfo); } string path = string(BConstants::PATH_BUNDLE_BACKUP_HOME).append(BConstants::SA_BUNDLE_BACKUP_RESTORE); @@ -197,6 +311,30 @@ ErrCode BackupExtExtension::PublishFile(const string &fileName) } VerifyCaller(); + // 对于manage.json,需要读取文件信息到容器 + if (strcmp(fileName.data(), BConstants::EXT_BACKUP_MANAGE.data()) == 0) { + if (!getInfoFromIndexFile(indexInfos_)) { + throw BError(BError::Codes::EXT_INVAL_ARG, "Index file not exist"); + } + for (auto &waitedFile : waitedFiles_) { + auto task = [obj {wptr(this)}, waitedFile]() { + auto ptr = obj.promote(); + ptr->GetFileHandle(waitedFile); + }; + // 读取等待中的waitedFiles_,触发操作 + threadPool_.AddTask([task]() { + try { + task(); + } catch (...) { + HILOGE("Failed to add task to thread pool"); + } + }); + } + unique_lock lock(lock_); + tars_.push_back(fileName); + return ERR_OK; + } + string path = string(BConstants::PATH_BUNDLE_BACKUP_HOME).append(BConstants::SA_BUNDLE_BACKUP_RESTORE); string tarName = path + fileName; { @@ -244,24 +382,6 @@ ErrCode BackupExtExtension::HandleBackup() return 0; } -static bool IsUserTar(const string &tarFile, const string &indexFile) -{ - if (tarFile.empty()) { - return false; - } - BJsonCachedEntity cachedEntity(UniqueFd(open(indexFile.data(), O_RDONLY))); - auto cache = cachedEntity.Structuralize(); - auto info = cache.GetExtManageInfo(); - for (auto &item : info) { - if (item.hashName == tarFile) { - HILOGI("tarFile:%{public}s isUserTar:%{public}d", tarFile.data(), item.isUserTar); - return item.isUserTar; - } - } - HILOGE("Can not find tarFile %{public}s", tarFile.data()); - return false; -} - static pair> GetFileInfos(const vector &includes, const vector &excludes) { auto [errCode, files, smallFiles] = BDir::GetBigFiles(includes, excludes); @@ -650,6 +770,17 @@ ErrCode BackupExtExtension::HandleRestore() if (extension_->WasFromSpeicalVersion() && extension_->RestoreDataReady()) { HILOGI("Restore directly when upgrading."); AsyncTaskRestoreForUpgrade(); + } else { + // To provide fd for manage.json first. + auto proxy = ServiceProxy::GetInstance(); + ErrCode ret = + proxy->AppFileReady(string(BConstants::EXT_BACKUP_MANAGE), UniqueFd(open(INDEX_FILE_BACKUP.data(), O_RDONLY))); + if (SUCCEEDED(ret)) { + HILOGI("Restore start: Manage.json request successfully"); + } else { + HILOGI("Restore start: AppFileReady interface fails to be invoked: %{public}d", ret); + } + return ret; } return 0; diff --git a/services/backup_sa/src/module_ipc/service.cpp b/services/backup_sa/src/module_ipc/service.cpp index 937146137211e0a1781b5604f962f71c147f19d0..93d5c85dcd5a68f5edade60424099b291d065863 100644 --- a/services/backup_sa/src/module_ipc/service.cpp +++ b/services/backup_sa/src/module_ipc/service.cpp @@ -353,9 +353,6 @@ ErrCode Service::PublishFile(const BFileInfo &fileInfo) sched_->Sched(fileInfo.owner); return BError(BError::Codes::OK); } - if (fileInfo.fileName.find('/') != string::npos) { - throw BError(BError::Codes::SA_INVAL_ARG, "Filename is not valid"); - } auto backUpConnection = session_->GetExtConnection(fileInfo.owner); @@ -513,9 +510,6 @@ ErrCode Service::GetFileHandle(const string &bundleName, const string &fileName) } return BError(BError::Codes::OK); } - if (fileName.find('/') != string::npos) { - throw BError(BError::Codes::SA_INVAL_ARG, "Filename is not valid"); - } auto action = session_->GetServiceSchedAction(bundleName); if (action == BConstants::ServiceSchedAction::RUNNING) { auto backUpConnection = session_->GetExtConnection(bundleName);