• 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 
IsValidPath(const std::string & path)156 static bool IsValidPath(const std::string &path)
157 {
158     if (path.find("/./") != std::string::npos ||
159         path.find("/../") != std::string::npos) {
160         return false;
161     }
162     return true;
163 }
164 
CreateShareFile(struct HmdfsShareControl & shareControl,const char * file,const std::string & deviceId)165 static int CreateShareFile(struct HmdfsShareControl &shareControl, const char* file,
166                            const std::string &deviceId)
167 {
168     int32_t dirFd = open(file, O_RDONLY);
169     if (dirFd < 0) {
170         LOGE("RemoteFileShare::CreateShareFile, open share path failed with %{public}d", errno);
171         return errno;
172     }
173 
174     memset_s(shareControl.deviceId, HMDFS_CID_SIZE, '\0', HMDFS_CID_SIZE);
175     if (memcpy_s(shareControl.deviceId, HMDFS_CID_SIZE, deviceId.c_str(), deviceId.size()) != 0) {
176         LOGE("RemoteFileShare::CreateShareFile, memcpy_s failed with %{public}d", errno);
177         close(dirFd);
178         return errno;
179     }
180 
181     if (ioctl(dirFd, HMDFS_IOC_SET_SHARE_PATH, &shareControl) < 0) {
182         LOGE("RemoteFileShare::CreateShareFile, ioctl failed with %{public}d", errno);
183         close(dirFd);
184         return errno;
185     }
186     close(dirFd);
187     return 0;
188 }
189 
CheckInputValidity(const int & fd,const int & userId,const std::string & deviceId)190 static int CheckInputValidity(const int &fd, const int &userId, const std::string &deviceId)
191 {
192     return (fd < 0) || (userId < USER_ID_INIT) || (deviceId != SHARE_ALL_DEVICE &&
193                                                         deviceId.size() != HMDFS_CID_SIZE);
194 }
195 
CreateSharePath(const int & fd,std::string & sharePath,const int & userId,const std::string & deviceId)196 int RemoteFileShare::CreateSharePath(const int &fd, std::string &sharePath,
197                                      const int &userId, const std::string &deviceId)
198 {
199     struct HmdfsShareControl shareControl;
200     shareControl.fd = fd;
201 
202     if (CheckInputValidity(fd, userId, deviceId) != 0) {
203         LOGE("RemoteFileShare::CreateSharePath, invalid argument with %{public}d", EINVAL);
204         return EINVAL;
205     }
206 
207     const std::string processName = GetProcessName();
208     if (processName == "") {
209         LOGE("RemoteFileShare::CreateSharePath, GetProcessName failed with %{public}d", errno);
210         return errno;
211     }
212 
213     const std::string PACKAGE_PATH = GetLowerSharePath(userId, processName);
214     if (!IsValidPath(PACKAGE_PATH)) {
215         LOGE("RemoteFileShare::CreateSharePath, GetLowerSharePath failed with %{private}s", PACKAGE_PATH.c_str());
216         return EACCES;
217     }
218 
219     const std::string LOWER_SHARE_PATH = PACKAGE_PATH + SHARE_PATH_DIR;
220     if (CreateShareDir(PACKAGE_PATH) != 0)
221         return errno;
222     if (CreateShareDir(LOWER_SHARE_PATH) != 0) {
223         DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
224         return errno;
225     }
226 
227     const std::string SHARE_PATH = GetSharePath(userId, processName) + SHARE_PATH_DIR;
228     char realPath[PATH_MAX] = {'\0'};
229     if (!realpath(SHARE_PATH.c_str(), realPath)) {
230         LOGE("RemoteFileShare::CreateSharePath, realpath failed with %{public}d", errno);
231         DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
232         return errno;
233     }
234 
235     std::string file_name = GetFileName(shareControl.fd);
236     if (file_name == "") {
237         LOGE("RemoteFileShare::CreateSharePath, get error file name");
238         DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
239         return EBADF;
240     }
241     sharePath = SHARE_PATH + "/" + file_name;
242 
243     if (CreateShareFile(shareControl, realPath, deviceId) != 0) {
244         LOGE("RemoteFileShare::CreateSharePath, create share file failed with %{public}d", errno);
245         /* When the file is exist, we should not delete the dictionary */
246         if (errno == EEXIST) {
247             return 0;
248         }
249         sharePath = "";
250         DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH);
251         return errno;
252     }
253     LOGI("RemoteFileShare::CreateSharePath, create %{public}s successfully", sharePath.c_str());
254     return 0;
255 }
256 
GetDistributedPath(Uri & uri,const int & userId,std::string & distributedPath)257 static int GetDistributedPath(Uri &uri, const int &userId, std::string &distributedPath)
258 {
259     distributedPath = DST_PATH_HEAD + std::to_string(userId) + DST_PATH_MID +
260                       uri.GetAuthority() + REMOTE_SHARE_PATH_DIR + uri.GetPath();
261     if (distributedPath.size() >= PATH_MAX) {
262         return -EINVAL;
263     }
264 
265     return 0;
266 }
267 
GetPhysicalPath(Uri & uri,const std::string & userId)268 static std::string GetPhysicalPath(Uri &uri, const std::string &userId)
269 {
270     std::string sandboxPath = uri.GetPath();
271     if (!IsValidPath(sandboxPath) || uri.GetScheme() != FILE_SCHEME) {
272         LOGE("Sandbox path from uri is error with %{public}s", sandboxPath.c_str());
273         return "";
274     }
275 
276     std::string physicalPath = "";
277     int ret = SandboxHelper::GetPhysicalPath(uri.ToString(), userId, physicalPath);
278     if (ret != 0) {
279         LOGE("Get physical path failed with %{public}d", ret);
280         return "";
281     }
282     return physicalPath;
283 }
284 
InitHmdfsInfo(struct HmdfsDstInfo & hdi,const std::string & physicalPath,const std::string & distributedPath,const std::string & bundleName)285 static void InitHmdfsInfo(struct HmdfsDstInfo &hdi, const std::string &physicalPath,
286                           const std::string &distributedPath, const std::string &bundleName)
287 {
288     hdi.localLen = physicalPath.size() + 1;
289     hdi.localPathIndex = reinterpret_cast<uint64_t>(physicalPath.c_str());
290 
291     hdi.distributedLen = distributedPath.size() + 1;
292     hdi.distributedPathIndex = reinterpret_cast<uint64_t>(distributedPath.c_str());
293 
294     hdi.bundleNameLen = bundleName.size() + 1;
295     hdi.bundleNameIndex = reinterpret_cast<uint64_t>(bundleName.c_str());
296 
297     hdi.size = reinterpret_cast<uint64_t>(&hdi.size);
298 }
299 
SetHmdfsUriInfo(struct HmdfsUriInfo & hui,Uri & uri,uint64_t fileSize)300 static void SetHmdfsUriInfo(struct HmdfsUriInfo &hui, Uri &uri, uint64_t fileSize)
301 {
302     std::string bundleName = uri.GetAuthority();
303     std::string path = uri.GetPath();
304 
305     hui.uriStr = SandboxHelper::Encode(FILE_SCHEME + "://" + bundleName + DISTRIBUTED_DIR_PATH +
306                                        REMOTE_SHARE_PATH_DIR + path);
307     hui.fileSize = fileSize;
308     return;
309 }
310 
SetPublicDirHmdfsInfo(const std::string & physicalPath,const std::string & uriStr,struct HmdfsUriInfo & hui)311 static int32_t SetPublicDirHmdfsInfo(const std::string &physicalPath, const std::string &uriStr,
312                                      struct HmdfsUriInfo &hui)
313 {
314     hui.uriStr = uriStr;
315     struct stat buf = {};
316     if (stat(physicalPath.c_str(), &buf) != 0) {
317         LOGE("Failed to get physical path stat with %{public}d", -errno);
318         return -errno;
319     }
320     hui.fileSize = static_cast<size_t>(buf.st_size);
321     return 0;
322 }
323 
GetDfsUriFromLocal(const std::string & uriStr,const int32_t & userId,struct HmdfsUriInfo & hui)324 int32_t RemoteFileShare::GetDfsUriFromLocal(const std::string &uriStr, const int32_t &userId,
325                                             struct HmdfsUriInfo &hui)
326 {
327     Uri uri(SandboxHelper::Decode(uriStr));
328     std::string bundleName = uri.GetAuthority();
329     LOGD("GetDfsUriFromLocal begin with uri:%{private}s, decode uri:%{private}s",
330          uriStr.c_str(), uri.ToString().c_str());
331     std::string physicalPath = GetPhysicalPath(uri, std::to_string(userId));
332     if (physicalPath == "") {
333         LOGE("Failed to get physical path");
334         return -EINVAL;
335     }
336 
337     if (bundleName == MEDIA_AUTHORITY || bundleName == FILE_MANAGER_AUTHORITY) {
338         (void)SetPublicDirHmdfsInfo(physicalPath, uriStr, hui);
339         return 0;
340     }
341 
342     std::string distributedPath;
343     int ret = GetDistributedPath(uri, userId, distributedPath);
344     if (ret != 0) {
345         LOGE("Path is too long with %{public}d", ret);
346         return ret;
347     }
348 
349     struct HmdfsDstInfo hdi;
350     LOGD("PhysicalPath: %{private}s DistributedPath: %{private}s BundleName: %{private}s",
351          physicalPath.c_str(), distributedPath.c_str(), bundleName.c_str());
352     InitHmdfsInfo(hdi, physicalPath, distributedPath, bundleName);
353 
354     std::string ioctlDir = SHAER_PATH_HEAD + std::to_string(userId) + SHAER_PATH_MID;
355     int32_t dirFd = open(ioctlDir.c_str(), O_RDONLY);
356     if (dirFd < 0) {
357         LOGE("Open share path failed with %{public}d", errno);
358         return errno;
359     }
360 
361     ret = ioctl(dirFd, HMDFS_IOC_GET_DST_PATH, &hdi);
362     if (ret != 0) {
363         LOGE("Ioctl failed with %{public}d", errno);
364         close(dirFd);
365         return -errno;
366     }
367 
368     close(dirFd);
369     SetHmdfsUriInfo(hui, uri, hdi.size);
370     LOGD("GetDfsUriFromLocal successfully with %{private}s", hui.uriStr.c_str());
371     return 0;
372 }
373 } // namespace ModuleRemoteFileShare
374 } // namespace AppFileService
375 } // namespace OHOS
376