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