1 /*
2  * Copyright (c) 2023-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 #include "session_restore_n_exporter.h"
16 
17 #include <functional>
18 #include <memory>
19 #include <fcntl.h>
20 
21 #include "b_error/b_error.h"
22 #include "b_filesystem/b_dir.h"
23 #include "b_filesystem/b_file.h"
24 #include "b_incremental_restore_session.h"
25 #include "b_ohos/startup/backup_para.h"
26 #include "b_resources/b_constants.h"
27 #include "b_sa/b_sa_utils.h"
28 #include "b_session_restore.h"
29 #include "backup_kit_inner.h"
30 #include "filemgmt_libhilog.h"
31 #include "general_callbacks.h"
32 #include "service_proxy.h"
33 
34 namespace OHOS::FileManagement::Backup {
35 using namespace std;
36 using namespace LibN;
37 
38 struct RestoreEntity {
39     unique_ptr<BSessionRestore> sessionWhole;
40     unique_ptr<BIncrementalRestoreSession> sessionSheet;
41     shared_ptr<GeneralCallbacks> callbacks;
42 };
43 
OnFileReadySheet(weak_ptr<GeneralCallbacks> pCallbacks,const BFileInfo & fileInfo,UniqueFd fd,UniqueFd manifestFd,int32_t sysErrno)44 static void OnFileReadySheet(weak_ptr<GeneralCallbacks> pCallbacks, const BFileInfo &fileInfo,
45     UniqueFd fd, UniqueFd manifestFd, int32_t sysErrno)
46 {
47     if (pCallbacks.expired()) {
48         HILOGI("callbacks is unbound");
49         return;
50     }
51     auto callbacks = pCallbacks.lock();
52     if (!callbacks) {
53         HILOGI("callback function onFileReady has already been released");
54         return;
55     }
56     if (!bool(callbacks->onFileReady)) {
57         HILOGI("callback function onFileReady is undefined");
58         return;
59     }
60     ErrCode errCode = BError::GetCodeByErrno(sysErrno);
61     std::string errMsg = "system errno: " + to_string(sysErrno);
62     std::tuple<uint32_t, std::string> errInfo = std::make_tuple(errCode, errMsg);
63 
64     auto cbCompl = [bundleName {fileInfo.owner}, fileName {fileInfo.fileName},
65                     fd {make_shared<UniqueFd>(fd.Release())},
66                     manifestFd {make_shared<UniqueFd>(manifestFd.Release())},
67                     errInfo](napi_env env, NError err) -> NVal {
68         if (err) {
69             return {env, err.GetNapiErr(env)};
70         }
71         HILOGI("callback function restore OnFileReadySheet errCode: %{public}d", std::get<0>(errInfo));
72         NVal obj;
73         ErrParam errorParam = [ errInfo ]() {
74             return errInfo;
75         };
76         if (std::get<0>(errInfo) != 0) {
77             obj = NVal {env, NError(errorParam).GetNapiErr(env)};
78             napi_status status = napi_set_named_property(env, obj.val_, FILEIO_TAG_ERR_DATA.c_str(),
79                 NVal::CreateUTF8String(env, bundleName).val_);
80             if (status != napi_ok) {
81                 HILOGE("Failed to set data, status %{public}d, bundleName %{public}s", status, bundleName.c_str());
82             }
83         } else {
84             obj = NVal::CreateObject(env);
85             obj.AddProp({
86                 NVal::DeclareNapiProperty(BConstants::BUNDLE_NAME.c_str(),
87                     NVal::CreateUTF8String(env, bundleName).val_),
88                 NVal::DeclareNapiProperty(BConstants::URI.c_str(), NVal::CreateUTF8String(env, fileName).val_),
89                 NVal::DeclareNapiProperty(BConstants::FD.c_str(), NVal::CreateInt32(env, fd->Release()).val_),
90                 NVal::DeclareNapiProperty(BConstants::MANIFEST_FD.c_str(),
91                     NVal::CreateInt32(env, manifestFd->Release()).val_)});
92         }
93         return {obj};
94     };
95 
96     callbacks->onFileReady.ThreadSafeSchedule(cbCompl);
97 }
98 
onBundleBegin(weak_ptr<GeneralCallbacks> pCallbacks,ErrCode err,const BundleName name)99 static void onBundleBegin(weak_ptr<GeneralCallbacks> pCallbacks, ErrCode err, const BundleName name)
100 {
101     HILOGI("Callback onBundleBegin, bundleName=%{public}s, errCode=%{public}d", name.c_str(), err);
102     if (pCallbacks.expired()) {
103         HILOGI("callbacks is unbound");
104         return;
105     }
106     auto callbacks = pCallbacks.lock();
107     if (!callbacks) {
108         HILOGI("callback function onBundleBegin has already been released");
109         return;
110     }
111     if (!bool(callbacks->onBundleBegin)) {
112         HILOGI("callback function onBundleBegin is undefined");
113         return;
114     }
115 
116     ErrCode errCode = BError::GetBackupCodeByErrno(err);
117     std::string errMsg = BError::GetBackupMsgByErrno(errCode) + ", origin errno: " + to_string(err);
118     std::tuple<uint32_t, std::string> errInfo = std::make_tuple(errCode, errMsg);
119 
120     auto cbCompl = [name {name}, errCode {err}, errInfo](napi_env env, NError err) -> NVal {
121         NVal bundleName = NVal::CreateUTF8String(env, name);
122         if (!err && errCode == 0) {
123             return bundleName;
124         }
125         ErrParam errorParam = [ errInfo ]() {
126             return errInfo;
127         };
128         NVal res;
129         if (err) {
130             res = NVal {env, err.GetNapiErr(env)};
131         } else {
132             res = NVal {env, NError(errorParam).GetNapiErr(env)};
133         }
134         napi_status status = napi_set_named_property(env, res.val_, FILEIO_TAG_ERR_DATA.c_str(), bundleName.val_);
135         if (status != napi_ok) {
136             HILOGE("Failed to set data property, status %{public}d, bundleName %{public}s", status, name.c_str());
137         }
138 
139         return res;
140     };
141 
142     callbacks->onBundleBegin.ThreadSafeSchedule(cbCompl);
143 }
144 
onBundleEnd(weak_ptr<GeneralCallbacks> pCallbacks,ErrCode err,const BundleName name)145 static void onBundleEnd(weak_ptr<GeneralCallbacks> pCallbacks, ErrCode err, const BundleName name)
146 {
147     HILOGI("Callback onBundleEnd, bundleName=%{public}s, errCode=%{public}d", name.c_str(), err);
148     if (pCallbacks.expired()) {
149         HILOGI("callbacks is unbound");
150         return;
151     }
152     auto callbacks = pCallbacks.lock();
153     if (!callbacks) {
154         HILOGI("callback function onBundleEnd has already been released");
155         return;
156     }
157     if (!bool(callbacks->onBundleEnd)) {
158         HILOGI("callback function onBundleEnd is undefined");
159         return;
160     }
161 
162     ErrCode errCode = BError::GetBackupCodeByErrno(err);
163     std::string errMsg = BError::GetBackupMsgByErrno(errCode) + ", origin errno: " + to_string(err);
164     std::tuple<uint32_t, std::string> errInfo = std::make_tuple(errCode, errMsg);
165 
166     auto cbCompl = [name {name}, errCode {err}, errInfo](napi_env env, NError err) -> NVal {
167         NVal bundleName = NVal::CreateUTF8String(env, name);
168         if (!err && errCode == 0) {
169             return bundleName;
170         }
171         ErrParam errorParam = [ errInfo ]() {
172             return errInfo;
173         };
174         NVal res;
175         if (err) {
176             res = NVal {env, err.GetNapiErr(env)};
177         } else {
178             res = NVal {env, NError(errorParam).GetNapiErr(env)};
179         }
180         napi_status status = napi_set_named_property(env, res.val_, FILEIO_TAG_ERR_DATA.c_str(), bundleName.val_);
181         if (status != napi_ok) {
182             HILOGE("Failed to set data property, status %{public}d, bundleName %{public}s", status, name.c_str());
183         }
184 
185         return res;
186     };
187 
188     callbacks->onBundleEnd.ThreadSafeSchedule(cbCompl);
189 }
190 
onAllBundlesEnd(weak_ptr<GeneralCallbacks> pCallbacks,ErrCode err)191 static void onAllBundlesEnd(weak_ptr<GeneralCallbacks> pCallbacks, ErrCode err)
192 {
193     if (pCallbacks.expired()) {
194         HILOGI("callbacks is unbound");
195         return;
196     }
197     auto callbacks = pCallbacks.lock();
198     if (!callbacks) {
199         HILOGI("callback function onAllBundlesEnd has already been released");
200         return;
201     }
202     if (!bool(callbacks->onAllBundlesEnd)) {
203         HILOGI("callback function onAllBundlesEnd is undefined");
204         return;
205     }
206 
207     ErrCode errCode = BError::GetBackupCodeByErrno(err);
208     std::string errMsg = BError::GetBackupMsgByErrno(errCode) + ", origin errno: " + to_string(err);
209     std::tuple<uint32_t, std::string> errInfo = std::make_tuple(errCode, errMsg);
210 
211     auto cbCompl = [errCode {err}, errInfo](napi_env env, NError err) -> NVal {
212         if (!err && errCode == 0) {
213             return NVal::CreateUndefined(env);
214         }
215         ErrParam errorParam = [ errInfo ]() {
216             return errInfo;
217         };
218         NVal res;
219         if (err) {
220             res = NVal {env, err.GetNapiErr(env)};
221         } else {
222             res = NVal {env, NError(errorParam).GetNapiErr(env)};
223         }
224 
225         return res;
226     };
227 
228     callbacks->onAllBundlesEnd.ThreadSafeSchedule(cbCompl);
229 }
230 
OnBackupServiceDied(weak_ptr<GeneralCallbacks> pCallbacks)231 static void OnBackupServiceDied(weak_ptr<GeneralCallbacks> pCallbacks)
232 {
233     HILOGI("Callback OnBackupServiceDied.");
234     if (pCallbacks.expired()) {
235         HILOGI("callbacks is unbound");
236         return;
237     }
238     auto callbacks = pCallbacks.lock();
239     if (!callbacks) {
240         HILOGI("js callback function onBackupServiceDied has already been released");
241         return;
242     }
243     if (!bool(callbacks->onBackupServiceDied)) {
244         HILOGI("callback function onBackupServiceDied is undefined");
245         return;
246     }
247 
248     auto cbCompl = [](napi_env env, vector<napi_value> &argv) -> bool {
249         napi_value napi_res = nullptr;
250         napi_get_undefined(env, &napi_res);
251         argv.push_back(napi_res);
252         return true;
253     };
254     callbacks->onBackupServiceDied.CallJsMethod(cbCompl);
255 }
256 
OnResultReport(weak_ptr<GeneralCallbacks> pCallbacks,const std::string bundleName,const std::string result)257 static void OnResultReport(weak_ptr<GeneralCallbacks> pCallbacks, const std::string bundleName,
258     const std::string result)
259 {
260     HILOGI("Callback OnResultReport, bundleName=%{public}s", bundleName.c_str());
261     if (pCallbacks.expired()) {
262         HILOGI("callbacks is unbound");
263         return;
264     }
265     auto callbacks = pCallbacks.lock();
266     if (!callbacks) {
267         HILOGI("callback function onResultReport has already been released");
268         return;
269     }
270     if (!bool(callbacks->onResultReport)) {
271         HILOGI("callback function onResultReport is undefined");
272         return;
273     }
274     auto cbCompl = [bName {bundleName}, res {result}](napi_env env, vector<napi_value> &argv) -> bool {
275         napi_value napi_bName = nullptr;
276         napi_create_string_utf8(env, bName.c_str(), bName.size(), &napi_bName);
277         argv.push_back(napi_bName);
278         napi_value napi_res = nullptr;
279         napi_create_string_utf8(env, res.c_str(), res.size(), &napi_res);
280         argv.push_back(napi_res);
281         return true;
282     };
283     callbacks->onResultReport.CallJsMethod(cbCompl);
284 }
285 
OnProcess(weak_ptr<GeneralCallbacks> pCallbacks,const BundleName name,const std::string processInfo)286 static void OnProcess(weak_ptr<GeneralCallbacks> pCallbacks, const BundleName name, const std::string processInfo)
287 {
288     HILOGI("Callback OnProcess, bundleName=%{public}s", name.c_str());
289     if (pCallbacks.expired()) {
290         HILOGI("callbacks is unbound");
291         return;
292     }
293     auto callbacks = pCallbacks.lock();
294     if (!callbacks) {
295         HILOGI("callback function OnProcess has already been released");
296         return;
297     }
298     if (!bool(callbacks->onProcess)) {
299         HILOGI("callback function OnProcess is undefined");
300         return;
301     }
302     auto cbCompl = [bundleName {name}, process {processInfo}](napi_env env, vector<napi_value> &argv) -> bool {
303         napi_value napi_bName = nullptr;
304         napi_create_string_utf8(env, bundleName.c_str(), bundleName.size(), &napi_bName);
305         argv.push_back(napi_bName);
306         napi_value napi_process = nullptr;
307         napi_create_string_utf8(env, process.c_str(), process.size(), &napi_process);
308         argv.push_back(napi_process);
309         return true;
310     };
311     callbacks->onProcess.CallJsMethod(cbCompl);
312 }
313 
VerifyAppendBundlesParam(NFuncArg & funcArg,int32_t & fd,std::vector<std::string> & bundleNames,std::vector<std::string> & bundleInfos,napi_env env)314 static bool VerifyAppendBundlesParam(NFuncArg &funcArg, int32_t &fd, std::vector<std::string> &bundleNames,
315     std::vector<std::string> &bundleInfos, napi_env env)
316 {
317     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) {
318         HILOGE("Number of arguments unmatched.");
319         NError(BError(BError::Codes::SDK_INVAL_ARG, "Number of arguments unmatched.").GetCode()).ThrowErr(env);
320         return false;
321     }
322     NVal remoteCap(env, funcArg[NARG_POS::FIRST]);
323     auto [err, jsFd] = remoteCap.ToInt32();
324     if (!err) {
325         HILOGE("First argument is not remote capabilitily file number.");
326         NError(BError(BError::Codes::SDK_INVAL_ARG, "First argument is not remote capabilitily file number.").GetCode())
327             .ThrowErr(env);
328         return false;
329     }
330     fd = jsFd;
331     NVal jsBundles(env, funcArg[NARG_POS::SECOND]);
332     auto [succ, jsBundleNames, ignore] = jsBundles.ToStringArray();
333     if (!succ) {
334         HILOGE("First argument is not bundles array.");
335         NError(BError(BError::Codes::SDK_INVAL_ARG, "First argument is not bundles array.").GetCode()).ThrowErr(env);
336         return false;
337     }
338     bundleNames = jsBundleNames;
339     NVal jsInfos(env, funcArg[NARG_POS::THIRD]);
340     if (jsInfos.TypeIs(napi_undefined) || jsInfos.TypeIs(napi_null)) {
341         HILOGW("Third param is not exist");
342         return true;
343     }
344     auto [deSuc, jsBundleInfos, deIgnore] = jsInfos.ToStringArray();
345     if (deSuc) {
346         bundleInfos = jsBundleInfos;
347         if (bundleNames.size() != bundleInfos.size()) {
348             HILOGE("bundleNames count is not equals bundleInfos count");
349             return false;
350         }
351         return true;
352     }
353     HILOGI("Third param is callback");
354     return true;
355 }
356 
ParseFileMeta(napi_env env,const NVal & fileMeta)357 static std::tuple<bool, std::unique_ptr<char[]>, std::unique_ptr<char[]>> ParseFileMeta(napi_env env,
358     const NVal &fileMeta)
359 {
360     bool succ = false;
361     std::unique_ptr<char[]> bundleName = nullptr;
362     tie(succ, bundleName, ignore) = fileMeta.GetProp(BConstants::BUNDLE_NAME).ToUTF8String();
363     if (!succ) {
364         HILOGE("First argument is not have property bundle name.");
365         return { false, nullptr, nullptr };
366     }
367 
368     std::unique_ptr<char[]> fileName = nullptr;
369     tie(succ, fileName, ignore) = fileMeta.GetProp(BConstants::URI).ToUTF8String();
370     if (!succ) {
371         HILOGE("First argument is not have property file name.");
372         return { false, nullptr, nullptr };
373     }
374 
375     return { true, move(bundleName), move(fileName) };
376 }
377 
VerifyPublishFileParam(NFuncArg & funcArg,std::string & bundleName,std::string & fileName,napi_env env)378 static bool VerifyPublishFileParam(NFuncArg &funcArg, std::string &bundleName, std::string &fileName, napi_env env)
379 {
380     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
381         HILOGE("Number of arguments unmatched.");
382         NError(BError(BError::Codes::SDK_INVAL_ARG, "Number of arguments unmatched.").GetCode()).ThrowErr(env);
383         return false;
384     }
385 
386     NVal fileMeta(env, funcArg[NARG_POS::FIRST]);
387     if (!fileMeta.TypeIs(napi_object)) {
388         HILOGE("First arguments is not an object.");
389         NError(BError(BError::Codes::SDK_INVAL_ARG, "First arguments is not an object.").GetCode()).ThrowErr(env);
390         return false;
391     }
392     auto [succ, bundle, file] = ParseFileMeta(env, fileMeta);
393     if (!succ) {
394         HILOGE("ParseFileMeta failed.");
395         NError(BError(BError::Codes::SDK_INVAL_ARG, "ParseFileMeta failed.").GetCode()).ThrowErr(env);
396         return false;
397     }
398     bundleName = string(bundle.get());
399     fileName = string(file.get());
400     return true;
401 }
402 
VerifyNapiObject(napi_env env,NFuncArg & funcArg)403 static bool VerifyNapiObject(napi_env env, NFuncArg &funcArg)
404 {
405     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
406         HILOGE("Number of arguments unmatched.");
407         NError(BError(BError::Codes::SDK_INVAL_ARG, "Number of arguments unmatched.").GetCode()).ThrowErr(env);
408         return true;
409     }
410     return false;
411 }
412 
VerifyNarg(napi_env env,NVal & callbacks)413 static bool VerifyNarg(napi_env env, NVal &callbacks)
414 {
415     if (!callbacks.TypeIs(napi_object)) {
416         HILOGE("First argument is not an object.");
417         NError(BError(BError::Codes::SDK_INVAL_ARG, "First argument is not an object.").GetCode()).ThrowErr(env);
418         return true;
419     }
420     return false;
421 }
422 
Constructor(napi_env env,napi_callback_info cbinfo)423 napi_value SessionRestoreNExporter::Constructor(napi_env env, napi_callback_info cbinfo)
424 {
425     HILOGI("called SessionRestore::Constructor begin");
426     if (!SAUtils::CheckBackupPermission()) {
427         HILOGE("Has not permission!");
428         NError(E_PERMISSION).ThrowErr(env);
429         return nullptr;
430     }
431     if (!SAUtils::IsSystemApp()) {
432         HILOGE("System App check fail!");
433         NError(E_PERMISSION_SYS).ThrowErr(env);
434         return nullptr;
435     }
436     NFuncArg funcArg(env, cbinfo);
437     if (VerifyNapiObject(env, funcArg)) {
438         return nullptr;
439     }
440     NVal callbacks(env, funcArg[NARG_POS::FIRST]);
441     if (VerifyNarg(env, callbacks)) {
442         return nullptr;
443     }
444 
445     NVal ptr(env, funcArg.GetThisVar());
446     auto restoreEntity = std::make_unique<RestoreEntity>();
447     restoreEntity->callbacks = make_shared<GeneralCallbacks>(env, ptr, callbacks);
448     restoreEntity->sessionWhole = nullptr;
449     restoreEntity->sessionSheet = BIncrementalRestoreSession::Init(BIncrementalRestoreSession::Callbacks {
450         .onFileReady = bind(OnFileReadySheet, restoreEntity->callbacks, placeholders::_1, placeholders::_2,
451             placeholders::_3, placeholders::_4),
452         .onBundleStarted = bind(onBundleBegin, restoreEntity->callbacks, placeholders::_1, placeholders::_2),
453         .onBundleFinished = bind(onBundleEnd, restoreEntity->callbacks, placeholders::_1, placeholders::_2),
454         .onAllBundlesFinished = bind(onAllBundlesEnd, restoreEntity->callbacks, placeholders::_1),
455         .onResultReport = bind(OnResultReport, restoreEntity->callbacks, placeholders::_1, placeholders::_2),
456         .onBackupServiceDied = bind(OnBackupServiceDied, restoreEntity->callbacks),
457         .onProcess = bind(OnProcess, restoreEntity->callbacks, placeholders::_1, placeholders::_2)});
458     if (!restoreEntity->sessionSheet) {
459         NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to init restore").GetCode()).ThrowErr(env);
460         return nullptr;
461     }
462     if (!NClass::SetEntityFor<RestoreEntity>(env, funcArg.GetThisVar(), move(restoreEntity))) {
463         NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to set SessionRestore entity.").GetCode()).ThrowErr(env);
464         return nullptr;
465     }
466 
467     HILOGI("called SessionRestore::Constructor end");
468     return funcArg.GetThisVar();
469 }
470 
GetAppendBundlesCBExec(napi_env env,NFuncArg & funcArg,const int32_t fdRestore,const std::vector<std::string> & bundleNames,const std::vector<std::string> & bundleInfos)471 static NContextCBExec GetAppendBundlesCBExec(napi_env env, NFuncArg &funcArg, const int32_t fdRestore,
472     const std::vector<std::string> &bundleNames, const std::vector<std::string> &bundleInfos)
473 {
474     auto restoreEntity = NClass::GetEntityOf<RestoreEntity>(env, funcArg.GetThisVar());
475     if (!(restoreEntity && (restoreEntity->sessionWhole || restoreEntity->sessionSheet))) {
476         HILOGE("Failed to get RestoreSession entity.");
477         NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get RestoreSession entity.").GetCode()).ThrowErr(env);
478         return nullptr;
479     }
480     return [entity {restoreEntity}, fd {fdRestore}, bundles {bundleNames}, infos {bundleInfos}]() -> NError {
481         if (!(entity && (entity->sessionWhole || entity->sessionSheet))) {
482             return NError(BError(BError::Codes::SDK_INVAL_ARG, "restore session is nullptr").GetCode());
483         }
484         if (fcntl(fd, F_GETFD) == -1) {
485             HILOGE("AppendBundles fd is invalid.");
486             return NError(BError(BError::Codes::SDK_INVAL_ARG, "AppendBundles fd is invalid.").GetCode());
487         }
488         if (entity->sessionWhole) {
489             if (!infos.empty()) {
490                 return NError(entity->sessionWhole->AppendBundles(UniqueFd(fd), bundles, infos));
491             }
492             return NError(entity->sessionWhole->AppendBundles(UniqueFd(fd), bundles));
493         }
494         if (!infos.empty()) {
495             return NError(entity->sessionSheet->AppendBundles(UniqueFd(fd), bundles, infos));
496         }
497         return NError(entity->sessionSheet->AppendBundles(UniqueFd(fd), bundles));
498     };
499 }
500 
AppendBundles(napi_env env,napi_callback_info cbinfo)501 napi_value SessionRestoreNExporter::AppendBundles(napi_env env, napi_callback_info cbinfo)
502 {
503     HILOGI("called SessionRestore::AppendBundles begin");
504     if (!SAUtils::CheckBackupPermission()) {
505         HILOGE("Has not permission!");
506         NError(E_PERMISSION).ThrowErr(env);
507         return nullptr;
508     }
509     if (!SAUtils::IsSystemApp()) {
510         HILOGE("System App check fail!");
511         NError(E_PERMISSION_SYS).ThrowErr(env);
512         return nullptr;
513     }
514     int32_t fdRestore = BConstants::INVALID_FD_NUM;
515     std::vector<std::string> bundleNames;
516     std::vector<std::string> bundleInfos;
517     NFuncArg funcArg(env, cbinfo);
518     if (!VerifyAppendBundlesParam(funcArg, fdRestore, bundleNames, bundleInfos, env)) {
519         return nullptr;
520     }
521     auto cbExec = GetAppendBundlesCBExec(env, funcArg, fdRestore, bundleNames, bundleInfos);
522     if (cbExec == nullptr) {
523         HILOGE("GetAppendBundlesCBExec fail!");
524         return nullptr;
525     }
526     auto cbCompl = [](napi_env env, NError err) -> NVal {
527         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUndefined(env);
528     };
529     HILOGD("Called SessionRestore::AppendBundles end.");
530 
531     NVal thisVar(env, funcArg.GetThisVar());
532     if (funcArg.GetArgc() == NARG_CNT::TWO) {
533         return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_;
534     } else if (!bundleInfos.empty()) {
535         HILOGI("The third param is string array");
536         return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_;
537     } else {
538         HILOGI("The third param is call back");
539         NVal cb(env, funcArg[NARG_POS::THIRD]);
540         return NAsyncWorkCallback(env, thisVar, cb).Schedule(className, cbExec, cbCompl).val_;
541     }
542 }
543 
GetPublishFileCBExec(napi_env env,NFuncArg & funcArg,const std::string & bundleName,const std::string & fileName)544 static NContextCBExec GetPublishFileCBExec(napi_env env, NFuncArg &funcArg, const std::string &bundleName,
545     const std::string &fileName)
546 {
547     auto restoreEntity = NClass::GetEntityOf<RestoreEntity>(env, funcArg.GetThisVar());
548     if (!(restoreEntity && (restoreEntity->sessionWhole || restoreEntity->sessionSheet))) {
549         HILOGE("Failed to get RestoreSession entity.");
550         NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get RestoreSession entity.").GetCode()).ThrowErr(env);
551         return nullptr;
552     }
553     return [entity {restoreEntity}, bundleName {bundleName}, fileName {fileName}]() -> NError {
554         if (!(entity && (entity->sessionWhole || entity->sessionSheet))) {
555             return NError(BError(BError::Codes::SDK_INVAL_ARG, "restore session is nullptr").GetCode());
556         }
557         BFileInfo fileInfo(bundleName, fileName, 0);
558         if (entity->sessionWhole) {
559             return NError(entity->sessionWhole->PublishFile(fileInfo));
560         }
561         if (SAUtils::IsSABundleName(fileName)) {
562             HILOGI("SA %{public}s pushlish file", bundleName.c_str());
563             if (fcntl(std::atoi(fileName.c_str()), F_GETFD) == -1) {
564                 HILOGE("PublishFile fd is invalid.");
565                 return NError(BError(BError::Codes::SDK_INVAL_ARG, "PublishFile fd is invalid.").GetCode());
566             }
567             return NError(entity->sessionSheet->PublishSAFile(fileInfo, UniqueFd(std::atoi(fileName.c_str()))));
568         }
569         return NError(entity->sessionSheet->PublishFile(fileInfo));
570     };
571 }
572 
PublishFile(napi_env env,napi_callback_info cbinfo)573 napi_value SessionRestoreNExporter::PublishFile(napi_env env, napi_callback_info cbinfo)
574 {
575     HILOGD("called SessionRestore::PublishFile begin");
576     if (!SAUtils::CheckBackupPermission()) {
577         HILOGE("Has not permission!");
578         NError(E_PERMISSION).ThrowErr(env);
579         return nullptr;
580     }
581     if (!SAUtils::IsSystemApp()) {
582         HILOGE("System App check fail!");
583         NError(E_PERMISSION_SYS).ThrowErr(env);
584         return nullptr;
585     }
586     std::string bundleName;
587     std::string fileName;
588     NFuncArg funcArg(env, cbinfo);
589     if (!VerifyPublishFileParam(funcArg, bundleName, fileName, env)) {
590         return nullptr;
591     }
592     auto cbExec = GetPublishFileCBExec(env, funcArg, bundleName, fileName);
593     if (cbExec == nullptr) {
594         HILOGE("GetPublishFileCBExec fail!");
595         return nullptr;
596     }
597     auto cbCompl = [](napi_env env, NError err) -> NVal {
598         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUndefined(env);
599     };
600     HILOGD("Called SessionRestore::PublishFile end.");
601 
602     NVal thisVar(env, funcArg.GetThisVar());
603     if (funcArg.GetArgc() == NARG_CNT::ONE) {
604         return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_;
605     } else {
606         NVal cb(env, funcArg[NARG_POS::SECOND]);
607         return NAsyncWorkCallback(env, thisVar, cb).Schedule(className, cbExec, cbCompl).val_;
608     }
609 }
610 
GetFileHandleCBExec(napi_env env,NFuncArg & funcArg,std::unique_ptr<char[]> bundleName,std::unique_ptr<char[]> fileName)611 static NContextCBExec GetFileHandleCBExec(napi_env env, NFuncArg &funcArg, std::unique_ptr<char[]> bundleName,
612     std::unique_ptr<char[]> fileName)
613 {
614     auto restoreEntity = NClass::GetEntityOf<RestoreEntity>(env, funcArg.GetThisVar());
615     if (!(restoreEntity && (restoreEntity->sessionWhole || restoreEntity->sessionSheet))) {
616         HILOGE("Failed to get RestoreSession entity.");
617         NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get RestoreSession entity.").GetCode()).ThrowErr(env);
618         return nullptr;
619     }
620     return [entity {restoreEntity}, bundleName {string(bundleName.get())},
621         fileName {string(fileName.get())}]() -> NError {
622         if (!(entity && (entity->sessionWhole || entity->sessionSheet))) {
623             return NError(BError(BError::Codes::SDK_INVAL_ARG, "restore session is nullptr").GetCode());
624         }
625         string bundle = bundleName;
626         string file = fileName;
627         if (entity->sessionWhole) {
628             return NError(entity->sessionWhole->GetFileHandle(bundle, file));
629         }
630         return NError(entity->sessionSheet->GetFileHandle(bundle, file));
631     };
632 }
633 
GetFileHandle(napi_env env,napi_callback_info cbinfo)634 napi_value SessionRestoreNExporter::GetFileHandle(napi_env env, napi_callback_info cbinfo)
635 {
636     HILOGD("called SessionRestore::GetFileHandle begin");
637     if (!SAUtils::CheckBackupPermission()) {
638         HILOGE("Has not permission!");
639         NError(E_PERMISSION).ThrowErr(env);
640         return nullptr;
641     }
642     if (!SAUtils::IsSystemApp()) {
643         HILOGE("System App check fail!");
644         NError(E_PERMISSION_SYS).ThrowErr(env);
645         return nullptr;
646     }
647     NFuncArg funcArg(env, cbinfo);
648     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
649         HILOGE("Number of arguments unmatched.");
650         NError(BError(BError::Codes::SDK_INVAL_ARG, "Number of arguments unmatched.").GetCode()).ThrowErr(env);
651         return nullptr;
652     }
653 
654     NVal fileMeta(env, funcArg[NARG_POS::FIRST]);
655     if (!fileMeta.TypeIs(napi_object)) {
656         HILOGE("First arguments is not an object.");
657         NError(BError(BError::Codes::SDK_INVAL_ARG, "First arguments is not an object.").GetCode()).ThrowErr(env);
658         return nullptr;
659     }
660 
661     auto [succ, bundleName, fileName] = ParseFileMeta(env, fileMeta);
662     if (!succ) {
663         HILOGE("ParseFileMeta failed.");
664         NError(BError(BError::Codes::SDK_INVAL_ARG, "ParseFileMeta failed.").GetCode()).ThrowErr(env);
665         return nullptr;
666     }
667 
668     auto cbExec = GetFileHandleCBExec(env, funcArg, move(bundleName), move(fileName));
669     if (cbExec == nullptr) {
670         HILOGE("GetFileHandleCBExec fail!");
671         return nullptr;
672     }
673     auto cbCompl = [](napi_env env, NError err) -> NVal {
674         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUndefined(env);
675     };
676     HILOGD("Called SessionRestore::GetFileHandle end.");
677 
678     NVal thisVar(env, funcArg.GetThisVar());
679     if (funcArg.GetArgc() == NARG_CNT::ONE) {
680         return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_;
681     } else {
682         NVal cb(env, funcArg[NARG_POS::SECOND]);
683         return NAsyncWorkCallback(env, thisVar, cb).Schedule(className, cbExec, cbCompl).val_;
684     }
685 }
686 
Release(napi_env env,napi_callback_info cbinfo)687 napi_value SessionRestoreNExporter::Release(napi_env env, napi_callback_info cbinfo)
688 {
689     HILOGI("called SessionRestore::Release begin");
690     if (!SAUtils::CheckBackupPermission()) {
691         HILOGE("Has not permission!");
692         NError(E_PERMISSION).ThrowErr(env);
693         return nullptr;
694     }
695     if (!SAUtils::IsSystemApp()) {
696         HILOGE("System App check fail!");
697         NError(E_PERMISSION_SYS).ThrowErr(env);
698         return nullptr;
699     }
700     NFuncArg funcArg(env, cbinfo);
701     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
702         HILOGE("Number of arguments unmatched.");
703         NError(BError(BError::Codes::SDK_INVAL_ARG, "Number of arguments unmatched.").GetCode()).ThrowErr(env);
704         return nullptr;
705     }
706 
707     auto restoreEntity = NClass::GetEntityOf<RestoreEntity>(env, funcArg.GetThisVar());
708     if (!(restoreEntity && (restoreEntity->sessionWhole || restoreEntity->sessionSheet))) {
709         HILOGE("Failed to get RestoreSession entity.");
710         NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get RestoreSession entity.").GetCode()).ThrowErr(env);
711         return nullptr;
712     }
713 
714     auto cbExec = [entity {restoreEntity}]() -> NError {
715         if (!(entity && (entity->sessionWhole || entity->sessionSheet))) {
716             return NError(BError(BError::Codes::SDK_INVAL_ARG, "restore session is nullptr").GetCode());
717         }
718         if (entity->sessionWhole) {
719             return NError(entity->sessionWhole->Release());
720         }
721         return NError(entity->sessionSheet->Release());
722     };
723     auto cbCompl = [](napi_env env, NError err) -> NVal {
724         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUndefined(env);
725     };
726     HILOGI("Called SessionRestore::Release end.");
727 
728     NVal thisVar(env, funcArg.GetThisVar());
729     return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_;
730 }
731 
Export()732 bool SessionRestoreNExporter::Export()
733 {
734     HILOGD("called SessionRestoreNExporter::Export begin");
735     vector<napi_property_descriptor> props = {
736         NVal::DeclareNapiFunction("appendBundles", AppendBundles),
737         NVal::DeclareNapiFunction("publishFile", PublishFile),
738         NVal::DeclareNapiFunction("getFileHandle", GetFileHandle),
739         NVal::DeclareNapiFunction("release", Release),
740     };
741 
742     auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props));
743     if (!succ) {
744         HILOGE("Failed to define class");
745         NError(EIO).ThrowErr(exports_.env_);
746         return false;
747     }
748     succ = NClass::SaveClass(exports_.env_, className, classValue);
749     if (!succ) {
750         HILOGE("Failed to save class");
751         NError(EIO).ThrowErr(exports_.env_);
752         return false;
753     }
754 
755     HILOGD("called SessionRestoreNExporter::Export end");
756     return exports_.AddProp(className, classValue);
757 }
758 
GetClassName()759 string SessionRestoreNExporter::GetClassName()
760 {
761     return SessionRestoreNExporter::className;
762 }
763 
SessionRestoreNExporter(napi_env env,napi_value exports)764 SessionRestoreNExporter::SessionRestoreNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
765 
~SessionRestoreNExporter()766 SessionRestoreNExporter::~SessionRestoreNExporter() {}
767 } // namespace OHOS::FileManagement::Backup