• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) && !defined(CROSS_PLATFORM)
38 #include "ipc_skeleton.h"
39 #include "tokenid_kit.h"
40 #endif
41 
42 namespace OHOS {
43 namespace FileManagement {
44 namespace ModuleFileIO {
45 using namespace std;
46 using namespace OHOS::FileManagement::LibN;
47 
48 namespace {
49     const std::vector<std::string> PUBLIC_DIR_PATHS = {
50         "/Documents"
51     };
52 }
53 
InitAccessModeType(napi_env env,napi_value exports)54 void InitAccessModeType(napi_env env, napi_value exports)
55 {
56     char propertyName[] = "AccessModeType";
57     napi_property_descriptor desc[] = {
58         DECLARE_NAPI_STATIC_PROPERTY("EXIST", NVal::CreateInt32(env, MODE_EXIST).val_),
59         DECLARE_NAPI_STATIC_PROPERTY("WRITE", NVal::CreateInt32(env, MODE_WRITE).val_),
60         DECLARE_NAPI_STATIC_PROPERTY("READ", NVal::CreateInt32(env, MODE_READ).val_),
61         DECLARE_NAPI_STATIC_PROPERTY("READ_WRITE", NVal::CreateInt32(env, MODE_READ_WRITE).val_),
62     };
63     napi_value obj = nullptr;
64     napi_status status = napi_create_object(env, &obj);
65     if (status != napi_ok) {
66         HILOGE("Failed to create object at initializing openMode");
67         return;
68     }
69     status = napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
70     if (status != napi_ok) {
71         HILOGE("Failed to set properties of character at initializing openMode");
72         return;
73     }
74     status = napi_set_named_property(env, exports, propertyName, obj);
75     if (status != napi_ok) {
76         HILOGE("Failed to set direction property at initializing openMode");
77         return;
78     }
79 }
80 
InitOpenMode(napi_env env,napi_value exports)81 void InitOpenMode(napi_env env, napi_value exports)
82 {
83     char propertyName[] = "OpenMode";
84     napi_property_descriptor desc[] = {
85         DECLARE_NAPI_STATIC_PROPERTY("READ_ONLY", NVal::CreateInt32(env, USR_READ_ONLY).val_),
86         DECLARE_NAPI_STATIC_PROPERTY("WRITE_ONLY", NVal::CreateInt32(env, USR_WRITE_ONLY).val_),
87         DECLARE_NAPI_STATIC_PROPERTY("READ_WRITE", NVal::CreateInt32(env, USR_RDWR).val_),
88         DECLARE_NAPI_STATIC_PROPERTY("CREATE", NVal::CreateInt32(env, USR_CREATE).val_),
89         DECLARE_NAPI_STATIC_PROPERTY("TRUNC", NVal::CreateInt32(env, USR_TRUNC).val_),
90         DECLARE_NAPI_STATIC_PROPERTY("APPEND", NVal::CreateInt32(env, USR_APPEND).val_),
91         DECLARE_NAPI_STATIC_PROPERTY("NONBLOCK", NVal::CreateInt32(env, USR_NONBLOCK).val_),
92         DECLARE_NAPI_STATIC_PROPERTY("DIR", NVal::CreateInt32(env, USR_DIRECTORY).val_),
93         DECLARE_NAPI_STATIC_PROPERTY("NOFOLLOW", NVal::CreateInt32(env, USR_NOFOLLOW).val_),
94         DECLARE_NAPI_STATIC_PROPERTY("SYNC", NVal::CreateInt32(env, USR_SYNC).val_),
95     };
96     napi_value obj = nullptr;
97     napi_status status = napi_create_object(env, &obj);
98     if (status != napi_ok) {
99         HILOGE("Failed to create object at initializing openMode");
100         return;
101     }
102     status = napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
103     if (status != napi_ok) {
104         HILOGE("Failed to set properties of character at initializing openMode");
105         return;
106     }
107     status = napi_set_named_property(env, exports, propertyName, obj);
108     if (status != napi_ok) {
109         HILOGE("Failed to set direction property at initializing openMode");
110         return;
111     }
112 }
113 
InitWhenceType(napi_env env,napi_value exports)114 void InitWhenceType(napi_env env, napi_value exports)
115 {
116     char propertyName[] = "WhenceType";
117     napi_property_descriptor desc[] = {
118         DECLARE_NAPI_STATIC_PROPERTY("SEEK_SET", NVal::CreateInt32(env, SEEK_SET).val_),
119         DECLARE_NAPI_STATIC_PROPERTY("SEEK_CUR", NVal::CreateInt32(env, SEEK_CUR).val_),
120         DECLARE_NAPI_STATIC_PROPERTY("SEEK_END", NVal::CreateInt32(env, SEEK_END).val_),
121     };
122     napi_value obj = nullptr;
123     napi_status status = napi_create_object(env, &obj);
124     if (status != napi_ok) {
125         HILOGE("Failed to create object at initializing whenceType");
126         return;
127     }
128     status = napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
129     if (status != napi_ok) {
130         HILOGE("Failed to set properties of character at initializing whenceType");
131         return;
132     }
133     status = napi_set_named_property(env, exports, propertyName, obj);
134     if (status != napi_ok) {
135         HILOGE("Failed to set direction property at initializing whenceType");
136         return;
137     }
138 }
139 
GetActualLen(napi_env env,size_t bufLen,size_t bufOff,NVal op)140 static tuple<bool, size_t> GetActualLen(napi_env env, size_t bufLen, size_t bufOff, NVal op)
141 {
142     bool succ = false;
143     size_t retLen = bufLen - bufOff;
144 
145     if (op.HasProp("length")) {
146         int64_t opLength = 0;
147 #ifdef WIN_PLATFORM
148         tie(succ, opLength) = op.GetPropValue("length").ToInt64(static_cast<int64_t>(retLen));
149 #else
150         tie(succ, opLength) = op.GetProp("length").ToInt64(static_cast<int64_t>(retLen));
151 #endif
152         if (!succ || opLength < 0 || static_cast<size_t>(opLength) > retLen) {
153             HILOGE("Invalid option.length");
154             NError(EINVAL).ThrowErr(env);
155             return { false, 0 };
156         }
157         retLen = static_cast<size_t>(opLength);
158     }
159     return { true, retLen };
160 }
161 
ConvertJsFlags(unsigned int & flags)162 unsigned int CommonFunc::ConvertJsFlags(unsigned int &flags)
163 {
164     // default value is usrReadOnly 00
165     unsigned int flagsABI = 0;
166     flagsABI |= ((flags & USR_WRITE_ONLY) == USR_WRITE_ONLY) ? WRONLY : 0;
167     flagsABI |= ((flags & USR_RDWR) == USR_RDWR) ? RDWR : 0;
168     flagsABI |= ((flags & USR_CREATE) == USR_CREATE) ? CREATE : 0;
169     flagsABI |= ((flags & USR_TRUNC) == USR_TRUNC) ? TRUNC : 0;
170     flagsABI |= ((flags & USR_APPEND) == USR_APPEND) ? APPEND : 0;
171     flagsABI |= ((flags & USR_NONBLOCK) == USR_NONBLOCK) ? NONBLOCK : 0;
172     flagsABI |= ((flags & USR_DIRECTORY) == USR_DIRECTORY) ? DIRECTORY : 0;
173     flagsABI |= ((flags & USR_NOFOLLOW) == USR_NOFOLLOW) ? NOFOLLOW : 0;
174     flagsABI |= ((flags & USR_SYNC) == USR_SYNC) ? SYNC : 0;
175     flags = flagsABI;
176     return flagsABI;
177 }
178 
179 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
InstantiateStat(napi_env env,const uv_stat_t & buf,shared_ptr<FileInfo> fileInfo,bool async)180 NVal CommonFunc::InstantiateStat(napi_env env, const uv_stat_t &buf, shared_ptr<FileInfo> fileInfo, bool async)
181 {
182     napi_value objStat = NClass::InstantiateClass(env, StatNExporter::className_, {});
183     if (!objStat) {
184         HILOGE("Failed to instantiate stat class");
185         if (async) {
186             return {env, NError(EIO).GetNapiErr(env)};
187         }
188         NError(EIO).ThrowErr(env);
189         return NVal();
190     }
191 
192     auto statEntity = NClass::GetEntityOf<StatEntity>(env, objStat);
193     if (!statEntity) {
194         HILOGE("Failed to get stat entity");
195         if (async) {
196             return {env, NError(EIO).GetNapiErr(env)};
197         }
198         NError(EIO).ThrowErr(env);
199         return NVal();
200     }
201 
202     statEntity->stat_ = buf;
203     statEntity->fileInfo_ = fileInfo;
204     return { env, objStat };
205 }
206 #endif
207 
InstantiateStat(napi_env env,const uv_stat_t & buf,bool async)208 NVal CommonFunc::InstantiateStat(napi_env env, const uv_stat_t &buf, bool async)
209 {
210     napi_value objStat = NClass::InstantiateClass(env, StatNExporter::className_, {});
211     if (!objStat) {
212         HILOGE("Failed to instantiate stat class");
213         if (async) {
214             return {env, NError(EIO).GetNapiErr(env)};
215         }
216         NError(EIO).ThrowErr(env);
217         return NVal();
218     }
219 
220     auto statEntity = NClass::GetEntityOf<StatEntity>(env, objStat);
221     if (!statEntity) {
222         HILOGE("Failed to get stat entity");
223         if (async) {
224             return {env, NError(EIO).GetNapiErr(env)};
225         }
226         NError(EIO).ThrowErr(env);
227         return NVal();
228     }
229 
230     statEntity->stat_ = buf;
231     return { env, objStat };
232 }
233 
234 #ifndef WIN_PLATFORM
InstantiateFile(napi_env env,int fd,const string & pathOrUri,bool isUri)235 NVal CommonFunc::InstantiateFile(napi_env env, int fd, const string &pathOrUri, bool isUri)
236 {
237     napi_value objFile = NClass::InstantiateClass(env, FileNExporter::className_, {});
238     if (!objFile) {
239         HILOGE("Failed to instantiate class");
240         NError(EIO).ThrowErr(env);
241         close(fd);
242         return NVal();
243     }
244 
245     auto fileEntity = NClass::GetEntityOf<FileEntity>(env, objFile);
246     if (!fileEntity) {
247         HILOGE("Failed to get fileEntity");
248         NError(EIO).ThrowErr(env);
249         close(fd);
250         return NVal();
251     }
252     auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(fd, false);
253     if (fdg == nullptr) {
254         HILOGE("Failed to request heap memory.");
255         close(fd);
256         NError(ENOMEM).ThrowErr(env);
257         return NVal();
258     }
259     fileEntity->fd_.swap(fdg);
260     if (isUri) {
261         fileEntity->path_ = "";
262         fileEntity->uri_ = pathOrUri;
263     } else {
264         fileEntity->path_ = pathOrUri;
265         fileEntity->uri_ = "";
266     }
267     return { env, objFile };
268 }
269 
InstantiateStream(napi_env env,shared_ptr<FILE> fp,bool async)270 NVal CommonFunc::InstantiateStream(napi_env env, shared_ptr<FILE> fp, bool async)
271 {
272     napi_value objStream = NClass::InstantiateClass(env, StreamNExporter::className_, {});
273     if (!objStream) {
274         HILOGE("INNER BUG. Cannot instantiate stream");
275         if (async) {
276             return {env, NError(EIO).GetNapiErr(env)};
277         }
278         NError(EIO).ThrowErr(env);
279         return NVal();
280     }
281 
282     auto streamEntity = NClass::GetEntityOf<StreamEntity>(env, objStream);
283     if (!streamEntity) {
284         HILOGE("Cannot instantiate stream because of void entity");
285         if (async) {
286             return {env, NError(EIO).GetNapiErr(env)};
287         }
288         NError(EIO).ThrowErr(env);
289         return NVal();
290     }
291     streamEntity->fp.swap(fp);
292     return { env, objStream };
293 }
294 #endif
295 
fs_req_cleanup(uv_fs_t * req)296 void CommonFunc::fs_req_cleanup(uv_fs_t* req)
297 {
298     uv_fs_req_cleanup(req);
299     if (req) {
300         delete req;
301         req = nullptr;
302     }
303 }
304 
GetModeFromFlags(unsigned int flags)305 string CommonFunc::GetModeFromFlags(unsigned int flags)
306 {
307     const string readMode = "r";
308     const string writeMode = "w";
309     const string appendMode = "a";
310     const string truncMode = "t";
311     string mode = readMode;
312     mode += (((flags & O_RDWR) == O_RDWR) ? writeMode : "");
313     mode = (((flags & O_WRONLY) == O_WRONLY) ? writeMode : mode);
314     if (mode != readMode) {
315         mode += ((flags & O_TRUNC) ? truncMode : "");
316         mode += ((flags & O_APPEND) ? appendMode : "");
317     }
318     return mode;
319 }
320 
CheckPublicDirPath(const std::string & sandboxPath)321 bool CommonFunc::CheckPublicDirPath(const std::string &sandboxPath)
322 {
323     for (const std::string &path : PUBLIC_DIR_PATHS) {
324         if (sandboxPath.find(path) == 0) {
325             return true;
326         }
327     }
328     return false;
329 }
330 
Decode(const std::string & uri)331 string CommonFunc::Decode(const std::string &uri)
332 {
333     std::ostringstream outPutStream;
334     const int32_t encodeLen = 2;
335     size_t index = 0;
336     while (index < uri.length()) {
337         if (uri[index] == '%') {
338             int hex = 0;
339             std::istringstream inputStream(uri.substr(index + 1, encodeLen));
340             inputStream >> std::hex >> hex;
341             outPutStream << static_cast<char>(hex);
342             index += encodeLen + 1;
343         } else {
344             outPutStream << uri[index];
345             index++;
346         }
347     }
348 
349     return outPutStream.str();
350 }
351 
352 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) && !defined(CROSS_PLATFORM)
IsNumeric(const string & str)353 bool IsNumeric(const string &str)
354 {
355     if (str.empty()) {
356         return false;
357     }
358     for (char const &c : str) {
359         if (!isdigit(c)) {
360             return false;
361         }
362     }
363     return true;
364 }
365 
SetQueryMap(Uri * uri,std::unordered_map<std::string,std::string> & queryMap)366 void SetQueryMap(Uri* uri, std::unordered_map<std::string,
367       std::string> &queryMap)
368 {
369     // file://media/image/12?networkid=xxxx&api_version=xxxx?times=xxx&user=101
370     string query = uri->GetQuery();
371     string pairString;
372     stringstream queryStream(query);
373 
374     while (getline(queryStream, pairString, '&')) {
375         size_t splitIndex = pairString.find('=');
376         if (splitIndex == string::npos || splitIndex == (pairString.length() - 1)) {
377             HILOGE("failed to parse query, query field is %{private}s!", pairString.c_str());
378             continue;
379         }
380         queryMap[pairString.substr(0, splitIndex)] = pairString.substr(splitIndex + 1);
381     }
382     return;
383 }
384 
GetAndCheckUserId(Uri * uri,string & userId)385 bool CommonFunc::GetAndCheckUserId(Uri* uri, string &userId)
386 {
387     if (uri->ToString().find("user=") == string::npos) {
388         return false;
389     }
390 
391     std::unordered_map<std::string, std::string> queryMap;
392     SetQueryMap(uri, queryMap);
393     auto it = queryMap.find("user");
394     if (it != queryMap.end()) {
395         userId = it->second;
396         if (!IsNumeric(userId)) {
397             HILOGE("IsNumeric check fail");
398             return false;
399         }
400         return true;
401     } else {
402         HILOGE("GetAndCheckUserId no match userId");
403     }
404     return false;
405 }
406 
407 /*
408  * For compatibility considerations, filtering system applications require non permission verification
409 */
IsSystemApp()410 bool CommonFunc::IsSystemApp()
411 {
412     uint64_t fullTokenId = OHOS::IPCSkeleton::GetSelfTokenID();
413     return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullTokenId);
414 }
415 #endif
416 
GetCopyPathArg(napi_env env,napi_value srcPath,napi_value dstPath)417 tuple<bool, unique_ptr<char[]>, unique_ptr<char[]>> CommonFunc::GetCopyPathArg(napi_env env,
418                                                                                napi_value srcPath,
419                                                                                napi_value dstPath)
420 {
421     bool succ = false;
422     unique_ptr<char[]> src = nullptr;
423     tie(succ, src, ignore) = NVal(env, srcPath).ToUTF8StringPath();
424     if (!succ) {
425         HILOGE("Failed to convert the src path to UTF-8 string");
426         return { false, nullptr, nullptr };
427     }
428 
429     unique_ptr<char[]> dest = nullptr;
430     tie(succ, dest, ignore) = NVal(env, dstPath).ToUTF8StringPath();
431     if (!succ) {
432         HILOGE("Failed to convert the dest path to UTF-8 string");
433         return { false, nullptr, nullptr };
434     }
435     return make_tuple(true, move(src), move(dest));
436 }
437 
DecodeString(napi_env env,NVal jsStr,NVal encoding)438 static tuple<bool, unique_ptr<char[]>, size_t> DecodeString(napi_env env, NVal jsStr, NVal encoding)
439 {
440     if (!jsStr.TypeIs(napi_string)) {
441         return { false, nullptr, 0 };
442     }
443     if (!encoding) {
444         return jsStr.ToUTF8String();
445     }
446 
447     bool succ = false;
448     unique_ptr<char[]> encodingBuf = nullptr;
449     tie(succ, encodingBuf, ignore) = encoding.ToUTF8String("utf-8");
450     if (!succ) {
451         HILOGE("Failed to convert encoding to UTF8");
452         return { false, nullptr, 0 };
453     }
454 
455     string_view encodingStr(encodingBuf.get());
456     if (encodingStr == "utf-8") {
457         return jsStr.ToUTF8String();
458     } else if (encodingStr == "utf-16") {
459         return jsStr.ToUTF16String();
460     } else {
461         HILOGE("Failed to recognize the str type");
462         return { false, nullptr, 0 };
463     }
464 }
465 
GetReadArg(napi_env env,napi_value readBuf,napi_value option)466 tuple<bool, void *, size_t, int64_t> CommonFunc::GetReadArg(napi_env env,
467     napi_value readBuf, napi_value option)
468 {
469     size_t retLen = 0;
470     int64_t offset = -1;
471     bool succ = false;
472 
473     NVal txt(env, readBuf);
474     void *buf = nullptr;
475     size_t bufLen = 0;
476     tie(succ, buf, bufLen) = txt.ToArraybuffer();
477     if (!succ || bufLen > UINT_MAX) {
478         HILOGE("Invalid arraybuffer");
479         NError(EINVAL).ThrowErr(env);
480         return { false, nullptr, retLen, offset };
481     }
482     NVal op = NVal(env, option);
483     tie(succ, retLen) = GetActualLen(env, bufLen, 0, op);
484     if (!succ) {
485         HILOGE("Failed to get actual length");
486         return { false, nullptr, retLen, offset };
487     }
488 #ifdef WIN_PLATFORM
489     if (op.HasProp("offset") && !op.GetPropValue("offset").TypeIs(napi_undefined)) {
490         tie(succ, offset) = op.GetPropValue("offset").ToInt64();
491 #else
492     if (op.HasProp("offset") && !op.GetProp("offset").TypeIs(napi_undefined)) {
493         tie(succ, offset) = op.GetProp("offset").ToInt64();
494 #endif
495         if (!succ || offset < 0) {
496             HILOGE("option.offset shall be positive number");
497             NError(EINVAL).ThrowErr(env);
498             return { false, nullptr, retLen, offset };
499         }
500     }
501     return { true, buf, retLen, offset };
502 }
503 
504 tuple<bool, unique_ptr<char[]>, void *, size_t, int64_t> CommonFunc::GetWriteArg(napi_env env,
505     napi_value argWBuf, napi_value argOption)
506 {
507     size_t bufLen = 0;
508     int64_t offset = -1;
509     bool succ = false;
510     void *buf = nullptr;
511     NVal op(env, argOption);
512     NVal jsBuffer(env, argWBuf);
513     unique_ptr<char[]> bufferGuard = nullptr;
514 #ifdef WIN_PLATFORM
515     tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetPropValue("encoding"));
516 #else
517     tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
518 #endif
519     if (!succ) {
520         tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
521         if (!succ) {
522             HILOGE("Illegal write buffer or encoding");
523             NError(EINVAL).ThrowErr(env);
524             return { false, nullptr, nullptr, 0, offset };
525         }
526     } else {
527         buf = bufferGuard.get();
528     }
529     if (bufLen > UINT_MAX) {
530         HILOGE("The Size of buffer is too large");
531         NError(EINVAL).ThrowErr(env);
532         return { false, nullptr, nullptr, 0, offset } ;
533     }
534     size_t retLen = 0;
535     tie(succ, retLen) = GetActualLen(env, bufLen, 0, op);
536     if (!succ) {
537         HILOGE("Failed to get actual length");
538         return { false, nullptr, nullptr, 0, offset };
539     }
540 
541 #ifdef WIN_PLATFORM
542     if (op.HasProp("offset") && !op.GetPropValue("offset").TypeIs(napi_undefined)) {
543         tie(succ, offset) = op.GetPropValue("offset").ToInt64();
544 #else
545     if (op.HasProp("offset") && !op.GetProp("offset").TypeIs(napi_undefined)) {
546         tie(succ, offset) = op.GetProp("offset").ToInt64();
547 #endif
548         if (!succ || offset < 0) {
549             HILOGE("option.offset shall be positive number");
550             NError(EINVAL).ThrowErr(env);
551             return { false, nullptr, nullptr, 0, offset };
552         }
553     }
554     return { true, move(bufferGuard), buf, retLen, offset };
555 }
556 } // namespace ModuleFileIO
557 } // namespace FileManagement
558 } // namespace OHOS
559