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
16 #include "remote_file_share.h"
17
18 #include <fcntl.h>
19 #include <sys/ioctl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <climits>
24 #include <pthread.h>
25
26 #include "log.h"
27 #ifdef ENABLE_DEVICE_MANAGER
28 #include "device_manager.h"
29 #include "device_manager_callback.h"
30 #endif
31 #include "sandbox_helper.h"
32 #include "securec.h"
33 #include "uri.h"
34
35 namespace OHOS {
36 namespace AppFileService {
37 namespace ModuleRemoteFileShare {
38 #ifdef ENABLE_DEVICE_MANAGER
39 using namespace OHOS::DistributedHardware;
40 #endif
41 namespace {
42 const int HMDFS_CID_SIZE = 64;
43 const int USER_ID_INIT = 100;
44 const unsigned HMDFS_IOC = 0xf2;
45 const std::string FILE_SCHEME = "file";
46 const std::string DISTRIBUTED_DIR_PATH = "/data/storage/el2/distributedfiles";
47 const std::string DST_PATH_HEAD = "/data/service/el2/";
48 const std::string DST_PATH_MID = "/hmdfs/account/data/";
49 const std::string SHAER_PATH_HEAD = "/mnt/hmdfs/";
50 const std::string SHAER_PATH_MID = "/account/merge_view/services/";
51 const std::string LOWER_SHARE_PATH_HEAD = "/mnt/hmdfs/";
52 const std::string LOWER_SHARE_PATH_MID = "/account/device_view/local/services/";
53 const std::string SHARE_PATH_DIR = "/.share";
54 const std::string REMOTE_SHARE_PATH_DIR = "/.remote_share";
55 const std::string MEDIA_AUTHORITY = "media";
56 const std::string FILE_MANAGER_AUTHORITY = "docs";
57 const std::string PACKAGE_NAME = "get_dfs_uri_from_local";
58 const std::string NETWORK_PARA = "?networkid=";
59 }
60
61 #define HMDFS_IOC_SET_SHARE_PATH _IOW(HMDFS_IOC, 1, struct HmdfsShareControl)
62 #define HMDFS_IOC_GET_DST_PATH _IOR(HMDFS_IOC, 3, unsigned int)
63
64 struct HmdfsShareControl {
65 int fd;
66 char deviceId[HMDFS_CID_SIZE];
67 };
68
69 struct HmdfsDstInfo {
70 uint64_t localLen;
71 uint64_t localPathIndex;
72 uint64_t distributedLen;
73 uint64_t distributedPathIndex;
74 uint64_t bundleNameLen;
75 uint64_t bundleNameIndex;
76 uint64_t size;
77 };
78
79 #ifdef ENABLE_DEVICE_MANAGER
80 class InitDMCallback : public DmInitCallback {
81 public:
82 InitDMCallback() = default;
83 ~InitDMCallback() override = default;
OnRemoteDied()84 void OnRemoteDied() override {};
85 };
86 #endif
87
GetProcessName()88 static std::string GetProcessName()
89 {
90 char pthreadName[PATH_MAX];
91 int ret = pthread_getname_np(pthread_self(), pthreadName, sizeof(pthreadName));
92 if (ret != 0) {
93 LOGE("RemoteFileShare::GetProcessName, pthread_getname_np failed with %{public}d", errno);
94 return "";
95 }
96 std::string pthreadNameStr = pthreadName;
97 LOGI("RemoteFileShare::GetProcessName, thread name is %{public}s", pthreadNameStr.c_str());
98 return pthreadNameStr;
99 }
100
GetFileName(const int & fd)101 static std::string GetFileName(const int &fd)
102 {
103 char buf[PATH_MAX] = {'\0'};
104 char filePath[PATH_MAX] = {'\0'};
105
106 int ret = snprintf_s(buf, sizeof(buf), sizeof(buf), "/proc/self/fd/%d", fd);
107 if (ret < 0) {
108 LOGE("RemoteFileShare::GetFileName, snprintf failed with %{public}d", errno);
109 return "";
110 }
111
112 ret = readlink(buf, filePath, PATH_MAX);
113 if (ret < 0 || ret >= PATH_MAX) {
114 LOGE("RemoteFileShare::GetFileName, readlink failed with %{public}d", errno);
115 return "";
116 }
117
118 std::string fileName = filePath;
119 std::size_t firstSlash = fileName.rfind("/");
120 if (firstSlash == fileName.npos) {
121 LOGE("RemoteFileShare::GetFileName, get error path");
122 return "";
123 }
124 fileName = fileName.substr(firstSlash + 1, fileName.size() - firstSlash);
125 return fileName;
126 }
127
CreateShareDir(const std::string & path)128 static int CreateShareDir(const std::string &path)
129 {
130 if (access(path.c_str(), F_OK) != 0) {
131 int ret = mkdir(path.c_str(), S_IRWXU);
132 if (ret != 0) {
133 LOGE("RemoteFileShare::CreateShareDir, make dir failed with %{public}d", errno);
134 return errno;
135 }
136 }
137 return 0;
138 }
139
GetSharePath(const int & userId,const std::string & packageName)140 static std::string GetSharePath(const int &userId, const std::string &packageName)
141 {
142 return SHAER_PATH_HEAD + std::to_string(userId) + SHAER_PATH_MID + packageName;
143 }
144
GetLowerSharePath(const int & userId,const std::string & packageName)145 static std::string GetLowerSharePath(const int &userId, const std::string &packageName)
146 {
147 return LOWER_SHARE_PATH_HEAD + std::to_string(userId) + LOWER_SHARE_PATH_MID + packageName;
148 }
149
DeleteShareDir(const std::string & PACKAGE_PATH,const std::string & SHARE_PATH)150 static bool DeleteShareDir(const std::string &PACKAGE_PATH, const std::string &SHARE_PATH)
151 {
152 bool result = true;
153 if (access(SHARE_PATH.c_str(), F_OK) == 0) {
154 int ret = rmdir(SHARE_PATH.c_str());
155 if (ret != 0) {
156 LOGE("RemoteFileShare::DeleteShareDir, delete dir failed with %{public}d", errno);
157 result = false;
158 } else {
159 LOGI("RemoteFileShare::DeleteShareDir, delete path successfully");
160 }
161 }
162 if (access(PACKAGE_PATH.c_str(), F_OK) == 0) {
163 int ret = rmdir(PACKAGE_PATH.c_str());
164 if (ret != 0) {
165 LOGE("RemoteFileShare::DeleteShareDir, delete dir failed with %{public}d", errno);
166 result = false;
167 } else {
168 LOGI("RemoteFileShare::DeleteShareDir, delete path successfully");
169 }
170 }
171 return result;
172 }
173
CreateShareFile(struct HmdfsShareControl & shareControl,const char * file,const std::string & deviceId)174 static int CreateShareFile(struct HmdfsShareControl &shareControl, const char* file,
175 const std::string &deviceId)
176 {
177 int32_t dirFd = open(file, O_RDONLY);
178 if (dirFd < 0) {
179 LOGE("RemoteFileShare::CreateShareFile, open share path failed with %{public}d", errno);
180 return errno;
181 }
182
183 memset_s(shareControl.deviceId, HMDFS_CID_SIZE, '\0', HMDFS_CID_SIZE);
184 if (memcpy_s(shareControl.deviceId, HMDFS_CID_SIZE, deviceId.c_str(), deviceId.size()) != 0) {
185 LOGE("RemoteFileShare::CreateShareFile, memcpy_s failed with %{public}d", errno);
186 close(dirFd);
187 return errno;
188 }
189
190 if (ioctl(dirFd, HMDFS_IOC_SET_SHARE_PATH, &shareControl) < 0) {
191 LOGE("RemoteFileShare::CreateShareFile, ioctl failed with %{public}d", errno);
192 }
193 close(dirFd);
194 return 0;
195 }
196
CheckInputValidity(const int & fd,const int & userId,const std::string & deviceId)197 static int CheckInputValidity(const int &fd, const int &userId, const std::string &deviceId)
198 {
199 return (fd < 0) || (userId < USER_ID_INIT) || (deviceId != SHARE_ALL_DEVICE &&
200 deviceId.size() != HMDFS_CID_SIZE);
201 }
202
CreateSharePath(const int & fd,std::string & sharePath,const int & userId,const std::string & deviceId)203 int RemoteFileShare::CreateSharePath(const int &fd, std::string &sharePath,
204 const int &userId, const std::string &deviceId)
205 {
206 struct HmdfsShareControl shareControl;
207 shareControl.fd = fd;
208
209 if (CheckInputValidity(fd, userId, deviceId) != 0) {
210 LOGE("RemoteFileShare::CreateSharePath, invalid argument with %{public}d", EINVAL);
211 return EINVAL;
212 }
213
214 const std::string processName = GetProcessName();
215 if (processName == "") {
216 LOGE("RemoteFileShare::CreateSharePath, GetProcessName failed with %{public}d", errno);
217 return errno;
218 }
219
220 const std::string PACKAGE_PATH = GetLowerSharePath(userId, processName);
221 if (!SandboxHelper::IsValidPath(PACKAGE_PATH)) {
222 LOGE("RemoteFileShare::CreateSharePath, GetLowerSharePath failed");
223 return EACCES;
224 }
225
226 const std::string LOWER_SHARE_PATH = PACKAGE_PATH + SHARE_PATH_DIR;
227 if (CreateShareDir(PACKAGE_PATH) != 0)
228 return errno;
229 if (CreateShareDir(LOWER_SHARE_PATH) != 0) {
230 DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
231 return errno;
232 }
233
234 const std::string SHARE_PATH = GetSharePath(userId, processName) + SHARE_PATH_DIR;
235 char realPath[PATH_MAX] = {'\0'};
236 if (!realpath(SHARE_PATH.c_str(), realPath)) {
237 LOGE("RemoteFileShare::CreateSharePath, realpath failed with %{public}d", errno);
238 DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
239 return errno;
240 }
241
242 std::string file_name = GetFileName(shareControl.fd);
243 if (file_name == "") {
244 LOGE("RemoteFileShare::CreateSharePath, get error file name");
245 DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
246 return EBADF;
247 }
248 sharePath = SHARE_PATH + "/" + file_name;
249
250 if (CreateShareFile(shareControl, realPath, deviceId) != 0) {
251 LOGE("RemoteFileShare::CreateSharePath, create share file failed with %{public}d", errno);
252 /* When the file is exist, we should not delete the dictionary */
253 if (errno == EEXIST) {
254 return 0;
255 }
256 sharePath = "";
257 DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
258 return errno;
259 }
260 LOGI("RemoteFileShare::CreateSharePath, create successfully");
261 return 0;
262 }
263
GetDistributedPath(Uri & uri,const int & userId,std::string & distributedPath)264 static int GetDistributedPath(Uri &uri, const int &userId, std::string &distributedPath)
265 {
266 distributedPath = DST_PATH_HEAD + std::to_string(userId) + DST_PATH_MID + uri.GetAuthority() +
267 REMOTE_SHARE_PATH_DIR + SandboxHelper::Decode(uri.GetPath());
268 if (distributedPath.size() >= PATH_MAX) {
269 return -EINVAL;
270 }
271
272 return 0;
273 }
274
GetPhysicalPath(Uri & uri,const std::string & userId)275 static std::string GetPhysicalPath(Uri &uri, const std::string &userId)
276 {
277 std::string sandboxPath = SandboxHelper::Decode(uri.GetPath());
278 if (!SandboxHelper::IsValidPath(sandboxPath) || uri.GetScheme() != FILE_SCHEME) {
279 LOGE("Sandbox path from uri is error");
280 return "";
281 }
282
283 std::string physicalPath = "";
284 int ret = SandboxHelper::GetPhysicalPath(uri.ToString(), userId, physicalPath);
285 if (ret != 0) {
286 LOGE("Get physical path failed with %{public}d", ret);
287 return "";
288 }
289 return physicalPath;
290 }
291
InitHmdfsInfo(struct HmdfsDstInfo & hdi,const std::string & physicalPath,const std::string & distributedPath,const std::string & bundleName)292 static void InitHmdfsInfo(struct HmdfsDstInfo &hdi, const std::string &physicalPath,
293 const std::string &distributedPath, const std::string &bundleName)
294 {
295 hdi.localLen = physicalPath.size() + 1;
296 hdi.localPathIndex = reinterpret_cast<uint64_t>(physicalPath.c_str());
297
298 hdi.distributedLen = distributedPath.size() + 1;
299 hdi.distributedPathIndex = reinterpret_cast<uint64_t>(distributedPath.c_str());
300
301 hdi.bundleNameLen = bundleName.size() + 1;
302 hdi.bundleNameIndex = reinterpret_cast<uint64_t>(bundleName.c_str());
303
304 hdi.size = reinterpret_cast<uint64_t>(&hdi.size);
305 }
306
GetLocalNetworkId()307 static std::string GetLocalNetworkId()
308 {
309 const std::string LOCAL = "local";
310 std::string networkId = LOCAL;
311 #ifdef ENABLE_DEVICE_MANAGER
312 auto callback = std::make_shared<InitDMCallback>();
313 int32_t ret = DeviceManager::GetInstance().InitDeviceManager(PACKAGE_NAME, callback);
314 if (ret != 0) {
315 return "";
316 }
317
318 DmDeviceInfo info;
319 ret = DeviceManager::GetInstance().GetLocalDeviceInfo(PACKAGE_NAME, info);
320 networkId = std::string(info.networkId);
321 LOGD("GetLocalNetworkId :%{private}s", networkId.c_str());
322 if (ret != 0 || networkId.empty()) {
323 return "";
324 }
325 #endif
326 return networkId;
327 }
328
SetHmdfsUriInfo(struct HmdfsUriInfo & hui,Uri & uri,uint64_t fileSize)329 static void SetHmdfsUriInfo(struct HmdfsUriInfo &hui, Uri &uri, uint64_t fileSize)
330 {
331 std::string bundleName = uri.GetAuthority();
332 std::string networkId = NETWORK_PARA + GetLocalNetworkId();
333
334 hui.uriStr = FILE_SCHEME + "://" + bundleName + DISTRIBUTED_DIR_PATH + REMOTE_SHARE_PATH_DIR +
335 uri.GetPath() + networkId;
336
337 hui.fileSize = fileSize;
338 return;
339 }
340
SetPublicDirHmdfsInfo(const std::string & physicalPath,const std::string & uriStr,struct HmdfsUriInfo & hui)341 static int32_t SetPublicDirHmdfsInfo(const std::string &physicalPath, const std::string &uriStr,
342 struct HmdfsUriInfo &hui)
343 {
344 hui.uriStr = uriStr + NETWORK_PARA + GetLocalNetworkId();
345 struct stat buf = {};
346 if (stat(physicalPath.c_str(), &buf) != 0) {
347 LOGE("Failed to get physical path stat with %{public}d", -errno);
348 return -errno;
349 }
350 hui.fileSize = static_cast<size_t>(buf.st_size);
351 return 0;
352 }
353
GetDfsUriFromLocal(const std::string & uriStr,const int32_t & userId,struct HmdfsUriInfo & hui)354 int32_t RemoteFileShare::GetDfsUriFromLocal(const std::string &uriStr, const int32_t &userId,
355 struct HmdfsUriInfo &hui)
356 {
357 Uri uri(uriStr);
358 std::string bundleName = uri.GetAuthority();
359 LOGD("GetDfsUriFromLocal begin");
360 std::string physicalPath = GetPhysicalPath(uri, std::to_string(userId));
361 if (physicalPath == "") {
362 LOGE("Failed to get physical path");
363 return -EINVAL;
364 }
365
366 if (bundleName == MEDIA_AUTHORITY || bundleName == FILE_MANAGER_AUTHORITY) {
367 (void)SetPublicDirHmdfsInfo(physicalPath, uriStr, hui);
368 LOGD("GetDfsUriFromLocal successfully");
369 return 0;
370 }
371
372 std::string distributedPath;
373 int ret = GetDistributedPath(uri, userId, distributedPath);
374 if (ret != 0) {
375 LOGE("Path is too long with %{public}d", ret);
376 return ret;
377 }
378
379 struct HmdfsDstInfo hdi;
380 InitHmdfsInfo(hdi, physicalPath, distributedPath, bundleName);
381
382 std::string ioctlDir = SHAER_PATH_HEAD + std::to_string(userId) + SHAER_PATH_MID;
383 int32_t dirFd = open(ioctlDir.c_str(), O_RDONLY);
384 if (dirFd < 0) {
385 LOGE("Open share path failed with %{public}d", errno);
386 return errno;
387 }
388
389 ret = ioctl(dirFd, HMDFS_IOC_GET_DST_PATH, &hdi);
390 if (ret != 0) {
391 LOGE("Ioctl failed with %{public}d", errno);
392 close(dirFd);
393 return -errno;
394 }
395
396 close(dirFd);
397 SetHmdfsUriInfo(hui, uri, hdi.size);
398 LOGD("GetDfsUriFromLocal successfully");
399 return 0;
400 }
401 } // namespace ModuleRemoteFileShare
402 } // namespace AppFileService
403 } // namespace OHOS
404