1 /*
2 * Copyright (c) 2025 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
16 #include "access_core.h"
17
18 #include <unistd.h>
19
20 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
21 #include <sys/xattr.h>
22
23 #include "bundle_mgr_proxy.h"
24 #include "if_system_ability_manager.h"
25 #include "ipc_skeleton.h"
26 #include "iservice_registry.h"
27 #include "rust_file.h"
28 #include "system_ability_definition.h"
29
30 #endif
31
32 #ifdef FILE_API_TRACE
33 #include "hitrace_meter.h"
34 #endif
35
36 #include "filemgmt_libhilog.h"
37
38 namespace OHOS {
39 namespace FileManagement {
40 namespace ModuleFileIO {
41 using namespace std;
42 using namespace AppExecFwk;
43
44 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
45 const string CLOUDDISK_FILE_PREFIX = "/data/storage/el2/cloud";
46 const string DISTRIBUTED_FILE_PREFIX = "/data/storage/el2/distributedfiles";
47 const string PACKAGE_NAME_FLAG = "<PackageName>";
48 const string USER_ID_FLAG = "<currentUserId>";
49 const string PHYSICAL_PATH_PREFIX = "/mnt/hmdfs/<currentUserId>/account/device_view/local/data/<PackageName>";
50 const string CLOUD_FILE_LOCATION = "user.cloud.location";
51 const char POSITION_LOCAL = '1';
52 const char POSITION_BOTH = '3';
53 const int BASE_USER_RANGE = 200000;
54 #endif
55
UvAccess(const string & path,int mode)56 static int UvAccess(const string &path, int mode)
57 {
58 std::unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup) *> accessReq = {new uv_fs_t, FsUtils::FsReqCleanup};
59 if (!accessReq) {
60 HILOGE("Failed to request heap memory.");
61 return ENOMEM;
62 }
63 return uv_fs_access(nullptr, accessReq.get(), path.c_str(), mode, nullptr);
64 }
65
66 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
IsCloudOrDistributedFilePath(const string & path)67 static bool IsCloudOrDistributedFilePath(const string &path)
68 {
69 return path.find(CLOUDDISK_FILE_PREFIX) == 0 || path.find(DISTRIBUTED_FILE_PREFIX) == 0;
70 }
71
GetCurrentUserId()72 static int GetCurrentUserId()
73 {
74 int uid = IPCSkeleton::GetCallingUid();
75 int userId = uid / BASE_USER_RANGE;
76 return userId;
77 }
78
GetBundleMgrProxy()79 static sptr<BundleMgrProxy> GetBundleMgrProxy()
80 {
81 sptr<ISystemAbilityManager> systemAbilityManager =
82 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
83 if (!systemAbilityManager) {
84 HILOGE("fail to get system ability mgr");
85 return nullptr;
86 }
87 sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
88 if (!remoteObject) {
89 HILOGE("fail to get bundle manager proxy");
90 return nullptr;
91 }
92
93 return iface_cast<BundleMgrProxy>(remoteObject);
94 }
95
GetSelfBundleName()96 static string GetSelfBundleName()
97 {
98 sptr<BundleMgrProxy> bundleMgrProxy = GetBundleMgrProxy();
99 if (!bundleMgrProxy) {
100 HILOGE("bundleMgrProxy is nullptr");
101 return "";
102 }
103 BundleInfo bundleInfo;
104 auto ret = bundleMgrProxy->GetBundleInfoForSelf(0, bundleInfo);
105 if (ret != 0) {
106 HILOGE("bundleName get fail");
107 return "";
108 }
109 return bundleInfo.name;
110 }
111
HandleLocalCheck(const string & path,int mode)112 static int HandleLocalCheck(const string &path, int mode)
113 {
114 // check if the file of /data/storage/el2/cloud is on the local
115 if (path.find(CLOUDDISK_FILE_PREFIX) == 0) {
116 char val[2] = {'\0'};
117 if (getxattr(path.c_str(), CLOUD_FILE_LOCATION.c_str(), val, sizeof(val)) < 0) {
118 HILOGI("get cloud file location fail, err: %{public}d", errno);
119 return errno;
120 }
121 if (val[0] == POSITION_LOCAL || val[0] == POSITION_BOTH) {
122 return 0;
123 }
124 return ENOENT;
125 }
126 // check if the distributed file of /data/storage/el2/distributedfiles is on the local,
127 // convert into physical path(/mnt/hmdfs/<currentUserId>/account/device_view/local/data/<PackageName>) and check
128 if (path.find(DISTRIBUTED_FILE_PREFIX) == 0) {
129 int userId = GetCurrentUserId();
130 string bundleName = GetSelfBundleName();
131 string relativePath = path.substr(DISTRIBUTED_FILE_PREFIX.length());
132 string physicalPath = PHYSICAL_PATH_PREFIX + relativePath;
133 physicalPath.replace(physicalPath.find(USER_ID_FLAG), USER_ID_FLAG.length(), to_string(userId));
134 physicalPath.replace(physicalPath.find(PACKAGE_NAME_FLAG), PACKAGE_NAME_FLAG.length(), bundleName);
135
136 return UvAccess(physicalPath, mode);
137 }
138
139 return ENOENT;
140 }
141 #endif
142
Access(const string & path,int mode,int flag)143 static int Access(const string &path, int mode, int flag)
144 {
145 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
146 if (flag == LOCAL_FLAG && IsCloudOrDistributedFilePath(path)) {
147 return HandleLocalCheck(path, mode);
148 }
149 #endif
150 return UvAccess(path, mode);
151 }
152
GetMode(const std::optional<AccessModeType> & modeOpt,bool * hasMode)153 static int GetMode(const std::optional<AccessModeType> &modeOpt, bool *hasMode)
154 {
155 if (modeOpt.has_value()) {
156 int mode = static_cast<int>(modeOpt.value());
157 *hasMode = true;
158 if ((static_cast<unsigned int>(mode) & 0x06) == static_cast<unsigned int>(mode)) {
159 return mode;
160 }
161 }
162
163 return -1;
164 }
165
ValidAccessArgs(const std::string & path,const std::optional<AccessModeType> & modeOpt,int & finalMode)166 static bool ValidAccessArgs(const std::string &path, const std::optional<AccessModeType> &modeOpt,
167 int &finalMode)
168 {
169 if (path.empty()) {
170 HILOGE("Invalid path");
171 return false;
172 }
173 bool hasMode = false;
174 int mode = GetMode(modeOpt, &hasMode);
175 if (mode < 0 && hasMode) {
176 HILOGE("Invalid mode");
177 return false;
178 }
179 finalMode = hasMode ? mode : 0;
180 return true;
181 }
182
DoAccess(const std::string & path,const std::optional<AccessModeType> & mode)183 FsResult<bool> AccessCore::DoAccess(const std::string& path, const std::optional<AccessModeType> &mode)
184 {
185 int finalMode = 0;
186 int flag = DEFAULT_FLAG;
187 if (!ValidAccessArgs(path, mode, finalMode)) {
188 return FsResult<bool>::Error(EINVAL);
189 }
190 int ret = Access(path, finalMode, flag);
191 if (ret < 0 && (std::string_view(uv_err_name(ret)) != "ENOENT")) {
192 HILOGE("Failed to access file by path");
193 return FsResult<bool>::Error(ret);
194 }
195 bool isAccess = (ret == 0);
196 return FsResult<bool>::Success(isAccess);
197 }
198
DoAccess(const std::string & path,const AccessModeType & mode,const AccessFlag & flag)199 FsResult<bool> AccessCore::DoAccess(const std::string& path, const AccessModeType &mode, const AccessFlag &flag)
200 {
201 int finalMode = static_cast<int>(mode);
202 int finalFlag = static_cast<int>(flag);
203 if (!ValidAccessArgs(path, std::make_optional(mode), finalMode)) {
204 return FsResult<bool>::Error(EINVAL);
205 }
206 int ret = Access(path, finalMode, finalFlag);
207 if (ret < 0 && (std::string_view(uv_err_name(ret)) != "ENOENT")) {
208 HILOGE("Failed to access file by path");
209 return FsResult<bool>::Error(ret);
210 }
211 bool isAccess = (ret == 0);
212 return FsResult<bool>::Success(isAccess);
213 }
214
215 } // namespace ModuleFileIO
216 } // namespace FileManagement
217 } // namespace OHOS