1 /*
2 * Copyright (c) 2022-2023 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 <sstream>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <vector>
25
26 #include "class_stat/stat_entity.h"
27 #include "class_stat/stat_n_exporter.h"
28 #ifndef WIN_PLATFORM
29 #include "class_file/file_entity.h"
30 #include "class_file/file_n_exporter.h"
31 #include "class_stream/stream_entity.h"
32 #include "class_stream/stream_n_exporter.h"
33 #endif
34 #include "filemgmt_libhilog.h"
35 #include "filemgmt_libn.h"
36 #include "file_utils.h"
37
38 namespace OHOS {
39 namespace FileManagement {
40 namespace ModuleFileIO {
41 using namespace std;
42 using namespace OHOS::FileManagement::LibN;
43
44 namespace {
45 const std::vector<std::string> PUBLIC_DIR_PATHS = {
46 "/Documents"
47 };
48 }
49
InitAccessModeType(napi_env env,napi_value exports)50 void InitAccessModeType(napi_env env, napi_value exports)
51 {
52 char propertyName[] = "AccessModeType";
53 napi_property_descriptor desc[] = {
54 DECLARE_NAPI_STATIC_PROPERTY("EXIST", NVal::CreateInt32(env, MODE_EXIST).val_),
55 DECLARE_NAPI_STATIC_PROPERTY("WRITE", NVal::CreateInt32(env, MODE_WRITE).val_),
56 DECLARE_NAPI_STATIC_PROPERTY("READ", NVal::CreateInt32(env, MODE_READ).val_),
57 DECLARE_NAPI_STATIC_PROPERTY("READ_WRITE", NVal::CreateInt32(env, MODE_READ_WRITE).val_),
58 };
59 napi_value obj = nullptr;
60 napi_status status = napi_create_object(env, &obj);
61 if (status != napi_ok) {
62 HILOGE("Failed to create object at initializing openMode");
63 return;
64 }
65 status = napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
66 if (status != napi_ok) {
67 HILOGE("Failed to set properties of character at initializing openMode");
68 return;
69 }
70 status = napi_set_named_property(env, exports, propertyName, obj);
71 if (status != napi_ok) {
72 HILOGE("Failed to set direction property at initializing openMode");
73 return;
74 }
75 }
76
InitOpenMode(napi_env env,napi_value exports)77 void InitOpenMode(napi_env env, napi_value exports)
78 {
79 char propertyName[] = "OpenMode";
80 napi_property_descriptor desc[] = {
81 DECLARE_NAPI_STATIC_PROPERTY("READ_ONLY", NVal::CreateInt32(env, USR_READ_ONLY).val_),
82 DECLARE_NAPI_STATIC_PROPERTY("WRITE_ONLY", NVal::CreateInt32(env, USR_WRITE_ONLY).val_),
83 DECLARE_NAPI_STATIC_PROPERTY("READ_WRITE", NVal::CreateInt32(env, USR_RDWR).val_),
84 DECLARE_NAPI_STATIC_PROPERTY("CREATE", NVal::CreateInt32(env, USR_CREATE).val_),
85 DECLARE_NAPI_STATIC_PROPERTY("TRUNC", NVal::CreateInt32(env, USR_TRUNC).val_),
86 DECLARE_NAPI_STATIC_PROPERTY("APPEND", NVal::CreateInt32(env, USR_APPEND).val_),
87 DECLARE_NAPI_STATIC_PROPERTY("NONBLOCK", NVal::CreateInt32(env, USR_NONBLOCK).val_),
88 DECLARE_NAPI_STATIC_PROPERTY("DIR", NVal::CreateInt32(env, USR_DIRECTORY).val_),
89 DECLARE_NAPI_STATIC_PROPERTY("NOFOLLOW", NVal::CreateInt32(env, USR_NOFOLLOW).val_),
90 DECLARE_NAPI_STATIC_PROPERTY("SYNC", NVal::CreateInt32(env, USR_SYNC).val_),
91 };
92 napi_value obj = nullptr;
93 napi_status status = napi_create_object(env, &obj);
94 if (status != napi_ok) {
95 HILOGE("Failed to create object at initializing openMode");
96 return;
97 }
98 status = napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
99 if (status != napi_ok) {
100 HILOGE("Failed to set properties of character at initializing openMode");
101 return;
102 }
103 status = napi_set_named_property(env, exports, propertyName, obj);
104 if (status != napi_ok) {
105 HILOGE("Failed to set direction property at initializing openMode");
106 return;
107 }
108 }
109
InitWhenceType(napi_env env,napi_value exports)110 void InitWhenceType(napi_env env, napi_value exports)
111 {
112 char propertyName[] = "WhenceType";
113 napi_property_descriptor desc[] = {
114 DECLARE_NAPI_STATIC_PROPERTY("SEEK_SET", NVal::CreateInt32(env, SEEK_SET).val_),
115 DECLARE_NAPI_STATIC_PROPERTY("SEEK_CUR", NVal::CreateInt32(env, SEEK_CUR).val_),
116 DECLARE_NAPI_STATIC_PROPERTY("SEEK_END", NVal::CreateInt32(env, SEEK_END).val_),
117 };
118 napi_value obj = nullptr;
119 napi_status status = napi_create_object(env, &obj);
120 if (status != napi_ok) {
121 HILOGE("Failed to create object at initializing whenceType");
122 return;
123 }
124 status = napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
125 if (status != napi_ok) {
126 HILOGE("Failed to set properties of character at initializing whenceType");
127 return;
128 }
129 status = napi_set_named_property(env, exports, propertyName, obj);
130 if (status != napi_ok) {
131 HILOGE("Failed to set direction property at initializing whenceType");
132 return;
133 }
134 }
135
GetActualLen(napi_env env,size_t bufLen,size_t bufOff,NVal op)136 static tuple<bool, size_t> GetActualLen(napi_env env, size_t bufLen, size_t bufOff, NVal op)
137 {
138 bool succ = false;
139 size_t retLen = bufLen - bufOff;
140
141 if (op.HasProp("length")) {
142 int64_t opLength = 0;
143 #ifdef WIN_PLATFORM
144 tie(succ, opLength) = op.GetPropValue("length").ToInt64(static_cast<int64_t>(retLen));
145 #else
146 tie(succ, opLength) = op.GetProp("length").ToInt64(static_cast<int64_t>(retLen));
147 #endif
148 if (!succ || opLength < 0 || static_cast<size_t>(opLength) > retLen) {
149 HILOGE("Invalid option.length");
150 NError(EINVAL).ThrowErr(env);
151 return { false, 0 };
152 }
153 retLen = static_cast<size_t>(opLength);
154 }
155 return { true, retLen };
156 }
157
ConvertJsFlags(unsigned int & flags)158 unsigned int CommonFunc::ConvertJsFlags(unsigned int &flags)
159 {
160 // default value is usrReadOnly 00
161 unsigned int flagsABI = 0;
162 flagsABI |= ((flags & USR_WRITE_ONLY) == USR_WRITE_ONLY) ? WRONLY : 0;
163 flagsABI |= ((flags & USR_RDWR) == USR_RDWR) ? RDWR : 0;
164 flagsABI |= ((flags & USR_CREATE) == USR_CREATE) ? CREATE : 0;
165 flagsABI |= ((flags & USR_TRUNC) == USR_TRUNC) ? TRUNC : 0;
166 flagsABI |= ((flags & USR_APPEND) == USR_APPEND) ? APPEND : 0;
167 flagsABI |= ((flags & USR_NONBLOCK) == USR_NONBLOCK) ? NONBLOCK : 0;
168 flagsABI |= ((flags & USR_DIRECTORY) == USR_DIRECTORY) ? DIRECTORY : 0;
169 flagsABI |= ((flags & USR_NOFOLLOW) == USR_NOFOLLOW) ? NOFOLLOW : 0;
170 flagsABI |= ((flags & USR_SYNC) == USR_SYNC) ? SYNC : 0;
171 flags = flagsABI;
172 return flagsABI;
173 }
174
175 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
InstantiateStat(napi_env env,const uv_stat_t & buf,shared_ptr<FileInfo> fileInfo)176 NVal CommonFunc::InstantiateStat(napi_env env, const uv_stat_t &buf, shared_ptr<FileInfo> fileInfo)
177 {
178 napi_value objStat = NClass::InstantiateClass(env, StatNExporter::className_, {});
179 if (!objStat) {
180 HILOGE("Failed to instantiate stat class");
181 NError(EIO).ThrowErr(env);
182 return NVal();
183 }
184
185 auto statEntity = NClass::GetEntityOf<StatEntity>(env, objStat);
186 if (!statEntity) {
187 HILOGE("Failed to get stat entity");
188 NError(EIO).ThrowErr(env);
189 return NVal();
190 }
191
192 statEntity->stat_ = buf;
193 statEntity->fileInfo_ = fileInfo;
194 return { env, objStat };
195 }
196 #endif
197
InstantiateStat(napi_env env,const uv_stat_t & buf)198 NVal CommonFunc::InstantiateStat(napi_env env, const uv_stat_t &buf)
199 {
200 napi_value objStat = NClass::InstantiateClass(env, StatNExporter::className_, {});
201 if (!objStat) {
202 HILOGE("Failed to instantiate stat class");
203 NError(EIO).ThrowErr(env);
204 return NVal();
205 }
206
207 auto statEntity = NClass::GetEntityOf<StatEntity>(env, objStat);
208 if (!statEntity) {
209 HILOGE("Failed to get stat entity");
210 NError(EIO).ThrowErr(env);
211 return NVal();
212 }
213
214 statEntity->stat_ = buf;
215 return { env, objStat };
216 }
217
218 #ifndef WIN_PLATFORM
InstantiateFile(napi_env env,int fd,const string & pathOrUri,bool isUri)219 NVal CommonFunc::InstantiateFile(napi_env env, int fd, const string &pathOrUri, bool isUri)
220 {
221 napi_value objFile = NClass::InstantiateClass(env, FileNExporter::className_, {});
222 if (!objFile) {
223 HILOGE("Failed to instantiate class");
224 NError(EIO).ThrowErr(env);
225 close(fd);
226 return NVal();
227 }
228
229 auto fileEntity = NClass::GetEntityOf<FileEntity>(env, objFile);
230 if (!fileEntity) {
231 HILOGE("Failed to get fileEntity");
232 NError(EIO).ThrowErr(env);
233 close(fd);
234 return NVal();
235 }
236 auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(fd, false);
237 if (fdg == nullptr) {
238 HILOGE("Failed to request heap memory.");
239 close(fd);
240 NError(ENOMEM).ThrowErr(env);
241 return NVal();
242 }
243 fileEntity->fd_.swap(fdg);
244 if (isUri) {
245 fileEntity->path_ = "";
246 fileEntity->uri_ = pathOrUri;
247 } else {
248 fileEntity->path_ = pathOrUri;
249 fileEntity->uri_ = "";
250 }
251 return { env, objFile };
252 }
253
InstantiateStream(napi_env env,shared_ptr<FILE> fp)254 NVal CommonFunc::InstantiateStream(napi_env env, shared_ptr<FILE> fp)
255 {
256 napi_value objStream = NClass::InstantiateClass(env, StreamNExporter::className_, {});
257 if (!objStream) {
258 HILOGE("INNER BUG. Cannot instantiate stream");
259 NError(EIO).ThrowErr(env);
260 return NVal();
261 }
262
263 auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, objStream);
264 if (!streamEntity) {
265 HILOGE("Cannot instantiate stream because of void entity");
266 NError(EIO).ThrowErr(env);
267 return NVal();
268 }
269
270 streamEntity->fp.swap(fp);
271 return { env, objStream };
272 }
273 #endif
274
fs_req_cleanup(uv_fs_t * req)275 void CommonFunc::fs_req_cleanup(uv_fs_t* req)
276 {
277 uv_fs_req_cleanup(req);
278 if (req) {
279 delete req;
280 req = nullptr;
281 }
282 }
283
GetModeFromFlags(unsigned int flags)284 string CommonFunc::GetModeFromFlags(unsigned int flags)
285 {
286 const string readMode = "r";
287 const string writeMode = "w";
288 const string appendMode = "a";
289 const string truncMode = "t";
290 string mode = readMode;
291 mode += (((flags & O_RDWR) == O_RDWR) ? writeMode : "");
292 mode = (((flags & O_WRONLY) == O_WRONLY) ? writeMode : mode);
293 if (mode != readMode) {
294 mode += ((flags & O_TRUNC) ? truncMode : "");
295 mode += ((flags & O_APPEND) ? appendMode : "");
296 }
297 return mode;
298 }
299
CheckPublicDirPath(const std::string & sandboxPath)300 bool CommonFunc::CheckPublicDirPath(const std::string &sandboxPath)
301 {
302 for (const std::string &path : PUBLIC_DIR_PATHS) {
303 if (sandboxPath.find(path) == 0) {
304 return true;
305 }
306 }
307 return false;
308 }
309
Decode(const std::string & uri)310 string CommonFunc::Decode(const std::string &uri)
311 {
312 std::ostringstream outPutStream;
313 const int32_t encodeLen = 2;
314 size_t index = 0;
315 while (index < uri.length()) {
316 if (uri[index] == '%') {
317 int hex = 0;
318 std::istringstream inputStream(uri.substr(index + 1, encodeLen));
319 inputStream >> std::hex >> hex;
320 outPutStream << static_cast<char>(hex);
321 index += encodeLen + 1;
322 } else {
323 outPutStream << uri[index];
324 index++;
325 }
326 }
327
328 return outPutStream.str();
329 }
330
GetCopyPathArg(napi_env env,napi_value srcPath,napi_value dstPath)331 tuple<bool, unique_ptr<char[]>, unique_ptr<char[]>> CommonFunc::GetCopyPathArg(napi_env env,
332 napi_value srcPath,
333 napi_value dstPath)
334 {
335 bool succ = false;
336 unique_ptr<char[]> src = nullptr;
337 tie(succ, src, ignore) = NVal(env, srcPath).ToUTF8StringPath();
338 if (!succ) {
339 HILOGE("Failed to convert the src path to UTF-8 string");
340 return { false, nullptr, nullptr };
341 }
342
343 unique_ptr<char[]> dest = nullptr;
344 tie(succ, dest, ignore) = NVal(env, dstPath).ToUTF8StringPath();
345 if (!succ) {
346 HILOGE("Failed to convert the dest path to UTF-8 string");
347 return { false, nullptr, nullptr };
348 }
349 return make_tuple(true, move(src), move(dest));
350 }
351
DecodeString(napi_env env,NVal jsStr,NVal encoding)352 static tuple<bool, unique_ptr<char[]>, size_t> DecodeString(napi_env env, NVal jsStr, NVal encoding)
353 {
354 if (!jsStr.TypeIs(napi_string)) {
355 return { false, nullptr, 0 };
356 }
357 if (!encoding) {
358 return jsStr.ToUTF8String();
359 }
360
361 bool succ = false;
362 unique_ptr<char[]> encodingBuf = nullptr;
363 tie(succ, encodingBuf, ignore) = encoding.ToUTF8String("utf-8");
364 if (!succ) {
365 HILOGE("Failed to convert encoding to UTF8");
366 return { false, nullptr, 0 };
367 }
368
369 string_view encodingStr(encodingBuf.get());
370 if (encodingStr == "utf-8") {
371 return jsStr.ToUTF8String();
372 } else if (encodingStr == "utf-16") {
373 return jsStr.ToUTF16String();
374 } else {
375 HILOGE("Failed to recognize the str type");
376 return { false, nullptr, 0 };
377 }
378 }
379
GetReadArg(napi_env env,napi_value readBuf,napi_value option)380 tuple<bool, void *, size_t, int64_t> CommonFunc::GetReadArg(napi_env env,
381 napi_value readBuf, napi_value option)
382 {
383 size_t retLen = 0;
384 int64_t offset = -1;
385 bool succ = false;
386
387 NVal txt(env, readBuf);
388 void *buf = nullptr;
389 size_t bufLen = 0;
390 tie(succ, buf, bufLen) = txt.ToArraybuffer();
391 if (!succ || bufLen > UINT_MAX) {
392 HILOGE("Invalid arraybuffer");
393 NError(EINVAL).ThrowErr(env);
394 return { false, nullptr, retLen, offset };
395 }
396 NVal op = NVal(env, option);
397 tie(succ, retLen) = GetActualLen(env, bufLen, 0, op);
398 if (!succ) {
399 HILOGE("Failed to get actual length");
400 return { false, nullptr, retLen, offset };
401 }
402 #ifdef WIN_PLATFORM
403 if (op.HasProp("offset") && !op.GetPropValue("offset").TypeIs(napi_undefined)) {
404 tie(succ, offset) = op.GetPropValue("offset").ToInt64();
405 #else
406 if (op.HasProp("offset") && !op.GetProp("offset").TypeIs(napi_undefined)) {
407 tie(succ, offset) = op.GetProp("offset").ToInt64();
408 #endif
409 if (!succ || offset < 0) {
410 HILOGE("option.offset shall be positive number");
411 NError(EINVAL).ThrowErr(env);
412 return { false, nullptr, retLen, offset };
413 }
414 }
415 return { true, buf, retLen, offset };
416 }
417
418 tuple<bool, unique_ptr<char[]>, void *, size_t, int64_t> CommonFunc::GetWriteArg(napi_env env,
419 napi_value argWBuf, napi_value argOption)
420 {
421 size_t bufLen = 0;
422 int64_t offset = -1;
423 bool succ = false;
424 void *buf = nullptr;
425 NVal op(env, argOption);
426 NVal jsBuffer(env, argWBuf);
427 unique_ptr<char[]> bufferGuard = nullptr;
428 #ifdef WIN_PLATFORM
429 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetPropValue("encoding"));
430 #else
431 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
432 #endif
433 if (!succ) {
434 tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
435 if (!succ) {
436 HILOGE("Illegal write buffer or encoding");
437 NError(EINVAL).ThrowErr(env);
438 return { false, nullptr, nullptr, 0, offset };
439 }
440 } else {
441 buf = bufferGuard.get();
442 }
443 if (bufLen > UINT_MAX) {
444 HILOGE("The Size of buffer is too large");
445 NError(EINVAL).ThrowErr(env);
446 return { false, nullptr, nullptr, 0, offset } ;
447 }
448 size_t retLen = 0;
449 tie(succ, retLen) = GetActualLen(env, bufLen, 0, op);
450 if (!succ) {
451 HILOGE("Failed to get actual length");
452 return { false, nullptr, nullptr, 0, offset };
453 }
454
455 #ifdef WIN_PLATFORM
456 if (op.HasProp("offset") && !op.GetPropValue("offset").TypeIs(napi_undefined)) {
457 tie(succ, offset) = op.GetPropValue("offset").ToInt64();
458 #else
459 if (op.HasProp("offset") && !op.GetProp("offset").TypeIs(napi_undefined)) {
460 tie(succ, offset) = op.GetProp("offset").ToInt64();
461 #endif
462 if (!succ || offset < 0) {
463 HILOGE("option.offset shall be positive number");
464 NError(EINVAL).ThrowErr(env);
465 return { false, nullptr, nullptr, 0, offset };
466 }
467 }
468 return { true, move(bufferGuard), buf, retLen, offset };
469 }
470 } // namespace ModuleFileIO
471 } // namespace FileManagement
472 } // namespace OHOS
473