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