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