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