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