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