• 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 <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