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