• 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 
16 #include "remote_file_share.h"
17 
18 #include <climits>
19 #include <fcntl.h>
20 #include <pthread.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.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 "unique_fd.h"
34 #include "uri.h"
35 
36 namespace OHOS {
37 namespace AppFileService {
38 namespace ModuleRemoteFileShare {
39 #ifdef ENABLE_DEVICE_MANAGER
40 using namespace OHOS::DistributedHardware;
41 #endif
42 namespace {
43 const int HMDFS_CID_SIZE = 64;
44 const int USER_ID_INIT = 100;
45 const unsigned HMDFS_IOC = 0xf2;
46 const std::string FILE_SCHEME = "file";
47 const std::string DISTRIBUTED_DIR_PATH = "/data/storage/el2/distributedfiles";
48 const std::string DST_PATH_HEAD = "/data/service/el2/";
49 const std::string DST_PATH_MID = "/hmdfs/account/data/";
50 const std::string SHAER_PATH_HEAD = "/mnt/hmdfs/";
51 const std::string SHAER_PATH_MID = "/account/merge_view/services/";
52 const std::string LOWER_SHARE_PATH_HEAD = "/mnt/hmdfs/";
53 const std::string LOWER_SHARE_PATH_MID = "/account/device_view/local/services/";
54 const std::string SHARE_PATH_DIR = "/.share";
55 const std::string REMOTE_SHARE_PATH_DIR = "/.remote_share";
56 const std::string MEDIA_AUTHORITY = "media";
57 const std::string FILE_MANAGER_AUTHORITY = "docs";
58 const std::string PACKAGE_NAME = "get_dfs_uri_from_local";
59 const std::string NETWORK_PARA = "?networkid=";
60 const std::string MEDIA_BUNDLE_NAME = "com.ohos.medialibrary.medialibrarydata";
61 const std::string FILE_MANAGER_URI_HEAD = "/storage/";
62 const std::string REMOTE_SHARE_PATH_MID = "hmdfs/";
63 } //namespace
64 
65 #define HMDFS_IOC_SET_SHARE_PATH _IOW(HMDFS_IOC, 1, struct HmdfsShareControl)
66 #define HMDFS_IOC_GET_DST_PATH _IOR(HMDFS_IOC, 3, unsigned int)
67 
68 struct HmdfsShareControl {
69     int fd;
70     char deviceId[HMDFS_CID_SIZE];
71 };
72 
73 struct HmdfsDstInfo {
74     uint64_t localLen;
75     uint64_t localPathIndex;
76     uint64_t distributedLen;
77     uint64_t distributedPathIndex;
78     uint64_t bundleNameLen;
79     uint64_t bundleNameIndex;
80     uint64_t size;
81 };
82 
83 #ifdef ENABLE_DEVICE_MANAGER
84 class InitDMCallback : public DmInitCallback {
85 public:
86     InitDMCallback() = default;
87     ~InitDMCallback() override = default;
OnRemoteDied()88     void OnRemoteDied() override {};
89 };
90 #endif
91 
GetProcessName()92 static std::string GetProcessName()
93 {
94     char pthreadName[PATH_MAX];
95     int ret = pthread_getname_np(pthread_self(), pthreadName, sizeof(pthreadName));
96     if (ret != 0) {
97         LOGE("RemoteFileShare::GetProcessName, pthread_getname_np failed with %{public}d", errno);
98         return "";
99     }
100     std::string pthreadNameStr = pthreadName;
101     LOGI("RemoteFileShare::GetProcessName, thread name is %{public}s", pthreadNameStr.c_str());
102     return pthreadNameStr;
103 }
104 
GetFileName(const int & fd)105 static std::string GetFileName(const int &fd)
106 {
107     char buf[PATH_MAX] = {'\0'};
108     char filePath[PATH_MAX] = {'\0'};
109 
110     int ret = snprintf_s(buf, sizeof(buf), sizeof(buf), "/proc/self/fd/%d", fd);
111     if (ret < 0) {
112         LOGE("RemoteFileShare::GetFileName, snprintf failed with %{public}d", errno);
113         return "";
114     }
115 
116     ret = readlink(buf, filePath, PATH_MAX);
117     if (ret < 0 || ret >= PATH_MAX) {
118         LOGE("RemoteFileShare::GetFileName, readlink failed with %{public}d", errno);
119         return "";
120     }
121 
122     std::string fileName = filePath;
123     std::size_t firstSlash = fileName.rfind("/");
124     if (firstSlash == fileName.npos) {
125         LOGE("RemoteFileShare::GetFileName, get error path");
126         return "";
127     }
128     fileName = fileName.substr(firstSlash + 1, fileName.size() - firstSlash);
129     return fileName;
130 }
131 
CreateShareDir(const std::string & path)132 static int CreateShareDir(const std::string &path)
133 {
134     if (access(path.c_str(), F_OK) != 0) {
135         int ret = mkdir(path.c_str(), S_IRWXU);
136         if (ret != 0) {
137             LOGE("RemoteFileShare::CreateShareDir, make dir failed with %{public}d", errno);
138             return errno;
139         }
140     }
141     return 0;
142 }
143 
GetSharePath(const int & userId,const std::string & packageName)144 static std::string GetSharePath(const int &userId, const std::string &packageName)
145 {
146     return SHAER_PATH_HEAD + std::to_string(userId) + SHAER_PATH_MID + packageName;
147 }
148 
GetLowerSharePath(const int & userId,const std::string & packageName)149 static std::string GetLowerSharePath(const int &userId, const std::string &packageName)
150 {
151     return LOWER_SHARE_PATH_HEAD + std::to_string(userId) + LOWER_SHARE_PATH_MID + packageName;
152 }
153 
DeleteShareDir(const std::string & PACKAGE_PATH,const std::string & SHARE_PATH)154 static bool DeleteShareDir(const std::string &PACKAGE_PATH, const std::string &SHARE_PATH)
155 {
156     bool result = true;
157     if (access(SHARE_PATH.c_str(), F_OK) == 0) {
158         int ret = rmdir(SHARE_PATH.c_str());
159         if (ret != 0) {
160             LOGE("RemoteFileShare::DeleteShareDir, delete dir failed with %{public}d", errno);
161             result = false;
162         } else {
163             LOGI("RemoteFileShare::DeleteShareDir, delete path successfully");
164         }
165     }
166     if (access(PACKAGE_PATH.c_str(), F_OK) == 0) {
167         int ret = rmdir(PACKAGE_PATH.c_str());
168         if (ret != 0) {
169             LOGE("RemoteFileShare::DeleteShareDir, delete dir failed with %{public}d", errno);
170             result = false;
171         } else {
172             LOGI("RemoteFileShare::DeleteShareDir, delete path successfully");
173         }
174     }
175     return result;
176 }
177 
CreateShareFile(struct HmdfsShareControl & shareControl,const char * file,const std::string & deviceId)178 static int CreateShareFile(struct HmdfsShareControl &shareControl, const char *file, const std::string &deviceId)
179 {
180     int32_t dirFd = open(file, O_RDONLY);
181     if (dirFd < 0) {
182         LOGE("RemoteFileShare::CreateShareFile, open share path failed with %{public}d", errno);
183         return errno;
184     }
185 
186     memset_s(shareControl.deviceId, HMDFS_CID_SIZE, '\0', HMDFS_CID_SIZE);
187     if (memcpy_s(shareControl.deviceId, HMDFS_CID_SIZE, deviceId.c_str(), deviceId.size()) != 0) {
188         LOGE("RemoteFileShare::CreateShareFile, memcpy_s failed with %{public}d", errno);
189         close(dirFd);
190         return errno;
191     }
192 
193     if (ioctl(dirFd, HMDFS_IOC_SET_SHARE_PATH, &shareControl) < 0) {
194         LOGE("RemoteFileShare::CreateShareFile, ioctl failed with %{public}d", errno);
195     }
196     close(dirFd);
197     return 0;
198 }
199 
CheckInputValidity(const int & fd,const int & userId,const std::string & deviceId)200 static int CheckInputValidity(const int &fd, const int &userId, const std::string &deviceId)
201 {
202     return (fd < 0) || (userId < USER_ID_INIT) || (deviceId != SHARE_ALL_DEVICE && deviceId.size() != HMDFS_CID_SIZE);
203 }
204 
CreateSharePath(const int & fd,std::string & sharePath,const int & userId,const std::string & deviceId)205 int RemoteFileShare::CreateSharePath(const int &fd,
206                                      std::string &sharePath,
207                                      const int &userId,
208                                      const std::string &deviceId)
209 {
210     struct HmdfsShareControl shareControl;
211     shareControl.fd = fd;
212 
213     if (CheckInputValidity(fd, userId, deviceId) != 0) {
214         LOGE("RemoteFileShare::CreateSharePath, invalid argument with %{public}d", EINVAL);
215         return EINVAL;
216     }
217 
218     const std::string processName = GetProcessName();
219     if (processName == "") {
220         LOGE("RemoteFileShare::CreateSharePath, GetProcessName failed with %{public}d", errno);
221         return errno;
222     }
223 
224     const std::string PACKAGE_PATH = GetLowerSharePath(userId, processName);
225     if (!SandboxHelper::IsValidPath(PACKAGE_PATH)) {
226         LOGE("RemoteFileShare::CreateSharePath, GetLowerSharePath failed");
227         return EACCES;
228     }
229 
230     const std::string LOWER_SHARE_PATH = PACKAGE_PATH + SHARE_PATH_DIR;
231     if (CreateShareDir(PACKAGE_PATH) != 0)
232         return errno;
233     if (CreateShareDir(LOWER_SHARE_PATH) != 0) {
234         DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
235         return errno;
236     }
237 
238     const std::string SHARE_PATH = GetSharePath(userId, processName) + SHARE_PATH_DIR;
239     char realPath[PATH_MAX] = {'\0'};
240     if (!realpath(SHARE_PATH.c_str(), realPath)) {
241         LOGE("RemoteFileShare::CreateSharePath, realpath failed with %{public}d", errno);
242         DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
243         return errno;
244     }
245 
246     std::string file_name = GetFileName(shareControl.fd);
247     if (file_name == "") {
248         LOGE("RemoteFileShare::CreateSharePath, get error file name");
249         DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
250         return EBADF;
251     }
252     sharePath = SHARE_PATH + "/" + file_name;
253 
254     if (CreateShareFile(shareControl, realPath, deviceId) != 0) {
255         LOGE("RemoteFileShare::CreateSharePath, create share file failed with %{public}d", errno);
256         /* When the file is exist, we should not delete the dictionary */
257         if (errno == EEXIST) {
258             return 0;
259         }
260         sharePath = "";
261         DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
262         return errno;
263     }
264     LOGI("RemoteFileShare::CreateSharePath, create successfully");
265     return 0;
266 }
267 
GetDistributedPath(Uri & uri,const int & userId,std::string & distributedPath,const std::string & bundleName)268 static int GetDistributedPath(Uri &uri,
269                               const int &userId,
270                               std::string &distributedPath,
271                               const std::string &bundleName)
272 {
273     distributedPath = DST_PATH_HEAD + std::to_string(userId) + DST_PATH_MID + bundleName +
274                       REMOTE_SHARE_PATH_DIR + SandboxHelper::Decode(uri.GetPath());
275     if (distributedPath.size() >= PATH_MAX) {
276         return -EINVAL;
277     }
278 
279     return 0;
280 }
281 
GetPhysicalPath(Uri & uri,const std::string & userId)282 static std::string GetPhysicalPath(Uri &uri, const std::string &userId)
283 {
284     std::string sandboxPath = SandboxHelper::Decode(uri.GetPath());
285     if (!SandboxHelper::IsValidPath(sandboxPath) || uri.GetScheme() != FILE_SCHEME) {
286         LOGE("Sandbox path from uri is error");
287         return "";
288     }
289 
290     std::string physicalPath = "";
291     int ret = SandboxHelper::GetPhysicalPath(uri.ToString(), userId, physicalPath);
292     if (ret != 0) {
293         LOGE("Get physical path failed with %{public}d", ret);
294         return "";
295     }
296     return physicalPath;
297 }
298 
InitHmdfsInfo(struct HmdfsDstInfo & hdi,const std::string & physicalPath,const std::string & distributedPath,const std::string & bundleName)299 static void InitHmdfsInfo(struct HmdfsDstInfo &hdi,
300                           const std::string &physicalPath,
301                           const std::string &distributedPath,
302                           const std::string &bundleName)
303 {
304     hdi.localLen = physicalPath.size() + 1;
305     hdi.localPathIndex = reinterpret_cast<uint64_t>(physicalPath.c_str());
306 
307     hdi.distributedLen = distributedPath.size() + 1;
308     hdi.distributedPathIndex = reinterpret_cast<uint64_t>(distributedPath.c_str());
309 
310     hdi.bundleNameLen = bundleName.size() + 1;
311     hdi.bundleNameIndex = reinterpret_cast<uint64_t>(bundleName.c_str());
312 
313     hdi.size = reinterpret_cast<uint64_t>(&hdi.size);
314 }
315 
GetLocalNetworkId()316 static std::string GetLocalNetworkId()
317 {
318     const std::string LOCAL = "local";
319     std::string networkId = LOCAL;
320 #ifdef ENABLE_DEVICE_MANAGER
321     auto callback = std::make_shared<InitDMCallback>();
322     int32_t ret = DeviceManager::GetInstance().InitDeviceManager(PACKAGE_NAME, callback);
323     if (ret != 0) {
324         return "";
325     }
326 
327     DmDeviceInfo info;
328     ret = DeviceManager::GetInstance().GetLocalDeviceInfo(PACKAGE_NAME, info);
329     networkId = std::string(info.networkId);
330     LOGD("GetLocalNetworkId :%{private}s", networkId.c_str());
331     if (ret != 0 || networkId.empty()) {
332         return "";
333     }
334 #endif
335     return networkId;
336 }
337 
SetHmdfsUriInfo(struct HmdfsUriInfo & hui,Uri & uri,uint64_t fileSize,const std::string & networkId,const std::string & bundleName)338 static void SetHmdfsUriInfo(struct HmdfsUriInfo &hui,
339                             Uri &uri,
340                             uint64_t fileSize,
341                             const std::string &networkId,
342                             const std::string &bundleName)
343 {
344     hui.uriStr = FILE_SCHEME + "://" + bundleName + DISTRIBUTED_DIR_PATH + REMOTE_SHARE_PATH_DIR +
345                  uri.GetPath() + networkId;
346 
347     hui.fileSize = fileSize;
348     return;
349 }
350 
SetPublicDirHmdfsInfo(const std::string & physicalPath,const std::string & uriStr,struct HmdfsUriInfo & hui,const std::string & networkId)351 static int32_t SetPublicDirHmdfsInfo(const std::string &physicalPath, const std::string &uriStr,
352                                      struct HmdfsUriInfo &hui, const std::string &networkId)
353 {
354     hui.uriStr = uriStr + networkId;
355     struct stat buf = {};
356     if (stat(physicalPath.c_str(), &buf) != 0) {
357         LOGE("Failed to get physical path stat with %{public}d", -errno);
358         return -errno;
359     }
360     hui.fileSize = static_cast<size_t>(buf.st_size);
361     return 0;
362 }
363 
GetMergePathFd(HmdfsDstInfo & hdi,UniqueFd & dirFd,const int32_t & userId)364 static int32_t GetMergePathFd(HmdfsDstInfo &hdi, UniqueFd &dirFd, const int32_t &userId)
365 {
366     LOGI("Open merge path start");
367     std::string ioctlDir = SHAER_PATH_HEAD + std::to_string(userId) + SHAER_PATH_MID;
368     UniqueFd dirMergeFd(open(ioctlDir.c_str(), O_RDONLY));
369     if (dirFd < 0) {
370         LOGE("Open merge path failed with %{public}d", errno);
371         return errno;
372     }
373     int32_t ret = ioctl(dirMergeFd, HMDFS_IOC_GET_DST_PATH, &hdi);
374     if (ret != 0) {
375         LOGE("Ioctl merge failed with %{public}d", errno);
376         return -errno;
377     }
378     dirFd = std::move(dirMergeFd);
379     return 0;
380 }
381 
GetDfsUriFromLocal(const std::string & uriStr,const int32_t & userId,struct HmdfsUriInfo & hui)382 int32_t RemoteFileShare::GetDfsUriFromLocal(const std::string &uriStr, const int32_t &userId, struct HmdfsUriInfo &hui)
383 {
384     LOGI("GetDfsUriFromLocal start");
385     Uri uri(uriStr);
386     std::string bundleName = uri.GetAuthority();
387     std::string physicalPath = GetPhysicalPath(uri, std::to_string(userId));
388     if (physicalPath == "") {
389         LOGE("Failed to get physical path");
390         return -EINVAL;
391     }
392     if (bundleName == MEDIA_AUTHORITY) {
393         bundleName = MEDIA_BUNDLE_NAME;
394     }
395 
396     std::string networkId = NETWORK_PARA + GetLocalNetworkId();
397     if (bundleName == FILE_MANAGER_AUTHORITY) {
398         (void)SetPublicDirHmdfsInfo(physicalPath, uriStr, hui, networkId);
399         LOGD("GetDfsUriFromLocal successfully");
400         return 0;
401     }
402 
403     std::string distributedPath;
404     int ret = GetDistributedPath(uri, userId, distributedPath, bundleName);
405     if (ret != 0) {
406         LOGE("Path is too long with %{public}d", ret);
407         return ret;
408     }
409 
410     struct HmdfsDstInfo hdi;
411     InitHmdfsInfo(hdi, physicalPath, distributedPath, bundleName);
412     LOGI("open ioctlDir Create ioctl start");
413     std::string ioctlDir = SHAER_PATH_HEAD + std::to_string(userId) + LOWER_SHARE_PATH_MID;
414     UniqueFd dirFd(open(ioctlDir.c_str(), O_RDONLY));
415     if (dirFd < 0) {
416         LOGE("Open share path failed with %{public}d", errno);
417         return errno;
418     }
419 
420     ret = ioctl(dirFd, HMDFS_IOC_GET_DST_PATH, &hdi);
421     if (ret != 0 && GetMergePathFd(hdi, dirFd, userId) != 0) {
422         return errno;
423     }
424     SetHmdfsUriInfo(hui, uri, hdi.size, networkId, bundleName);
425     LOGI("GetDfsUriFromLocal successfully");
426     return 0;
427 }
428 
GetDfsUrisFromLocal(const std::vector<std::string> & uriList,const int32_t & userId,std::unordered_map<std::string,HmdfsUriInfo> & uriToDfsUriMaps)429 int32_t RemoteFileShare::GetDfsUrisFromLocal(const std::vector<std::string> &uriList,
430                                              const int32_t &userId,
431                                              std::unordered_map<std::string, HmdfsUriInfo> &uriToDfsUriMaps)
432 {
433     LOGI("GetDfsUrisFromLocal start");
434     std::string ioctlDir = SHAER_PATH_HEAD + std::to_string(userId) + LOWER_SHARE_PATH_MID;
435     UniqueFd dirFd(open(ioctlDir.c_str(), O_RDONLY));
436     if (dirFd < 0) {
437         LOGE("Open share path failed with %{public}d", errno);
438         return errno;
439     }
440     LOGI("open ioctlDir end");
441     std::string networkId = NETWORK_PARA + GetLocalNetworkId();
442     for (auto &uriStr : uriList) {
443         Uri uri(uriStr);
444         std::string bundleName = uri.GetAuthority();
445         LOGD("GetDfsUriFromLocal begin, uri: %{private}s", uriStr.c_str());
446         std::string physicalPath = GetPhysicalPath(uri, std::to_string(userId));
447         if (physicalPath == "") {
448             LOGE("Failed to get physical path");
449             return -EINVAL;
450         }
451         if (bundleName == MEDIA_AUTHORITY) {
452             bundleName = MEDIA_BUNDLE_NAME;
453         }
454         if (bundleName == FILE_MANAGER_AUTHORITY) {
455             HmdfsUriInfo dfsUriInfo;
456             (void)SetPublicDirHmdfsInfo(physicalPath, uriStr, dfsUriInfo, networkId);
457             uriToDfsUriMaps.insert({uriStr, dfsUriInfo});
458             LOGD("GetDfsUriFromLocal successfully");
459             continue;
460         }
461 
462         std::string distributedPath;
463         int ret = GetDistributedPath(uri, userId, distributedPath, bundleName);
464         if (ret != 0) {
465             LOGE("Path is too long with %{public}d", ret);
466             return ret;
467         }
468         struct HmdfsDstInfo hdi;
469         InitHmdfsInfo(hdi, physicalPath, distributedPath, bundleName);
470         ret = ioctl(dirFd, HMDFS_IOC_GET_DST_PATH, &hdi);
471         if (ret != 0 && GetMergePathFd(hdi, dirFd, userId) != 0) {
472             return errno;
473         }
474         HmdfsUriInfo dfsUriInfo;
475         SetHmdfsUriInfo(dfsUriInfo, uri, hdi.size, networkId, bundleName);
476         uriToDfsUriMaps.insert({uriStr, dfsUriInfo});
477     }
478     LOGI("GetDfsUrisFromLocal successfully");
479     return 0;
480 }
481 
TransRemoteUriToLocal(const std::vector<std::string> & uriList,const std::string & networkId,const std::string & deviceId,std::vector<std::string> & resultList)482 int32_t RemoteFileShare::TransRemoteUriToLocal(const std::vector<std::string> &uriList,
483                                                const std::string &networkId,
484                                                const std::string &deviceId,
485                                                std::vector<std::string> &resultList)
486 {
487     if (networkId.empty() || deviceId.empty()) {
488         LOGE("RemoteFileShare::TransRemoteUriToLocal, invalid argument with %{public}d", EINVAL);
489         return EINVAL;
490     }
491     constexpr int splitThree = 3;
492     bool allValid = true;
493     std::vector<std::string> tmpResultList;
494     for (auto &uriStr : uriList) {
495         Uri uri(uriStr);
496         std::string bundleName = uri.GetAuthority();
497         std::string sandboxPath = SandboxHelper::Decode(uri.GetPath());
498         if (!SandboxHelper::IsValidPath(sandboxPath) || uri.GetScheme() != FILE_SCHEME) {
499             LOGE("Sandbox path from uri is error");
500             allValid = false;
501             break;
502         }
503         if ((bundleName != FILE_MANAGER_AUTHORITY) || (sandboxPath.find(FILE_MANAGER_URI_HEAD) != 0)) {
504             LOGE("Sandbox path doesn't begin with docs/storage");
505             allValid = false;
506             break;
507         }
508         int cnt = 0;
509         size_t pos = 0;
510         std::string part;
511         while (cnt < splitThree && pos != std::string::npos) {
512             pos = sandboxPath.find('/', pos + 1);
513             cnt++;
514         }
515         if (pos != std::string::npos) {
516             part = sandboxPath.substr(pos + 1);
517         }
518         if (part.empty()) {
519             allValid = false;
520             break;
521         }
522         std::string localUri = FILE_SCHEME + "://" + bundleName + FILE_MANAGER_URI_HEAD +
523                                REMOTE_SHARE_PATH_MID + deviceId + "/" + part;
524         tmpResultList.push_back(localUri);
525     }
526     if (!allValid) {
527         LOGW("Failed to update uriList");
528         resultList = uriList;
529         return -EINVAL;
530     }
531     resultList = tmpResultList;
532     return 0;
533 }
534 } // namespace ModuleRemoteFileShare
535 } // namespace AppFileService
536 } // namespace OHOS
537