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 #include "file_uri_n_exporter.h"
16 
17 #include <string>
18 #include <vector>
19 
20 #include "file_uri_entity.h"
21 #include "file_utils.h"
22 #include "log.h"
23 #include "uri.h"
24 #include "sandbox_helper.h"
25 
26 using namespace std;
27 namespace OHOS {
28 namespace AppFileService {
29 namespace ModuleFileUri {
30 using namespace FileManagement;
31 using namespace FileManagement::LibN;
32 const std::string MEDIA_AUTHORITY = "media";
Constructor(napi_env env,napi_callback_info info)33 napi_value FileUriNExporter::Constructor(napi_env env, napi_callback_info info)
34 {
35     NFuncArg funcArg(env, info);
36     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
37         LOGE("Number of arguments unmatched");
38         NError(EINVAL).ThrowErr(env);
39         return nullptr;
40     }
41     auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
42     if (!succPath) {
43         LOGE("Failed to get path");
44         NError(EINVAL).ThrowErr(env);
45         return nullptr;
46     }
47     auto fileuriEntity = CreateUniquePtr<FileUriEntity>(string(path.get()));
48     if (fileuriEntity == nullptr) {
49         LOGE("Failed to request heap memory.");
50         NError(ENOMEM).ThrowErr(env);
51         return nullptr;
52     }
53     if (!NClass::SetEntityFor<FileUriEntity>(env, funcArg.GetThisVar(), move(fileuriEntity))) {
54         LOGE("Failed to set file entity");
55         NError(EIO).ThrowErr(env);
56         return nullptr;
57     }
58     return funcArg.GetThisVar();
59 }
60 
UriToString(napi_env env,napi_callback_info info)61 napi_value FileUriNExporter::UriToString(napi_env env, napi_callback_info info)
62 {
63     NFuncArg funcArg(env, info);
64     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
65         LOGE("Number of arguments unmatched");
66         NError(EINVAL).ThrowErr(env);
67         return nullptr;
68     }
69     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
70     if (!fileuriEntity) {
71         LOGE("Failed to get file entity");
72         NError(EINVAL).ThrowErr(env);
73         return nullptr;
74     }
75     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.ToString()).val_;
76 }
77 
GetFileUriName(napi_env env,napi_callback_info info)78 napi_value FileUriNExporter::GetFileUriName(napi_env env, napi_callback_info info)
79 {
80     NFuncArg funcArg(env, info);
81     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
82         LOGE("Number of arguments unmatched");
83         NError(EINVAL).ThrowErr(env);
84         return nullptr;
85     }
86     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
87     if (!fileuriEntity) {
88         LOGE("Failed to get file entity");
89         NError(EINVAL).ThrowErr(env);
90         return nullptr;
91     }
92     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.GetName()).val_;
93 }
94 
GetFullDirectoryUri(napi_env env,napi_callback_info info)95 napi_value FileUriNExporter::GetFullDirectoryUri(napi_env env, napi_callback_info info)
96 {
97     NFuncArg funcArg(env, info);
98     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
99         LOGE("Number of arguments unmatched");
100         NError(E_PARAMS).ThrowErr(env);
101         return nullptr;
102     }
103     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
104     if (!fileuriEntity) {
105         LOGE("Failed to get file entity");
106         NError(EINVAL).ThrowErr(env);
107         return nullptr;
108     }
109     string uri = fileuriEntity->fileUri_.GetFullDirectoryUri();
110     if (uri == "") {
111         LOGE("No such file or directory!");
112         NError(ENOENT).ThrowErr(env);
113     }
114     return NVal::CreateUTF8String(env, uri).val_;
115 }
116 
IsRemoteUri(napi_env env,napi_callback_info info)117 napi_value FileUriNExporter::IsRemoteUri(napi_env env, napi_callback_info info)
118 {
119     NFuncArg funcArg(env, info);
120     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
121         LOGE("Number of arguments unmatched");
122         NError(E_PARAMS).ThrowErr(env);
123         return nullptr;
124     }
125     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
126     if (!fileuriEntity) {
127         LOGE("Failed to get file entity");
128         NError(EINVAL).ThrowErr(env);
129         return nullptr;
130     }
131     bool isRemoteUri = fileuriEntity->fileUri_.IsRemoteUri();
132     return NVal::CreateBool(env, isRemoteUri).val_;
133 }
134 
GetFileUriPath(napi_env env,napi_callback_info info)135 napi_value FileUriNExporter::GetFileUriPath(napi_env env, napi_callback_info info)
136 {
137     NFuncArg funcArg(env, info);
138     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
139         LOGE("Number of arguments unmatched");
140         NError(EINVAL).ThrowErr(env);
141         return nullptr;
142     }
143     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
144     if (!fileuriEntity) {
145         LOGE("Failed to get file entity");
146         NError(EINVAL).ThrowErr(env);
147         return nullptr;
148     }
149     string bundleName = fileuriEntity->fileUri_.uri_.GetAuthority();
150     if (bundleName == MEDIA_AUTHORITY) {
151         return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.GetPath()).val_;
152     }
153     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.GetRealPath()).val_;
154 }
155 
Split(const std::string & path,Uri & uri)156 static std::string Split(const std::string &path, Uri &uri)
157 {
158     std::string normalizeUri = "";
159     if (!uri.GetScheme().empty()) {
160         normalizeUri += uri.GetScheme() + ":";
161     }
162     if (uri.GetPath().empty()) {
163         normalizeUri += uri.GetSchemeSpecificPart();
164     } else {
165         if (!uri.GetHost().empty()) {
166             normalizeUri += "//";
167             if (!uri.GetUserInfo().empty()) {
168                 normalizeUri += uri.GetUserInfo() + "@";
169             }
170             normalizeUri += uri.GetHost();
171             if (uri.GetPort() != -1) {
172                 normalizeUri += ":" + std::to_string(uri.GetPort());
173             }
174         } else if (!uri.GetAuthority().empty()) {
175             normalizeUri += "//" + uri.GetAuthority();
176         }
177         normalizeUri += path;
178     }
179     if (!uri.GetQuery().empty()) {
180         normalizeUri += "?" + uri.GetQuery();
181     }
182     if (!uri.GetFragment().empty()) {
183         normalizeUri += "#" + uri.GetFragment();
184     }
185     return normalizeUri;
186 }
187 
NormalizeUri(Uri & uri)188 static std::string NormalizeUri(Uri &uri)
189 {
190     std::vector<std::string> temp;
191     size_t pathLen = uri.GetPath().size();
192     if (pathLen == 0) {
193         return uri.ToString();
194     }
195     size_t pos = 0;
196     size_t left = 0;
197     while ((pos = uri.GetPath().find('/', left)) != std::string::npos) {
198         temp.push_back(uri.GetPath().substr(left, pos - left));
199         left = pos + 1;
200     }
201     if (left != pathLen) {
202         temp.push_back(uri.GetPath().substr(left));
203     }
204     size_t tempLen = temp.size();
205     std::vector<std::string> normalizeTemp;
206     for (size_t i = 0; i < tempLen; ++i) {
207         if (!temp[i].empty() && !(temp[i] == ".") && !(temp[i] == "..")) {
208             normalizeTemp.push_back(temp[i]);
209         }
210         if (temp[i] == "..") {
211             if (!normalizeTemp.empty() && normalizeTemp.back() != "..") {
212                 normalizeTemp.pop_back();
213             } else {
214                 normalizeTemp.push_back(temp[i]);
215             }
216         }
217     }
218     std::string normalizePath = "";
219     tempLen = normalizeTemp.size();
220     if (tempLen == 0) {
221         normalizePath = "/";
222     } else {
223         for (size_t i = 0; i < tempLen; ++i) {
224             normalizePath += "/" + normalizeTemp[i];
225         }
226     }
227     return Split(normalizePath, uri);
228 }
229 
Normalize(napi_env env,napi_callback_info info)230 napi_value FileUriNExporter::Normalize(napi_env env, napi_callback_info info)
231 {
232     NFuncArg funcArg(env, info);
233     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
234         LOGE("Number of arguments unmatched");
235         NError(EINVAL).ThrowErr(env);
236         return nullptr;
237     }
238     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
239     if (!fileuriEntity) {
240         LOGE("Failed to get file entity");
241         NError(EINVAL).ThrowErr(env);
242         return nullptr;
243     }
244 
245     napi_value uriObj = NClass::InstantiateClass(env, FileUriNExporter::className,
246         {NVal::CreateUTF8String(env, NormalizeUri(fileuriEntity->fileUri_.uri_)).val_});
247     if (!uriObj) {
248         LOGE("Failed to construct FileUriNExporter.");
249         NError(E_UNKNOWN_ERROR).ThrowErr(env);
250         return nullptr;
251     }
252 
253     return uriObj;
254 }
255 
Equals(napi_env env,napi_callback_info info)256 napi_value FileUriNExporter::Equals(napi_env env, napi_callback_info info)
257 {
258     NFuncArg funcArg(env, info);
259     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
260         LOGE("Number of arguments unmatched");
261         NError(EINVAL).ThrowErr(env);
262         return nullptr;
263     }
264     auto thisEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
265     if (!thisEntity) {
266         LOGE("Failed to get file entity");
267         NError(EINVAL).ThrowErr(env);
268         return nullptr;
269     }
270 
271     auto otherEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg[NARG_POS::FIRST]);
272     if (!otherEntity) {
273         LOGE("Failed to get file entity");
274         NError(EINVAL).ThrowErr(env);
275         return nullptr;
276     }
277 
278     return NVal::CreateBool(env, thisEntity->fileUri_.uri_.Equals(otherEntity->fileUri_.uri_)).val_;
279 }
280 
EqualsTo(napi_env env,napi_callback_info info)281 napi_value FileUriNExporter::EqualsTo(napi_env env, napi_callback_info info)
282 {
283     NFuncArg funcArg(env, info);
284     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
285         LOGE("Number of arguments unmatched");
286         NError(E_PARAMS).ThrowErr(env);
287         return nullptr;
288     }
289     auto thisEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
290     if (!thisEntity) {
291         LOGE("Failed to get file entity");
292         NError(E_PARAMS).ThrowErr(env);
293         return nullptr;
294     }
295 
296     auto otherEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg[NARG_POS::FIRST]);
297     if (!otherEntity) {
298         LOGE("Failed to get file entity");
299         NError(E_PARAMS).ThrowErr(env);
300         return nullptr;
301     }
302     return NVal::CreateBool(env, thisEntity->fileUri_.uri_.Equals(otherEntity->fileUri_.uri_)).val_;
303 }
304 
IsAbsolute(napi_env env,napi_callback_info info)305 napi_value FileUriNExporter::IsAbsolute(napi_env env, napi_callback_info info)
306 {
307     NFuncArg funcArg(env, info);
308     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
309         LOGE("Number of arguments unmatched");
310         NError(EINVAL).ThrowErr(env);
311         return nullptr;
312     }
313     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
314     if (!fileuriEntity) {
315         LOGE("Failed to get file entity");
316         NError(EINVAL).ThrowErr(env);
317         return nullptr;
318     }
319     return NVal::CreateBool(env, fileuriEntity->fileUri_.uri_.IsAbsolute()).val_;
320 }
321 
GetScheme(napi_env env,napi_callback_info info)322 napi_value FileUriNExporter::GetScheme(napi_env env, napi_callback_info info)
323 {
324     NFuncArg funcArg(env, info);
325     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
326         LOGE("Number of arguments unmatched");
327         NError(EINVAL).ThrowErr(env);
328         return nullptr;
329     }
330     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
331     if (!fileuriEntity) {
332         LOGE("Failed to get file entity");
333         NError(EINVAL).ThrowErr(env);
334         return nullptr;
335     }
336 
337     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.uri_.GetScheme()).val_;
338 }
339 
GetAuthority(napi_env env,napi_callback_info info)340 napi_value FileUriNExporter::GetAuthority(napi_env env, napi_callback_info info)
341 {
342     NFuncArg funcArg(env, info);
343     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
344         LOGE("Number of arguments unmatched");
345         NError(EINVAL).ThrowErr(env);
346         return nullptr;
347     }
348     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
349     if (!fileuriEntity) {
350         LOGE("Failed to get file entity");
351         NError(EINVAL).ThrowErr(env);
352         return nullptr;
353     }
354 
355     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.uri_.GetAuthority()).val_;
356 }
357 
GetSsp(napi_env env,napi_callback_info info)358 napi_value FileUriNExporter::GetSsp(napi_env env, napi_callback_info info)
359 {
360     NFuncArg funcArg(env, info);
361     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
362         LOGE("Number of arguments unmatched");
363         NError(EINVAL).ThrowErr(env);
364         return nullptr;
365     }
366     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
367     if (!fileuriEntity) {
368         LOGE("Failed to get file entity");
369         NError(EINVAL).ThrowErr(env);
370         return nullptr;
371     }
372 
373     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.uri_.GetSchemeSpecificPart()).val_;
374 }
375 
GetUserInfo(napi_env env,napi_callback_info info)376 napi_value FileUriNExporter::GetUserInfo(napi_env env, napi_callback_info info)
377 {
378     NFuncArg funcArg(env, info);
379     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
380         LOGE("Number of arguments unmatched");
381         NError(EINVAL).ThrowErr(env);
382         return nullptr;
383     }
384     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
385     if (!fileuriEntity) {
386         LOGE("Failed to get file entity");
387         NError(EINVAL).ThrowErr(env);
388         return nullptr;
389     }
390 
391     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.uri_.GetUserInfo()).val_;
392 }
393 
GetHost(napi_env env,napi_callback_info info)394 napi_value FileUriNExporter::GetHost(napi_env env, napi_callback_info info)
395 {
396     NFuncArg funcArg(env, info);
397     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
398         LOGE("Number of arguments unmatched");
399         NError(EINVAL).ThrowErr(env);
400         return nullptr;
401     }
402     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
403     if (!fileuriEntity) {
404         LOGE("Failed to get file entity");
405         NError(EINVAL).ThrowErr(env);
406         return nullptr;
407     }
408 
409     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.uri_.GetHost()).val_;
410 }
411 
GetPort(napi_env env,napi_callback_info info)412 napi_value FileUriNExporter::GetPort(napi_env env, napi_callback_info info)
413 {
414     NFuncArg funcArg(env, info);
415     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
416         LOGE("Number of arguments unmatched");
417         NError(EINVAL).ThrowErr(env);
418         return nullptr;
419     }
420     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
421     if (!fileuriEntity) {
422         LOGE("Failed to get file entity");
423         NError(EINVAL).ThrowErr(env);
424         return nullptr;
425     }
426 
427     return NVal::CreateUTF8String(env, to_string(fileuriEntity->fileUri_.uri_.GetPort())).val_;
428 }
429 
GetQuery(napi_env env,napi_callback_info info)430 napi_value FileUriNExporter::GetQuery(napi_env env, napi_callback_info info)
431 {
432     NFuncArg funcArg(env, info);
433     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
434         LOGE("Number of arguments unmatched");
435         NError(EINVAL).ThrowErr(env);
436         return nullptr;
437     }
438     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
439     if (!fileuriEntity) {
440         LOGE("Failed to get file entity");
441         NError(EINVAL).ThrowErr(env);
442         return nullptr;
443     }
444 
445     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.uri_.GetQuery()).val_;
446 }
447 
GetFragment(napi_env env,napi_callback_info info)448 napi_value FileUriNExporter::GetFragment(napi_env env, napi_callback_info info)
449 {
450     NFuncArg funcArg(env, info);
451     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
452         LOGE("Number of arguments unmatched");
453         NError(EINVAL).ThrowErr(env);
454         return nullptr;
455     }
456     auto fileuriEntity = NClass::GetEntityOf<FileUriEntity>(env, funcArg.GetThisVar());
457     if (!fileuriEntity) {
458         LOGE("Failed to get file entity");
459         NError(EINVAL).ThrowErr(env);
460         return nullptr;
461     }
462 
463     return NVal::CreateUTF8String(env, fileuriEntity->fileUri_.uri_.GetFragment()).val_;
464 }
465 
Export()466 bool FileUriNExporter::Export()
467 {
468     vector<napi_property_descriptor> props = {
469         NVal::DeclareNapiFunction("toString", UriToString),
470         NVal::DeclareNapiGetter("name", GetFileUriName),
471         NVal::DeclareNapiGetter("path", GetFileUriPath),
472         NVal::DeclareNapiFunction("getFullDirectoryUri", GetFullDirectoryUri),
473         NVal::DeclareNapiFunction("isRemoteUri", IsRemoteUri),
474         NVal::DeclareNapiFunction("normalize", Normalize),
475         NVal::DeclareNapiFunction("equals", Equals),
476         NVal::DeclareNapiFunction("equalsTo", EqualsTo),
477         NVal::DeclareNapiFunction("checkIsAbsolute", IsAbsolute),
478         NVal::DeclareNapiGetter("scheme", GetScheme),
479         NVal::DeclareNapiGetter("authority", GetAuthority),
480         NVal::DeclareNapiGetter("ssp", GetSsp),
481         NVal::DeclareNapiGetter("userInfo", GetUserInfo),
482         NVal::DeclareNapiGetter("host", GetHost),
483         NVal::DeclareNapiGetter("port", GetPort),
484         NVal::DeclareNapiGetter("query", GetQuery),
485         NVal::DeclareNapiGetter("fragment", GetFragment),
486     };
487 
488     auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props));
489     if (!succ) {
490         LOGE("Failed to define class");
491         NError(EIO).ThrowErr(exports_.env_);
492         return false;
493     }
494     succ = NClass::SaveClass(exports_.env_, className, classValue);
495     if (!succ) {
496         LOGE("Failed to save class");
497         NError(EIO).ThrowErr(exports_.env_);
498         return false;
499     }
500 
501     return exports_.AddProp(className, classValue);
502 }
503 
GetClassName()504 string FileUriNExporter::GetClassName()
505 {
506     return FileUriNExporter::className;
507 }
508 
FileUriNExporter(napi_env env,napi_value exports)509 FileUriNExporter::FileUriNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
510 
~FileUriNExporter()511 FileUriNExporter::~FileUriNExporter() {}
512 } // namespace ModuleFileUri
513 } // namespace AppFileService
514 } // namespace OHOS
515