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