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