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(path, 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");
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         }
302         return (ret < 0 && (string_view(uv_err_name(ret)) != "ENOENT")) ? NError(ret) : NError(ERRNO_NOERR);
303     };
304 
305     auto cbComplete = [result](napi_env env, NError err) -> NVal {
306         if (err) {
307             return { env, err.GetNapiErr(env) };
308         }
309         return NVal::CreateBool(env, result->isAccess);
310     };
311 
312     NVal thisVar(env, funcArg.GetThisVar());
313     if (funcArg.GetArgc() == NARG_CNT::ONE || NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_number)) {
314         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_ACCESS_NAME, cbExec, cbComplete).val_;
315     } else {
316         NVal cb(env, funcArg[NARG_POS::SECOND]);
317         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_ACCESS_NAME, cbExec, cbComplete).val_;
318     }
319 }
320 
Unlink(napi_env env,napi_callback_info info)321 napi_value PropNExporter::Unlink(napi_env env, napi_callback_info info)
322 {
323     NFuncArg funcArg(env, info);
324     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
325         HILOGE("Number of Arguments Unmatched");
326         NError(EINVAL).ThrowErr(env);
327         return nullptr;
328     }
329 
330     auto [succ, tmp, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
331     if (!succ) {
332         HILOGE("Invalid path from JS first argument");
333         NError(EINVAL).ThrowErr(env);
334         return nullptr;
335     }
336 
337     auto cbExec = [path = string(tmp.get())]() -> NError {
338         std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> unlink_req = {
339             new uv_fs_t, CommonFunc::fs_req_cleanup };
340         if (!unlink_req) {
341             HILOGE("Failed to request heap memory.");
342             return NError(ENOMEM);
343         }
344         int ret = uv_fs_unlink(nullptr, unlink_req.get(), path.c_str(), nullptr);
345         if (ret < 0) {
346             HILOGD("Failed to unlink with path");
347             return NError(ret);
348         }
349         return NError(ERRNO_NOERR);
350     };
351 
352     auto cbCompl = [](napi_env env, NError err) -> NVal {
353         if (err) {
354             return { env, err.GetNapiErr(env) };
355         }
356         return { NVal::CreateUndefined(env) };
357     };
358 
359     NVal thisVar(env, funcArg.GetThisVar());
360     if (funcArg.GetArgc() == NARG_CNT::ONE) {
361         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_UNLINK_NAME, cbExec, cbCompl).val_;
362     } else {
363         NVal cb(env, funcArg[NARG_POS::SECOND]);
364         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_UNLINK_NAME, cbExec, cbCompl).val_;
365     }
366 }
367 
UnlinkSync(napi_env env,napi_callback_info info)368 napi_value PropNExporter::UnlinkSync(napi_env env, napi_callback_info info)
369 {
370     NFuncArg funcArg(env, info);
371     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
372         HILOGE("Number of arguments unmatched");
373         NError(EINVAL).ThrowErr(env);
374         return nullptr;
375     }
376 
377     auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
378     if (!succ) {
379         HILOGE("Invalid path from JS first argument");
380         NError(EINVAL).ThrowErr(env);
381         return nullptr;
382     }
383 
384     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> unlink_req = {
385         new uv_fs_t, CommonFunc::fs_req_cleanup };
386     if (!unlink_req) {
387         HILOGE("Failed to request heap memory.");
388         NError(ENOMEM).ThrowErr(env);
389         return nullptr;
390     }
391     int ret = uv_fs_unlink(nullptr, unlink_req.get(), path.get(), nullptr);
392     if (ret < 0) {
393         HILOGD("Failed to unlink with path");
394         NError(ret).ThrowErr(env);
395         return nullptr;
396     }
397 
398     return NVal::CreateUndefined(env).val_;
399 }
400 
MkdirCore(const string & path)401 static int MkdirCore(const string &path)
402 {
403     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> mkdir_req = {
404         new uv_fs_t, CommonFunc::fs_req_cleanup };
405     if (!mkdir_req) {
406         HILOGE("Failed to request heap memory.");
407         return ENOMEM;
408     }
409     return uv_fs_mkdir(nullptr, mkdir_req.get(), path.c_str(), DIR_DEFAULT_PERM, nullptr);
410 }
411 
MkdirExec(const string & path,bool recursion,bool hasOption)412 static NError MkdirExec(const string &path, bool recursion, bool hasOption)
413 {
414 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
415     if (hasOption) {
416         int ret = AccessCore(path, 0);
417         if (ret == ERRNO_NOERR) {
418             HILOGD("The path already exists");
419             return NError(EEXIST);
420         }
421         if (ret != -ENOENT) {
422             HILOGE("Failed to check for illegal path or request for heap memory");
423             return NError(ret);
424         }
425         if (::Mkdirs(path.c_str(), static_cast<MakeDirectionMode>(recursion)) < 0) {
426             HILOGD("Failed to create directories, error: %{public}d", errno);
427             return NError(errno);
428         }
429         ret = AccessCore(path, 0);
430         if (ret) {
431             HILOGE("Failed to verify the result of Mkdirs function");
432             return NError(ret);
433         }
434         return NError(ERRNO_NOERR);
435     }
436 #endif
437     int ret = MkdirCore(path);
438     if (ret) {
439         HILOGD("Failed to create directory");
440         return NError(ret);
441     }
442     return NError(ERRNO_NOERR);
443 }
444 
Mkdir(napi_env env,napi_callback_info info)445 napi_value PropNExporter::Mkdir(napi_env env, napi_callback_info info)
446 {
447     NFuncArg funcArg(env, info);
448     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
449         HILOGE("Number of arguments unmatched");
450         NError(EINVAL).ThrowErr(env);
451         return nullptr;
452     }
453     auto [succ, tmp, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
454     if (!succ) {
455         HILOGE("Invalid path from JS first argument");
456         NError(EINVAL).ThrowErr(env);
457         return nullptr;
458     }
459     bool recursion = false;
460     bool hasOption = false;
461 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
462     if (funcArg.GetArgc() >= NARG_CNT::TWO) {
463         NVal option(env, funcArg[NARG_POS::SECOND]);
464         if (!option.TypeIs(napi_function)) {
465             tie(hasOption, recursion) = option.ToBool(false);
466             if (!hasOption) {
467                 NError(EINVAL).ThrowErr(env);
468                 return nullptr;
469             }
470         }
471     }
472 #endif
473     auto cbExec = [path = string(tmp.get()), recursion, hasOption]() -> NError {
474         return MkdirExec(path, recursion, hasOption);
475     };
476     auto cbCompl = [](napi_env env, NError err) -> NVal {
477         if (err) {
478             return { env, err.GetNapiErr(env) };
479         }
480         return { NVal::CreateUndefined(env) };
481     };
482 
483     NVal thisVar(env, funcArg.GetThisVar());
484     if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
485         !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
486         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_MKDIR_NAME, cbExec, cbCompl).val_;
487     } else {
488         NVal cb(env, funcArg[funcArg.GetArgc() - 1]);
489         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_MKDIR_NAME, cbExec, cbCompl).val_;
490     }
491 }
492 
MkdirSync(napi_env env,napi_callback_info info)493 napi_value PropNExporter::MkdirSync(napi_env env, napi_callback_info info)
494 {
495     NFuncArg funcArg(env, info);
496     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
497         HILOGE("Number of arguments unmatched");
498         NError(EINVAL).ThrowErr(env);
499         return nullptr;
500     }
501 
502     auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
503     if (!succ) {
504         HILOGE("Invalid path from JS first argument");
505         NError(EINVAL).ThrowErr(env);
506         return nullptr;
507     }
508     bool hasOption = false;
509     bool recursion = false;
510 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
511     if (funcArg.GetArgc() == NARG_CNT::TWO) {
512         tie(hasOption, recursion) = NVal(env, funcArg[NARG_POS::SECOND]).ToBool(false);
513         if (!hasOption) {
514             HILOGE("Invalid recursion mode");
515             NError(EINVAL).ThrowErr(env);
516             return nullptr;
517         }
518     }
519 #endif
520     auto err = MkdirExec(path.get(), recursion, hasOption);
521     if (err) {
522         err.ThrowErr(env);
523         return nullptr;
524     }
525     return NVal::CreateUndefined(env).val_;
526 }
527 
ReadSync(napi_env env,napi_callback_info info)528 napi_value PropNExporter::ReadSync(napi_env env, napi_callback_info info)
529 {
530 #ifdef FILE_API_TRACE
531     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
532 #endif
533     NFuncArg funcArg(env, info);
534 
535     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) {
536         HILOGE("Number of arguments unmatched");
537         NError(EINVAL).ThrowErr(env);
538         return nullptr;
539     }
540 
541     bool succ = false;
542     int fd = 0;
543     tie(succ, fd) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
544     if (!succ || fd < 0) {
545         HILOGE("Invalid fd from JS first argument");
546         NError(EINVAL).ThrowErr(env);
547         return nullptr;
548     }
549 
550     void *buf = nullptr;
551     size_t len = 0;
552     int64_t offset = -1;
553     tie(succ, buf, len, offset) =
554         CommonFunc::GetReadArg(env, funcArg[NARG_POS::SECOND], funcArg[NARG_POS::THIRD]);
555     if (!succ) {
556         HILOGE("Failed to resolve buf and options");
557         NError(EINVAL).ThrowErr(env);
558         return nullptr;
559     }
560 
561     uv_buf_t buffer = uv_buf_init(static_cast<char *>(buf), static_cast<unsigned int>(len));
562     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> read_req = {
563         new uv_fs_t, CommonFunc::fs_req_cleanup };
564     if (!read_req) {
565         HILOGE("Failed to request heap memory.");
566         NError(ENOMEM).ThrowErr(env);
567         return nullptr;
568     }
569     int ret = uv_fs_read(nullptr, read_req.get(), fd, &buffer, 1, offset, nullptr);
570     if (ret < 0) {
571         HILOGE("Failed to read file for %{public}d", ret);
572         NError(ret).ThrowErr(env);
573         return nullptr;
574     }
575 
576     return NVal::CreateInt64(env, static_cast<int64_t>(ret)).val_;
577 }
578 
ReadExec(shared_ptr<AsyncIOReadArg> arg,char * buf,size_t len,int32_t fd,int64_t offset)579 static NError ReadExec(shared_ptr<AsyncIOReadArg> arg, char *buf, size_t len, int32_t fd, int64_t offset)
580 {
581     uv_buf_t buffer = uv_buf_init(buf, len);
582     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> read_req = {
583         new uv_fs_t, CommonFunc::fs_req_cleanup };
584     if (!read_req) {
585         HILOGE("Failed to request heap memory.");
586         return NError(ENOMEM);
587     }
588     int ret = uv_fs_read(nullptr, read_req.get(), fd, &buffer, 1, offset, nullptr);
589     if (ret < 0) {
590         HILOGE("Failed to read file for %{public}d", ret);
591         return NError(ret);
592     }
593     arg->lenRead = ret;
594     return NError(ERRNO_NOERR);
595 }
596 
Read(napi_env env,napi_callback_info info)597 napi_value PropNExporter::Read(napi_env env, napi_callback_info info)
598 {
599 #ifdef FILE_API_TRACE
600     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
601 #endif
602     NFuncArg funcArg(env, info);
603     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) {
604         HILOGE("Number of arguments unmatched");
605         NError(EINVAL).ThrowErr(env);
606         return nullptr;
607     }
608 
609     bool succ = false;
610     void *buf = nullptr;
611     size_t len = 0;
612     int32_t fd = 0;
613     int64_t offset = -1;
614     tie(succ, fd) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
615     if (!succ || fd < 0) {
616         HILOGE("Invalid fd from JS first argument");
617         NError(EINVAL).ThrowErr(env);
618         return nullptr;
619     }
620 
621     tie(succ, buf, len, offset) =
622         CommonFunc::GetReadArg(env, funcArg[NARG_POS::SECOND], funcArg[NARG_POS::THIRD]);
623     if (!succ) {
624         HILOGE("Failed to resolve buf and options");
625         NError(EINVAL).ThrowErr(env);
626         return nullptr;
627     }
628 
629     auto arg = CreateSharedPtr<AsyncIOReadArg>(NVal(env, funcArg[NARG_POS::SECOND]));
630     if (arg == nullptr) {
631         HILOGE("Failed to request heap memory.");
632         NError(ENOMEM).ThrowErr(env);
633         return nullptr;
634     }
635     auto cbExec = [arg, buf, len, fd, offset]() -> NError {
636         return ReadExec(arg, static_cast<char *>(buf), len, fd, offset);
637     };
638 
639     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
640         if (err) {
641             return { env, err.GetNapiErr(env) };
642         }
643         return { NVal::CreateInt64(env, static_cast<int64_t>(arg->lenRead)) };
644     };
645 
646     NVal thisVar(env, funcArg.GetThisVar());
647     if (funcArg.GetArgc() == NARG_CNT::TWO || (funcArg.GetArgc() == NARG_CNT::THREE &&
648         !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function))) {
649         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_READ_NAME, cbExec, cbCompl).val_;
650     } else {
651         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::THREE) ? NARG_POS::THIRD : NARG_POS::FOURTH);
652         NVal cb(env, funcArg[cbIdx]);
653         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_READ_NAME, cbExec, cbCompl).val_;
654     }
655 }
656 
WriteExec(shared_ptr<AsyncIOWrtieArg> arg,char * buf,size_t len,int32_t fd,int64_t offset)657 static NError WriteExec(shared_ptr<AsyncIOWrtieArg> arg, char *buf, size_t len, int32_t fd, int64_t offset)
658 {
659     uv_buf_t buffer = uv_buf_init(buf, static_cast<unsigned int>(len));
660     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> write_req = {
661         new uv_fs_t, CommonFunc::fs_req_cleanup };
662     if (!write_req) {
663         HILOGE("Failed to request heap memory.");
664         return NError(ENOMEM);
665     }
666     int ret = uv_fs_write(nullptr, write_req.get(), fd, &buffer, 1, offset, nullptr);
667     if (ret < 0) {
668         HILOGE("Failed to write file for %{public}d", ret);
669         return NError(ret);
670     }
671     arg->actLen = ret;
672     return NError(ERRNO_NOERR);
673 }
674 
Write(napi_env env,napi_callback_info info)675 napi_value PropNExporter::Write(napi_env env, napi_callback_info info)
676 {
677     NFuncArg funcArg(env, info);
678     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) {
679         HILOGE("Number of arguments unmatched");
680         NError(EINVAL).ThrowErr(env);
681         return nullptr;
682     }
683 
684     auto[succ, fd] = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
685     if (!succ || fd < 0) {
686         HILOGE("Invalid fd from JS first argument");
687         NError(EINVAL).ThrowErr(env);
688         return nullptr;
689     }
690 
691     unique_ptr<char[]> bufGuard = nullptr;
692     void *buf = nullptr;
693     size_t len = 0;
694     int64_t offset = -1;
695     tie(succ, bufGuard, buf, len, offset) =
696         CommonFunc::GetWriteArg(env, funcArg[NARG_POS::SECOND], funcArg[NARG_POS::THIRD]);
697     if (!succ) {
698         HILOGE("Failed to resolve buf and options");
699         NError(EINVAL).ThrowErr(env);
700         return nullptr;
701     }
702 
703     auto arg = CreateSharedPtr<AsyncIOWrtieArg>(move(bufGuard));
704     if (arg == nullptr) {
705         HILOGE("Failed to request heap memory.");
706         NError(ENOMEM).ThrowErr(env);
707         return nullptr;
708     }
709     auto cbExec = [arg, buf, len, fd = fd, offset]() -> NError {
710         return WriteExec(arg, static_cast<char *>(buf), len, fd, offset);
711     };
712 
713     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
714         if (err) {
715             return { env, err.GetNapiErr(env) };
716         } else {
717             return { NVal::CreateInt64(env, static_cast<int64_t>(arg->actLen)) };
718         }
719     };
720 
721     NVal thisVar(env, funcArg.GetThisVar());
722     if (funcArg.GetArgc() == NARG_CNT::TWO || (funcArg.GetArgc() == NARG_CNT::THREE &&
723         !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function))) {
724         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_WRITE_NAME, cbExec, cbCompl).val_;
725     } else {
726         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::THREE) ? NARG_POS::THIRD : NARG_POS::FOURTH);
727         NVal cb(env, funcArg[cbIdx]);
728         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_WRITE_NAME, cbExec, cbCompl).val_;
729     }
730 }
731 
WriteSync(napi_env env,napi_callback_info info)732 napi_value PropNExporter::WriteSync(napi_env env, napi_callback_info info)
733 {
734     NFuncArg funcArg(env, info);
735     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) {
736         HILOGE("Number of arguments unmatched");
737         NError(EINVAL).ThrowErr(env);
738         return nullptr;
739     }
740 
741     bool succ = false;
742     int32_t fd = 0;
743     tie(succ, fd) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
744     if (!succ || fd < 0) {
745         HILOGE("Invalid fd from JS first argument");
746         NError(EINVAL).ThrowErr(env);
747         return nullptr;
748     }
749 
750     void *buf = nullptr;
751     size_t len = 0;
752     int64_t offset = -1;
753     unique_ptr<char[]> bufGuard = nullptr;
754     tie(succ, bufGuard, buf, len, offset) =
755         CommonFunc::GetWriteArg(env, funcArg[NARG_POS::SECOND], funcArg[NARG_POS::THIRD]);
756     if (!succ) {
757         HILOGE("Failed to resolve buf and options");
758         return nullptr;
759     }
760 
761     uv_buf_t buffer = uv_buf_init(static_cast<char *>(buf), static_cast<unsigned int>(len));
762     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> write_req = {
763         new uv_fs_t, CommonFunc::fs_req_cleanup };
764     if (!write_req) {
765         HILOGE("Failed to request heap memory.");
766         NError(ENOMEM).ThrowErr(env);
767         return nullptr;
768     }
769     int ret = uv_fs_write(nullptr, write_req.get(), fd, &buffer, 1, offset, nullptr);
770     if (ret < 0) {
771         HILOGE("Failed to write file for %{public}d", ret);
772         NError(ret).ThrowErr(env);
773         return nullptr;
774     }
775 
776     return NVal::CreateInt64(env, static_cast<int64_t>(ret)).val_;
777 }
ExportSync()778 bool PropNExporter::ExportSync()
779 {
780     return exports_.AddProp({
781         NVal::DeclareNapiFunction("accessSync", AccessSync),
782         NVal::DeclareNapiFunction("closeSync", Close::Sync),
783         NVal::DeclareNapiFunction("fdatasyncSync", Fdatasync::Sync),
784         NVal::DeclareNapiFunction("fsyncSync", Fsync::Sync),
785         NVal::DeclareNapiFunction("lstatSync", Lstat::Sync),
786         NVal::DeclareNapiFunction("mkdirSync", MkdirSync),
787         NVal::DeclareNapiFunction("mkdtempSync", Mkdtemp::Sync),
788         NVal::DeclareNapiFunction("openSync", Open::Sync),
789         NVal::DeclareNapiFunction("readSync", ReadSync),
790         NVal::DeclareNapiFunction("renameSync", Rename::Sync),
791         NVal::DeclareNapiFunction("rmdirSync", Rmdirent::Sync),
792         NVal::DeclareNapiFunction("statSync", Stat::Sync),
793         NVal::DeclareNapiFunction("truncateSync", Truncate::Sync),
794         NVal::DeclareNapiFunction("unlinkSync", UnlinkSync),
795         NVal::DeclareNapiFunction("utimes", Utimes::Sync),
796         NVal::DeclareNapiFunction("writeSync", WriteSync),
797 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
798         NVal::DeclareNapiFunction("copyDirSync", CopyDir::Sync),
799         NVal::DeclareNapiFunction("copyFileSync", CopyFile::Sync),
800         NVal::DeclareNapiFunction("createRandomAccessFileSync", CreateRandomAccessFile::Sync),
801         NVal::DeclareNapiFunction("createStreamSync", CreateStream::Sync),
802         NVal::DeclareNapiFunction("createReadStream", CreateStreamRw::Read),
803         NVal::DeclareNapiFunction("createWriteStream", CreateStreamRw::Write),
804         NVal::DeclareNapiFunction("dup", Dup::Sync),
805         NVal::DeclareNapiFunction("fdopenStreamSync", FdopenStream::Sync),
806         NVal::DeclareNapiFunction("listFileSync", ListFile::Sync),
807         NVal::DeclareNapiFunction("lseek", Lseek::Sync),
808         NVal::DeclareNapiFunction("moveDirSync", MoveDir::Sync),
809         NVal::DeclareNapiFunction("moveFileSync", Move::Sync),
810         NVal::DeclareNapiFunction("readLinesSync", ReadLines::Sync),
811         NVal::DeclareNapiFunction("readTextSync", ReadText::Sync),
812         NVal::DeclareNapiFunction("symlinkSync", Symlink::Sync),
813         NVal::DeclareNapiFunction("setxattrSync", Xattr::SetSync),
814         NVal::DeclareNapiFunction("getxattrSync", Xattr::GetSync),
815         NVal::DeclareNapiFunction("setxattr", Xattr::SetAsync),
816         NVal::DeclareNapiFunction("getxattr", Xattr::GetAsync),
817 #endif
818     });
819 }
820 
ExportAsync()821 bool PropNExporter::ExportAsync()
822 {
823     return exports_.AddProp({
824         NVal::DeclareNapiFunction("access", Access),
825         NVal::DeclareNapiFunction("close", Close::Async),
826         NVal::DeclareNapiFunction("fdatasync", Fdatasync::Async),
827         NVal::DeclareNapiFunction("fsync", Fsync::Async),
828         NVal::DeclareNapiFunction("lstat", Lstat::Async),
829         NVal::DeclareNapiFunction("mkdir", Mkdir),
830         NVal::DeclareNapiFunction("mkdtemp", Mkdtemp::Async),
831         NVal::DeclareNapiFunction("open", Open::Async),
832         NVal::DeclareNapiFunction("rename", Rename::Async),
833         NVal::DeclareNapiFunction("rmdir", Rmdirent::Async),
834         NVal::DeclareNapiFunction("stat", Stat::Async),
835         NVal::DeclareNapiFunction("truncate", Truncate::Async),
836         NVal::DeclareNapiFunction("read", Read),
837         NVal::DeclareNapiFunction("write", Write),
838         NVal::DeclareNapiFunction("unlink", Unlink),
839 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
840         NVal::DeclareNapiFunction("copyDir", CopyDir::Async),
841         NVal::DeclareNapiFunction("copyFile", CopyFile::Async),
842         NVal::DeclareNapiFunction("copy", Copy::Async),
843         NVal::DeclareNapiFunction("createRandomAccessFile", CreateRandomAccessFile::Async),
844         NVal::DeclareNapiFunction("createStream", CreateStream::Async),
845         NVal::DeclareNapiFunction("fdopenStream", FdopenStream::Async),
846         NVal::DeclareNapiFunction("listFile", ListFile::Async),
847         NVal::DeclareNapiFunction("moveDir", MoveDir::Async),
848         NVal::DeclareNapiFunction("moveFile", Move::Async),
849         NVal::DeclareNapiFunction("readLines", ReadLines::Async),
850         NVal::DeclareNapiFunction("readText", ReadText::Async),
851         NVal::DeclareNapiFunction("symlink", Symlink::Async),
852         NVal::DeclareNapiFunction("createWatcher", Watcher::CreateWatcher),
853         NVal::DeclareNapiFunction("connectDfs", ConnectDfs::Async),
854         NVal::DeclareNapiFunction("disconnectDfs", DisconnectDfs::Async),
855 #endif
856     });
857 }
858 
Export()859 bool PropNExporter::Export()
860 {
861     return ExportSync() && ExportAsync();
862 }
863 
864 #ifdef WIN_PLATFORM
GetNExporterName()865 string PropNExporter::GetNExporterName()
866 #else
867 string PropNExporter::GetClassName()
868 #endif
869 {
870     return PropNExporter::className_;
871 }
872 
PropNExporter(napi_env env,napi_value exports)873 PropNExporter::PropNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
874 
~PropNExporter()875 PropNExporter::~PropNExporter() {}
876 } // namespace ModuleFileIO
877 } // namespace FileManagement
878 } // namespace OHOS