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