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