1 /*
2 * Copyright (c) 2022 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 "common_func.h"
17
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include "class_stat/stat_entity.h"
25 #include "class_stat/stat_n_exporter.h"
26 #include "class_stream/stream_entity.h"
27 #include "class_stream/stream_n_exporter.h"
28 #include "filemgmt_libhilog.h"
29 #include "filemgmt_libn.h"
30
31 namespace OHOS {
32 namespace FileManagement {
33 namespace ModuleFileIO {
34 using namespace std;
35 using namespace OHOS::FileManagement::LibN;
36
InitOpenMode(napi_env env,napi_value exports)37 void InitOpenMode(napi_env env, napi_value exports)
38 {
39 char propertyName[] = "OpenMode";
40 napi_property_descriptor desc[] = {
41 DECLARE_NAPI_STATIC_PROPERTY("READ_ONLY", NVal::CreateInt32(env, RDONLY).val_),
42 DECLARE_NAPI_STATIC_PROPERTY("WRITE_ONLY", NVal::CreateInt32(env, WRONLY).val_),
43 DECLARE_NAPI_STATIC_PROPERTY("READ_WRITE", NVal::CreateInt32(env, RDWR).val_),
44 DECLARE_NAPI_STATIC_PROPERTY("CREATE", NVal::CreateInt32(env, CREATE).val_),
45 DECLARE_NAPI_STATIC_PROPERTY("TRUNC", NVal::CreateInt32(env, TRUNC).val_),
46 DECLARE_NAPI_STATIC_PROPERTY("APPEND", NVal::CreateInt32(env, APPEND).val_),
47 DECLARE_NAPI_STATIC_PROPERTY("NONBLOCK", NVal::CreateInt32(env, NONBLOCK).val_),
48 DECLARE_NAPI_STATIC_PROPERTY("DIR", NVal::CreateInt32(env, DIRECTORY).val_),
49 DECLARE_NAPI_STATIC_PROPERTY("NOFOLLOW", NVal::CreateInt32(env, NOFOLLOW).val_),
50 DECLARE_NAPI_STATIC_PROPERTY("SYNC", NVal::CreateInt32(env, SYNC).val_),
51 };
52 napi_value obj = nullptr;
53 napi_status status = napi_create_object(env, &obj);
54 if (status != napi_ok) {
55 HILOGE("Failed to create object at initializing openMode");
56 return;
57 }
58 status = napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
59 if (status != napi_ok) {
60 HILOGE("Failed to set properties of character at initializing openMode");
61 return;
62 }
63 status = napi_set_named_property(env, exports, propertyName, obj);
64 if (status != napi_ok) {
65 HILOGE("Failed to set direction property at initializing openMode");
66 return;
67 }
68 }
69
GetActualLen(napi_env env,size_t bufLen,size_t bufOff,NVal op)70 static tuple<bool, size_t> GetActualLen(napi_env env, size_t bufLen, size_t bufOff, NVal op)
71 {
72 bool succ = false;
73 size_t retLen = 0;
74
75 if (op.HasProp("length")) {
76 int64_t opLength = 0;
77 tie(succ, opLength) = op.GetProp("length").ToInt64();
78 if (!succ) {
79 HILOGE("Invalid option.length, expect integer");
80 NError(EINVAL).ThrowErr(env);
81 return { false, 0 };
82 }
83 if (opLength < 0) {
84 retLen = bufLen - bufOff;
85 } else if (static_cast<size_t>(opLength) > bufLen - bufOff) {
86 HILOGE("Invalid option.length, buffer limit exceeded");
87 NError(EINVAL).ThrowErr(env);
88 return { false, 0 };
89 } else {
90 retLen = static_cast<size_t>(opLength);
91 }
92 } else {
93 retLen = bufLen - bufOff;
94 }
95
96 return { true, retLen };
97 }
98
ConvertJsFlags(unsigned int & flags)99 unsigned int CommonFunc::ConvertJsFlags(unsigned int &flags)
100 {
101 static constexpr unsigned int usrReadOnly = 00;
102 static constexpr unsigned int usrWriteOnly = 01;
103 static constexpr unsigned int usrReadWrite = 02;
104 static constexpr unsigned int usrCreate = 0100;
105 static constexpr unsigned int usrExecuteLock = 0200;
106 static constexpr unsigned int usrTruncate = 01000;
107 static constexpr unsigned int usrAppend = 02000;
108 static constexpr unsigned int usrNoneBlock = 04000;
109 static constexpr unsigned int usrDirectory = 0200000;
110 static constexpr unsigned int usrNoFollowed = 0400000;
111 static constexpr unsigned int usrSynchronous = 04010000;
112
113 unsigned int flagsABI = 0;
114 flagsABI |= ((flags & usrReadOnly) == usrReadOnly) ? O_RDONLY : 0;
115 flagsABI |= ((flags & usrWriteOnly) == usrWriteOnly) ? O_WRONLY : 0;
116 flagsABI |= ((flags & usrReadWrite) == usrReadWrite) ? O_RDWR : 0;
117 flagsABI |= ((flags & usrCreate) == usrCreate) ? O_CREAT : 0;
118 flagsABI |= ((flags & usrExecuteLock) == usrExecuteLock) ? O_EXCL : 0;
119 flagsABI |= ((flags & usrTruncate) == usrTruncate) ? O_TRUNC : 0;
120 flagsABI |= ((flags & usrAppend) == usrAppend) ? O_APPEND : 0;
121 flagsABI |= ((flags & usrNoneBlock) == usrNoneBlock) ? O_NONBLOCK : 0;
122 flagsABI |= ((flags & usrDirectory) == usrDirectory) ? O_DIRECTORY : 0;
123 flagsABI |= ((flags & usrNoFollowed) == usrNoFollowed) ? O_NOFOLLOW : 0;
124 flagsABI |= ((flags & usrSynchronous) == usrSynchronous) ? O_SYNC : 0;
125 flags = flagsABI;
126 return flagsABI;
127 }
128
InstantiateStat(napi_env env,struct stat & buf)129 NVal CommonFunc::InstantiateStat(napi_env env, struct stat &buf)
130 {
131 napi_value objStat = NClass::InstantiateClass(env, StatNExporter::className_, {});
132 if (!objStat) {
133 HILOGE("Failed to instantiate stat class");
134 NError(EIO).ThrowErr(env);
135 return NVal();
136 }
137
138 auto statEntity = NClass::GetEntityOf<StatEntity>(env, objStat);
139 if (!statEntity) {
140 HILOGE("Failed to get stat entity");
141 NError(EIO).ThrowErr(env);
142 return NVal();
143 }
144
145 statEntity->stat_ = buf;
146 return { env, objStat };
147 }
148
InstantiateStream(napi_env env,unique_ptr<FILE,decltype(& fclose) > fp)149 NVal CommonFunc::InstantiateStream(napi_env env, unique_ptr<FILE, decltype(&fclose)> fp)
150 {
151 napi_value objStream = NClass::InstantiateClass(env, StreamNExporter::className_, {});
152 if (!objStream) {
153 HILOGE("INNER BUG. Cannot instantiate stream");
154 NError(EIO).ThrowErr(env);
155 return NVal();
156 }
157
158 auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, objStream);
159 if (!streamEntity) {
160 HILOGE("Cannot instantiate stream because of void entity");
161 NError(EIO).ThrowErr(env);
162 return NVal();
163 }
164
165 streamEntity->fp.swap(fp);
166 return { env, objStream };
167 }
168
fs_req_cleanup(uv_fs_t * req)169 void CommonFunc::fs_req_cleanup(uv_fs_t* req)
170 {
171 uv_fs_req_cleanup(req);
172 if (req) {
173 delete req;
174 req = nullptr;
175 }
176 }
177
GetModeFromFlags(unsigned int flags)178 string CommonFunc::GetModeFromFlags(unsigned int flags)
179 {
180 const string RDONLY = "r";
181 const string WRONLY = "w";
182 const string APPEND = "a";
183 const string TRUNC = "t";
184 string mode = RDONLY;
185 mode += (((flags & O_RDWR) == O_RDWR) ? WRONLY : "");
186 mode = (((flags & O_WRONLY) == O_WRONLY) ? WRONLY : mode);
187 if (mode != RDONLY) {
188 mode += ((flags & O_TRUNC) ? TRUNC : "");
189 mode += ((flags & O_APPEND) ? APPEND : "");
190 }
191 return mode;
192 }
193
GetCopyPathArg(napi_env env,napi_value srcPath,napi_value dstPath)194 tuple<bool, unique_ptr<char[]>, unique_ptr<char[]>> CommonFunc::GetCopyPathArg(napi_env env,
195 napi_value srcPath,
196 napi_value dstPath)
197 {
198 bool succ = false;
199 unique_ptr<char[]> src = nullptr;
200 tie(succ, src, ignore) = NVal(env, srcPath).ToUTF8String();
201 if (!succ) {
202 HILOGE("Failed to convert the src path to UTF-8 string");
203 return { false, nullptr, nullptr };
204 }
205
206 unique_ptr<char[]> dest = nullptr;
207 tie(succ, dest, ignore) = NVal(env, dstPath).ToUTF8String();
208 if (!succ) {
209 HILOGE("Failed to convert the dest path to UTF-8 string");
210 return { false, nullptr, nullptr };
211 }
212 return make_tuple(true, move(src), move(dest));
213 }
214
DecodeString(napi_env env,NVal jsStr,NVal encoding)215 static tuple<bool, unique_ptr<char[]>, size_t> DecodeString(napi_env env, NVal jsStr, NVal encoding)
216 {
217 if (!jsStr.TypeIs(napi_string)) {
218 return { false, nullptr, 0 };
219 }
220
221 bool succ = false;
222 if (!encoding) {
223 return jsStr.ToUTF8String();
224 }
225
226 unique_ptr<char[]> encodingBuf = nullptr;
227 tie(succ, encodingBuf, ignore) = encoding.ToUTF8String();
228 if (!succ) {
229 return { false, nullptr, 0 };
230 }
231 string_view encodingStr(encodingBuf.release());
232 if (encodingStr == "utf-8") {
233 return jsStr.ToUTF8String();
234 } else if (encodingStr == "utf-16") {
235 return jsStr.ToUTF16String();
236 } else {
237 HILOGE("Failed to recognize the str type");
238 return { false, nullptr, 0 };
239 }
240 }
241
GetReadArg(napi_env env,napi_value readBuf,napi_value option)242 tuple<bool, void *, size_t, bool, int64_t> CommonFunc::GetReadArg(napi_env env,
243 napi_value readBuf, napi_value option)
244 {
245 size_t retLen = 0;
246 int64_t position = 0;
247 bool succ = false;
248 bool posAssigned = false;
249
250 NVal txt(env, readBuf);
251 void *buf = nullptr;
252 size_t bufLen = 0;
253 tie(succ, buf, bufLen) = txt.ToArraybuffer();
254 if (!succ || bufLen > UINT_MAX) {
255 HILOGE("Invalid arraybuffer");
256 NError(EINVAL).ThrowErr(env);
257 return { false, nullptr, 0, posAssigned, position };
258 }
259 NVal op = NVal(env, option);
260 tie(succ, retLen) = GetActualLen(env, bufLen, 0, op);
261 if (!succ) {
262 HILOGE("Failed to get actual length");
263 return { false, nullptr, 0, posAssigned, position };
264 }
265
266 if (op.HasProp("offset")) {
267 tie(succ, position) = op.GetProp("offset").ToInt64();
268 if (succ && position >= 0) {
269 posAssigned = true;
270 } else {
271 HILOGE("option.offset shall be positive number");
272 NError(EINVAL).ThrowErr(env);
273 return { false, nullptr, 0, posAssigned, position };
274 }
275 }
276
277 return { true, buf, retLen, posAssigned, position };
278 }
279
GetWriteArg(napi_env env,napi_value argWBuf,napi_value argOption)280 tuple<bool, unique_ptr<char[]>, void *, size_t, bool, int64_t> CommonFunc::GetWriteArg(napi_env env,
281 napi_value argWBuf, napi_value argOption)
282 {
283 int64_t retPos = 0;
284 size_t bufLen = 0;
285 bool hasPos = false;
286 bool succ = false;
287 void *buf = nullptr;
288 NVal op(env, argOption);
289 NVal jsBuffer(env, argWBuf);
290 unique_ptr<char[]> bufferGuard = nullptr;
291 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
292 if (!succ) {
293 tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
294 if (!succ) {
295 HILOGE("Illegal write buffer or encoding");
296 NError(EINVAL).ThrowErr(env);
297 return { false, nullptr, nullptr, 0, hasPos, retPos };
298 }
299 } else {
300 buf = bufferGuard.get();
301 }
302 if (bufLen > UINT_MAX) {
303 HILOGE("The Size of buffer is too large");
304 NError(EINVAL).ThrowErr(env);
305 return { false, nullptr, nullptr, 0, hasPos, retPos} ;
306 }
307 size_t retLen = 0;
308 tie(succ, retLen) = GetActualLen(env, bufLen, 0, op);
309 if (!succ) {
310 HILOGE("Failed to get actual length");
311 return { false, nullptr, nullptr, 0, hasPos, retPos };
312 }
313
314 if (op.HasProp("offset")) {
315 int64_t position = 0;
316 tie(succ, position) = op.GetProp("offset").ToInt64();
317 if (!succ || position < 0) {
318 HILOGE("option.offset shall be positive number");
319 NError(EINVAL).ThrowErr(env);
320 return { false, nullptr, nullptr, 0, hasPos, retPos };
321 }
322 hasPos = true;
323 retPos = position;
324 } else {
325 retPos = INVALID_POSITION;
326 }
327 return { true, move(bufferGuard), buf, retLen, hasPos, retPos };
328 }
329 } // namespace ModuleFileIO
330 } // namespace FileManagement
331 } // namespace OHOS
332