• 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 
16 #include "stream_n_exporter.h"
17 
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cstring>
21 #include <cinttypes>
22 #include <memory>
23 #include <securec.h>
24 #include <sstream>
25 #include <string>
26 
27 #include "common_func.h"
28 #include "file_utils.h"
29 #include "filemgmt_libhilog.h"
30 #include "flush.h"
31 #include "stream_entity.h"
32 
33 namespace OHOS {
34 namespace FileManagement {
35 namespace ModuleFileIO {
36 using namespace std;
37 using namespace OHOS::FileManagement::LibN;
38 
ReadSync(napi_env env,napi_callback_info cbInfo)39 napi_value StreamNExporter::ReadSync(napi_env env, napi_callback_info cbInfo)
40 {
41     NFuncArg funcArg(env, cbInfo);
42     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
43         HILOGE("Number of arguments unmatched");
44         NError(EINVAL).ThrowErr(env);
45         return nullptr;
46     }
47 
48     auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, funcArg.GetThisVar());
49     if (!streamEntity || !streamEntity->fp) {
50         HILOGE("Failed to get entity of Stream");
51         NError(EIO).ThrowErr(env);
52         return nullptr;
53     }
54     FILE *filp = nullptr;
55     filp = streamEntity->fp.get();
56 
57     auto [succ, buf, len, offset] =
58         CommonFunc::GetReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
59     if (!succ) {
60         HILOGE("Failed to resolve buf and options");
61         return nullptr;
62     }
63 
64     if (offset >= 0) {
65         int ret = fseek(filp, static_cast<long>(offset), SEEK_SET);
66         if (ret < 0) {
67             HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
68             NError(errno).ThrowErr(env);
69             return nullptr;
70         }
71     }
72 
73     size_t actLen = fread(buf, 1, len, filp);
74     if ((actLen != static_cast<size_t>(len) && !feof(filp)) || ferror(filp)) {
75         HILOGE("Invalid buffer size and pointer, actlen: %{public}zu", actLen);
76         NError(EIO).ThrowErr(env);
77         return nullptr;
78     }
79 
80     return NVal::CreateInt64(env, actLen).val_;
81 }
82 
CloseSync(napi_env env,napi_callback_info cbInfo)83 napi_value StreamNExporter::CloseSync(napi_env env, napi_callback_info cbInfo)
84 {
85     NFuncArg funcArg(env, cbInfo);
86     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
87         HILOGE("Number of arguments unmatched");
88         NError(EINVAL).ThrowErr(env);
89         return nullptr;
90     }
91 
92     auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, funcArg.GetThisVar());
93     if (!streamEntity || !streamEntity->fp) {
94         HILOGE("Failed to get entity of Stream");
95         NError(EIO).ThrowErr(env);
96         return nullptr;
97     }
98     streamEntity->fp.reset();
99     (void)NClass::RemoveEntityOfFinal<StreamEntity>(env, funcArg.GetThisVar());
100 
101     return NVal::CreateUndefined(env).val_;
102 }
103 
WriteSync(napi_env env,napi_callback_info cbInfo)104 napi_value StreamNExporter::WriteSync(napi_env env, napi_callback_info cbInfo)
105 {
106     NFuncArg funcArg(env, cbInfo);
107     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
108         HILOGE("Number of arguments unmatched");
109         NError(EINVAL).ThrowErr(env);
110         return nullptr;
111     }
112 
113     auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, funcArg.GetThisVar());
114     if (!streamEntity || !streamEntity->fp) {
115         HILOGE("Failed to get entity of Stream");
116         NError(EIO).ThrowErr(env);
117         return nullptr;
118     }
119     FILE *filp = nullptr;
120     filp = streamEntity->fp.get();
121 
122     auto [succ, bufGuard, buf, len, offset] =
123         CommonFunc::GetWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
124     if (!succ) {
125         HILOGE("Failed to resolve buf and options");
126         return nullptr;
127     }
128     if (offset >= 0) {
129         int ret = fseek(filp, static_cast<long>(offset), SEEK_SET);
130         if (ret < 0) {
131             HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
132             NError(errno).ThrowErr(env);
133             return nullptr;
134         }
135     }
136 
137     size_t writeLen = fwrite(buf, 1, len, filp);
138     if ((writeLen == 0) && (writeLen != len)) {
139         HILOGE("Failed to fwrite stream");
140         NError(EIO).ThrowErr(env);
141         return nullptr;
142     }
143 
144     return NVal::CreateInt64(env, static_cast<int64_t>(writeLen)).val_;
145 }
146 
WriteExec(napi_env env,NFuncArg & funcArg,StreamEntity * streamEntity)147 static napi_value WriteExec(napi_env env, NFuncArg &funcArg, StreamEntity *streamEntity)
148 {
149     auto [succ, bufGuard, buf, len, offset] =
150         CommonFunc::GetWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
151     if (!succ) {
152         HILOGE("Failed to resolve buf and options");
153         return nullptr;
154     }
155 
156     auto arg = CreateSharedPtr<AsyncWriteArg>(move(bufGuard));
157     if (arg == nullptr) {
158         HILOGE("Failed to request heap memory.");
159         NError(ENOMEM).ThrowErr(env);
160         return nullptr;
161     }
162     auto cbExec = [arg, buf = buf, len = len, streamEntity, offset = offset]() -> NError {
163         if (!streamEntity || !streamEntity->fp.get()) {
164             HILOGE("Stream has been closed in write cbExec possibly");
165             return NError(EIO);
166         }
167         if (offset >= 0) {
168             int ret = fseek(streamEntity->fp.get(), static_cast<long>(offset), SEEK_SET);
169             if (ret < 0) {
170                 HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
171                 return NError(errno);
172             }
173         }
174         arg->actLen = fwrite(buf, 1, len, streamEntity->fp.get());
175         if ((arg->actLen == 0) && (arg->actLen != len)) {
176             HILOGE("Failed to fwrite stream");
177             return NError(EIO);
178         }
179         return NError(ERRNO_NOERR);
180     };
181 
182     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
183         if (err) {
184             return { env, err.GetNapiErr(env) };
185         }
186         return { NVal::CreateInt64(env, static_cast<int64_t>(arg->actLen)) };
187     };
188 
189     NVal thisVar(env, funcArg.GetThisVar());
190     if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
191         !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
192         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_STREAM_WRITE_NAME, cbExec, cbCompl).val_;
193     } else {
194         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD);
195         NVal cb(env, funcArg[cbIdx]);
196         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_STREAM_WRITE_NAME, cbExec, cbCompl).val_;
197     }
198 }
199 
Write(napi_env env,napi_callback_info cbInfo)200 napi_value StreamNExporter::Write(napi_env env, napi_callback_info cbInfo)
201 {
202     NFuncArg funcArg(env, cbInfo);
203     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
204         HILOGE("Number of arguments unmatched");
205         NError(EINVAL).ThrowErr(env);
206         return nullptr;
207     }
208 
209     auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, funcArg.GetThisVar());
210     if (!streamEntity || !streamEntity->fp) {
211         HILOGE("Failed to get entity of Stream");
212         NError(EIO).ThrowErr(env);
213         return nullptr;
214     }
215     return WriteExec(env, funcArg, streamEntity);
216 }
217 
ReadExec(napi_env env,NFuncArg & funcArg,StreamEntity * streamEntity)218 static napi_value ReadExec(napi_env env, NFuncArg &funcArg, StreamEntity *streamEntity)
219 {
220     auto [succ, buf, len, offset] =
221         CommonFunc::GetReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
222     if (!succ) {
223         HILOGE("Failed to resolve buf and options");
224         NError(EINVAL).ThrowErr(env);
225         return nullptr;
226     }
227 
228     auto arg = CreateSharedPtr<AsyncReadArg>(NVal(env, funcArg[NARG_POS::FIRST]));
229     if (arg == nullptr) {
230         HILOGE("Failed to request heap memory.");
231         NError(ENOMEM).ThrowErr(env);
232         return nullptr;
233     }
234     auto cbExec = [arg, buf = buf, len = len, streamEntity, offset = offset]() -> NError {
235         if (!streamEntity || !streamEntity->fp.get()) {
236             HILOGE("Stream has been closed in read cbExec possibly");
237             return NError(EIO);
238         }
239         if (offset >= 0) {
240             int ret = fseek(streamEntity->fp.get(), static_cast<long>(offset), SEEK_SET);
241             if (ret < 0) {
242                 HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
243                 return NError(errno);
244             }
245         }
246         size_t actLen = fread(buf, 1, len, streamEntity->fp.get());
247         if ((actLen != static_cast<size_t>(len) && !feof(streamEntity->fp.get())) || ferror(streamEntity->fp.get())) {
248             HILOGE("Invalid buffer size and pointer, actlen: %{public}zu", actLen);
249             return NError(EIO);
250         } else {
251             arg->lenRead = actLen;
252             return NError(ERRNO_NOERR);
253         }
254     };
255 
256     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
257         if (err) {
258             return { env, err.GetNapiErr(env) };
259         }
260         return { NVal::CreateInt64(env, arg->lenRead) };
261     };
262 
263     NVal thisVar(env, funcArg.GetThisVar());
264     if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
265         !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
266         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_STREAM_READ_NAME, cbExec, cbCompl).val_;
267     } else {
268         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD);
269         NVal cb(env, funcArg[cbIdx]);
270         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_STREAM_READ_NAME, cbExec, cbCompl).val_;
271     }
272 }
273 
Read(napi_env env,napi_callback_info cbInfo)274 napi_value StreamNExporter::Read(napi_env env, napi_callback_info cbInfo)
275 {
276     NFuncArg funcArg(env, cbInfo);
277     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
278         HILOGE("Number of arguments unmatched");
279         NError(EINVAL).ThrowErr(env);
280         return nullptr;
281     }
282 
283     auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, funcArg.GetThisVar());
284     if (!streamEntity || !streamEntity->fp) {
285         HILOGE("Failed to get entity of Stream");
286         NError(EIO).ThrowErr(env);
287         return nullptr;
288     }
289     return ReadExec(env, funcArg, streamEntity);
290 }
291 
Close(napi_env env,napi_callback_info cbInfo)292 napi_value StreamNExporter::Close(napi_env env, napi_callback_info cbInfo)
293 {
294     NFuncArg funcArg(env, cbInfo);
295     if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
296         HILOGE("Number of arguments unmatched");
297         NError(EINVAL).ThrowErr(env);
298         return nullptr;
299     }
300 
301     auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, funcArg.GetThisVar());
302     if (!streamEntity || !streamEntity->fp) {
303         HILOGE("Failed to get entity of Stream");
304         NError(EIO).ThrowErr(env);
305         return nullptr;
306     }
307 
308     auto fp = NClass::RemoveEntityOfFinal<StreamEntity>(env, funcArg.GetThisVar());
309     if (!fp) {
310         NError(EINVAL).ThrowErr(env);
311         return nullptr;
312     }
313 
314     auto cbExec = []() -> NError {
315         return NError(ERRNO_NOERR);
316     };
317 
318     auto cbCompl = [](napi_env env, NError err) -> NVal {
319         if (err) {
320             return { env, err.GetNapiErr(env) };
321         } else {
322             return NVal::CreateUndefined(env);
323         }
324     };
325 
326     NVal thisVar(env, funcArg.GetThisVar());
327     if (funcArg.GetArgc() == NARG_CNT::ZERO) {
328         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_STREAM_CLOSE_NAME, cbExec, cbCompl).val_;
329     } else {
330         NVal cb(env, funcArg[NARG_POS::FIRST]);
331         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_STREAM_CLOSE_NAME, cbExec, cbCompl).val_;
332     }
333 }
334 
Constructor(napi_env env,napi_callback_info cbInfo)335 napi_value StreamNExporter::Constructor(napi_env env, napi_callback_info cbInfo)
336 {
337     NFuncArg funcArg(env, cbInfo);
338     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
339         HILOGE("Number of arguments unmatched");
340         NError(EINVAL).ThrowErr(env);
341         return nullptr;
342     }
343 
344     auto streamEntity = CreateUniquePtr<StreamEntity>();
345     if (streamEntity == nullptr) {
346         HILOGE("Failed to request heap memory.");
347         NError(ENOMEM).ThrowErr(env);
348         return nullptr;
349     }
350     if (!NClass::SetEntityFor<StreamEntity>(env, funcArg.GetThisVar(), move(streamEntity))) {
351         HILOGE("INNER BUG. Failed to wrap entity for obj stream");
352         NError(EIO).ThrowErr(env);
353         return nullptr;
354     }
355     return funcArg.GetThisVar();
356 }
357 
Export()358 bool StreamNExporter::Export()
359 {
360     vector<napi_property_descriptor> props = {
361         NVal::DeclareNapiFunction("writeSync", WriteSync),
362         NVal::DeclareNapiFunction("flush", Flush::Async),
363         NVal::DeclareNapiFunction("flushSync", Flush::Sync),
364         NVal::DeclareNapiFunction("readSync", ReadSync),
365         NVal::DeclareNapiFunction("closeSync", CloseSync),
366         NVal::DeclareNapiFunction("write", Write),
367         NVal::DeclareNapiFunction("read", Read),
368         NVal::DeclareNapiFunction("close", Close),
369     };
370 
371     string className = GetClassName();
372     bool succ = false;
373     napi_value cls = nullptr;
374     tie(succ, cls) = NClass::DefineClass(exports_.env_, className, StreamNExporter::Constructor, move(props));
375     if (!succ) {
376         HILOGE("INNER BUG. Failed to define class");
377         NError(EIO).ThrowErr(exports_.env_);
378         return false;
379     }
380     succ = NClass::SaveClass(exports_.env_, className, cls);
381     if (!succ) {
382         HILOGE("INNER BUG. Failed to save class");
383         NError(EIO).ThrowErr(exports_.env_);
384         return false;
385     }
386 
387     return exports_.AddProp(className, cls);
388 }
389 
GetClassName()390 string StreamNExporter::GetClassName()
391 {
392     return StreamNExporter::className_;
393 }
394 
StreamNExporter(napi_env env,napi_value exports)395 StreamNExporter::StreamNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
396 
~StreamNExporter()397 StreamNExporter::~StreamNExporter() {}
398 } // namespace ModuleFileIO
399 } // namespace FileManagement
400 } // namespace OHOS
401