• 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 #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 
OpenFileByDatashareHasUserId(const string & path,unsigned int flags,const string & userId)151 static int OpenFileByDatashareHasUserId(const string &path, unsigned int flags, const string &userId)
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(),
161         MEDIALIBRARY_DATA_URI + "?user=" + userId);
162     if (!dataShareHelper) {
163         HILOGE("Failed to connect to datashare");
164         return -E_PERMISSION;
165     }
166     Uri uri(path);
167     int fd = dataShareHelper->OpenFile(uri, CommonFunc::GetModeFromFlags(flags));
168     return fd;
169 }
170 
OpenFileByDatashare(const string & path,unsigned int flags)171 static int OpenFileByDatashare(const string &path, unsigned int flags)
172 {
173     std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = nullptr;
174     sptr<FileIoToken> remote = new (std::nothrow) IRemoteStub<FileIoToken>();
175     if (!remote) {
176         HILOGE("Failed to get remote object");
177         return -ENOMEM;
178     }
179 
180     dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI);
181     if (!dataShareHelper) {
182         HILOGE("Failed to connect to datashare");
183         return -E_PERMISSION;
184     }
185     Uri uri(path);
186     int fd = dataShareHelper->OpenFile(uri, CommonFunc::GetModeFromFlags(flags));
187     return fd;
188 }
189 
OpenByFileDataUri(Uri & uri,const string & uriStr,unsigned int mode)190 static tuple<int, string> OpenByFileDataUri(Uri &uri, const string &uriStr, unsigned int mode)
191 {
192     string bundleName = uri.GetAuthority();
193     AppFileService::ModuleFileUri::FileUri fileUri(uriStr);
194     string realPath = fileUri.GetRealPath();
195     if (bundleName == MEDIA) {
196         string userId;
197         if (CommonFunc::GetAndCheckUserId(&uri, userId) && CommonFunc::IsSystemApp()) {
198             int res = OpenFileByDatashareHasUserId(uri.ToString(), mode, userId);
199             if (res < 0) {
200                 HILOGE("Failed to open file by DatashareHasUserId error %{public}d", res);
201             }
202             return { res, uri.ToString() };
203         } else {
204             int res = OpenFileByDatashare(uri.ToString(), mode);
205             if (res < 0) {
206                 HILOGE("Failed to open file by Datashare error %{public}d", res);
207             }
208             return { res, uri.ToString() };
209         }
210     } else if (bundleName == DOCS && access(realPath.c_str(), F_OK) != 0) {
211         int res = OpenFileByDatashare(uri.ToString(), mode);
212         if (res < 0) {
213             HILOGE("Failed to open file by Datashare error %{public}d", res);
214             return { -ENOENT, uri.ToString() };
215         }
216         return { res, uri.ToString() };
217     }
218     int ret = OpenFileByPath(realPath, mode);
219     if (ret < 0) {
220         HILOGE("Failed to open file for libuv error %{public}d", ret);
221     }
222     return { ret, uriStr };
223 }
224 
OpenFileByBroker(const Uri & uri,uint32_t mode)225 static tuple<int, string> OpenFileByBroker(const Uri &uri, uint32_t mode)
226 {
227     uint32_t flag = (mode % MAX_WANT_FLAG) > 0 ?
228         AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION :
229         AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION;
230     int ret = AAFwk::AbilityManagerClient::GetInstance()->OpenFile(uri, flag);
231     if (ret < 0) {
232         HILOGE("Failed to open file by Broker error %{public}d", ret);
233     }
234     return { ret, uri.ToString() };
235 }
236 
OpenFileByUri(const string & path,unsigned int mode)237 static tuple<int, string> OpenFileByUri(const string &path, unsigned int mode)
238 {
239     Uri uri(path);
240     string uriType = uri.GetScheme();
241     if (uriType == SCHEME_FILE) {
242         return OpenByFileDataUri(uri, path, mode);
243     } else if (uriType == SCHEME_BROKER) {
244         return OpenFileByBroker(uri, mode);
245     } else if (uriType == DATASHARE) {
246         // datashare:////#fdFromBinder=xx
247         int fd = -1;
248         if (RemoteUri::IsRemoteUri(path, fd, mode)) {
249             if (fd >= 0) {
250                 return { fd, path };
251             }
252             HILOGE("Failed to open file by RemoteUri");
253         }
254     }
255     HILOGE("Failed to open file by invalid uri");
256     return { -EINVAL, path };
257 }
258 #endif
259 
Sync(napi_env env,napi_callback_info info)260 napi_value Open::Sync(napi_env env, napi_callback_info info)
261 {
262 #ifdef FILE_API_TRACE
263     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
264 #endif
265     NFuncArg funcArg(env, info);
266     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
267         HILOGE("Number of arguments unmatched");
268         NError(EINVAL).ThrowErr(env);
269         return nullptr;
270     }
271     auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
272     if (!succPath) {
273         HILOGE("Invalid path");
274         NError(EINVAL).ThrowErr(env);
275         return nullptr;
276     }
277     auto [succMode, mode] = GetJsFlags(env, funcArg);
278     if (!succMode) {
279         return nullptr;
280     }
281     string pathStr(path.get());
282 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
283     if (pathStr.find("://") != string::npos) {
284         auto [res, uriStr] = OpenFileByUri(pathStr, mode);
285         if (res < 0) {
286             NError(res).ThrowErr(env);
287             return nullptr;
288         }
289         return InstantiateFile(env, res, uriStr, true).val_;
290     }
291 #endif
292     int ret = OpenFileByPath(pathStr, mode);
293     if (ret < 0) {
294         HILOGD("Failed to open file for libuv error %{public}d", ret);
295         NError(ret).ThrowErr(env);
296         return nullptr;
297     }
298     return InstantiateFile(env, ret, pathStr, false).val_;
299 }
300 
301 struct AsyncOpenFileArg {
302     int fd;
303     string path;
304     string uri;
305 };
306 
AsyncCbExec(shared_ptr<AsyncOpenFileArg> arg,const string & path,unsigned int mode)307 static NError AsyncCbExec(shared_ptr<AsyncOpenFileArg> arg, const string &path, unsigned int mode)
308 {
309     string pathStr(path);
310 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
311     if (pathStr.find("://") != string::npos) {
312         auto [res, uriStr] = OpenFileByUri(pathStr, mode);
313         if (res < 0) {
314             return NError(res);
315         }
316         arg->fd = res;
317         arg->path = "";
318         arg->uri = uriStr;
319         return NError(ERRNO_NOERR);
320     }
321 #endif
322     int ret = OpenFileByPath(pathStr, mode);
323     if (ret < 0) {
324         HILOGD("Failed to open file for libuv error %{public}d", ret);
325         return NError(ret);
326     }
327     arg->fd = ret;
328     arg->path = pathStr;
329     arg->uri = "";
330     return NError(ERRNO_NOERR);
331 }
332 
Async(napi_env env,napi_callback_info info)333 napi_value Open::Async(napi_env env, napi_callback_info info)
334 {
335 #ifdef FILE_API_TRACE
336     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
337 #endif
338     NFuncArg funcArg(env, info);
339     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
340         HILOGE("Number of arguments unmatched");
341         NError(EINVAL).ThrowErr(env);
342         return nullptr;
343     }
344     auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
345     if (!succPath) {
346         HILOGE("Invalid path");
347         NError(EINVAL).ThrowErr(env);
348         return nullptr;
349     }
350     auto [succMode, mode] = GetJsFlags(env, funcArg);
351     if (!succMode) {
352         return nullptr;
353     }
354     auto arg = CreateSharedPtr<AsyncOpenFileArg>();
355     if (arg == nullptr) {
356         HILOGE("Failed to request heap memory.");
357         NError(ENOMEM).ThrowErr(env);
358         return nullptr;
359     }
360     auto cbExec = [arg, path = string(path.get()), mode = mode]() -> NError {
361         return AsyncCbExec(arg, path, mode);
362     };
363     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
364         if (err) {
365             return { env, err.GetNapiErr(env) };
366         }
367         if (arg->path.empty() && arg->uri.size()) {
368             return InstantiateFile(env, arg->fd, arg->uri, true, true);
369         }
370         return InstantiateFile(env, arg->fd, arg->path, false, true);
371     };
372     NVal thisVar(env, funcArg.GetThisVar());
373     if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
374         !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
375         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_OPEN_NAME, cbExec, cbCompl).val_;
376     } else {
377         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::THREE) ? NARG_POS::THIRD : NARG_POS::SECOND);
378         NVal cb(env, funcArg[cbIdx]);
379         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_OPEN_NAME, cbExec, cbCompl).val_;
380     }
381 }
382 } // namespace ModuleFileIO
383 } // namespace FileManagement
384 } // namespace OHOS