• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 
16 #include "prop_n_exporter.h"
17 
18 #include <cstring>
19 #include <ctime>
20 #include <iostream>
21 #include <memory>
22 #include <sstream>
23 #include <unistd.h>
24 
25 #include "class_file/file_entity.h"
26 #include "class_file/file_n_exporter.h"
27 #include "close.h"
28 #include "common_func.h"
29 #include "fdatasync.h"
30 #include "file_utils.h"
31 #include "filemgmt_libn.h"
32 #include "fsync.h"
33 #include "js_native_api.h"
34 #include "js_native_api_types.h"
35 #include "lstat.h"
36 #include "mkdtemp.h"
37 #include "open.h"
38 #include "rename.h"
39 #include "rmdirent.h"
40 #include "stat.h"
41 #include "truncate.h"
42 #include "utimes.h"
43 
44 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
45 #include <sys/xattr.h>
46 
47 #include "bundle_mgr_proxy.h"
48 #include "connectdfs.h"
49 #include "copy.h"
50 #include "copy_file.h"
51 #include "copydir.h"
52 #include "create_randomaccessfile.h"
53 #include "create_stream.h"
54 #include "create_streamrw.h"
55 #include "disconnectdfs.h"
56 #include "dup.h"
57 #include "fdopen_stream.h"
58 #include "ipc_skeleton.h"
59 #include "iservice_registry.h"
60 #include "listfile.h"
61 #include "lseek.h"
62 #include "move.h"
63 #include "movedir.h"
64 #include "read_lines.h"
65 #include "read_text.h"
66 #include "rust_file.h"
67 #include "symlink.h"
68 #include "system_ability_definition.h"
69 #include "watcher.h"
70 #include "xattr.h"
71 #endif
72 
73 #ifdef FILE_API_TRACE
74 #include "hitrace_meter.h"
75 #endif
76 
77 namespace OHOS {
78 namespace FileManagement {
79 namespace ModuleFileIO {
80 using namespace std;
81 using namespace OHOS::FileManagement::LibN;
82 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
83 const string CLOUDDISK_FILE_PREFIX = "/data/storage/el2/cloud";
84 const string DISTRIBUTED_FILE_PREFIX = "/data/storage/el2/distributedfiles";
85 const string PACKAGE_NAME_FLAG = "<PackageName>";
86 const string USER_ID_FLAG = "<currentUserId>";
87 const string PHYSICAL_PATH_PREFIX = "/mnt/hmdfs/<currentUserId>/account/device_view/local/data/<PackageName>";
88 const string CLOUD_FILE_LOCATION = "user.cloud.location";
89 const char POSITION_LOCAL = '1';
90 const char POSITION_BOTH = '3';
91 const int BASE_USER_RANGE = 200000;
92 #endif
93 
94 enum AccessFlag : int32_t {
95     DEFAULT_FLAG = -1,
96     LOCAL_FLAG,
97 };
98 
99 struct AccessArgs {
100     string path;
101     int mode = -1;
102     int flag = DEFAULT_FLAG;
103 };
104 
UvAccess(const string & path,int mode)105 static int UvAccess(const string &path, int mode)
106 {
107     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup) *> access_req = {new uv_fs_t,
108         CommonFunc::fs_req_cleanup};
109     if (!access_req) {
110         HILOGE("Failed to request heap memory.");
111         return ENOMEM;
112     }
113     return uv_fs_access(nullptr, access_req.get(), path.c_str(), mode, nullptr);
114 }
115 
116 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
IsCloudOrDistributedFilePath(const string & path)117 static bool IsCloudOrDistributedFilePath(const string &path)
118 {
119     return path.find(CLOUDDISK_FILE_PREFIX) == 0 || path.find(DISTRIBUTED_FILE_PREFIX) == 0;
120 }
121 
GetCurrentUserId()122 static int GetCurrentUserId()
123 {
124     int uid = IPCSkeleton::GetCallingUid();
125     int userId = uid / BASE_USER_RANGE;
126     return userId;
127 }
128 
GetBundleMgrProxy()129 static sptr<BundleMgrProxy> GetBundleMgrProxy()
130 {
131     sptr<ISystemAbilityManager> systemAbilityManager =
132         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
133     if (!systemAbilityManager) {
134         HILOGE("fail to get system ability mgr");
135         return nullptr;
136     }
137     sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
138     if (!remoteObject) {
139         HILOGE("fail to get bundle manager proxy");
140         return nullptr;
141     }
142 
143     return iface_cast<BundleMgrProxy>(remoteObject);
144 }
145 
GetSelfBundleName()146 static string GetSelfBundleName()
147 {
148     sptr<BundleMgrProxy> bundleMgrProxy = GetBundleMgrProxy();
149     if (!bundleMgrProxy) {
150         HILOGE("bundleMgrProxy is nullptr");
151         return "";
152     }
153     BundleInfo bundleInfo;
154     auto ret = bundleMgrProxy->GetBundleInfoForSelf(0, bundleInfo);
155     if (ret != 0) {
156         HILOGE("bundleName get fail");
157         return "";
158     }
159     return bundleInfo.name;
160 }
161 
HandleLocalCheck(const string & path,int mode)162 static int HandleLocalCheck(const string &path, int mode)
163 {
164     // check if the file of /data/storage/el2/cloud is on the local
165     if (path.find(CLOUDDISK_FILE_PREFIX) == 0) {
166         char val[2] = {'\0'};
167         if (getxattr(path.c_str(), CLOUD_FILE_LOCATION.c_str(), val, sizeof(val)) < 0) {
168             HILOGI("get cloud file location fail, err: %{public}d", errno);
169             return errno;
170         }
171         if (val[0] == POSITION_LOCAL || val[0] == POSITION_BOTH) {
172             return 0;
173         }
174         return ENOENT;
175     }
176     // check if the distributed file of /data/storage/el2/distributedfiles is on the local,
177     // convert into physical path(/mnt/hmdfs/<currentUserId>/account/device_view/local/data/<PackageName>) and check
178     if (path.find(DISTRIBUTED_FILE_PREFIX) == 0) {
179         int userId = GetCurrentUserId();
180         string bundleName = GetSelfBundleName();
181         string relativePath = path.substr(DISTRIBUTED_FILE_PREFIX.length());
182         string physicalPath = PHYSICAL_PATH_PREFIX + relativePath;
183         physicalPath.replace(physicalPath.find(USER_ID_FLAG), USER_ID_FLAG.length(), to_string(userId));
184         physicalPath.replace(physicalPath.find(PACKAGE_NAME_FLAG), PACKAGE_NAME_FLAG.length(), bundleName);
185 
186         return UvAccess(physicalPath, mode);
187     }
188 
189     return ENOENT;
190 }
191 #endif
192 
AccessCore(const string & path,int mode,int flag=DEFAULT_FLAG)193 static int AccessCore(const string &path, int mode, int flag = DEFAULT_FLAG)
194 {
195 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
196     if (flag == LOCAL_FLAG && IsCloudOrDistributedFilePath(path)) {
197         return HandleLocalCheck(path, mode);
198     }
199 #endif
200     return UvAccess(path, mode);
201 }
202 
GetMode(NVal secondVar,bool * hasMode)203 static int GetMode(NVal secondVar, bool *hasMode)
204 {
205     if (secondVar.TypeIs(napi_number)) {
206         bool succ = false;
207         int mode = 0;
208         *hasMode = true;
209         tie(succ, mode) = secondVar.ToInt32();
210         if (succ && (static_cast<unsigned int>(mode) & 0x06) == static_cast<unsigned int>(mode)) {
211             return mode;
212         }
213     }
214 
215     return -1;
216 }
217 
GetAccessArgs(napi_env env,const NFuncArg & funcArg,AccessArgs & args)218 static bool GetAccessArgs(napi_env env, const NFuncArg &funcArg, AccessArgs &args)
219 {
220     auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
221     if (!succ) {
222         HILOGE("Invalid path from JS first argument");
223         return false;
224     }
225     args.path = path.get();
226 
227     bool hasMode = false;
228     if (funcArg.GetArgc() >= NARG_CNT::TWO) {
229         args.mode = GetMode(NVal(env, funcArg[NARG_POS::SECOND]), &hasMode);
230     }
231     if (args.mode < 0 && hasMode) {
232         HILOGE("Invalid mode from JS second argument");
233         return false;
234     }
235     args.mode = hasMode ? args.mode : 0;
236 
237     if (funcArg.GetArgc() == NARG_CNT::THREE) {
238         tie(succ, args.flag) = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32(args.flag);
239         if (!succ) {
240             HILOGE("Invalid flag from JS third argument");
241             return false;
242         }
243     }
244 
245     return true;
246 }
247 
AccessSync(napi_env env,napi_callback_info info)248 napi_value PropNExporter::AccessSync(napi_env env, napi_callback_info info)
249 {
250     NFuncArg funcArg(env, info);
251     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
252         HILOGE("Number of arguments unmatched");
253         NError(EINVAL).ThrowErr(env);
254         return nullptr;
255     }
256 
257     AccessArgs args;
258     if (!GetAccessArgs(env, funcArg, args)) {
259         NError(EINVAL).ThrowErr(env);
260         return nullptr;
261     }
262 
263     bool isAccess = false;
264     int ret = AccessCore(args.path, args.mode, args.flag);
265     if (ret < 0 && (string_view(uv_err_name(ret)) != "ENOENT")) {
266         HILOGE("Failed to access file by path, ret:%{public}d", ret);
267         NError(ret).ThrowErr(env);
268         return nullptr;
269     }
270     if (ret == 0) {
271         isAccess = true;
272     }
273     return NVal::CreateBool(env, isAccess).val_;
274 }
275 
Access(napi_env env,napi_callback_info info)276 napi_value PropNExporter::Access(napi_env env, napi_callback_info info)
277 {
278     NFuncArg funcArg(env, info);
279     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
280         HILOGE("Number of arguments unmatched");
281         NError(EINVAL).ThrowErr(env);
282         return nullptr;
283     }
284 
285     AccessArgs args;
286     if (!GetAccessArgs(env, funcArg, args)) {
287         NError(EINVAL).ThrowErr(env);
288         return nullptr;
289     }
290 
291     auto result = CreateSharedPtr<AsyncAccessArg>();
292     if (result == nullptr) {
293         HILOGE("Failed to request heap memory.");
294         NError(ENOMEM).ThrowErr(env);
295         return nullptr;
296     }
297     auto cbExec = [path = args.path, result, mode = args.mode, flag = args.flag]() -> NError {
298         int ret = AccessCore(path, mode, flag);
299         if (ret == 0) {
300             result->isAccess = true;
301         } else {
302             HILOGE("Accesscore finish ret %{public}d", ret);
303         }
304         return (ret < 0 && (string_view(uv_err_name(ret)) != "ENOENT")) ? NError(ret) : NError(ERRNO_NOERR);
305     };
306 
307     auto cbComplete = [result](napi_env env, NError err) -> NVal {
308         if (err) {
309             return { env, err.GetNapiErr(env) };
310         }
311         return NVal::CreateBool(env, result->isAccess);
312     };
313 
314     NVal thisVar(env, funcArg.GetThisVar());
315     if (funcArg.GetArgc() == NARG_CNT::ONE || NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_number)) {
316         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_ACCESS_NAME, cbExec, cbComplete).val_;
317     } else {
318         NVal cb(env, funcArg[NARG_POS::SECOND]);
319         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_ACCESS_NAME, cbExec, cbComplete).val_;
320     }
321 }
322 
Unlink(napi_env env,napi_callback_info info)323 napi_value PropNExporter::Unlink(napi_env env, napi_callback_info info)
324 {
325     NFuncArg funcArg(env, info);
326     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
327         HILOGE("Number of Arguments Unmatched");
328         NError(EINVAL).ThrowErr(env);
329         return nullptr;
330     }
331 
332     auto [succ, tmp, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
333     if (!succ) {
334         HILOGE("Invalid path from JS first argument");
335         NError(EINVAL).ThrowErr(env);
336         return nullptr;
337     }
338 
339     auto cbExec = [path = string(tmp.get())]() -> NError {
340         std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> unlink_req = {
341             new uv_fs_t, CommonFunc::fs_req_cleanup };
342         if (!unlink_req) {
343             HILOGE("Failed to request heap memory.");
344             return NError(ENOMEM);
345         }
346         int ret = uv_fs_unlink(nullptr, unlink_req.get(), path.c_str(), nullptr);
347         if (ret < 0) {
348             HILOGD("Failed to unlink with path ret %{public}d", ret);
349             return NError(ret);
350         }
351         return NError(ERRNO_NOERR);
352     };
353 
354     auto cbCompl = [](napi_env env, NError err) -> NVal {
355         if (err) {
356             return { env, err.GetNapiErr(env) };
357         }
358         return { NVal::CreateUndefined(env) };
359     };
360 
361     NVal thisVar(env, funcArg.GetThisVar());
362     if (funcArg.GetArgc() == NARG_CNT::ONE) {
363         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_UNLINK_NAME, cbExec, cbCompl).val_;
364     } else {
365         NVal cb(env, funcArg[NARG_POS::SECOND]);
366         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_UNLINK_NAME, cbExec, cbCompl).val_;
367     }
368 }
369 
UnlinkSync(napi_env env,napi_callback_info info)370 napi_value PropNExporter::UnlinkSync(napi_env env, napi_callback_info info)
371 {
372     NFuncArg funcArg(env, info);
373     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
374         HILOGE("Number of arguments unmatched");
375         NError(EINVAL).ThrowErr(env);
376         return nullptr;
377     }
378 
379     auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
380     if (!succ) {
381         HILOGE("Invalid path from JS first argument");
382         NError(EINVAL).ThrowErr(env);
383         return nullptr;
384     }
385 
386     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> unlink_req = {
387         new uv_fs_t, CommonFunc::fs_req_cleanup };
388     if (!unlink_req) {
389         HILOGE("Failed to request heap memory.");
390         NError(ENOMEM).ThrowErr(env);
391         return nullptr;
392     }
393     int ret = uv_fs_unlink(nullptr, unlink_req.get(), path.get(), nullptr);
394     if (ret < 0) {
395         HILOGD("Failed to unlink with path ret %{public}d", ret);
396         NError(ret).ThrowErr(env);
397         return nullptr;
398     }
399 
400     return NVal::CreateUndefined(env).val_;
401 }
402 
MkdirCore(const string & path)403 static int MkdirCore(const string &path)
404 {
405     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> mkdir_req = {
406         new uv_fs_t, CommonFunc::fs_req_cleanup };
407     if (!mkdir_req) {
408         HILOGE("Failed to request heap memory.");
409         return ENOMEM;
410     }
411     return uv_fs_mkdir(nullptr, mkdir_req.get(), path.c_str(), DIR_DEFAULT_PERM, nullptr);
412 }
413 
MkdirExec(const string & path,bool recursion,bool hasOption)414 static NError MkdirExec(const string &path, bool recursion, bool hasOption)
415 {
416 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
417     if (hasOption) {
418         int ret = AccessCore(path, 0);
419         if (ret == ERRNO_NOERR) {
420             HILOGD("The path already exists");
421             return NError(EEXIST);
422         }
423         if (ret != -ENOENT) {
424             HILOGE("Failed to check for illegal path or request for heap memory, ret: %{public}d", ret);
425             return NError(ret);
426         }
427         if (::Mkdirs(path.c_str(), static_cast<MakeDirectionMode>(recursion)) < 0) {
428             HILOGD("Failed to create directories, error: %{public}d", errno);
429             return NError(errno);
430         }
431         ret = AccessCore(path, 0);
432         if (ret) {
433             HILOGE("Failed to verify the result of Mkdirs function, ret: %{public}d", ret);
434             return NError(ret);
435         }
436         return NError(ERRNO_NOERR);
437     }
438 #endif
439     int ret = MkdirCore(path);
440     if (ret) {
441         HILOGD("Failed to create directory");
442         return NError(ret);
443     }
444     return NError(ERRNO_NOERR);
445 }
446 
Mkdir(napi_env env,napi_callback_info info)447 napi_value PropNExporter::Mkdir(napi_env env, napi_callback_info info)
448 {
449     NFuncArg funcArg(env, info);
450     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
451         HILOGE("Number of arguments unmatched");
452         NError(EINVAL).ThrowErr(env);
453         return nullptr;
454     }
455     auto [succ, tmp, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
456     if (!succ) {
457         HILOGE("Invalid path from JS first argument");
458         NError(EINVAL).ThrowErr(env);
459         return nullptr;
460     }
461     bool recursion = false;
462     bool hasOption = false;
463 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
464     if (funcArg.GetArgc() >= NARG_CNT::TWO) {
465         NVal option(env, funcArg[NARG_POS::SECOND]);
466         if (!option.TypeIs(napi_function)) {
467             tie(hasOption, recursion) = option.ToBool(false);
468             if (!hasOption) {
469                 NError(EINVAL).ThrowErr(env);
470                 return nullptr;
471             }
472         }
473     }
474 #endif
475     auto cbExec = [path = string(tmp.get()), recursion, hasOption]() -> NError {
476         return MkdirExec(path, recursion, hasOption);
477     };
478     auto cbCompl = [](napi_env env, NError err) -> NVal {
479         if (err) {
480             return { env, err.GetNapiErr(env) };
481         }
482         return { NVal::CreateUndefined(env) };
483     };
484 
485     NVal thisVar(env, funcArg.GetThisVar());
486     if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
487         !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
488         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_MKDIR_NAME, cbExec, cbCompl).val_;
489     } else {
490         NVal cb(env, funcArg[funcArg.GetArgc() - 1]);
491         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_MKDIR_NAME, cbExec, cbCompl).val_;
492     }
493 }
494 
MkdirSync(napi_env env,napi_callback_info info)495 napi_value PropNExporter::MkdirSync(napi_env env, napi_callback_info info)
496 {
497     NFuncArg funcArg(env, info);
498     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
499         HILOGE("Number of arguments unmatched");
500         NError(EINVAL).ThrowErr(env);
501         return nullptr;
502     }
503 
504     auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
505     if (!succ) {
506         HILOGE("Invalid path from JS first argument");
507         NError(EINVAL).ThrowErr(env);
508         return nullptr;
509     }
510     bool hasOption = false;
511     bool recursion = false;
512 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
513     if (funcArg.GetArgc() == NARG_CNT::TWO) {
514         tie(hasOption, recursion) = NVal(env, funcArg[NARG_POS::SECOND]).ToBool(false);
515         if (!hasOption) {
516             HILOGE("Invalid recursion mode");
517             NError(EINVAL).ThrowErr(env);
518             return nullptr;
519         }
520     }
521 #endif
522     auto err = MkdirExec(path.get(), recursion, hasOption);
523     if (err) {
524         err.ThrowErr(env);
525         return nullptr;
526     }
527     return NVal::CreateUndefined(env).val_;
528 }
529 
ReadSync(napi_env env,napi_callback_info info)530 napi_value PropNExporter::ReadSync(napi_env env, napi_callback_info info)
531 {
532 #ifdef FILE_API_TRACE
533     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
534 #endif
535     NFuncArg funcArg(env, info);
536 
537     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) {
538         HILOGE("Number of arguments unmatched");
539         NError(EINVAL).ThrowErr(env);
540         return nullptr;
541     }
542 
543     bool succ = false;
544     int fd = 0;
545     tie(succ, fd) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
546     if (!succ || fd < 0) {
547         HILOGE("Invalid fd from JS first argument");
548         NError(EINVAL).ThrowErr(env);
549         return nullptr;
550     }
551 
552     void *buf = nullptr;
553     size_t len = 0;
554     int64_t offset = -1;
555     tie(succ, buf, len, offset) =
556         CommonFunc::GetReadArg(env, funcArg[NARG_POS::SECOND], funcArg[NARG_POS::THIRD]);
557     if (!succ) {
558         HILOGE("Failed to resolve buf and options");
559         NError(EINVAL).ThrowErr(env);
560         return nullptr;
561     }
562 
563     uv_buf_t buffer = uv_buf_init(static_cast<char *>(buf), static_cast<unsigned int>(len));
564     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> read_req = {
565         new uv_fs_t, CommonFunc::fs_req_cleanup };
566     if (!read_req) {
567         HILOGE("Failed to request heap memory.");
568         NError(ENOMEM).ThrowErr(env);
569         return nullptr;
570     }
571     int ret = uv_fs_read(nullptr, read_req.get(), fd, &buffer, 1, offset, nullptr);
572     if (ret < 0) {
573         HILOGE("Failed to read file for %{public}d", ret);
574         NError(ret).ThrowErr(env);
575         return nullptr;
576     }
577 
578     return NVal::CreateInt64(env, static_cast<int64_t>(ret)).val_;
579 }
580 
ReadExec(shared_ptr<AsyncIOReadArg> arg,char * buf,size_t len,int32_t fd,int64_t offset)581 static NError ReadExec(shared_ptr<AsyncIOReadArg> arg, char *buf, size_t len, int32_t fd, int64_t offset)
582 {
583     uv_buf_t buffer = uv_buf_init(buf, len);
584     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> read_req = {
585         new uv_fs_t, CommonFunc::fs_req_cleanup };
586     if (!read_req) {
587         HILOGE("Failed to request heap memory.");
588         return NError(ENOMEM);
589     }
590     int ret = uv_fs_read(nullptr, read_req.get(), fd, &buffer, 1, offset, nullptr);
591     if (ret < 0) {
592         HILOGE("Failed to read file for %{public}d", ret);
593         return NError(ret);
594     }
595     arg->lenRead = ret;
596     return NError(ERRNO_NOERR);
597 }
598 
Read(napi_env env,napi_callback_info info)599 napi_value PropNExporter::Read(napi_env env, napi_callback_info info)
600 {
601 #ifdef FILE_API_TRACE
602     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
603 #endif
604     NFuncArg funcArg(env, info);
605     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) {
606         HILOGE("Number of arguments unmatched");
607         NError(EINVAL).ThrowErr(env);
608         return nullptr;
609     }
610 
611     bool succ = false;
612     void *buf = nullptr;
613     size_t len = 0;
614     int32_t fd = 0;
615     int64_t offset = -1;
616     tie(succ, fd) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
617     if (!succ || fd < 0) {
618         HILOGE("Invalid fd from JS first argument");
619         NError(EINVAL).ThrowErr(env);
620         return nullptr;
621     }
622 
623     tie(succ, buf, len, offset) =
624         CommonFunc::GetReadArg(env, funcArg[NARG_POS::SECOND], funcArg[NARG_POS::THIRD]);
625     if (!succ) {
626         HILOGE("Failed to resolve buf and options");
627         NError(EINVAL).ThrowErr(env);
628         return nullptr;
629     }
630 
631     auto arg = CreateSharedPtr<AsyncIOReadArg>(NVal(env, funcArg[NARG_POS::SECOND]));
632     if (arg == nullptr) {
633         HILOGE("Failed to request heap memory.");
634         NError(ENOMEM).ThrowErr(env);
635         return nullptr;
636     }
637     auto cbExec = [arg, buf, len, fd, offset]() -> NError {
638         return ReadExec(arg, static_cast<char *>(buf), len, fd, offset);
639     };
640 
641     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
642         if (err) {
643             return { env, err.GetNapiErr(env) };
644         }
645         return { NVal::CreateInt64(env, static_cast<int64_t>(arg->lenRead)) };
646     };
647 
648     NVal thisVar(env, funcArg.GetThisVar());
649     if (funcArg.GetArgc() == NARG_CNT::TWO || (funcArg.GetArgc() == NARG_CNT::THREE &&
650         !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function))) {
651         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_READ_NAME, cbExec, cbCompl).val_;
652     } else {
653         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::THREE) ? NARG_POS::THIRD : NARG_POS::FOURTH);
654         NVal cb(env, funcArg[cbIdx]);
655         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_READ_NAME, cbExec, cbCompl).val_;
656     }
657 }
658 
WriteExec(shared_ptr<AsyncIOWrtieArg> arg,char * buf,size_t len,int32_t fd,int64_t offset)659 static NError WriteExec(shared_ptr<AsyncIOWrtieArg> arg, char *buf, size_t len, int32_t fd, int64_t offset)
660 {
661     uv_buf_t buffer = uv_buf_init(buf, static_cast<unsigned int>(len));
662     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> write_req = {
663         new uv_fs_t, CommonFunc::fs_req_cleanup };
664     if (!write_req) {
665         HILOGE("Failed to request heap memory.");
666         return NError(ENOMEM);
667     }
668     int ret = uv_fs_write(nullptr, write_req.get(), fd, &buffer, 1, offset, nullptr);
669     if (ret < 0) {
670         HILOGE("Failed to write file for %{public}d", ret);
671         return NError(ret);
672     }
673     arg->actLen = ret;
674     return NError(ERRNO_NOERR);
675 }
676 
Write(napi_env env,napi_callback_info info)677 napi_value PropNExporter::Write(napi_env env, napi_callback_info info)
678 {
679     NFuncArg funcArg(env, info);
680     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) {
681         HILOGE("Number of arguments unmatched");
682         NError(EINVAL).ThrowErr(env);
683         return nullptr;
684     }
685 
686     auto[succ, fd] = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
687     if (!succ || fd < 0) {
688         HILOGE("Invalid fd from JS first argument");
689         NError(EINVAL).ThrowErr(env);
690         return nullptr;
691     }
692 
693     unique_ptr<char[]> bufGuard = nullptr;
694     void *buf = nullptr;
695     size_t len = 0;
696     int64_t offset = -1;
697     tie(succ, bufGuard, buf, len, offset) =
698         CommonFunc::GetWriteArg(env, funcArg[NARG_POS::SECOND], funcArg[NARG_POS::THIRD]);
699     if (!succ) {
700         HILOGE("Failed to resolve buf and options");
701         NError(EINVAL).ThrowErr(env);
702         return nullptr;
703     }
704 
705     auto arg = CreateSharedPtr<AsyncIOWrtieArg>(move(bufGuard));
706     if (arg == nullptr) {
707         HILOGE("Failed to request heap memory.");
708         NError(ENOMEM).ThrowErr(env);
709         return nullptr;
710     }
711     auto cbExec = [arg, buf, len, fd = fd, offset]() -> NError {
712         return WriteExec(arg, static_cast<char *>(buf), len, fd, offset);
713     };
714 
715     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
716         if (err) {
717             return { env, err.GetNapiErr(env) };
718         } else {
719             return { NVal::CreateInt64(env, static_cast<int64_t>(arg->actLen)) };
720         }
721     };
722 
723     NVal thisVar(env, funcArg.GetThisVar());
724     if (funcArg.GetArgc() == NARG_CNT::TWO || (funcArg.GetArgc() == NARG_CNT::THREE &&
725         !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function))) {
726         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_WRITE_NAME, cbExec, cbCompl).val_;
727     } else {
728         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::THREE) ? NARG_POS::THIRD : NARG_POS::FOURTH);
729         NVal cb(env, funcArg[cbIdx]);
730         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_WRITE_NAME, cbExec, cbCompl).val_;
731     }
732 }
733 
WriteSync(napi_env env,napi_callback_info info)734 napi_value PropNExporter::WriteSync(napi_env env, napi_callback_info info)
735 {
736     NFuncArg funcArg(env, info);
737     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) {
738         HILOGE("Number of arguments unmatched");
739         NError(EINVAL).ThrowErr(env);
740         return nullptr;
741     }
742 
743     bool succ = false;
744     int32_t fd = 0;
745     tie(succ, fd) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
746     if (!succ || fd < 0) {
747         HILOGE("Invalid fd from JS first argument");
748         NError(EINVAL).ThrowErr(env);
749         return nullptr;
750     }
751 
752     void *buf = nullptr;
753     size_t len = 0;
754     int64_t offset = -1;
755     unique_ptr<char[]> bufGuard = nullptr;
756     tie(succ, bufGuard, buf, len, offset) =
757         CommonFunc::GetWriteArg(env, funcArg[NARG_POS::SECOND], funcArg[NARG_POS::THIRD]);
758     if (!succ) {
759         HILOGE("Failed to resolve buf and options");
760         return nullptr;
761     }
762 
763     uv_buf_t buffer = uv_buf_init(static_cast<char *>(buf), static_cast<unsigned int>(len));
764     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> write_req = {
765         new uv_fs_t, CommonFunc::fs_req_cleanup };
766     if (!write_req) {
767         HILOGE("Failed to request heap memory.");
768         NError(ENOMEM).ThrowErr(env);
769         return nullptr;
770     }
771     int ret = uv_fs_write(nullptr, write_req.get(), fd, &buffer, 1, offset, nullptr);
772     if (ret < 0) {
773         HILOGE("Failed to write file for %{public}d", ret);
774         NError(ret).ThrowErr(env);
775         return nullptr;
776     }
777 
778     return NVal::CreateInt64(env, static_cast<int64_t>(ret)).val_;
779 }
ExportSync()780 bool PropNExporter::ExportSync()
781 {
782     return exports_.AddProp({
783         NVal::DeclareNapiFunction("accessSync", AccessSync),
784         NVal::DeclareNapiFunction("closeSync", Close::Sync),
785         NVal::DeclareNapiFunction("fdatasyncSync", Fdatasync::Sync),
786         NVal::DeclareNapiFunction("fsyncSync", Fsync::Sync),
787         NVal::DeclareNapiFunction("lstatSync", Lstat::Sync),
788         NVal::DeclareNapiFunction("mkdirSync", MkdirSync),
789         NVal::DeclareNapiFunction("mkdtempSync", Mkdtemp::Sync),
790         NVal::DeclareNapiFunction("openSync", Open::Sync),
791         NVal::DeclareNapiFunction("readSync", ReadSync),
792         NVal::DeclareNapiFunction("renameSync", Rename::Sync),
793         NVal::DeclareNapiFunction("rmdirSync", Rmdirent::Sync),
794         NVal::DeclareNapiFunction("statSync", Stat::Sync),
795         NVal::DeclareNapiFunction("truncateSync", Truncate::Sync),
796         NVal::DeclareNapiFunction("unlinkSync", UnlinkSync),
797         NVal::DeclareNapiFunction("utimes", Utimes::Sync),
798         NVal::DeclareNapiFunction("writeSync", WriteSync),
799 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
800         NVal::DeclareNapiFunction("copyDirSync", CopyDir::Sync),
801         NVal::DeclareNapiFunction("copyFileSync", CopyFile::Sync),
802         NVal::DeclareNapiFunction("createRandomAccessFileSync", CreateRandomAccessFile::Sync),
803         NVal::DeclareNapiFunction("createStreamSync", CreateStream::Sync),
804         NVal::DeclareNapiFunction("createReadStream", CreateStreamRw::Read),
805         NVal::DeclareNapiFunction("createWriteStream", CreateStreamRw::Write),
806         NVal::DeclareNapiFunction("dup", Dup::Sync),
807         NVal::DeclareNapiFunction("fdopenStreamSync", FdopenStream::Sync),
808         NVal::DeclareNapiFunction("listFileSync", ListFile::Sync),
809         NVal::DeclareNapiFunction("lseek", Lseek::Sync),
810         NVal::DeclareNapiFunction("moveDirSync", MoveDir::Sync),
811         NVal::DeclareNapiFunction("moveFileSync", Move::Sync),
812         NVal::DeclareNapiFunction("readLinesSync", ReadLines::Sync),
813         NVal::DeclareNapiFunction("readTextSync", ReadText::Sync),
814         NVal::DeclareNapiFunction("symlinkSync", Symlink::Sync),
815         NVal::DeclareNapiFunction("setxattrSync", Xattr::SetSync),
816         NVal::DeclareNapiFunction("getxattrSync", Xattr::GetSync),
817         NVal::DeclareNapiFunction("setxattr", Xattr::SetAsync),
818         NVal::DeclareNapiFunction("getxattr", Xattr::GetAsync),
819 #endif
820     });
821 }
822 
ExportAsync()823 bool PropNExporter::ExportAsync()
824 {
825     return exports_.AddProp({
826         NVal::DeclareNapiFunction("access", Access),
827         NVal::DeclareNapiFunction("close", Close::Async),
828         NVal::DeclareNapiFunction("fdatasync", Fdatasync::Async),
829         NVal::DeclareNapiFunction("fsync", Fsync::Async),
830         NVal::DeclareNapiFunction("lstat", Lstat::Async),
831         NVal::DeclareNapiFunction("mkdir", Mkdir),
832         NVal::DeclareNapiFunction("mkdtemp", Mkdtemp::Async),
833         NVal::DeclareNapiFunction("open", Open::Async),
834         NVal::DeclareNapiFunction("rename", Rename::Async),
835         NVal::DeclareNapiFunction("rmdir", Rmdirent::Async),
836         NVal::DeclareNapiFunction("stat", Stat::Async),
837         NVal::DeclareNapiFunction("truncate", Truncate::Async),
838         NVal::DeclareNapiFunction("read", Read),
839         NVal::DeclareNapiFunction("write", Write),
840         NVal::DeclareNapiFunction("unlink", Unlink),
841 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
842         NVal::DeclareNapiFunction("copyDir", CopyDir::Async),
843         NVal::DeclareNapiFunction("copyFile", CopyFile::Async),
844         NVal::DeclareNapiFunction("copy", Copy::Async),
845         NVal::DeclareNapiFunction("createRandomAccessFile", CreateRandomAccessFile::Async),
846         NVal::DeclareNapiFunction("createStream", CreateStream::Async),
847         NVal::DeclareNapiFunction("fdopenStream", FdopenStream::Async),
848         NVal::DeclareNapiFunction("listFile", ListFile::Async),
849         NVal::DeclareNapiFunction("moveDir", MoveDir::Async),
850         NVal::DeclareNapiFunction("moveFile", Move::Async),
851         NVal::DeclareNapiFunction("readLines", ReadLines::Async),
852         NVal::DeclareNapiFunction("readText", ReadText::Async),
853         NVal::DeclareNapiFunction("symlink", Symlink::Async),
854         NVal::DeclareNapiFunction("createWatcher", Watcher::CreateWatcher),
855         NVal::DeclareNapiFunction("connectDfs", ConnectDfs::Async),
856         NVal::DeclareNapiFunction("disconnectDfs", DisconnectDfs::Async),
857 #endif
858     });
859 }
860 
Export()861 bool PropNExporter::Export()
862 {
863     return ExportSync() && ExportAsync();
864 }
865 
866 #ifdef WIN_PLATFORM
GetNExporterName()867 string PropNExporter::GetNExporterName()
868 #else
869 string PropNExporter::GetClassName()
870 #endif
871 {
872     return PropNExporter::className_;
873 }
874 
PropNExporter(napi_env env,napi_value exports)875 PropNExporter::PropNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
876 
~PropNExporter()877 PropNExporter::~PropNExporter() {}
878 } // namespace ModuleFileIO
879 } // namespace FileManagement
880 } // namespace OHOS