1 /*
2 * Copyright (c) 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 #include "read_text.h"
16
17 #include <fcntl.h>
18 #include <securec.h>
19 #include <sys/stat.h>
20 #include <tuple>
21 #include <unistd.h>
22
23 #include "common_func.h"
24 #include "filemgmt_libhilog.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 using namespace std;
30 using namespace OHOS::FileManagement::LibN;
31
GetReadTextArg(napi_env env,napi_value argOption)32 static tuple<bool, ssize_t, bool, ssize_t, unique_ptr<char[]>, bool> GetReadTextArg(napi_env env, napi_value argOption)
33 {
34 NVal op(env, argOption);
35 ssize_t offset = 0;
36 ssize_t len = 0;
37 bool succ = false;
38 bool hasOp = false;
39 bool hasLen = false;
40 unique_ptr<char[]> encoding;
41
42 if (op.HasProp("offset")) {
43 tie(succ, offset) = op.GetProp("offset").ToInt32();
44 if (!succ || offset < 0) {
45 HILOGE("Illegal option.offset parameter");
46 return { false, offset, hasLen, len, nullptr, hasOp };
47 }
48 hasOp = true;
49 }
50
51 if (op.HasProp("length")) {
52 tie(succ, len) = op.GetProp("length").ToInt32();
53 if (!succ || len < 0) {
54 HILOGE("Illegal option.length parameter");
55 return { false, offset, hasLen, len, nullptr, hasOp };
56 }
57 hasOp = true;
58 hasLen = true;
59 }
60
61 if (op.HasProp("encoding")) {
62 tie(succ, encoding, ignore) = op.GetProp("encoding").ToUTF8String();
63 if (!succ) {
64 HILOGE("Illegal option.encoding parameter");
65 return { false, offset, hasLen, len, nullptr, hasOp };
66 }
67 hasOp = true;
68 }
69
70 if (!op.TypeIs(napi_function)) {
71 hasOp = true;
72 }
73
74 return { true, offset, hasLen, len, move(encoding), hasOp };
75 }
76
ReadTextAsync(const std::string & path,std::shared_ptr<AsyncReadTextArg> arg,ssize_t offset,bool hasLen,ssize_t len)77 static NError ReadTextAsync(const std::string &path, std::shared_ptr<AsyncReadTextArg> arg, ssize_t offset,
78 bool hasLen, ssize_t len)
79 {
80 OHOS::DistributedFS::FDGuard sfd;
81 struct stat statbf;
82 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
83 new uv_fs_t, CommonFunc::fs_req_cleanup };
84 if (!open_req) {
85 HILOGE("Failed to request heap memory.");
86 return NError(ENOMEM);
87 }
88 int ret = uv_fs_open(nullptr, open_req.get(), path.c_str(), O_RDONLY,
89 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
90 if (ret < 0) {
91 HILOGE("Failed to open file, ret: %{public}d", ret);
92 return NError(errno);
93 }
94
95 sfd.SetFD(ret);
96 if (sfd.GetFD() < 0) {
97 HILOGE("Failed to open file by path");
98 return NError(errno);
99 }
100 if (fstat(sfd.GetFD(), &statbf) < 0) {
101 HILOGE("Failed to get stat of file by fd: %{public}d", sfd.GetFD());
102 return NError(errno);
103 }
104
105 if (offset > statbf.st_size) {
106 HILOGE("Invalid offset");
107 return NError(EINVAL);
108 }
109
110 len = (!hasLen || len > statbf.st_size) ? statbf.st_size : len;
111 string buffer(len, '\0');
112 uv_buf_t readbuf = uv_buf_init(const_cast<char *>(buffer.c_str()), len);
113 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> read_req = {
114 new uv_fs_t, CommonFunc::fs_req_cleanup };
115 if (!read_req) {
116 HILOGE("Failed to request heap memory.");
117 return NError(ENOMEM);
118 }
119 arg->len = uv_fs_read(nullptr, read_req.get(), sfd.GetFD(), &readbuf, 1, offset, nullptr);
120 if (arg->len < 0) {
121 HILOGE("Failed to read file by fd: %{public}d", sfd.GetFD());
122 return NError(errno);
123 }
124 arg->buffer = buffer;
125 return NError(ERRNO_NOERR);
126 }
127
Sync(napi_env env,napi_callback_info info)128 napi_value ReadText::Sync(napi_env env, napi_callback_info info)
129 {
130 NFuncArg funcArg(env, info);
131 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
132 HILOGE("Number of arguments unmatched");
133 NError(EINVAL).ThrowErr(env);
134 return nullptr;
135 }
136
137 auto [resGetFirstArg, path, unused] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
138 if (!resGetFirstArg) {
139 HILOGE("Invalid path");
140 NError(EINVAL).ThrowErr(env);
141 return nullptr;
142 }
143
144 auto [resGetReadTextArg, offset, hasLen, len, encoding, useless] = GetReadTextArg(env, funcArg[NARG_POS::SECOND]);
145 if (!resGetReadTextArg) {
146 NError(EINVAL).ThrowErr(env);
147 return nullptr;
148 }
149
150 OHOS::DistributedFS::FDGuard sfd;
151 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
152 new uv_fs_t, CommonFunc::fs_req_cleanup };
153 if (!open_req) {
154 HILOGE("Failed to request heap memory.");
155 NError(ENOMEM).ThrowErr(env);
156 return nullptr;
157 }
158 int ret = uv_fs_open(nullptr, open_req.get(), path.get(), O_RDONLY,
159 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
160 if (ret < 0) {
161 HILOGE("Failed to open file by ret: %{public}d", ret);
162 NError(errno).ThrowErr(env);
163 return nullptr;
164 }
165 sfd.SetFD(ret);
166 struct stat statbf;
167 if ((!sfd) || (fstat(sfd.GetFD(), &statbf) < 0)) {
168 HILOGE("Failed to get stat of file by fd: %{public}d", sfd.GetFD());
169 NError(errno).ThrowErr(env);
170 return nullptr;
171 }
172
173 if (offset > statbf.st_size) {
174 HILOGE("Invalid offset: %{public}zd", offset);
175 NError(EINVAL).ThrowErr(env);
176 return nullptr;
177 }
178
179 len = (!hasLen || len > statbf.st_size) ? statbf.st_size : len;
180 string buffer(len, '\0');
181 uv_buf_t readbuf = uv_buf_init(const_cast<char *>(buffer.c_str()), len);
182 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> read_req = {
183 new uv_fs_t, CommonFunc::fs_req_cleanup };
184 if (!read_req) {
185 HILOGE("Failed to request heap memory.");
186 NError(ENOMEM).ThrowErr(env);
187 return nullptr;
188 }
189 ret = uv_fs_read(nullptr, read_req.get(), sfd.GetFD(), &readbuf, 1, offset, nullptr);
190 if (ret < 0) {
191 HILOGE("Failed to read file by fd: %{public}d", sfd.GetFD());
192 NError(errno).ThrowErr(env);
193 return nullptr;
194 }
195
196 return NVal::CreateUTF8String(env, readbuf.base, ret).val_;
197 }
198
Async(napi_env env,napi_callback_info info)199 napi_value ReadText::Async(napi_env env, napi_callback_info info)
200 {
201 NFuncArg funcArg(env, info);
202 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
203 HILOGE("Number of arguments unmatched");
204 NError(EINVAL).ThrowErr(env);
205 return nullptr;
206 }
207
208 auto [resGetFirstArg, path, unused] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
209 if (!resGetFirstArg) {
210 HILOGE("Invalid path");
211 NError(EINVAL).ThrowErr(env);
212 return nullptr;
213 }
214
215 auto [resGetSecondArg, offset, hasLen, len, encoding, hasOp] = GetReadTextArg(env, funcArg[NARG_POS::SECOND]);
216 if (!resGetSecondArg) {
217 NError(EINVAL).ThrowErr(env);
218 return nullptr;
219 }
220
221 auto arg = make_shared<AsyncReadTextArg>(NVal(env, funcArg.GetThisVar()));
222 auto cbExec = [path = string(path.get()), arg, offset = offset, hasLen = hasLen, len = len]() -> NError {
223 return ReadTextAsync(path, arg, offset, hasLen, len);
224 };
225
226 auto cbComplete = [arg](napi_env env, NError err) -> NVal {
227 if (err) {
228 return { env, err.GetNapiErr(env) };
229 } else {
230 return NVal::CreateUTF8String(env, arg->buffer.c_str(), arg->len);
231 }
232 };
233
234 size_t argc = funcArg.GetArgc();
235 NVal thisVar(env, funcArg.GetThisVar());
236 if (argc == NARG_CNT::ONE || (argc == NARG_CNT::TWO && hasOp)) {
237 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_READTEXT_NAME, cbExec, cbComplete).val_;
238 } else {
239 int cbIdx = !hasOp ? NARG_POS::SECOND : NARG_POS::THIRD;
240 NVal cb(env, funcArg[cbIdx]);
241 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_READTEXT_NAME, cbExec, cbComplete).val_;
242 }
243 }
244 } // namespace ModuleFileIO
245 } // namespace FileManagement
246 } // namespace OHOS