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