1 /*
2 * Copyright (c) 2021 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 "file_share_exporter.h"
17
18 #include <cerrno>
19 #include <climits>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <stack>
26 #include <sys/sendfile.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <vector>
31
32 #include "../common/ability_helper.h"
33 #include "../common/common_func.h"
34 #include "../common/napi/n_class.h"
35 #include "../common/napi/n_func_arg.h"
36 #include "../common/napi/n_val.h"
37 #include "../common/uni_error.h"
38 #include "file_share_ability.h"
39 #include "uri.h"
40
41 using Uri = OHOS::Uri;
42 using namespace std;
43 namespace OHOS {
44 namespace DistributedFS {
45 namespace ModuleFMSExpoter {
46 const int OTHER_ARGUMENT_ERROR = 202;
47 const int URI_PARAMER_ERROR = 302;
48 const int FILE_IO_ERROR = 300;
49 const int FILE_PATH_ERROR = 301;
50 const int SUCCESS = 0;
51 const int FAILED = -1;
52 enum COMMON_NUM {
53 ZERO = 0,
54 ONE = 1,
55 TWO = 2,
56 THREE = 3,
57 };
58
CallBackSuccess(napi_env env,napi_ref successFuncRef,int32_t count,napi_value obj)59 void CallBackSuccess(napi_env env, napi_ref successFuncRef, int32_t count, napi_value obj)
60 {
61 napi_value results = nullptr;
62 napi_value successFunc = nullptr;
63 napi_value global = nullptr;
64 napi_get_global(env, &global);
65 napi_get_reference_value(env, successFuncRef, &successFunc);
66 if (successFunc == nullptr) {
67 return;
68 }
69 napi_call_function(env, global, successFunc, count, &obj, &results);
70 }
71
CallBackError(napi_env env,napi_ref failFuncRef,string errorProp,int errorCode)72 void CallBackError(napi_env env, napi_ref failFuncRef, string errorProp, int errorCode)
73 {
74 napi_value argvFail[2] = { 0 };
75 napi_value results = nullptr;
76 napi_value failFunc = nullptr;
77 napi_value global = nullptr;
78 napi_get_global(env, &global);
79 argvFail[0] = NVal::CreateUTF8String(env, errorProp).val_;
80 argvFail[1] = NVal::CreateInt32(env, errorCode).val_;
81 napi_get_reference_value(env, failFuncRef, &failFunc);
82 if (failFunc == nullptr) {
83 return;
84 }
85 napi_call_function(env, global, failFunc, COMMON_NUM::TWO, argvFail, &results);
86 }
87
CallComplete(napi_env env,napi_ref completeFuncRef)88 void CallComplete(napi_env env, napi_ref completeFuncRef)
89 {
90 napi_value completeFunc = nullptr;
91 napi_value results = nullptr;
92 napi_value global = nullptr;
93 napi_get_global(env, &global);
94 napi_get_reference_value(env, completeFuncRef, &completeFunc);
95 if (completeFunc == nullptr) {
96 return;
97 }
98 napi_call_function(env, global, completeFunc, COMMON_NUM::ZERO, nullptr, &results);
99 }
100
CheckUri(AppExecFwk::Ability * ability,napi_env env,string & path)101 bool CheckUri(AppExecFwk::Ability *ability, napi_env env, string &path)
102 {
103 string pathOrigin = path;
104 vector<string> uriSplit;
105 string pattern = "/";
106 if (path == "") {
107 return false;
108 }
109 string pathTmp = pathOrigin + pattern;
110 size_t pos = pathTmp.find(pattern);
111 while (pos != pathTmp.npos) {
112 string temp = pathTmp.substr(COMMON_NUM::ZERO, pos);
113 uriSplit.push_back(temp);
114 pathTmp = pathTmp.substr(pos + 1, pathTmp.size());
115 pos = pathTmp.find(pattern);
116 }
117 if (uriSplit[COMMON_NUM::ZERO] != "internal:" || uriSplit[COMMON_NUM::ONE] != "" ||
118 uriSplit.size() <= COMMON_NUM::TWO) {
119 return false;
120 }
121 if (uriSplit[COMMON_NUM::TWO] == "app") {
122 path = ability->GetDataDir();
123 } else if (uriSplit[COMMON_NUM::TWO] == "cache") {
124 path = ability->GetCacheDir();
125 } else {
126 return false;
127 }
128 for (size_t i = COMMON_NUM::THREE; i < uriSplit.size(); ++i) {
129 path = path + "/" + uriSplit[i];
130 }
131 return true;
132 }
133
GetRealPath(string & path)134 int GetRealPath(string &path)
135 {
136 unique_ptr<char[]> absPath = make_unique<char[]>(PATH_MAX + 1);
137 if (realpath(path.c_str(), absPath.get()) == nullptr) {
138 return errno;
139 }
140 path = absPath.get();
141 return SUCCESS;
142 }
143
CallbackUriResult(napi_env env,napi_ref napiFailFun,napi_ref napiSuccFun,string uriRet)144 void CallbackUriResult(napi_env env, napi_ref napiFailFun, napi_ref napiSuccFun, string uriRet)
145 {
146 if (uriRet == "") {
147 CallBackError(env, napiFailFun, "error: fuzzyFileToUri failed", FILE_IO_ERROR);
148 } else if (uriRet == "ERROR_AUTHORITY") {
149 CallBackError(env, napiFailFun, "error: authority is not exist", OTHER_ARGUMENT_ERROR);
150 } else if (uriRet == "ERROR_JSON_CONFIG") {
151 CallBackError(env, napiFailFun, "error: invalid json config", FILE_IO_ERROR);
152 } else {
153 CallBackSuccess(env, napiSuccFun, COMMON_NUM::ONE, NVal::CreateUTF8String(env, uriRet).val_);
154 }
155 }
156
CheckArgumentsError(napi_env env,napi_ref napiFailFun,string deviceIdStr,string authorityStr)157 int CheckArgumentsError(napi_env env, napi_ref napiFailFun, string deviceIdStr, string authorityStr)
158 {
159 if (deviceIdStr == "" || authorityStr == "") {
160 CallBackError(env, napiFailFun, "error: illegal arguments", OTHER_ARGUMENT_ERROR);
161 return FAILED;
162 }
163 return SUCCESS;
164 }
165
CheckUriError(napi_env env,napi_ref napiFailFun,AppExecFwk::Ability * ability,int checkPathResult,string path)166 int CheckUriError(napi_env env, napi_ref napiFailFun, AppExecFwk::Ability *ability, int checkPathResult, string path)
167 {
168 if (!checkPathResult) {
169 CallBackError(env, napiFailFun, "error: illegal uri", URI_PARAMER_ERROR);
170 return FAILED;
171 } else if (path.find(ability->GetDataDir()) != 0 && path.find(ability->GetCacheDir()) != 0) {
172 CallBackError(env, napiFailFun, "error: uri cannot out of this package", URI_PARAMER_ERROR);
173 return FAILED;
174 }
175 return SUCCESS;
176 }
177
CheckFilePathError(napi_env env,napi_ref napiFailFun,int realPathResult)178 int CheckFilePathError(napi_env env, napi_ref napiFailFun, int realPathResult)
179 {
180 if (realPathResult == ENOENT) {
181 CallBackError(env, napiFailFun, "error: file or directory not exist", FILE_PATH_ERROR);
182 return FAILED;
183 }
184 return SUCCESS;
185 }
186
CheckIOError(napi_env env,napi_ref napiFailFun,int realPathResult,string path)187 int CheckIOError(napi_env env, napi_ref napiFailFun, int realPathResult, string path)
188 {
189 struct stat buf;
190 if (realPathResult != SUCCESS) {
191 CallBackError(env, napiFailFun, "error: invalid uri", FILE_IO_ERROR);
192 return FAILED;
193 } else if (stat(path.c_str(), &buf) != SUCCESS || (buf.st_mode & S_IFMT) != S_IFREG) {
194 CallBackError(env, napiFailFun, "error: uri cannot be a directory", FILE_IO_ERROR);
195 return FAILED;
196 }
197 return SUCCESS;
198 }
199
FuzzyFileToUri(napi_env env,napi_callback_info info)200 napi_value FileShareExporter::FuzzyFileToUri(napi_env env, napi_callback_info info)
201 {
202 NFuncArg funcArg(env, info);
203 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
204 UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
205 return nullptr;
206 }
207 bool succ = false;
208 napi_ref napiSuccFun, napiCompFun, napiFailFun;
209 tie(succ, napiSuccFun, napiFailFun, napiCompFun) =
210 CommonFunc::GetCallbackHandles(env, funcArg[NARG_POS::FIRST]);
211
212 unique_ptr<char[]> uri = nullptr;
213 tie(succ, uri, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).GetProp("uri").ToUTF8String();
214
215 unique_ptr<char[]> deviceId = nullptr;
216 tie(succ, deviceId, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).GetProp("deviceId").ToUTF8String();
217
218 unique_ptr<char[]> authority = nullptr;
219 tie(succ, authority, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).GetProp("authority").ToUTF8String();
220
221 unique_ptr<char[]> displayname = nullptr;
222 tie(succ, displayname, ignore) =
223 NVal(env, funcArg[NARG_POS::FIRST]).GetProp("displayName").ToUTF8String();
224 string path = (uri == nullptr) ? "" : uri.get();
225 string deviceIdStr = (deviceId == nullptr) ? "" : deviceId.get();
226 string authorityStr = (authority == nullptr) ? "" : authority.get();
227 string displaynameStr = (displayname == nullptr) ? "" : displayname.get();
228
229 AppExecFwk::Ability *ability = AbilityHelper::GetJsAbility(env);
230 if (ability == nullptr) {
231 return nullptr;
232 }
233 bool checkPathResult = CheckUri(ability, env, path);
234 int realPathResult = GetRealPath(path);
235 if (CheckArgumentsError(env, napiFailFun, deviceIdStr, authorityStr) == FAILED ||
236 CheckUriError(env, napiFailFun, ability, checkPathResult, path) == FAILED ||
237 CheckFilePathError(env, napiFailFun, realPathResult) == FAILED ||
238 CheckIOError(env, napiFailFun, realPathResult, path) == FAILED) {
239 CallComplete(env, napiCompFun);
240 napi_delete_reference(env, napiSuccFun);
241 napi_delete_reference(env, napiFailFun);
242 napi_delete_reference(env, napiCompFun);
243 return nullptr;
244 }
245
246 Uri uriObj("");
247 uriObj = FileManager::FileShareAbility::FuzzyFileToUri(ability, deviceIdStr, authorityStr, path, displaynameStr);
248
249 string uriRet = uriObj.ToString();
250 CallbackUriResult(env, napiFailFun, napiSuccFun, uriRet);
251
252 CallComplete(env, napiCompFun);
253 napi_delete_reference(env, napiSuccFun);
254 napi_delete_reference(env, napiFailFun);
255 napi_delete_reference(env, napiCompFun);
256 return NVal::CreateUndefined(env).val_;
257 }
258
Export()259 bool FileShareExporter::Export()
260 {
261 return exports_.AddProp({
262 NVal::DeclareNapiFunction("fuzzyFileToUri", FuzzyFileToUri),
263 });
264 }
265
GetClassName()266 string FileShareExporter::GetClassName()
267 {
268 return FileShareExporter::className_;
269 }
270
FileShareExporter(napi_env env,napi_value exports)271 FileShareExporter::FileShareExporter(napi_env env, napi_value exports)
272 : NExporter(env, exports)
273 {}
274
~FileShareExporter()275 FileShareExporter::~FileShareExporter() {}
276 } // namespace ModuleFMSExpoter
277 } // namespace DistributedFS
278 } // namespace OHOS