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