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