• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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