1 /*
2 * Copyright (c) 2021-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 "../common/log.h"
25 #include "../common/napi/n_class.h"
26 #include "../common/napi/n_func_arg.h"
27 #include "../common/napi/n_val.h"
28 #include "../common/uni_error.h"
29
30 namespace OHOS {
31 namespace DistributedFS {
32 namespace ModuleFileIO {
33 using namespace std;
34
InitOpenMode(napi_env env,napi_value exports)35 void InitOpenMode(napi_env env, napi_value exports)
36 {
37 char propertyName[] = "OpenMode";
38 napi_property_descriptor desc[] = {
39 DECLARE_NAPI_STATIC_PROPERTY("READ_ONLY", NVal::CreateInt32(env, RDONLY).val_),
40 DECLARE_NAPI_STATIC_PROPERTY("WRITE_ONLY", NVal::CreateInt32(env, WRONLY).val_),
41 DECLARE_NAPI_STATIC_PROPERTY("READ_WRITE", NVal::CreateInt32(env, RDWR).val_),
42 DECLARE_NAPI_STATIC_PROPERTY("CREATE", NVal::CreateInt32(env, CREATE).val_),
43 DECLARE_NAPI_STATIC_PROPERTY("TRUNC", NVal::CreateInt32(env, TRUNC).val_),
44 DECLARE_NAPI_STATIC_PROPERTY("APPEND", NVal::CreateInt32(env, APPEND).val_),
45 DECLARE_NAPI_STATIC_PROPERTY("NONBLOCK", NVal::CreateInt32(env, NONBLOCK).val_),
46 DECLARE_NAPI_STATIC_PROPERTY("DIR", NVal::CreateInt32(env, DIRECTORY).val_),
47 DECLARE_NAPI_STATIC_PROPERTY("NOFOLLOW", NVal::CreateInt32(env, NOFOLLOW).val_),
48 DECLARE_NAPI_STATIC_PROPERTY("SYNC", NVal::CreateInt32(env, SYNC).val_),
49 };
50 napi_value obj = nullptr;
51 napi_create_object(env, &obj);
52 napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
53 napi_set_named_property(env, exports, propertyName, obj);
54 }
55
GetActualBuf(napi_env env,void * rawBuf,int64_t bufLen,NVal op)56 static tuple<bool, void *, int> GetActualBuf(napi_env env, void *rawBuf, int64_t bufLen, NVal op)
57 {
58 bool succ = false;
59 void *realBuf = nullptr;
60 int64_t opOffset = 0;
61 if (op.HasProp("offset")) {
62 tie(succ, opOffset) = op.GetProp("offset").ToInt64();
63 if (!succ || opOffset < 0) {
64 UniError(EINVAL).ThrowErr(env, "Invalid option.offset, positive integer is desired");
65 return { false, nullptr, opOffset };
66 } else if (opOffset > bufLen) {
67 UniError(EINVAL).ThrowErr(env, "Invalid option.offset, buffer limit exceeded");
68 return { false, nullptr, opOffset };
69 } else {
70 realBuf = static_cast<uint8_t *>(rawBuf) + opOffset;
71 }
72 } else {
73 realBuf = rawBuf;
74 }
75
76 return { true, realBuf, opOffset };
77 }
78
GetActualLen(napi_env env,int64_t bufLen,int64_t bufOff,NVal op)79 static tuple<bool, size_t> GetActualLen(napi_env env, int64_t bufLen, int64_t bufOff, NVal op)
80 {
81 bool succ = false;
82 int64_t retLen;
83
84 if (op.HasProp("length")) {
85 int64_t opLength;
86 tie(succ, opLength) = op.GetProp("length").ToInt64();
87 if (!succ) {
88 UniError(EINVAL).ThrowErr(env, "Invalid option.length, expect integer");
89 return { false, 0 };
90 }
91 if (opLength < 0) {
92 retLen = bufLen - bufOff;
93 } else if (opLength > bufLen - bufOff) {
94 UniError(EINVAL).ThrowErr(env, "Invalid option.length, buffer limit exceeded");
95 return { false, 0 };
96 } else {
97 retLen = opLength;
98 }
99 } else {
100 retLen = bufLen - bufOff;
101 }
102
103 return { true, retLen };
104 }
105
GetActualLenV9(napi_env env,int64_t bufLen,int64_t bufOff,NVal op)106 static tuple<bool, size_t> GetActualLenV9(napi_env env, int64_t bufLen, int64_t bufOff, NVal op)
107 {
108 bool succ = false;
109 int64_t retLen;
110
111 if (op.HasProp("length")) {
112 int64_t opLength;
113 tie(succ, opLength) = op.GetProp("length").ToInt64();
114 if (!succ) {
115 HILOGE("Invalid option.length, expect integer");
116 UniError(EINVAL).ThrowErr(env);
117 return { false, 0 };
118 }
119 if (opLength < 0) {
120 retLen = bufLen - bufOff;
121 } else if (opLength > bufLen - bufOff) {
122 HILOGE("Invalid option.length, buffer limit exceeded");
123 UniError(EINVAL).ThrowErr(env);
124 return { false, 0 };
125 } else {
126 retLen = opLength;
127 }
128 } else {
129 retLen = bufLen - bufOff;
130 }
131
132 return { true, retLen };
133 }
134
ConvertJsFlags(int & flags)135 int CommonFunc::ConvertJsFlags(int &flags)
136 {
137 static constexpr unsigned int usrReadOnly = 00;
138 static constexpr unsigned int usrWriteOnly = 01;
139 static constexpr unsigned int usrReadWrite = 02;
140 static constexpr unsigned int usrCreate = 0100;
141 static constexpr unsigned int usrExecuteLock = 0200;
142 static constexpr unsigned int usrTruncate = 01000;
143 static constexpr unsigned int usrAppend = 02000;
144 static constexpr unsigned int usrNoneBlock = 04000;
145 static constexpr unsigned int usrDirectory = 0200000;
146 static constexpr unsigned int usrNoFollowed = 0400000;
147 static constexpr unsigned int usrSynchronous = 04010000;
148
149 unsigned int flagsABI = 0;
150 flagsABI |= ((flags & usrReadOnly) == usrReadOnly) ? O_RDONLY : 0;
151 flagsABI |= ((flags & usrWriteOnly) == usrWriteOnly) ? O_WRONLY : 0;
152 flagsABI |= ((flags & usrReadWrite) == usrReadWrite) ? O_RDWR : 0;
153 flagsABI |= ((flags & usrCreate) == usrCreate) ? O_CREAT : 0;
154 flagsABI |= ((flags & usrExecuteLock) == usrExecuteLock) ? O_EXCL : 0;
155 flagsABI |= ((flags & usrTruncate) == usrTruncate) ? O_TRUNC : 0;
156 flagsABI |= ((flags & usrAppend) == usrAppend) ? O_APPEND : 0;
157 flagsABI |= ((flags & usrNoneBlock) == usrNoneBlock) ? O_NONBLOCK : 0;
158 flagsABI |= ((flags & usrDirectory) == usrDirectory) ? O_DIRECTORY : 0;
159 flagsABI |= ((flags & usrNoFollowed) == usrNoFollowed) ? O_NOFOLLOW : 0;
160 flagsABI |= ((flags & usrSynchronous) == usrSynchronous) ? O_SYNC : 0;
161 flags = flagsABI;
162 return flagsABI;
163 }
164
GetCopyPathArg(napi_env env,napi_value srcPath,napi_value dstPath)165 tuple<bool, unique_ptr<char[]>, unique_ptr<char[]>> CommonFunc::GetCopyPathArg(napi_env env,
166 napi_value srcPath,
167 napi_value dstPath)
168 {
169 bool succ = false;
170 unique_ptr<char[]> src;
171 tie(succ, src, ignore) = NVal(env, srcPath).ToUTF8String();
172 if (!succ) {
173 return { false, nullptr, nullptr };
174 }
175
176 unique_ptr<char[]> dest;
177 tie(succ, dest, ignore) = NVal(env, dstPath).ToUTF8String();
178 if (!succ) {
179 return { false, nullptr, nullptr };
180 }
181 return make_tuple(true, move(src), move(dest));
182 }
183
GetReadArg(napi_env env,napi_value readBuf,napi_value option)184 tuple<bool, void *, int64_t, bool, int64_t, int> CommonFunc::GetReadArg(napi_env env,
185 napi_value readBuf,
186 napi_value option)
187 {
188 bool succ = false;
189 void *retBuf = nullptr;
190 int64_t retLen = 0;
191 bool posAssigned = false;
192 int64_t position = 0;
193
194 NVal txt(env, readBuf);
195 void *buf = nullptr;
196 int64_t bufLen = 0;
197 int offset = 0;
198 tie(succ, buf, bufLen) = txt.ToArraybuffer();
199 if (!succ) {
200 UniError(EINVAL).ThrowErr(env, "Invalid read buffer, expect arraybuffer");
201 return { false, nullptr, 0, posAssigned, position, offset };
202 }
203
204 NVal op = NVal(env, option);
205 tie(succ, retBuf, offset) = GetActualBuf(env, buf, bufLen, op);
206 if (!succ) {
207 return { false, nullptr, 0, posAssigned, position, offset };
208 }
209
210 int64_t bufOff = static_cast<uint8_t *>(retBuf) - static_cast<uint8_t *>(buf);
211 tie(succ, retLen) = GetActualLen(env, bufLen, bufOff, op);
212 if (!succ) {
213 return { false, nullptr, 0, posAssigned, position, offset };
214 }
215
216 if (op.HasProp("position")) {
217 tie(succ, position) = op.GetProp("position").ToInt64();
218 if (succ && position >= 0) {
219 posAssigned = true;
220 } else {
221 UniError(EINVAL).ThrowErr(env, "option.position shall be positive number");
222 return { false, nullptr, 0, posAssigned, position, offset };
223 }
224 }
225
226 return { true, retBuf, retLen, posAssigned, position, offset };
227 }
228
DecodeString(napi_env env,NVal jsStr,NVal encoding)229 static tuple<bool, unique_ptr<char[]>, int64_t> DecodeString(napi_env env, NVal jsStr, NVal encoding)
230 {
231 unique_ptr<char[]> buf;
232 if (!jsStr.TypeIs(napi_string)) {
233 return { false, nullptr, 0 };
234 }
235
236 bool succ = false;
237 if (!encoding) {
238 return jsStr.ToUTF8String();
239 }
240
241 unique_ptr<char[]> encodingBuf;
242 tie(succ, encodingBuf, ignore) = encoding.ToUTF8String();
243 if (!succ) {
244 return { false, nullptr, 0 };
245 }
246 string encodingStr(encodingBuf.release());
247 if (encodingStr == "utf-8") {
248 return jsStr.ToUTF8String();
249 } else if (encodingStr == "utf-16") {
250 return jsStr.ToUTF16String();
251 } else {
252 return { false, nullptr, 0 };
253 }
254 }
255
GetWriteArg(napi_env env,napi_value argWBuf,napi_value argOption)256 tuple<bool, unique_ptr<char[]>, void *, int64_t, bool, int64_t> CommonFunc::GetWriteArg(napi_env env,
257 napi_value argWBuf,
258 napi_value argOption)
259 {
260 void *retBuf = nullptr;
261 int64_t retLen = 0;
262 bool hasPos = false;
263 int64_t retPos = 0;
264
265 bool succ = false;
266 void *buf = nullptr;
267 int64_t bufLen = 0;
268 NVal op(env, argOption);
269 NVal jsBuffer(env, argWBuf);
270 unique_ptr<char[]> bufferGuard;
271 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
272 if (!succ) {
273 tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
274 if (!succ) {
275 UniError(EINVAL).ThrowErr(env, "Illegal write buffer or encoding");
276 return { false, nullptr, nullptr, 0, hasPos, retPos };
277 }
278 } else {
279 buf = bufferGuard.get();
280 }
281
282 tie(succ, retBuf, ignore) = GetActualBuf(env, buf, bufLen, op);
283 if (!succ) {
284 return { false, nullptr, nullptr, 0, hasPos, retPos };
285 }
286
287 int64_t bufOff = static_cast<uint8_t *>(retBuf) - static_cast<uint8_t *>(buf);
288 tie(succ, retLen) = GetActualLen(env, bufLen, bufOff, op);
289 if (!succ) {
290 return { false, nullptr, nullptr, 0, hasPos, retPos };
291 }
292
293 if (op.HasProp("position")) {
294 int32_t position = 0;
295 tie(succ, position) = op.GetProp("position").ToInt32();
296 if (!succ || position < 0) {
297 UniError(EINVAL).ThrowErr(env, "option.position shall be positive number");
298 return { false, nullptr, nullptr, 0, hasPos, retPos };
299 }
300 hasPos = true;
301 retPos = position;
302 } else {
303 retPos = INVALID_POSITION;
304 }
305 return { true, move(bufferGuard), retBuf, retLen, hasPos, retPos };
306 }
307
GetReadArgV9(napi_env env,napi_value readBuf,napi_value option)308 tuple<bool, void *, int64_t, bool, int64_t> CommonFunc::GetReadArgV9(napi_env env,
309 napi_value readBuf, napi_value option)
310 {
311 bool succ = false;
312 int64_t retLen;
313 bool posAssigned = false;
314 int64_t position;
315
316 NVal txt(env, readBuf);
317 void *buf = nullptr;
318 int64_t bufLen;
319 tie(succ, buf, bufLen) = txt.ToArraybuffer();
320 if (!succ) {
321 HILOGE("Invalid read buffer, expect arraybuffer");
322 UniError(EINVAL).ThrowErr(env);
323 return { false, nullptr, 0, posAssigned, position };
324 }
325 NVal op = NVal(env, option);
326 tie(succ, retLen) = GetActualLenV9(env, bufLen, 0, op);
327 if (!succ) {
328 return { false, nullptr, 0, posAssigned, position };
329 }
330
331 if (op.HasProp("offset")) {
332 tie(succ, position) = op.GetProp("offset").ToInt64();
333 if (succ && position >= 0) {
334 posAssigned = true;
335 } else {
336 HILOGE("option.offset shall be positive number");
337 UniError(EINVAL).ThrowErr(env);
338 return { false, nullptr, 0, posAssigned, position };
339 }
340 }
341
342 return { true, buf, retLen, posAssigned, position };
343 }
344
GetWriteArgV9(napi_env env,napi_value argWBuf,napi_value argOption)345 tuple<bool, unique_ptr<char[]>, void *, int64_t, bool, int64_t> CommonFunc::GetWriteArgV9(napi_env env,
346 napi_value argWBuf, napi_value argOption)
347 {
348 int64_t retLen;
349 bool hasPos = false;
350 int64_t retPos;
351
352 bool succ = false;
353 void *buf = nullptr;
354 int64_t bufLen;
355 NVal op(env, argOption);
356 NVal jsBuffer(env, argWBuf);
357 unique_ptr<char[]> bufferGuard;
358 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
359 if (!succ) {
360 tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
361 if (!succ) {
362 HILOGE("Illegal write buffer or encoding");
363 UniError(EINVAL).ThrowErr(env);
364 return { false, nullptr, nullptr, 0, hasPos, retPos };
365 }
366 } else {
367 buf = bufferGuard.get();
368 }
369 tie(succ, retLen) = GetActualLenV9(env, bufLen, 0, op);
370 if (!succ) {
371 return { false, nullptr, nullptr, 0, hasPos, retPos };
372 }
373
374 if (op.HasProp("offset")) {
375 int32_t position = 0;
376 tie(succ, position) = op.GetProp("offset").ToInt32();
377 if (!succ || position < 0) {
378 HILOGE("option.offset shall be positive number");
379 UniError(EINVAL).ThrowErr(env);
380 return { false, nullptr, nullptr, 0, hasPos, retPos };
381 }
382 hasPos = true;
383 retPos = position;
384 } else {
385 retPos = INVALID_POSITION;
386 }
387 return { true, move(bufferGuard), buf, retLen, hasPos, retPos };
388 }
389
390 } // namespace ModuleFileIO
391 } // namespace DistributedFS
392 } // namespace OHOS
393