• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <set>
17 #include <sys/types.h>
18 #include <sys/xattr.h>
19 
20 #include "async_work.h"
21 #include "cloud_sync_manager.h"
22 #include "cloud_sync_napi.h"
23 #include "dfs_error.h"
24 #include "dfsu_access_token_helper.h"
25 #include "securec.h"
26 #include "uri.h"
27 #include "utils_log.h"
28 
29 namespace OHOS::FileManagement::CloudSync {
30 using namespace FileManagement::LibN;
31 using namespace std;
32 const int32_t PARAM0 = 0;
33 static const unsigned int READ_SIZE = 1024;
34 // The data size is consistent with IPC
35 static const unsigned int MAX_CHANGE_DATA_SIZE = 200 * 1024;
36 const string FILE_SCHEME = "file";
37 thread_local unique_ptr<ChangeListenerNapi> g_listObj = nullptr;
38 mutex CloudSyncNapi::sOnOffMutex_;
39 static mutex obsMutex_;
40 const int32_t AGING_DAYS = 30;
41 const int32_t GET_FILE_SYNC_MAX = 100;
42 CloudSyncState CloudSyncCallbackImpl::preState_ = CloudSyncState::COMPLETED;
43 ErrorType CloudSyncCallbackImpl::preError_ = ErrorType::NO_ERROR;
44 
45 class ObserverImpl : public AAFwk::DataAbilityObserverStub {
46 public:
ObserverImpl(const shared_ptr<CloudNotifyObserver> cloudNotifyObserver)47     explicit ObserverImpl(const shared_ptr<CloudNotifyObserver> cloudNotifyObserver)
48         : cloudNotifyObserver_(cloudNotifyObserver){};
49     void OnChange();
50     void OnChangeExt(const AAFwk::ChangeInfo &info);
51     static sptr<ObserverImpl> GetObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer);
52     static bool FindObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer);
53     static bool DeleteObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer);
54 
55 private:
56     struct ObserverParam {
57         sptr<ObserverImpl> obs_;
58         list<Uri> uris_;
59     };
60     shared_ptr<CloudNotifyObserver> cloudNotifyObserver_;
61     static ConcurrentMap<CloudNotifyObserver *, ObserverParam> observers_;
62 };
63 
64 ConcurrentMap<CloudNotifyObserver *, ObserverImpl::ObserverParam> ObserverImpl::observers_;
65 
OnChange()66 void ObserverImpl::OnChange() {}
67 
OnChangeExt(const AAFwk::ChangeInfo & info)68 void ObserverImpl::OnChangeExt(const AAFwk::ChangeInfo &info)
69 {
70     if (cloudNotifyObserver_ == nullptr) {
71         LOGE("cloudNotifyObserver_ is null!");
72         return;
73     }
74     cloudNotifyObserver_->OnchangeExt(info);
75 }
76 
GetObserver(const Uri & uri,const shared_ptr<CloudNotifyObserver> & observer)77 sptr<ObserverImpl> ObserverImpl::GetObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer)
78 {
79     lock_guard<mutex> lock(obsMutex_);
80     sptr<ObserverImpl> result = nullptr;
81     observers_.Compute(observer.get(), [&result, &uri, &observer](const auto &key, auto &value) {
82         if (value.obs_ == nullptr) {
83             value.obs_ = new (nothrow) ObserverImpl(observer);
84             value.uris_.push_back(uri);
85         } else {
86             auto it = find(value.uris_.begin(), value.uris_.end(), uri);
87             if (it == value.uris_.end()) {
88                 value.uris_.push_back(uri);
89             }
90         }
91 
92         result = value.obs_;
93         return result != nullptr;
94     });
95 
96     return result;
97 }
98 
FindObserver(const Uri & uri,const shared_ptr<CloudNotifyObserver> & observer)99 bool ObserverImpl::FindObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer)
100 {
101     lock_guard<mutex> lock(obsMutex_);
102     auto result = observers_.Find(observer.get());
103     if (result.first) {
104         auto it = std::find(result.second.uris_.begin(), result.second.uris_.end(), uri);
105         if (it == result.second.uris_.end()) {
106             return false;
107         }
108     }
109     return result.first;
110 }
111 
DeleteObserver(const Uri & uri,const shared_ptr<CloudNotifyObserver> & observer)112 bool ObserverImpl::DeleteObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer)
113 {
114     lock_guard<mutex> lock(obsMutex_);
115     return observers_.ComputeIfPresent(observer.get(), [&uri](auto &key, auto &value) {
116         value.uris_.remove_if([&uri](const auto &value) { return uri == value; });
117         return !value.uris_.empty();
118     });
119 }
120 
CloudSyncCallbackImpl(napi_env env,napi_value fun)121 CloudSyncCallbackImpl::CloudSyncCallbackImpl(napi_env env, napi_value fun) : env_(env)
122 {
123     if (fun != nullptr) {
124         napi_create_reference(env_, fun, 1, &cbOnRef_);
125     }
126 }
127 
OnComplete(UvChangeMsg * msg)128 void CloudSyncCallbackImpl::OnComplete(UvChangeMsg *msg)
129 {
130     auto cloudSyncCallback = msg->cloudSyncCallback_.lock();
131     if (cloudSyncCallback == nullptr || cloudSyncCallback->cbOnRef_ == nullptr) {
132         LOGE("cloudSyncCallback->cbOnRef_ is nullptr");
133         return;
134     }
135     auto env = cloudSyncCallback->env_;
136     auto ref = cloudSyncCallback->cbOnRef_;
137     napi_handle_scope scope = nullptr;
138     napi_open_handle_scope(env, &scope);
139     napi_value jsCallback = nullptr;
140     napi_status status = napi_get_reference_value(env, ref, &jsCallback);
141     if (status != napi_ok) {
142         LOGE("Create reference failed, status: %{public}d", status);
143         napi_close_handle_scope(env, scope);
144         return;
145     }
146     NVal obj = NVal::CreateObject(env);
147     obj.AddProp("state", NVal::CreateInt32(env, (int32_t)msg->state_).val_);
148     obj.AddProp("error", NVal::CreateInt32(env, (int32_t)msg->error_).val_);
149     napi_value retVal = nullptr;
150     napi_value global = nullptr;
151     napi_get_global(env, &global);
152     status = napi_call_function(env, global, jsCallback, ARGS_ONE, &(obj.val_), &retVal);
153     if (status != napi_ok) {
154         LOGE("napi call function failed, status: %{public}d", status);
155     }
156     napi_close_handle_scope(env, scope);
157 }
OnDeathRecipient()158 void CloudSyncCallbackImpl::OnDeathRecipient()
159 {
160     auto isInDownOrUpload = (preState_ == CloudSyncState::UPLOADING) || (preState_ == CloudSyncState::DOWNLOADING);
161     if (isInDownOrUpload && (preError_ == ErrorType::NO_ERROR)) {
162         OnSyncStateChanged(CloudSyncState::STOPPED, ErrorType::NO_ERROR);
163     }
164 }
165 
OnSyncStateChanged(CloudSyncState state,ErrorType error)166 void CloudSyncCallbackImpl::OnSyncStateChanged(CloudSyncState state, ErrorType error)
167 {
168     LOGI("notify - state: %{public}d, error: %{public}d", state, error);
169     UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(shared_from_this(), state, error);
170     if (msg == nullptr) {
171         LOGE("Failed to create uv message object");
172         return;
173     }
174 
175     auto task = [msg]() {
176         if (msg->cloudSyncCallback_.expired()) {
177             LOGE("cloudSyncCallback_ is expired");
178             delete msg;
179             return;
180         }
181         msg->cloudSyncCallback_.lock()->OnComplete(msg);
182         delete msg;
183     };
184     preState_ = state;
185     preError_ = error;
186     napi_status ret = napi_send_event(env_, task, napi_event_priority::napi_eprio_immediate);
187     if (ret != napi_ok) {
188         LOGE("Failed to execute libuv work queue, ret: %{public}d", ret);
189         delete msg;
190         return;
191     }
192 }
193 
DeleteReference()194 void CloudSyncCallbackImpl::DeleteReference()
195 {
196     if (cbOnRef_ != nullptr) {
197         napi_delete_reference(env_, cbOnRef_);
198         cbOnRef_ = nullptr;
199     }
200 }
201 
OnSyncStateChanged(SyncType type,SyncPromptState state)202 void CloudSyncCallbackImpl::OnSyncStateChanged(SyncType type, SyncPromptState state)
203 {
204     return;
205 }
206 
OnOptimizeProcess(const OptimizeState state,const int32_t progress)207 void CloudOptimizeCallbackImpl::OnOptimizeProcess(const OptimizeState state, const int32_t progress)
208 {
209     napi_env env = env_;
210     auto task = [this, env, state, progress] () {
211         if (!cbOnRef_) {
212             LOGE("cbOnRef_ is nullptr");
213             return;
214         }
215 
216         napi_handle_scope scope = nullptr;
217         napi_status status = napi_open_handle_scope(env, &scope);
218         if (status != napi_ok) {
219             LOGE("Create reference failed, status: %{public}d", status);
220             return;
221         }
222 
223         napi_value jsCallback = cbOnRef_.Deref(env).val_;
224         NVal obj = NVal::CreateObject(env);
225         obj.AddProp("state", NVal::CreateInt32(env, (int32_t)state).val_);
226         obj.AddProp("progress", NVal::CreateInt32(env, (int32_t)progress).val_);
227         napi_value retVal = nullptr;
228         status = napi_call_function(env_, nullptr, jsCallback, ARGS_ONE, &(obj.val_), &retVal);
229         if (status != napi_ok) {
230             LOGE("napi call function failed, status: %{public}d", status);
231         }
232         napi_close_handle_scope(env, scope);
233     };
234     auto ret = napi_send_event(env, task, napi_eprio_immediate);
235     if  (ret != 0) {
236         LOGE("failed to send event, ret: %{public}d", ret);
237     }
238 }
239 
GetBundleName(const napi_env & env,const NFuncArg & funcArg)240 string CloudSyncNapi::GetBundleName(const napi_env &env, const NFuncArg &funcArg)
241 {
242     string bundleName;
243     auto bundleEntity = NClass::GetEntityOf<BundleEntity>(env, funcArg.GetThisVar());
244     if (bundleEntity) {
245         bundleName = bundleEntity->bundleName_;
246     }
247     return bundleName;
248 }
249 
Constructor(napi_env env,napi_callback_info info)250 napi_value CloudSyncNapi::Constructor(napi_env env, napi_callback_info info)
251 {
252     NFuncArg funcArg(env, info);
253     if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
254         NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
255         return nullptr;
256     }
257     if (funcArg.GetArgc() == NARG_CNT::ZERO) {
258         LOGD("init without bundleName");
259         return funcArg.GetThisVar();
260     }
261     if (funcArg.GetArgc() == NARG_CNT::ONE) {
262         auto [succ, bundleName, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
263         if (!succ || bundleName.get() == string("")) {
264             LOGE("Failed to get bundle name");
265             NError(E_PARAMS).ThrowErr(env);
266             return nullptr;
267         }
268         auto bundleEntity = make_unique<BundleEntity>(bundleName.get());
269         if (!NClass::SetEntityFor<BundleEntity>(env, funcArg.GetThisVar(), move(bundleEntity))) {
270             LOGE("Failed to set file entity");
271             NError(EIO).ThrowErr(env);
272             return nullptr;
273         }
274         LOGI("init with bundleName");
275         return funcArg.GetThisVar();
276     }
277     return nullptr;
278 }
279 
InitArgsOnCallback(const napi_env & env,NFuncArg & funcArg)280 bool CloudSyncNapi::InitArgsOnCallback(const napi_env &env, NFuncArg &funcArg)
281 {
282     if (!funcArg.InitArgs(NARG_CNT::TWO)) {
283         NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
284         LOGE("OnCallback Number of arguments unmatched");
285         return false;
286     }
287 
288     auto [succ, type, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
289     if (!(succ && (type.get() == std::string("progress")))) {
290         NError(E_PARAMS).ThrowErr(env);
291         return false;
292     }
293 
294     if (!NVal(env, funcArg[(int)NARG_POS::SECOND]).TypeIs(napi_function)) {
295         LOGE("Argument type mismatch");
296         NError(E_PARAMS).ThrowErr(env);
297         return false;
298     }
299 
300     if (callback_ != nullptr) {
301         LOGI("callback already exist");
302         return false;
303     }
304     return true;
305 }
306 
OnCallback(napi_env env,napi_callback_info info)307 napi_value CloudSyncNapi::OnCallback(napi_env env, napi_callback_info info)
308 {
309     NFuncArg funcArg(env, info);
310     if (!InitArgsOnCallback(env, funcArg)) {
311         return nullptr;
312     }
313 
314     string bundleName = GetBundleName(env, funcArg);
315     callback_ = make_shared<CloudSyncCallbackImpl>(env, NVal(env, funcArg[(int)NARG_POS::SECOND]).val_);
316     int32_t ret = CloudSyncManager::GetInstance().RegisterCallback(callback_, bundleName);
317     if (ret != E_OK) {
318         LOGE("OnCallback Register error, result: %{public}d", ret);
319         NError(Convert2JsErrNum(ret)).ThrowErr(env);
320         return nullptr;
321     }
322 
323     return NVal::CreateUndefined(env).val_;
324 }
325 
InitArgsOffCallback(const napi_env & env,NFuncArg & funcArg)326 bool CloudSyncNapi::InitArgsOffCallback(const napi_env &env, NFuncArg &funcArg)
327 {
328     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
329         NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
330         LOGE("OffCallback Number of arguments unmatched");
331         return false;
332     }
333 
334     auto [succ, type, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
335     if (!(succ && (type.get() == std::string("progress")))) {
336         NError(E_PARAMS).ThrowErr(env);
337         return false;
338     }
339 
340     if (funcArg.GetArgc() == (uint)NARG_CNT::TWO && !NVal(env, funcArg[(int)NARG_POS::SECOND]).TypeIs(napi_function)) {
341         LOGE("Argument type mismatch");
342         NError(E_PARAMS).ThrowErr(env);
343         return false;
344     }
345     return true;
346 }
347 
OffCallback(napi_env env,napi_callback_info info)348 napi_value CloudSyncNapi::OffCallback(napi_env env, napi_callback_info info)
349 {
350     NFuncArg funcArg(env, info);
351     if (!InitArgsOffCallback(env, funcArg)) {
352         return nullptr;
353     }
354 
355     string bundleName = GetBundleName(env, funcArg);
356     int32_t ret = CloudSyncManager::GetInstance().UnRegisterCallback(bundleName);
357     if (ret != E_OK) {
358         LOGE("OffCallback UnRegister error, result: %{public}d", ret);
359         NError(Convert2JsErrNum(ret)).ThrowErr(env);
360         return nullptr;
361     }
362     if (callback_ != nullptr) {
363         /* napi delete reference */
364         callback_->DeleteReference();
365         callback_ = nullptr;
366     }
367     return NVal::CreateUndefined(env).val_;
368 }
369 
Start(napi_env env,napi_callback_info info)370 napi_value CloudSyncNapi::Start(napi_env env, napi_callback_info info)
371 {
372     NFuncArg funcArg(env, info);
373     if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
374         LOGE("Failed to init args");
375         NError(E_PARAMS).ThrowErr(env);
376         return nullptr;
377     }
378 
379     string bundleName = GetBundleName(env, funcArg);
380     auto cbExec = [bundleName]() -> NError {
381         int32_t ret = CloudSyncManager::GetInstance().StartSync(bundleName);
382         if (ret != E_OK) {
383             LOGE("Start Sync error, result: %{public}d", ret);
384             return NError(Convert2JsErrNum(ret));
385         }
386         return NError(ERRNO_NOERR);
387     };
388 
389     auto cbComplete = [](napi_env env, NError err) -> NVal {
390         if (err) {
391             return {env, err.GetNapiErr(env)};
392         }
393         return NVal::CreateUndefined(env);
394     };
395 
396     std::string procedureName = "Start";
397     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
398     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_;
399 }
400 
Stop(napi_env env,napi_callback_info info)401 napi_value CloudSyncNapi::Stop(napi_env env, napi_callback_info info)
402 {
403     NFuncArg funcArg(env, info);
404     if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
405         NError(E_PARAMS).ThrowErr(env);
406         return nullptr;
407     }
408 
409     string bundleName = GetBundleName(env, funcArg);
410     auto cbExec = [bundleName]() -> NError {
411         int32_t ret = CloudSyncManager::GetInstance().StopSync(bundleName);
412         if (ret != E_OK) {
413             LOGE("Stop Sync error, result: %{public}d", ret);
414             return NError(Convert2JsErrNum(ret));
415         }
416         return NError(ERRNO_NOERR);
417     };
418 
419     auto cbComplete = [](napi_env env, NError err) -> NVal {
420         if (err) {
421             return {env, err.GetNapiErr(env)};
422         }
423         return NVal::CreateUndefined(env);
424     };
425 
426     std::string procedureName = "Stop";
427     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
428     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_;
429 }
430 
CheckRef(napi_env env,napi_ref ref,ChangeListenerNapi & listObj,const string & uri)431 bool CloudSyncNapi::CheckRef(napi_env env, napi_ref ref, ChangeListenerNapi &listObj, const string &uri)
432 {
433     napi_value offCallback = nullptr;
434     napi_status status = napi_get_reference_value(env, ref, &offCallback);
435     if (status != napi_ok) {
436         LOGE("Create reference fail, status: %{public}d", status);
437         return false;
438     }
439     bool isSame = false;
440     shared_ptr<CloudNotifyObserver> obs;
441     string obsUri;
442     {
443         lock_guard<mutex> lock(sOnOffMutex_);
444         for (auto it = listObj.observers_.begin(); it < listObj.observers_.end(); it++) {
445             napi_value onCallback = nullptr;
446             status = napi_get_reference_value(env, (*it)->ref_, &onCallback);
447             if (status != napi_ok) {
448                 LOGE("Create reference fail, status: %{public}d", status);
449                 return false;
450             }
451             napi_strict_equals(env, offCallback, onCallback, &isSame);
452             if (isSame) {
453                 obsUri = (*it)->uri_;
454                 if (uri.compare(obsUri) != 0) {
455                     return true;
456                 }
457                 return false;
458             }
459         }
460     }
461     return true;
462 }
463 
CheckIsValidUri(Uri uri)464 static bool CheckIsValidUri(Uri uri)
465 {
466     string scheme = uri.GetScheme();
467     if (scheme != FILE_SCHEME) {
468         return false;
469     }
470     string sandboxPath = uri.GetPath();
471     char realPath[PATH_MAX + 1]{'\0'};
472     if (realpath(sandboxPath.c_str(), realPath) == nullptr) {
473         LOGE("realpath failed with %{public}d", errno);
474         return false;
475     }
476     if (strncmp(realPath, sandboxPath.c_str(), sandboxPath.size()) != 0) {
477         LOGE("sandboxPath is not equal to realPath");
478         return false;
479     }
480     if (sandboxPath.find("/data/storage/el2/cloud") != 0) {
481         LOGE("not surported uri");
482         return false;
483     }
484     return true;
485 }
486 
GetRegisterParams(napi_env env,napi_callback_info info,RegisterParams & registerParams)487 static int32_t GetRegisterParams(napi_env env, napi_callback_info info, RegisterParams &registerParams)
488 {
489     NFuncArg funcArg(env, info);
490     if (!funcArg.InitArgs(NARG_CNT::THREE)) {
491         LOGE("Arguments number mismatch");
492         return E_PARAMS;
493     }
494 
495     auto [succUri, uri, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
496     if (!succUri) {
497         LOGE("get arg uri fail");
498         return E_PARAMS;
499     }
500     registerParams.uri = string(uri.get());
501     if (!CheckIsValidUri(Uri(registerParams.uri))) {
502         LOGE("RegisterChange uri parameter format error!");
503         return E_PARAMS;
504     }
505 
506     auto [succRecursion, recursion] = NVal(env, funcArg[(int)NARG_POS::SECOND]).ToBool();
507     if (!succRecursion) {
508         LOGE("get arg recursion fail");
509         return E_PARAMS;
510     }
511     registerParams.recursion = recursion;
512 
513     if (!NVal(env, funcArg[(int)NARG_POS::THIRD]).TypeIs(napi_function)) {
514         LOGE("Argument type mismatch");
515         return E_PARAMS;
516     }
517     napi_status status =
518         napi_create_reference(env, NVal(env, funcArg[(int)NARG_POS::THIRD]).val_, 1, &registerParams.cbOnRef);
519     if (status != napi_ok) {
520         LOGE("Create reference fail, status: %{public}d", status);
521         return E_PARAMS;
522     }
523 
524     return ERR_OK;
525 }
526 
RegisterToObs(napi_env env,const RegisterParams & registerParams)527 int32_t CloudSyncNapi::RegisterToObs(napi_env env, const RegisterParams &registerParams)
528 {
529     auto observer = make_shared<CloudNotifyObserver>(*g_listObj, registerParams.uri, registerParams.cbOnRef);
530     Uri uri(registerParams.uri);
531     auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
532     if (obsMgrClient == nullptr) {
533         LOGE("get DataObsMgrClient failed");
534         return E_SA_LOAD_FAILED;
535     }
536     sptr<ObserverImpl> obs = ObserverImpl::GetObserver(uri, observer);
537     if (obs == nullptr) {
538         LOGE("new ObserverImpl failed");
539         return E_INVAL_ARG;
540     }
541     ErrCode ret = obsMgrClient->RegisterObserverExt(uri, obs, registerParams.recursion);
542     if (ret != E_OK) {
543         LOGE("ObsMgr register fail");
544         ObserverImpl::DeleteObserver(uri, observer);
545         return E_INVAL_ARG;
546     }
547     lock_guard<mutex> lock(CloudSyncNapi::sOnOffMutex_);
548     g_listObj->observers_.push_back(observer);
549     return E_OK;
550 }
551 
RegisterChange(napi_env env,napi_callback_info info)552 napi_value CloudSyncNapi::RegisterChange(napi_env env, napi_callback_info info)
553 {
554     if (g_listObj == nullptr) {
555         g_listObj = make_unique<ChangeListenerNapi>(env);
556     }
557 
558     RegisterParams registerParams;
559     int32_t ret = GetRegisterParams(env, info, registerParams);
560     if (ret != ERR_OK) {
561         LOGE("Get Params fail");
562         NError(ret).ThrowErr(env);
563         return nullptr;
564     }
565 
566     if (CheckRef(env, registerParams.cbOnRef, *g_listObj, registerParams.uri)) {
567         ret = RegisterToObs(env, registerParams);
568         if (ret != E_OK) {
569             LOGE("Get Params fail");
570             NError(ret).ThrowErr(env);
571             return nullptr;
572         }
573     } else {
574         LOGE("Check Ref fail");
575         NError(E_PARAMS).ThrowErr(env);
576         napi_delete_reference(env, registerParams.cbOnRef);
577         return nullptr;
578     }
579     return NVal::CreateUndefined(env).val_;
580 }
581 
UnregisterFromObs(napi_env env,const string & uri)582 napi_value CloudSyncNapi::UnregisterFromObs(napi_env env, const string &uri)
583 {
584     auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
585     if (obsMgrClient == nullptr) {
586         LOGE("get DataObsMgrClient failed");
587         NError(E_SA_LOAD_FAILED).ThrowErr(env);
588         return nullptr;
589     }
590     std::vector<std::shared_ptr<CloudNotifyObserver>> offObservers;
591     {
592         lock_guard<mutex> lock(sOnOffMutex_);
593         for (auto iter = g_listObj->observers_.begin(); iter != g_listObj->observers_.end();) {
594             if (uri == (*iter)->uri_) {
595                 offObservers.push_back(*iter);
596                 vector<shared_ptr<CloudNotifyObserver>>::iterator tmp = iter;
597                 iter = g_listObj->observers_.erase(tmp);
598             } else {
599                 iter++;
600             }
601         }
602     }
603     for (auto observer : offObservers) {
604         if (!ObserverImpl::FindObserver(Uri(uri), observer)) {
605             LOGE("observer not exist");
606             NError(E_PARAMS).ThrowErr(env);
607             return nullptr;
608         }
609         sptr<ObserverImpl> obs = ObserverImpl::GetObserver(Uri(uri), observer);
610         if (obs == nullptr) {
611             LOGE("new observerimpl failed");
612             NError(E_PARAMS).ThrowErr(env);
613             return nullptr;
614         }
615         ErrCode ret = obsMgrClient->UnregisterObserverExt(Uri(uri), obs);
616         if (ret != ERR_OK) {
617             LOGE("call obs unregister fail");
618             NError(E_PARAMS).ThrowErr(env);
619             return nullptr;
620         }
621         ObserverImpl::DeleteObserver(Uri(uri), observer);
622     }
623     return NVal::CreateUndefined(env).val_;
624 }
625 
UnregisterChange(napi_env env,napi_callback_info info)626 napi_value CloudSyncNapi::UnregisterChange(napi_env env, napi_callback_info info)
627 {
628     if (g_listObj == nullptr || g_listObj->observers_.empty()) {
629         LOGI("no obs to unregister");
630         return nullptr;
631     }
632 
633     NFuncArg funcArg(env, info);
634     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
635         LOGE("params number mismatch");
636         NError(E_PARAMS).ThrowErr(env);
637         return nullptr;
638     }
639     auto [succUri, uri, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
640     if (!succUri || !CheckIsValidUri(Uri(uri.get()))) {
641         LOGE("get uri fail");
642         NError(E_PARAMS).ThrowErr(env);
643         return nullptr;
644     }
645 
646     return UnregisterFromObs(env, uri.get());
647 }
648 
SetClassName(const std::string classname)649 void CloudSyncNapi::SetClassName(const std::string classname)
650 {
651     className_ = classname;
652 }
653 
GetClassName()654 std::string CloudSyncNapi::GetClassName()
655 {
656     return className_;
657 }
658 
ToExport(std::vector<napi_property_descriptor> props)659 bool CloudSyncNapi::ToExport(std::vector<napi_property_descriptor> props)
660 {
661     std::string className = GetClassName();
662     auto [succ, classValue] =
663         NClass::DefineClass(exports_.env_, className, Constructor, std::move(props));
664     if (!succ) {
665         NError(E_GETRESULT).ThrowErr(exports_.env_);
666         LOGE("Failed to define CloudSyncNapi class");
667         return false;
668     }
669 
670     succ = NClass::SaveClass(exports_.env_, className, classValue);
671     if (!succ) {
672         NError(E_GETRESULT).ThrowErr(exports_.env_);
673         LOGE("Failed to save CloudSyncNapi class");
674         return false;
675     }
676 
677     return exports_.AddProp(className, classValue);
678 }
679 
Export()680 bool CloudSyncNapi::Export()
681 {
682     std::vector<napi_property_descriptor> props = {
683         NVal::DeclareNapiFunction("on", OnCallback),
684         NVal::DeclareNapiFunction("off", OffCallback),
685         NVal::DeclareNapiFunction("start", Start),
686         NVal::DeclareNapiFunction("stop", Stop),
687         NVal::DeclareNapiFunction("getCoreFileSyncState", GetCoreFileSyncState),
688         NVal::DeclareNapiFunction("getFileSyncState", GetFileSyncState),
689         NVal::DeclareNapiFunction("optimizeStorage", OptimizeStorage),
690         NVal::DeclareNapiFunction("startOptimizeSpace", StartOptimizeStorage),
691         NVal::DeclareNapiFunction("stopOptimizeSpace", StopOptimizeStorage),
692     };
693     std::string className = GetClassName();
694     auto [succ, classValue] =
695         NClass::DefineClass(exports_.env_, className, CloudSyncNapi::Constructor, std::move(props));
696     if (!succ) {
697         NError(E_GETRESULT).ThrowErr(exports_.env_);
698         LOGE("Failed to define GallerySync class");
699         return false;
700     }
701 
702     succ = NClass::SaveClass(exports_.env_, className, classValue);
703     if (!succ) {
704         NError(E_GETRESULT).ThrowErr(exports_.env_);
705         LOGE("Failed to save GallerySync class");
706         return false;
707     }
708 
709     return exports_.AddProp(className, classValue);
710 }
711 
HandOptimizeStorageParams(napi_env env,napi_callback_info info,NFuncArg & funcArg,OptimizeSpaceOptions & optimizeOptions)712 int32_t CloudSyncNapi::HandOptimizeStorageParams(napi_env env, napi_callback_info info, NFuncArg &funcArg,
713     OptimizeSpaceOptions &optimizeOptions)
714 {
715     bool succ = false;
716     auto argv = NVal(env, funcArg[NARG_POS::FIRST]);
717     if (!argv.HasProp("totalSize") || !argv.HasProp("agingDays")) {
718         return ERR_BAD_VALUE;
719     }
720 
721     int64_t totalSize = 0;
722     int32_t agingDays = 0;
723     tie(succ, totalSize) = argv.GetProp("totalSize").ToInt64();
724     if (!succ) {
725         return ERR_BAD_VALUE;
726     }
727     tie(succ, agingDays) = argv.GetProp("agingDays").ToInt32();
728     if (!succ) {
729         return ERR_BAD_VALUE;
730     }
731 
732     if (!NVal(env, funcArg[(int)NARG_POS::SECOND]).TypeIs(napi_function)) {
733         LOGE("Argument type mismatch");
734         return ERR_BAD_VALUE;
735     }
736 
737     LOGI("totalSize:%{public}lld, agingDays:%{public}d", static_cast<long long>(totalSize), agingDays);
738     optimizeOptions.totalSize = totalSize;
739     optimizeOptions.agingDays = agingDays;
740     return ERR_OK;
741 }
742 
StartOptimizeStorage(napi_env env,napi_callback_info info)743 napi_value CloudSyncNapi::StartOptimizeStorage(napi_env env, napi_callback_info info)
744 {
745     LOGI("StartOptimizeStorage enter");
746     NFuncArg funcArg(env, info);
747     if (!funcArg.InitArgs(NARG_CNT::TWO)) {
748         NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
749         LOGE("Number of arguments unmatched");
750         return nullptr;
751     }
752     OptimizeSpaceOptions optimizeOptions {};
753     int32_t res = HandOptimizeStorageParams(env, info, funcArg, optimizeOptions);
754     if (res != ERR_OK) {
755         LOGE("hand paeams failed");
756         NError(E_PARAMS).ThrowErr(env);
757         return nullptr;
758     }
759 
760     auto callback = make_shared<CloudOptimizeCallbackImpl>(env, NVal(env, funcArg[(int)NARG_POS::SECOND]));
761     auto cbExec = [optimizeOptions, callback]() -> NError {
762         int32_t ret = CloudSyncManager::GetInstance().OptimizeStorage(optimizeOptions, callback);
763         if (ret != E_OK) {
764             LOGE("StartOptimizeStorage error, result: %{public}d", ret);
765             return NError(Convert2JsErrNum(ret));
766         }
767         return NError(ERRNO_NOERR);
768     };
769 
770     auto cbComplete = [](napi_env env, NError err) -> NVal {
771         if (err) {
772             return {env, err.GetNapiErr(env)};
773         }
774         return NVal::CreateUndefined(env);
775     };
776 
777     std::string procedureName = "StartOptimizeStorage";
778     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::THREE));
779     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_;
780 }
781 
StopOptimizeStorage(napi_env env,napi_callback_info info)782 napi_value CloudSyncNapi::StopOptimizeStorage(napi_env env, napi_callback_info info)
783 {
784     LOGI("StopOptimizeStorage enter");
785     int32_t ret = CloudSyncManager::GetInstance().StopOptimizeStorage();
786     if (ret != E_OK) {
787         LOGE("StopOptimizeStorage error, result: %{public}d", ret);
788         NError(Convert2JsErrNum(ret)).ThrowErr(env);
789         return nullptr;
790     }
791 
792     return NVal::CreateUndefined(env).val_;
793 }
794 
OptimizeStorage(napi_env env,napi_callback_info info)795 napi_value CloudSyncNapi::OptimizeStorage(napi_env env, napi_callback_info info)
796 {
797     NFuncArg funcArg(env, info);
798     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
799         LOGE("Failed to init args");
800         NError(E_PARAMS).ThrowErr(env);
801         return nullptr;
802     }
803 
804     OptimizeSpaceOptions optimizeOptions {};
805     optimizeOptions.totalSize = 0;
806     optimizeOptions.agingDays = AGING_DAYS;
807 
808     auto cbExec = [optimizeOptions]() -> NError {
809         int32_t ret = CloudSyncManager::GetInstance().OptimizeStorage(optimizeOptions);
810         if (ret != E_OK) {
811             LOGE("OptimizeStorage error, result: %{public}d", ret);
812             return NError(Convert2JsErrNum(ret));
813         }
814         return NError(ERRNO_NOERR);
815     };
816 
817     auto cbComplete = [](napi_env env, NError err) -> NVal {
818         if (err) {
819             return {env, err.GetNapiErr(env)};
820         }
821         return NVal::CreateUndefined(env);
822     };
823 
824     std::string procedureName = "OptimizeStorage";
825     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
826     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_;
827 }
828 
IsGetSingleFileStatus(const napi_env & env,const NFuncArg & funcArg)829 static bool IsGetSingleFileStatus(const napi_env &env, const NFuncArg &funcArg)
830 {
831     if (!NVal(env, funcArg[(int)NARG_POS::FIRST]).TypeIs(napi_string)) {
832         return false;
833     }
834     return true;
835 }
836 
GetxattrErr()837 static tuple<int32_t, int32_t> GetxattrErr()
838 {
839     LOGE("getxattr failed, errno : %{public}d", errno);
840     std::set<int32_t> errForSingleFileSync = { ENOENT, EACCES, EAGAIN, EINTR, ENOSYS };
841     if (errForSingleFileSync.find(errno) != errForSingleFileSync.end()) {
842         return { errno, -1 };
843     }
844     return { E_UNKNOWN_ERR, -1 };
845 }
846 
GetSingleFileSyncState(const string & uri)847 tuple<int32_t, int32_t> CloudSyncNapi::GetSingleFileSyncState(const string &uri)
848 {
849     Uri fileUri(uri);
850     char resolvedPath[PATH_MAX] = {'\0'};
851 
852     if (!CheckIsValidUri(fileUri)) {
853         LOGE("Path illegally crossess");
854         return { E_ILLEGAL_URI, -1 };
855     }
856 
857     if (realpath(fileUri.GetPath().c_str(), resolvedPath) == nullptr) {
858         LOGE("get realPath failed");
859         return { LibN::USER_FILE_MANAGER_SYS_CAP_TAG + E_URIM, -1 };
860     }
861 
862     std::string sandBoxPath(resolvedPath);
863     std::string xattrKey = "user.cloud.filestatus";
864     auto xattrValueSize = getxattr(sandBoxPath.c_str(), xattrKey.c_str(), nullptr, 0);
865     if (xattrValueSize < 0) {
866         return GetxattrErr();
867     }
868     std::unique_ptr<char[]> xattrValue = std::make_unique<char[]>((long)xattrValueSize + 1);
869     if (xattrValue == nullptr) {
870         LOGE("Failed to allocate memory for xattrValue, errno : %{public}d", errno);
871         return { E_UNKNOWN_ERR, -1 };
872     }
873     xattrValueSize = getxattr(sandBoxPath.c_str(), xattrKey.c_str(), xattrValue.get(), xattrValueSize);
874     if (xattrValueSize <= 0) {
875         return GetxattrErr();
876     }
877 
878     std::string xattrValueStr(xattrValue.get(), xattrValueSize);
879     bool isValid = std::all_of(xattrValueStr.begin(), xattrValueStr.end(), ::isdigit);
880     if (!isValid) {
881         LOGE("invalid xattrValue");
882         return { E_PARAMS, -1};
883     }
884 
885     int32_t fileStatus = std::stoi(xattrValue.get());
886     int32_t val;
887     if (fileStatus == FileSync::FILESYNC_TO_BE_UPLOADED || fileStatus == FileSync::FILESYNC_UPLOADING ||
888         fileStatus == FileSync::FILESYNC_UPLOAD_FAILURE || fileStatus == FileSync::FILESYNC_UPLOAD_SUCCESS) {
889         val = statusMap[fileStatus];
890     } else {
891         val = FileSyncState::FILESYNCSTATE_COMPLETED;
892     }
893     return { E_OK, val };
894 }
895 
GetFileSyncStateForBatch(const string & uri)896 tuple<int32_t, int32_t> CloudSyncNapi::GetFileSyncStateForBatch(const string &uri)
897 {
898     Uri fileUri(uri);
899     char resolvedPath[PATH_MAX] = {'\0'};
900 
901     if (!CheckIsValidUri(fileUri)) {
902         LOGE("Path illegally crossess");
903         return { E_ILLEGAL_URI, -1 };
904     }
905 
906     if (realpath(fileUri.GetPath().c_str(), resolvedPath) == nullptr) {
907         LOGE("get realPath failed");
908         return { LibN::USER_FILE_MANAGER_SYS_CAP_TAG + E_URIM, -1 };
909     }
910 
911     std::string sandBoxPath(resolvedPath);
912 
913     std::string xattrKey = "user.cloud.filestatus";
914     auto xattrValueSize = getxattr(sandBoxPath.c_str(), xattrKey.c_str(), nullptr, 0);
915     if (xattrValueSize < 0) {
916         LOGE("getxattr failed, errno : %{public}d", errno);
917         return { LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS, -1 };
918     }
919     std::unique_ptr<char[]> xattrValue = std::make_unique<char[]>((long)xattrValueSize + 1);
920     if (xattrValue == nullptr) {
921         LOGE("Failed to allocate memory for xattrValue, errno : %{public}d", errno);
922         return { LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS, -1 };
923     }
924     xattrValueSize = getxattr(sandBoxPath.c_str(), xattrKey.c_str(), xattrValue.get(), xattrValueSize);
925     if (xattrValueSize <= 0) {
926         LOGE("getxattr failed, errno : %{public}d", errno);
927         return { LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS, -1 };
928     }
929 
930     std::string xattrValueStr(xattrValue.get(), xattrValueSize);
931     bool isValid = std::all_of(xattrValueStr.begin(), xattrValueStr.end(), ::isdigit);
932     if (!isValid) {
933         LOGE("invalid xattrValue");
934         return { E_PARAMS, -1};
935     }
936 
937     int32_t fileStatus = std::stoi(xattrValue.get());
938     int32_t val;
939     if (fileStatus == FileSync::FILESYNC_TO_BE_UPLOADED || fileStatus == FileSync::FILESYNC_UPLOADING ||
940         fileStatus == FileSync::FILESYNC_UPLOAD_FAILURE || fileStatus == FileSync::FILESYNC_UPLOAD_SUCCESS) {
941         val = statusMap[fileStatus];
942     } else {
943         val = FileSyncState::FILESYNCSTATE_COMPLETED;
944     }
945     return { E_OK, val };
946 }
947 
AsyncComplete(const napi_env & env,std::shared_ptr<BatchContext> ctx)948 static NVal AsyncComplete(const napi_env &env, std::shared_ptr<BatchContext> ctx)
949 {
950     napi_value results = nullptr;
951 
952     napi_status status = napi_create_array(env, &results);
953     if (status != napi_ok) {
954         LOGE("Failed to create array");
955         return { env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env) };
956     }
957 
958     int32_t index = 0;
959     for (auto result : ctx->resultList) {
960         status = napi_set_element(env, results, index, NVal::CreateInt32(env, result).val_);
961         if (status != napi_ok) {
962             LOGE("Failed to set element on data");
963             return { env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env) };
964         }
965         index++;
966     }
967     return { env, results };
968 }
969 
GetBatchFileSyncState(const napi_env & env,const NFuncArg & funcArg)970 napi_value CloudSyncNapi::GetBatchFileSyncState(const napi_env &env, const NFuncArg &funcArg)
971 {
972     NVal arrayVal(env, funcArg[static_cast<int>(NARG_POS::FIRST)]);
973     if (!arrayVal.TypeIs(napi_object)) {
974         LOGE("Invalid argments");
975         NError(E_PARAMS).ThrowErr(env);
976         return nullptr;
977     }
978 
979     auto [succ, uris, ignore] = arrayVal.ToStringArray();
980     auto ctx = std::make_shared<BatchContext>();
981     ctx->uriList.swap(uris);
982     if (ctx->uriList.size() > GET_FILE_SYNC_MAX) {
983         LOGE("The parameter is too long");
984         NError(E_PARAMS).ThrowErr(env);
985         return nullptr;
986     }
987 
988     auto cbExec = [env, ctx]() ->NError {
989         int32_t result = 0;
990         int32_t fileStatus = 0;
991         for (auto &uri : ctx->uriList) {
992             tie(result, fileStatus) = GetFileSyncStateForBatch(uri);
993             if (result != E_OK) {
994                 return NError(Convert2JsErrNum(result));
995             }
996             ctx->resultList.push_back(fileStatus);
997         }
998         return NError(NO_ERROR);
999     };
1000 
1001     auto cbComplete = [ctx](napi_env env, NError err) -> NVal {
1002         if (err) {
1003             return { env, err.GetNapiErr(env) };
1004         }
1005         return AsyncComplete(env, ctx);
1006     };
1007 
1008     std::string procedureName = "GetFileSyncState";
1009     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
1010     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_;
1011 }
1012 
CheckPermissions(const string & permission,bool isSystemApp)1013 static int32_t CheckPermissions(const string &permission, bool isSystemApp)
1014 {
1015     if (!permission.empty() && !DfsuAccessTokenHelper::CheckCallerPermission(permission)) {
1016         LOGE("permission denied");
1017         return E_PERMISSION_DENIED;
1018     }
1019     if (isSystemApp && !DfsuAccessTokenHelper::IsSystemApp()) {
1020         LOGE("caller hap is not system hap");
1021         return E_PERMISSION_SYSTEM;
1022     }
1023     return E_OK;
1024 }
1025 
GetFileSyncState(napi_env env,napi_callback_info info)1026 napi_value CloudSyncNapi::GetFileSyncState(napi_env env, napi_callback_info info)
1027 {
1028     NFuncArg funcArg(env, info);
1029     int32_t result = 0;
1030     int32_t fileStatus = 0;
1031 
1032     int ret = CheckPermissions(PERM_CLOUD_SYNC, true);
1033     if (ret != 0) {
1034         NError(Convert2JsErrNum(ret)).ThrowErr(env);
1035         return nullptr;
1036     }
1037 
1038     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
1039         LOGE("Number of arguments unmatched");
1040         NError(E_PARAMS).ThrowErr(env);
1041         return nullptr;
1042     }
1043 
1044     if (IsGetSingleFileStatus(env, funcArg)) {
1045         std::unique_ptr<char []> uri;
1046         bool succ = false;
1047         tie(succ, uri, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::FIRST)]).ToUTF8String();
1048         if (!succ) {
1049             LOGE("Invalid uri");
1050             NError(E_PARAMS).ThrowErr(env);
1051             return nullptr;
1052         }
1053         tie(result, fileStatus) = GetSingleFileSyncState(string(uri.get()));
1054         if (result != E_OK) {
1055             NError(Convert2JsErrNum(result)).ThrowErr(env);
1056             return nullptr;
1057         }
1058         return NVal::CreateInt32(env, fileStatus).val_;
1059     }
1060     return GetBatchFileSyncState(env, funcArg);
1061 }
1062 
GetxattrErrForPublic()1063 static tuple<int32_t, int32_t> GetxattrErrForPublic()
1064 {
1065     LOGE("getxattr failed, errno : %{public}d", errno);
1066     std::set<int32_t> errForSingleFileSync = { ENOENT, EACCES, EAGAIN, EINTR, ENOSYS };
1067     if (errForSingleFileSync.find(errno) != errForSingleFileSync.end()) {
1068         return { errno, -1 };
1069     }
1070     return { E_SERVICE_INNER_ERROR, -1 };
1071 }
1072 
DoGetCoreFileSyncState(const char * resolvedPath)1073 static tuple<int32_t, int32_t> DoGetCoreFileSyncState(const char *resolvedPath)
1074 {
1075     std::string sandBoxPath(resolvedPath);
1076     std::string xattrKey = "user.cloud.filestatus";
1077 
1078     auto xattrValueSize = getxattr(sandBoxPath.c_str(), xattrKey.c_str(), nullptr, 0);
1079     if (xattrValueSize < 0) {
1080         return GetxattrErrForPublic();
1081     }
1082     std::unique_ptr<char[]> xattrValue = std::make_unique<char[]>((long)xattrValueSize + 1);
1083     if (xattrValue == nullptr) {
1084         LOGE("Failed to allocate memory for xattrValue, errno : %{public}d", errno);
1085         return { E_SERVICE_INNER_ERROR, -1 };
1086     }
1087     xattrValueSize = getxattr(sandBoxPath.c_str(), xattrKey.c_str(), xattrValue.get(), xattrValueSize);
1088     if (xattrValueSize <= 0) {
1089         return GetxattrErrForPublic();
1090     }
1091 
1092     std::string xattrValueStr(xattrValue.get(), xattrValueSize);
1093     bool isValid = std::all_of(xattrValueStr.begin(), xattrValueStr.end(), ::isdigit);
1094     if (!isValid) {
1095         LOGE("invalid xattrValue");
1096         return { E_SERVICE_INNER_ERROR, -1 };
1097     }
1098 
1099     int32_t fileStatus = std::stoi(xattrValue.get());
1100     int32_t val;
1101     if (fileStatus >= 0 && fileStatus < publicStatusMap.size()) {
1102         val = publicStatusMap[fileStatus];
1103     } else {
1104         LOGE("invalid value");
1105         return { E_SERVICE_INNER_ERROR, -1 };
1106     }
1107     return { E_OK, val };
1108 }
1109 
GetCoreFileSyncState(napi_env env,napi_callback_info info)1110 napi_value CloudSyncNapi::GetCoreFileSyncState(napi_env env, napi_callback_info info)
1111 {
1112     NFuncArg funcArg(env, info);
1113     int32_t result = 0;
1114     int32_t fileStatus = 0;
1115 
1116     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
1117         LOGE("Number of arguments unmatched");
1118         NError(EINVAL).ThrowErr(env);
1119         return nullptr;
1120     }
1121 
1122     std::unique_ptr<char []> uri;
1123     bool succ = false;
1124     tie(succ, uri, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::FIRST)]).ToUTF8String();
1125     if (!succ) {
1126         LOGE("GetCoreFileSyncState get uri parameter failed!");
1127         NError(EINVAL).ThrowErr(env);
1128         return nullptr;
1129     }
1130 
1131     Uri fileUri(string(uri.get()));
1132 
1133     if (!CheckIsValidUri(fileUri)) {
1134         LOGE("Path illegally crossess");
1135         NError(Convert2JsErrNum(E_ILLEGAL_URI)).ThrowErr(env);
1136         return nullptr;
1137     }
1138 
1139     char resolvedPath[PATH_MAX] = {'\0'};
1140 
1141     if (realpath(fileUri.GetPath().c_str(), resolvedPath) == nullptr) {
1142         LOGE("get realPath failed");
1143         NError(Convert2JsErrNum(E_INVALID_URI)).ThrowErr(env);
1144         return nullptr;
1145     }
1146 
1147     tie(result, fileStatus) = DoGetCoreFileSyncState(resolvedPath);
1148     if (result != E_OK) {
1149         NError(Convert2JsErrNum(result)).ThrowErr(env);
1150         return nullptr;
1151     }
1152     return NVal::CreateInt32(env, fileStatus).val_;
1153 }
1154 
OnChange(CloudChangeListener & listener,const napi_ref cbRef)1155 void ChangeListenerNapi::OnChange(CloudChangeListener &listener, const napi_ref cbRef)
1156 {
1157     if (static_cast<NotifyType>(listener.changeInfo.changeType_) == NotifyType::NOTIFY_NONE ||
1158         listener.changeInfo.uris_.empty() || listener.changeInfo.size_ > MAX_CHANGE_DATA_SIZE) {
1159         LOGD("notify data is invalid: %{public}d %{public}zu %{public}d",
1160              static_cast<int>(listener.changeInfo.changeType_), listener.changeInfo.uris_.size(),
1161              listener.changeInfo.size_);
1162         return;
1163     }
1164 
1165     UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(env_, cbRef, listener.changeInfo, listener.strUri);
1166     if (msg == nullptr) {
1167         LOGE("Failed to create uv message object");
1168         return;
1169     }
1170     msg->data_ = (uint8_t *)malloc(msg->changeInfo_.size_);
1171     if (msg->data_ == nullptr) {
1172         LOGE("new msg->data failed");
1173         delete msg;
1174         return;
1175     }
1176     int copyRet = memcpy_s(msg->data_, msg->changeInfo_.size_, msg->changeInfo_.data_, msg->changeInfo_.size_);
1177     if (copyRet != 0) {
1178         LOGE("Parcel data copy failed, err = %{public}d", copyRet);
1179         free(msg->data_);
1180         delete msg;
1181         return;
1182     }
1183 
1184     auto ret = SendEvent(msg);
1185     if (ret != napi_ok) {
1186         LOGE("Failed to execute libuv work queue, ret: %{public}d", ret);
1187         free(msg->data_);
1188         delete msg;
1189         return;
1190     }
1191 }
1192 
SendEvent(UvChangeMsg * msg)1193 int32_t ChangeListenerNapi::SendEvent(UvChangeMsg *msg)
1194 {
1195     auto task = [msg]() {
1196         // js thread
1197         napi_env env = msg->env_;
1198         napi_handle_scope scope = nullptr;
1199         if (napi_open_handle_scope(env, &scope) != napi_ok) {
1200             LOGE("Failed to open handle scope");
1201             return;
1202         }
1203         do {
1204             napi_value jsCallback = nullptr;
1205             napi_status status = napi_get_reference_value(env, msg->ref_, &jsCallback);
1206             if (status != napi_ok) {
1207                 LOGE("Create reference fail, status: %{public}d", status);
1208                 break;
1209             }
1210 
1211             napi_value retVal = nullptr;
1212             napi_value result[ARGS_ONE];
1213             result[PARAM0] = ChangeListenerNapi::SolveOnChange(env, msg);
1214             if (result[PARAM0] == nullptr) {
1215                 break;
1216             }
1217 
1218             status = napi_call_function(env, nullptr, jsCallback, ARGS_ONE, result, &retVal);
1219             if (status != napi_ok) {
1220                 LOGE("CallJs napi_call_function fail, status: %{public}d", status);
1221             }
1222         } while (0);
1223         napi_close_handle_scope(env, scope);
1224         free(msg->data_);
1225         delete msg;
1226     };
1227     return napi_send_event(env_, task, napi_event_priority::napi_eprio_immediate);
1228 }
1229 
SetValueArray(const napi_env & env,const char * fieldStr,const std::list<Uri> listValue,napi_value & result)1230 static napi_status SetValueArray(const napi_env &env, const char *fieldStr, const std::list<Uri> listValue,
1231     napi_value &result)
1232 {
1233     napi_value value = nullptr;
1234     napi_status status = napi_create_array_with_length(env, listValue.size(), &value);
1235     if (status != napi_ok) {
1236         LOGE("Create array error! field: %{public}s", fieldStr);
1237         return status;
1238     }
1239     int elementIndex = 0;
1240     for (auto uri : listValue) {
1241         napi_value uriRet = nullptr;
1242         napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &uriRet);
1243         status = napi_set_element(env, value, elementIndex++, uriRet);
1244         if (status != napi_ok) {
1245             LOGE("Set lite item failed, error: %d", status);
1246         }
1247     }
1248     status = napi_set_named_property(env, result, fieldStr, value);
1249     if (status != napi_ok) {
1250         LOGE("Set array named property error! field: %{public}s", fieldStr);
1251     }
1252 
1253     return status;
1254 }
1255 
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)1256 static napi_status SetValueInt32(const napi_env &env, const char *fieldStr, const int intValue, napi_value &result)
1257 {
1258     napi_value value;
1259     napi_status status = napi_create_int32(env, intValue, &value);
1260     if (status != napi_ok) {
1261         LOGE("Set value create int32 error! field: %{public}s", fieldStr);
1262         return status;
1263     }
1264     status = napi_set_named_property(env, result, fieldStr, value);
1265     if (status != napi_ok) {
1266         LOGE("Set int32 named property error! field: %{public}s", fieldStr);
1267     }
1268     return status;
1269 }
1270 
SetIsDir(const napi_env & env,const shared_ptr<MessageParcel> parcel,napi_value & result)1271 static napi_status SetIsDir(const napi_env &env, const shared_ptr<MessageParcel> parcel, napi_value &result)
1272 {
1273     uint32_t len = 0;
1274     napi_status status = napi_invalid_arg;
1275     if (!parcel->ReadUint32(len)) {
1276         LOGE("Failed to read sub uri list length");
1277         return status;
1278     }
1279     napi_value isDirArray = nullptr;
1280     napi_create_array_with_length(env, len, &isDirArray);
1281     int elementIndex = 0;
1282     if (len > READ_SIZE) {
1283         return napi_invalid_arg;
1284     }
1285     for (uint32_t i = 0; i < len; i++) {
1286         bool isDir = parcel->ReadBool();
1287         napi_value isDirRet = nullptr;
1288         napi_get_boolean(env, isDir, &isDirRet);
1289         napi_set_element(env, isDirArray, elementIndex++, isDirRet);
1290     }
1291     status = napi_set_named_property(env, result, "isDirectory", isDirArray);
1292     if (status != napi_ok) {
1293         LOGE("Set subUri named property error!");
1294     }
1295     return status;
1296 }
1297 
SolveOnChange(napi_env env,UvChangeMsg * msg)1298 napi_value ChangeListenerNapi::SolveOnChange(napi_env env, UvChangeMsg *msg)
1299 {
1300     static napi_value result;
1301     if (msg->changeInfo_.uris_.empty()) {
1302         napi_get_undefined(env, &result);
1303         return result;
1304     }
1305     napi_create_object(env, &result);
1306     SetValueArray(env, "uris", msg->changeInfo_.uris_, result);
1307     SetValueInt32(env, "type", (int)msg->changeInfo_.changeType_, result);
1308 
1309     if (msg->changeInfo_.size_ > MAX_CHANGE_DATA_SIZE || msg->data_ == nullptr) {
1310         LOGE("change info is invalid");
1311         return nullptr;
1312     }
1313     uint8_t *parcelData = (uint8_t *)malloc(msg->changeInfo_.size_);
1314     if (parcelData == nullptr) {
1315         LOGE("new parcelData failed");
1316         return nullptr;
1317     }
1318     int copyRet = memcpy_s(parcelData, msg->changeInfo_.size_, msg->data_, msg->changeInfo_.size_);
1319     if (copyRet != 0) {
1320         LOGE("Parcel data copy failed, err = %{public}d", copyRet);
1321         free(parcelData);
1322         return nullptr;
1323     }
1324 
1325     shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
1326     if (!parcel->ParseFrom(reinterpret_cast<uintptr_t>(parcelData), msg->changeInfo_.size_)) {
1327         LOGE("parcel parse failed");
1328         free(parcelData);
1329         return nullptr;
1330     }
1331     napi_status status = SetIsDir(env, parcel, result);
1332     if (status != napi_ok) {
1333         LOGE("Set subArray named property error! field: subUris");
1334         return nullptr;
1335     }
1336 
1337     return result;
1338 }
1339 
OnChange()1340 void CloudNotifyObserver::OnChange() {}
1341 
OnchangeExt(const AAFwk::ChangeInfo & changeInfo)1342 void CloudNotifyObserver::OnchangeExt(const AAFwk::ChangeInfo &changeInfo)
1343 {
1344     CloudChangeListener listener;
1345     listener.changeInfo = changeInfo;
1346     listener.strUri = uri_;
1347     listObj_.OnChange(listener, ref_);
1348 }
1349 
1350 } // namespace OHOS::FileManagement::CloudSync
1351