1 /*
2 * Copyright (c) 2022-2023 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 "truncate.h"
17
18 #include <cstring>
19 #include <tuple>
20 #include <unistd.h>
21
22 #include "common_func.h"
23 #include "file_utils.h"
24 #include "filemgmt_libhilog.h"
25
26 namespace OHOS::FileManagement::ModuleFileIO {
27 using namespace std;
28 using namespace OHOS::FileManagement::LibN;
29
ParseJsFile(napi_env env,napi_value pathOrFdFromJsArg)30 static tuple<bool, FileInfo> ParseJsFile(napi_env env, napi_value pathOrFdFromJsArg)
31 {
32 auto [isPath, path, ignore] = NVal(env, pathOrFdFromJsArg).ToUTF8StringPath();
33 if (isPath) {
34 return { true, FileInfo { true, move(path), {} } };
35 }
36 auto [isFd, fd] = NVal(env, pathOrFdFromJsArg).ToInt32();
37 if (!isFd || fd < 0) {
38 HILOGE("Invalid fd");
39 NError(EINVAL).ThrowErr(env);
40 return { false, FileInfo { false, {}, {} } };
41 }
42 auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(fd, false);
43 if (fdg == nullptr) {
44 HILOGE("Failed to request heap memory.");
45 NError(ENOMEM).ThrowErr(env);
46 return { false, FileInfo { false, {}, {} } };
47 }
48 return { true, FileInfo { false, {}, move(fdg) } };
49 };
50
TruncateCore(napi_env env,FileInfo & fileInfo,int64_t truncateLen)51 static NError TruncateCore(napi_env env, FileInfo &fileInfo, int64_t truncateLen)
52 {
53 if (fileInfo.isPath) {
54 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
55 new uv_fs_t, CommonFunc::fs_req_cleanup };
56 if (!open_req) {
57 HILOGE("Failed to request heap memory.");
58 return NError(ENOMEM);
59 }
60 int ret = uv_fs_open(nullptr, open_req.get(), fileInfo.path.get(), O_RDWR,
61 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
62 if (ret < 0) {
63 return NError(ret);
64 }
65 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> ftruncate_req = {
66 new uv_fs_t, CommonFunc::fs_req_cleanup };
67 if (!ftruncate_req) {
68 HILOGE("Failed to request heap memory.");
69 return NError(ENOMEM);
70 }
71 ret = uv_fs_ftruncate(nullptr, ftruncate_req.get(), ret, truncateLen, nullptr);
72 if (ret < 0) {
73 HILOGE("Failed to truncate file by path");
74 return NError(ret);
75 }
76 } else {
77 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> ftruncate_req = {
78 new uv_fs_t, CommonFunc::fs_req_cleanup };
79 if (!ftruncate_req) {
80 HILOGE("Failed to request heap memory.");
81 return NError(ENOMEM);
82 }
83 int ret = uv_fs_ftruncate(nullptr, ftruncate_req.get(), fileInfo.fdg->GetFD(), truncateLen, nullptr);
84 if (ret < 0) {
85 HILOGE("Failed to truncate file by fd for libuv error %{public}d", ret);
86 return NError(ret);
87 }
88 }
89 return NError(ERRNO_NOERR);
90 }
91
Sync(napi_env env,napi_callback_info info)92 napi_value Truncate::Sync(napi_env env, napi_callback_info info)
93 {
94 NFuncArg funcArg(env, info);
95 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
96 HILOGE("Number of arguments unmatched");
97 NError(EINVAL).ThrowErr(env);
98 return nullptr;
99 }
100 auto [succ, fileInfo] = ParseJsFile(env, funcArg[NARG_POS::FIRST]);
101 if (!succ) {
102 NError(EINVAL).ThrowErr(env);
103 return nullptr;
104 }
105 int64_t truncateLen = 0;
106 if (funcArg.GetArgc() == NARG_CNT::TWO) {
107 tie(succ, truncateLen) = NVal(env, funcArg[NARG_POS::SECOND]).ToInt64(truncateLen);
108 if (!succ || truncateLen < 0) {
109 HILOGE("Invalid truncate length");
110 NError(EINVAL).ThrowErr(env);
111 return nullptr;
112 }
113 }
114 auto err = TruncateCore(env, fileInfo, truncateLen);
115 if (err) {
116 err.ThrowErr(env);
117 return nullptr;
118 }
119
120 return NVal::CreateUndefined(env).val_;
121 }
122
Async(napi_env env,napi_callback_info info)123 napi_value Truncate::Async(napi_env env, napi_callback_info info)
124 {
125 NFuncArg funcArg(env, info);
126 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
127 HILOGE("Number of arguments unmatched");
128 NError(EINVAL).ThrowErr(env);
129 return nullptr;
130 }
131 auto [succ, fileInfo] = ParseJsFile(env, funcArg[NARG_POS::FIRST]);
132 if (!succ) {
133 return nullptr;
134 }
135 int64_t truncateLen = 0;
136 if (funcArg.GetArgc() >= NARG_CNT::TWO) {
137 tie(succ, truncateLen) = NVal(env, funcArg[NARG_POS::SECOND]).ToInt64(truncateLen);
138 if (!succ || truncateLen < 0) {
139 HILOGE("Invalid truncate length");
140 NError(EINVAL).ThrowErr(env);
141 return nullptr;
142 }
143 }
144 auto cbExec = [fileInfo = make_shared<FileInfo>(move(fileInfo)), truncateLen, env = env]() -> NError {
145 return TruncateCore(env, *fileInfo, truncateLen);
146 };
147 auto cbCompl = [](napi_env env, NError err) -> NVal {
148 if (err) {
149 return { env, err.GetNapiErr(env) };
150 } else {
151 return NVal::CreateUndefined(env);
152 }
153 };
154 NVal thisVar(env, funcArg.GetThisVar());
155 if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
156 !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
157 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_TRUNCATE_NAME, cbExec, cbCompl).val_;
158 } else {
159 NVal cb(env, funcArg[((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD)]);
160 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_TRUNCATE_NAME, cbExec, cbCompl).val_;
161 }
162 }
163 } // namespace OHOS::FileManagement::ModuleFileIO