1 /*
2 * Copyright (c) 2021 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 #include "../../common/file_helper/fd_guard.h"
23 #include "../../common/napi/n_async/n_async_work_callback.h"
24 #include "../../common/napi/n_async/n_async_work_promise.h"
25 #include "../../common/napi/n_func_arg.h"
26 #include "../common_func.h"
27
28 namespace OHOS {
29 namespace DistributedFS {
30 namespace ModuleFileIO {
31 using namespace std;
32
GetReadTextArg(napi_env env,napi_value argOption)33 static tuple<bool, ssize_t, bool, ssize_t, unique_ptr<char[]>, bool> GetReadTextArg(napi_env env, napi_value argOption)
34 {
35 NVal op(env, argOption);
36 ssize_t position = 0;
37 ssize_t len = 0;
38 bool succ = false;
39 bool hasOp = false;
40 bool hasLen = false;
41 unique_ptr<char[]> encoding;
42 if (op.HasProp("position")) {
43 tie(succ, position) = op.GetProp("position").ToInt32();
44 if (!succ) {
45 return { false, position, hasLen, len, nullptr, hasOp };
46 }
47 hasOp = true;
48 }
49 if (op.HasProp("length")) {
50 tie(succ, len) = op.GetProp("length").ToInt32();
51 if (!succ) {
52 return { false, position, hasLen, len, nullptr, hasOp };
53 }
54 hasOp = true;
55 hasLen = true;
56 }
57 if (op.HasProp("encoding")) {
58 tie(succ, encoding, ignore) = op.GetProp("encoding").ToUTF8String();
59 if (!succ) {
60 return { false, position, hasLen, len, nullptr, hasOp };
61 }
62 hasOp = true;
63 }
64 return { true, position, hasLen, len, move(encoding), hasOp };
65 }
66
Sync(napi_env env,napi_callback_info info)67 napi_value ReadText::Sync(napi_env env, napi_callback_info info)
68 {
69 NFuncArg funcArg(env, info);
70 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
71 UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
72 return nullptr;
73 }
74 unique_ptr<char[]> path;
75 bool succ = false;
76 FDGuard sfd;
77 tie(succ, path, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
78 if (!succ) {
79 UniError(EINVAL).ThrowErr(env, "Invalid path");
80 return nullptr;
81 }
82 ssize_t position = 0;
83 ssize_t len = 0;
84 unique_ptr<char[]> encoding;
85 bool hasLen = false;
86 tie(succ, position, hasLen, len, encoding, ignore) = GetReadTextArg(env, funcArg[NARG_POS::SECOND]);
87 if (!succ) {
88 UniError(EINVAL).ThrowErr(env, "Invalid option");
89 return nullptr;
90 }
91 struct stat statbf;
92 int ret;
93 sfd.SetFD(open(path.get(), O_RDONLY));
94 if ((!sfd) || (fstat(sfd.GetFD(), &statbf) == -1)) {
95 UniError(errno).ThrowErr(env);
96 return nullptr;
97 }
98 if (position > statbf.st_size) {
99 UniError(EINVAL).ThrowErr(env, "Invalid position");
100 return nullptr;
101 }
102 len = !hasLen ? statbf.st_size : len;
103 len = ((len < statbf.st_size) ? len : statbf.st_size);
104 std::unique_ptr<char[]> readbuf = std::make_unique<char[]>(len + 1);
105 if (readbuf == nullptr) {
106 UniError(EINVAL).ThrowErr(env, "file is too large");
107 return nullptr;
108 }
109 if (memset_s(readbuf.get(), len + 1, 0, len + 1) != EOK) {
110 UniError(errno).ThrowErr(env, "dfs mem error");
111 return nullptr;
112 }
113 ret = position > 0 ? pread(sfd.GetFD(), readbuf.get(), len, position) : read(sfd.GetFD(), readbuf.get(), len);
114 if (ret == -1) {
115 UniError(EINVAL).ThrowErr(env, "Invalid read file");
116 return nullptr;
117 }
118 return NVal::CreateUTF8String(env, readbuf.get(), ret).val_;
119 }
120
AsyncExec(const std::string & path,std::shared_ptr<AsyncReadTextArg> arg,ssize_t position,bool hasLen,ssize_t len)121 UniError ReadText::AsyncExec(const std::string &path, std::shared_ptr<AsyncReadTextArg> arg, ssize_t position,
122 bool hasLen, ssize_t len)
123 {
124 if (arg == nullptr) {
125 return UniError(ENOMEM);
126 }
127
128 FDGuard sfd;
129 struct stat statbf;
130 arg->len = len;
131 sfd.SetFD(open(path.c_str(), O_RDONLY));
132 if (sfd.GetFD() == -1) {
133 return UniError(EINVAL);
134 }
135 if (fstat(sfd.GetFD(), &statbf) == -1) {
136 return UniError(EINVAL);
137 }
138 if (position > statbf.st_size) {
139 return UniError(EINVAL);
140 }
141 if (!hasLen) {
142 arg->len = statbf.st_size;
143 }
144 arg->len = ((arg->len < statbf.st_size) ? arg->len : statbf.st_size);
145 arg->buf = std::make_unique<char[]>(arg->len);
146 if (arg->buf == nullptr) {
147 return UniError(ENOMEM);
148 }
149 if (position > 0) {
150 arg->len = pread(sfd.GetFD(), arg->buf.get(), arg->len, position);
151 } else {
152 arg->len = read(sfd.GetFD(), arg->buf.get(), arg->len);
153 }
154 if (arg->len == -1) {
155 return UniError(EINVAL);
156 }
157
158 return UniError(ERRNO_NOERR);
159 }
160
Async(napi_env env,napi_callback_info info)161 napi_value ReadText::Async(napi_env env, napi_callback_info info)
162 {
163 NFuncArg funcArg(env, info);
164 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
165 UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
166 return nullptr;
167 }
168 unique_ptr<char[]> path;
169 bool succ = false;
170 tie(succ, path, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
171 if (!succ) {
172 UniError(EINVAL).ThrowErr(env, "Invalid path");
173 return nullptr;
174 }
175 ssize_t position;
176 ssize_t len;
177 unique_ptr<char[]> encoding;
178 bool hasOp = false;
179 bool hasLen = false;
180 tie(succ, position, hasLen, len, encoding, hasOp) = GetReadTextArg(env, funcArg[NARG_POS::SECOND]);
181 if (!succ) {
182 UniError(EINVAL).ThrowErr(env, "Invalid option");
183 return nullptr;
184 }
185 auto arg = make_shared<AsyncReadTextArg>(NVal(env, funcArg.GetThisVar()));
186 if (arg == nullptr) {
187 return nullptr;
188 }
189 auto cbExec = [path = string(path.get()), arg, position, hasLen, len](napi_env env) -> UniError {
190 return AsyncExec(path, arg, position, hasLen, len);
191 };
192 auto cbComplete = [arg](napi_env env, UniError err) -> NVal {
193 if (err) {
194 return { env, err.GetNapiErr(env) };
195 } else {
196 return NVal::CreateUTF8String(env, arg->buf.get(), arg->len);
197 }
198 };
199 size_t argc = funcArg.GetArgc();
200 NVal thisVar(env, funcArg.GetThisVar());
201 if (argc == NARG_CNT::ONE || (argc == NARG_CNT::TWO && hasOp)) {
202 return NAsyncWorkPromise(env, thisVar).Schedule("FileIOReadText", cbExec, cbComplete).val_;
203 } else {
204 int cbIdx = !hasOp ? NARG_POS::SECOND : NARG_POS::THIRD;
205 NVal cb(env, funcArg[cbIdx]);
206 return NAsyncWorkCallback(env, thisVar, cb).Schedule("FileIOReadText", cbExec, cbComplete).val_;
207 }
208 }
209 } // namespace ModuleFileIO
210 } // namespace DistributedFS
211 } // namespace OHOS