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,size_t bufLen,NVal op)56 static tuple<bool, void *, int64_t> GetActualBuf(napi_env env, void *rawBuf, size_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(opOffset);
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 > static_cast<int64_t>(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,size_t bufLen,size_t bufOff,NVal op)79 static tuple<bool, size_t> GetActualLen(napi_env env, size_t bufLen, size_t bufOff, NVal op)
80 {
81 bool succ = false;
82 size_t retLen = bufLen - bufOff;
83
84 if (op.HasProp("length")) {
85 int64_t opLength = 0;
86 tie(succ, opLength) = op.GetProp("length").ToInt64(static_cast<int64_t>(retLen));
87 if (!succ || opLength < 0 || static_cast<size_t>(opLength) > retLen) {
88 UniError(EINVAL).ThrowErr(env, "Invalid option.length");
89 return { false, 0 };
90 }
91 retLen = static_cast<size_t>(opLength);
92 }
93 return { true, retLen };
94 }
95
GetActualLenV9(napi_env env,int64_t bufLen,int64_t bufOff,NVal op)96 static tuple<bool, size_t> GetActualLenV9(napi_env env, int64_t bufLen, int64_t bufOff, NVal op)
97 {
98 bool succ = false;
99 int64_t retLen;
100
101 if (op.HasProp("length")) {
102 int64_t opLength;
103 tie(succ, opLength) = op.GetProp("length").ToInt64();
104 if (!succ) {
105 HILOGE("Invalid option.length, expect integer");
106 UniError(EINVAL).ThrowErr(env);
107 return { false, 0 };
108 }
109 if (opLength < 0) {
110 retLen = bufLen - bufOff;
111 } else if (opLength > bufLen - bufOff) {
112 HILOGE("Invalid option.length, buffer limit exceeded");
113 UniError(EINVAL).ThrowErr(env);
114 return { false, 0 };
115 } else {
116 retLen = opLength;
117 }
118 } else {
119 retLen = bufLen - bufOff;
120 }
121
122 return { true, retLen };
123 }
124
ConvertJsFlags(unsigned int & flags)125 unsigned int CommonFunc::ConvertJsFlags(unsigned int &flags)
126 {
127 static constexpr unsigned int usrWriteOnly = 01;
128 static constexpr unsigned int usrReadWrite = 02;
129 static constexpr unsigned int usrCreate = 0100;
130 static constexpr unsigned int usrExecuteLock = 0200;
131 static constexpr unsigned int usrTruncate = 01000;
132 static constexpr unsigned int usrAppend = 02000;
133 static constexpr unsigned int usrNoneBlock = 04000;
134 static constexpr unsigned int usrDirectory = 0200000;
135 static constexpr unsigned int usrNoFollowed = 0400000;
136 static constexpr unsigned int usrSynchronous = 04010000;
137
138 // default value is usrReadOnly 00
139 unsigned int flagsABI = 0;
140 flagsABI |= ((flags & usrWriteOnly) == usrWriteOnly) ? O_WRONLY : 0;
141 flagsABI |= ((flags & usrReadWrite) == usrReadWrite) ? O_RDWR : 0;
142 flagsABI |= ((flags & usrCreate) == usrCreate) ? O_CREAT : 0;
143 flagsABI |= ((flags & usrExecuteLock) == usrExecuteLock) ? O_EXCL : 0;
144 flagsABI |= ((flags & usrTruncate) == usrTruncate) ? O_TRUNC : 0;
145 flagsABI |= ((flags & usrAppend) == usrAppend) ? O_APPEND : 0;
146 flagsABI |= ((flags & usrNoneBlock) == usrNoneBlock) ? O_NONBLOCK : 0;
147 flagsABI |= ((flags & usrDirectory) == usrDirectory) ? O_DIRECTORY : 0;
148 flagsABI |= ((flags & usrNoFollowed) == usrNoFollowed) ? O_NOFOLLOW : 0;
149 flagsABI |= ((flags & usrSynchronous) == usrSynchronous) ? O_SYNC : 0;
150 flags = flagsABI;
151 return flagsABI;
152 }
153
GetCopyPathArg(napi_env env,napi_value srcPath,napi_value dstPath)154 tuple<bool, unique_ptr<char[]>, unique_ptr<char[]>> CommonFunc::GetCopyPathArg(napi_env env,
155 napi_value srcPath,
156 napi_value dstPath)
157 {
158 bool succ = false;
159 unique_ptr<char[]> src;
160 tie(succ, src, ignore) = NVal(env, srcPath).ToUTF8StringPath();
161 if (!succ) {
162 return { false, nullptr, nullptr };
163 }
164
165 unique_ptr<char[]> dest;
166 tie(succ, dest, ignore) = NVal(env, dstPath).ToUTF8StringPath();
167 if (!succ) {
168 return { false, nullptr, nullptr };
169 }
170 return make_tuple(true, move(src), move(dest));
171 }
172
GetReadArg(napi_env env,napi_value readBuf,napi_value option)173 tuple<bool, void *, size_t, int64_t, int64_t> CommonFunc::GetReadArg(napi_env env,
174 napi_value readBuf,
175 napi_value option)
176 {
177 bool succ = false;
178 void *retBuf = nullptr;
179 size_t retLen = 0;
180 int64_t position = -1;
181
182 NVal txt(env, readBuf);
183 void *buf = nullptr;
184 size_t bufLen = 0;
185 int64_t offset = 0;
186 tie(succ, buf, bufLen) = txt.ToArraybuffer();
187 if (!succ) {
188 UniError(EINVAL).ThrowErr(env, "Invalid read buffer, expect arraybuffer");
189 return { false, nullptr, 0, position, offset };
190 }
191
192 NVal op(env, option);
193 tie(succ, retBuf, offset) = GetActualBuf(env, buf, bufLen, op);
194 if (!succ) {
195 return { false, nullptr, 0, position, offset };
196 }
197
198 int64_t bufOff = static_cast<uint8_t *>(retBuf) - static_cast<uint8_t *>(buf);
199 tie(succ, retLen) = GetActualLen(env, bufLen, bufOff, op);
200 if (!succ) {
201 return { false, nullptr, 0, position, offset };
202 }
203
204 if (op.HasProp("position") && !op.GetProp("position").TypeIs(napi_undefined)) {
205 tie(succ, position) = op.GetProp("position").ToInt64();
206 if (!succ || position < 0) {
207 UniError(EINVAL).ThrowErr(env, "option.position shall be positive number");
208 return { false, nullptr, 0, position, offset };
209 }
210 }
211
212 return { true, retBuf, retLen, position, offset };
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 unique_ptr<char[]> buf = nullptr;
218 if (!jsStr.TypeIs(napi_string)) {
219 return { false, nullptr, 0 };
220 }
221 if (!encoding) {
222 return jsStr.ToUTF8String();
223 }
224
225 auto [succ, encodingBuf, ignore] = encoding.ToUTF8String("utf-8");
226 if (!succ) {
227 return { false, nullptr, 0 };
228 }
229 string_view encodingStr(encodingBuf.get());
230 if (encodingStr == "utf-8") {
231 return jsStr.ToUTF8String();
232 } else if (encodingStr == "utf-16") {
233 return jsStr.ToUTF16String();
234 } else {
235 return { false, nullptr, 0 };
236 }
237 }
238
GetWriteArg(napi_env env,napi_value argWBuf,napi_value argOption)239 tuple<bool, unique_ptr<char[]>, void *, size_t, int64_t> CommonFunc::GetWriteArg(napi_env env,
240 napi_value argWBuf,
241 napi_value argOption)
242 {
243 void *retBuf = nullptr;
244 size_t retLen = 0;
245 int64_t position = -1;
246 bool succ = false;
247 void *buf = nullptr;
248 size_t bufLen = 0;
249 NVal op(env, argOption);
250 NVal jsBuffer(env, argWBuf);
251 unique_ptr<char[]> bufferGuard = nullptr;
252 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
253 if (!succ) {
254 tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
255 if (!succ) {
256 UniError(EINVAL).ThrowErr(env, "Illegal write buffer or encoding");
257 return { false, nullptr, nullptr, 0, position };
258 }
259 } else {
260 buf = bufferGuard.get();
261 }
262
263 tie(succ, retBuf, ignore) = GetActualBuf(env, buf, bufLen, op);
264 if (!succ) {
265 return { false, nullptr, nullptr, 0, position };
266 }
267
268 int64_t bufOff = static_cast<uint8_t *>(retBuf) - static_cast<uint8_t *>(buf);
269 tie(succ, retLen) = GetActualLen(env, bufLen, bufOff, op);
270 if (!succ) {
271 return { false, nullptr, nullptr, 0, position };
272 }
273
274 if (op.HasProp("position") && !op.GetProp("position").TypeIs(napi_undefined)) {
275 tie(succ, position) = op.GetProp("position").ToInt64();
276 if (!succ || position < 0) {
277 UniError(EINVAL).ThrowErr(env, "option.position shall be positive number");
278 return { false, nullptr, nullptr, 0, position };
279 }
280 }
281 return { true, move(bufferGuard), retBuf, retLen, position };
282 }
283
GetReadArgV9(napi_env env,napi_value readBuf,napi_value option)284 tuple<bool, void *, int64_t, bool, int64_t> CommonFunc::GetReadArgV9(napi_env env,
285 napi_value readBuf, napi_value option)
286 {
287 bool succ = false;
288 int64_t retLen;
289 bool posAssigned = false;
290 int64_t position;
291
292 NVal txt(env, readBuf);
293 void *buf = nullptr;
294 int64_t bufLen;
295 tie(succ, buf, bufLen) = txt.ToArraybuffer();
296 if (!succ) {
297 HILOGE("Invalid read buffer, expect arraybuffer");
298 UniError(EINVAL).ThrowErr(env);
299 return { false, nullptr, 0, posAssigned, position };
300 }
301 NVal op = NVal(env, option);
302 tie(succ, retLen) = GetActualLenV9(env, bufLen, 0, op);
303 if (!succ) {
304 return { false, nullptr, 0, posAssigned, position };
305 }
306
307 if (op.HasProp("offset")) {
308 tie(succ, position) = op.GetProp("offset").ToInt64();
309 if (succ && position >= 0) {
310 posAssigned = true;
311 } else {
312 HILOGE("option.offset shall be positive number");
313 UniError(EINVAL).ThrowErr(env);
314 return { false, nullptr, 0, posAssigned, position };
315 }
316 }
317
318 return { true, buf, retLen, posAssigned, position };
319 }
320
GetWriteArgV9(napi_env env,napi_value argWBuf,napi_value argOption)321 tuple<bool, unique_ptr<char[]>, void *, int64_t, bool, int64_t> CommonFunc::GetWriteArgV9(napi_env env,
322 napi_value argWBuf, napi_value argOption)
323 {
324 int64_t retLen;
325 bool hasPos = false;
326 int64_t retPos;
327
328 bool succ = false;
329 void *buf = nullptr;
330 int64_t bufLen;
331 NVal op(env, argOption);
332 NVal jsBuffer(env, argWBuf);
333 unique_ptr<char[]> bufferGuard;
334 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
335 if (!succ) {
336 tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
337 if (!succ) {
338 HILOGE("Illegal write buffer or encoding");
339 UniError(EINVAL).ThrowErr(env);
340 return { false, nullptr, nullptr, 0, hasPos, retPos };
341 }
342 } else {
343 buf = bufferGuard.get();
344 }
345 tie(succ, retLen) = GetActualLenV9(env, bufLen, 0, op);
346 if (!succ) {
347 return { false, nullptr, nullptr, 0, hasPos, retPos };
348 }
349
350 if (op.HasProp("offset")) {
351 int32_t position = 0;
352 tie(succ, position) = op.GetProp("offset").ToInt32();
353 if (!succ || position < 0) {
354 HILOGE("option.offset shall be positive number");
355 UniError(EINVAL).ThrowErr(env);
356 return { false, nullptr, nullptr, 0, hasPos, retPos };
357 }
358 hasPos = true;
359 retPos = position;
360 } else {
361 retPos = INVALID_POSITION;
362 }
363 return { true, move(bufferGuard), buf, retLen, hasPos, retPos };
364 }
365
366 } // namespace ModuleFileIO
367 } // namespace DistributedFS
368 } // namespace OHOS
369