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 "open.h"
16
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <memory>
21
22 #include "class_file/file_entity.h"
23 #include "class_file/file_n_exporter.h"
24 #include "common_func.h"
25 #include "filemgmt_libhilog.h"
26 #include "file_utils.h"
27 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
28 #include "ability.h"
29 #include "ability_manager_client.h"
30 #include "bundle_info.h"
31 #include "bundle_mgr_proxy.h"
32 #include "datashare_helper.h"
33 #include "ipc_skeleton.h"
34 #include "iservice_registry.h"
35 #include "remote_uri.h"
36 #include "status_receiver_host.h"
37 #include "system_ability_definition.h"
38 #include "file_uri.h"
39 #endif
40
41 #ifdef FILE_API_TRACE
42 #include "hitrace_meter.h"
43 #endif
44
45 namespace OHOS {
46 namespace FileManagement {
47 namespace ModuleFileIO {
48 using namespace std;
49 using namespace OHOS::FileManagement::LibN;
50 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
51 using namespace OHOS::DistributedFS::ModuleRemoteUri;
52 using namespace OHOS::AppExecFwk;
53 #endif
54
55 const std::string PROCEDURE_OPEN_NAME = "FileIOOpen";
56 const std::string MEDIALIBRARY_DATA_URI = "datashare:///media";
57 const std::string FILE_DATA_URI = "file://";
58 const std::string PATH_SHARE = "/data/storage/el2/share";
59 const std::string MODE_RW = "/rw/";
60 const std::string MODE_R = "/r/";
61 const std::string MEDIA = "media";
62 const std::string DOCS = "docs";
63 const std::string DATASHARE = "datashare";
64 const std::string SCHEME_BROKER = "content";
65 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
66 constexpr uint32_t MAX_WANT_FLAG = 4;
67 #endif
68
GetJsFlags(napi_env env,const NFuncArg & funcArg)69 static tuple<bool, unsigned int> GetJsFlags(napi_env env, const NFuncArg &funcArg)
70 {
71 unsigned int flags = O_RDONLY;
72 if (funcArg.GetArgc() >= NARG_CNT::TWO) {
73 auto [succ, mode] = NVal(env, funcArg[NARG_POS::SECOND]).ToInt32(O_RDONLY);
74 int32_t invalidMode = (O_WRONLY | O_RDWR);
75 if (!succ || mode < 0 || ((mode & invalidMode) == invalidMode)) {
76 HILOGE("Invalid mode");
77 NError(EINVAL).ThrowErr(env);
78 return { false, flags };
79 }
80 flags = static_cast<unsigned int>(mode);
81 (void)CommonFunc::ConvertJsFlags(flags);
82 }
83 return { true, flags };
84 }
85
InstantiateFile(napi_env env,int fd,string pathOrUri,bool isUri,bool async=false)86 static NVal InstantiateFile(napi_env env, int fd, string pathOrUri, bool isUri, bool async = false)
87 {
88 napi_value objFile = NClass::InstantiateClass(env, FileNExporter::className_, {});
89 if (!objFile) {
90 HILOGE("Failed to instantiate class");
91 int ret = close(fd);
92 if (ret < 0) {
93 HILOGE("Failed to close fd");
94 }
95 if (async) {
96 return {env, NError(EIO).GetNapiErr(env)};
97 }
98 NError(EIO).ThrowErr(env);
99 return NVal();
100 }
101
102 auto fileEntity = NClass::GetEntityOf<FileEntity>(env, objFile);
103 if (!fileEntity) {
104 HILOGE("Failed to get fileEntity");
105 int ret = close(fd);
106 if (ret < 0) {
107 HILOGE("Failed to close fd");
108 }
109 if (async) {
110 return {env, NError(EIO).GetNapiErr(env)};
111 }
112 NError(EIO).ThrowErr(env);
113 return NVal();
114 }
115 auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(fd, false);
116 if (fdg == nullptr) {
117 HILOGE("Failed to request heap memory.");
118 close(fd);
119 if (async) {
120 return {env, NError(ENOMEM).GetNapiErr(env)};
121 }
122 NError(ENOMEM).ThrowErr(env);
123 return NVal();
124 }
125 fileEntity->fd_.swap(fdg);
126 if (isUri) {
127 fileEntity->path_ = "";
128 fileEntity->uri_ = pathOrUri;
129 } else {
130 fileEntity->path_ = pathOrUri;
131 fileEntity->uri_ = "";
132 }
133 return { env, objFile };
134 }
135
OpenFileByPath(const string & path,unsigned int mode)136 static int OpenFileByPath(const string &path, unsigned int mode)
137 {
138 unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
139 new uv_fs_t, CommonFunc::fs_req_cleanup };
140 if (!open_req) {
141 HILOGE("Failed to request heap memory.");
142 return -ENOMEM;
143 }
144 int ret = uv_fs_open(nullptr, open_req.get(), path.c_str(), mode, S_IRUSR |
145 S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
146 return ret;
147 }
148
149 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
150
OpenFileByDatashare(const string & path,unsigned int flags)151 static int OpenFileByDatashare(const string &path, unsigned int flags)
152 {
153 std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = nullptr;
154 sptr<FileIoToken> remote = new (std::nothrow) IRemoteStub<FileIoToken>();
155 if (!remote) {
156 HILOGE("Failed to get remote object");
157 return -ENOMEM;
158 }
159
160 dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI);
161 if (!dataShareHelper) {
162 HILOGE("Failed to connect to datashare");
163 return -E_PERMISSION;
164 }
165 Uri uri(path);
166 int fd = dataShareHelper->OpenFile(uri, CommonFunc::GetModeFromFlags(flags));
167 return fd;
168 }
169
OpenByFileDataUri(Uri & uri,const string & uriStr,unsigned int mode)170 static tuple<int, string> OpenByFileDataUri(Uri &uri, const string &uriStr, unsigned int mode)
171 {
172 string bundleName = uri.GetAuthority();
173 AppFileService::ModuleFileUri::FileUri fileUri(uriStr);
174 string realPath = fileUri.GetRealPath();
175 if (bundleName == MEDIA) {
176 int res = OpenFileByDatashare(uri.ToString(), mode);
177 if (res < 0) {
178 HILOGE("Failed to open file by Datashare error %{public}d", res);
179 }
180 return { res, uri.ToString() };
181 } else if (bundleName == DOCS && access(realPath.c_str(), F_OK) != 0) {
182 int res = OpenFileByDatashare(uri.ToString(), mode);
183 if (res < 0) {
184 HILOGE("Failed to open file by Datashare error %{public}d", res);
185 return { -ENOENT, uri.ToString() };
186 }
187 return { res, uri.ToString() };
188 }
189 int ret = OpenFileByPath(realPath, mode);
190 if (ret < 0) {
191 HILOGE("Failed to open file for libuv error %{public}d", ret);
192 }
193 return { ret, uriStr };
194 }
195
OpenFileByBroker(const Uri & uri,uint32_t mode)196 static tuple<int, string> OpenFileByBroker(const Uri &uri, uint32_t mode)
197 {
198 uint32_t flag = (mode % MAX_WANT_FLAG) > 0 ?
199 AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION :
200 AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION;
201 int ret = AAFwk::AbilityManagerClient::GetInstance()->OpenFile(uri, flag);
202 if (ret < 0) {
203 HILOGE("Failed to open file by Broker error %{public}d", ret);
204 }
205 return { ret, uri.ToString() };
206 }
207
OpenFileByUri(const string & path,unsigned int mode)208 static tuple<int, string> OpenFileByUri(const string &path, unsigned int mode)
209 {
210 Uri uri(path);
211 string uriType = uri.GetScheme();
212 if (uriType == SCHEME_FILE) {
213 return OpenByFileDataUri(uri, path, mode);
214 } else if (uriType == SCHEME_BROKER) {
215 return OpenFileByBroker(uri, mode);
216 } else if (uriType == DATASHARE) {
217 // datashare:////#fdFromBinder=xx
218 int fd = -1;
219 if (RemoteUri::IsRemoteUri(path, fd, mode)) {
220 if (fd >= 0) {
221 return { fd, path };
222 }
223 HILOGE("Failed to open file by RemoteUri");
224 }
225 }
226 HILOGE("Failed to open file by invalid uri");
227 return { -EINVAL, path };
228 }
229 #endif
230
Sync(napi_env env,napi_callback_info info)231 napi_value Open::Sync(napi_env env, napi_callback_info info)
232 {
233 #ifdef FILE_API_TRACE
234 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
235 #endif
236 NFuncArg funcArg(env, info);
237 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
238 HILOGE("Number of arguments unmatched");
239 NError(EINVAL).ThrowErr(env);
240 return nullptr;
241 }
242 auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
243 if (!succPath) {
244 HILOGE("Invalid path");
245 NError(EINVAL).ThrowErr(env);
246 return nullptr;
247 }
248 auto [succMode, mode] = GetJsFlags(env, funcArg);
249 if (!succMode) {
250 return nullptr;
251 }
252 string pathStr(path.get());
253 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
254 if (pathStr.find("://") != string::npos) {
255 auto [res, uriStr] = OpenFileByUri(pathStr, mode);
256 if (res < 0) {
257 NError(res).ThrowErr(env);
258 return nullptr;
259 }
260 return InstantiateFile(env, res, uriStr, true).val_;
261 }
262 #endif
263 int ret = OpenFileByPath(pathStr, mode);
264 if (ret < 0) {
265 HILOGD("Failed to open file for libuv error %{public}d", ret);
266 NError(ret).ThrowErr(env);
267 return nullptr;
268 }
269 return InstantiateFile(env, ret, pathStr, false).val_;
270 }
271
272 struct AsyncOpenFileArg {
273 int fd;
274 string path;
275 string uri;
276 };
277
AsyncCbExec(shared_ptr<AsyncOpenFileArg> arg,const string & path,unsigned int mode)278 static NError AsyncCbExec(shared_ptr<AsyncOpenFileArg> arg, const string &path, unsigned int mode)
279 {
280 string pathStr(path);
281 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
282 if (pathStr.find("://") != string::npos) {
283 auto [res, uriStr] = OpenFileByUri(pathStr, mode);
284 if (res < 0) {
285 return NError(res);
286 }
287 arg->fd = res;
288 arg->path = "";
289 arg->uri = uriStr;
290 return NError(ERRNO_NOERR);
291 }
292 #endif
293 int ret = OpenFileByPath(pathStr, mode);
294 if (ret < 0) {
295 HILOGD("Failed to open file for libuv error %{public}d", ret);
296 return NError(ret);
297 }
298 arg->fd = ret;
299 arg->path = pathStr;
300 arg->uri = "";
301 return NError(ERRNO_NOERR);
302 }
303
Async(napi_env env,napi_callback_info info)304 napi_value Open::Async(napi_env env, napi_callback_info info)
305 {
306 #ifdef FILE_API_TRACE
307 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
308 #endif
309 NFuncArg funcArg(env, info);
310 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
311 HILOGE("Number of arguments unmatched");
312 NError(EINVAL).ThrowErr(env);
313 return nullptr;
314 }
315 auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
316 if (!succPath) {
317 HILOGE("Invalid path");
318 NError(EINVAL).ThrowErr(env);
319 return nullptr;
320 }
321 auto [succMode, mode] = GetJsFlags(env, funcArg);
322 if (!succMode) {
323 return nullptr;
324 }
325 auto arg = CreateSharedPtr<AsyncOpenFileArg>();
326 if (arg == nullptr) {
327 HILOGE("Failed to request heap memory.");
328 NError(ENOMEM).ThrowErr(env);
329 return nullptr;
330 }
331 auto cbExec = [arg, path = string(path.get()), mode = mode]() -> NError {
332 return AsyncCbExec(arg, path, mode);
333 };
334 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
335 if (err) {
336 return { env, err.GetNapiErr(env) };
337 }
338 if (arg->path.empty() && arg->uri.size()) {
339 return InstantiateFile(env, arg->fd, arg->uri, true, true);
340 }
341 return InstantiateFile(env, arg->fd, arg->path, false, true);
342 };
343 NVal thisVar(env, funcArg.GetThisVar());
344 if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
345 !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
346 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_OPEN_NAME, cbExec, cbCompl).val_;
347 } else {
348 int cbIdx = ((funcArg.GetArgc() == NARG_CNT::THREE) ? NARG_POS::THIRD : NARG_POS::SECOND);
349 NVal cb(env, funcArg[cbIdx]);
350 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_OPEN_NAME, cbExec, cbCompl).val_;
351 }
352 }
353 } // namespace ModuleFileIO
354 } // namespace FileManagement
355 } // namespace OHOS