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