• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "file_share.h"
16 
17 #include <dirent.h>
18 #include <fcntl.h>
19 #include <stack>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 
25 #include "accesstoken_kit.h"
26 #include "hap_token_info.h"
27 #include "log.h"
28 #include "uri.h"
29 
30 namespace OHOS {
31 namespace AppFileService {
32 
33 struct FileShareInfo {
34     string providerBundleName_;
35     string targetBundleName_;
36     string providerLowerPath_;
37     string providerSandboxPath_;
38     vector<string> sharePath_;
39     vector<bool> isExist_;
40     string currentUid_;
41     SHARE_FILE_TYPE type_;
42 };
43 
GetTargetInfo(int32_t tokenId,string & bundleName,string & currentUid)44 static int32_t GetTargetInfo(int32_t tokenId, string &bundleName, string &currentUid)
45 {
46     Security::AccessToken::HapTokenInfo hapInfo;
47     int32_t result = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo);
48     if (result != 0) {
49         LOGE("Failed to get hap token info %{public}d", result);
50         return -EINVAL;
51     }
52     bundleName = hapInfo.bundleName;
53     currentUid = to_string(hapInfo.userID);
54     return 0;
55 }
56 
GetProviderBundleName(string uriStr,string & bundleName)57 static void GetProviderBundleName(string uriStr, string &bundleName)
58 {
59     Uri uri(uriStr);
60     bundleName = uri.GetAuthority();
61 }
62 
IsExistDir(const string & path)63 static bool IsExistDir(const string &path)
64 {
65     struct stat buf = {};
66     if (stat(path.c_str(), &buf) != 0) {
67         return false;
68     }
69     return S_ISDIR(buf.st_mode);
70 }
71 
IsExistFile(const string & path)72 static bool IsExistFile(const string &path)
73 {
74     struct stat buf = {};
75     if (stat(path.c_str(), &buf) != 0) {
76         LOGE("Get path stat failed, path: %s err %{public}d", path.c_str(), errno);
77         return false;
78     }
79     return S_ISREG(buf.st_mode);
80 }
81 
GetLowerPath(string & lowerPathHead,const string & lowerPathTail,FileShareInfo & info)82 static int32_t GetLowerPath(string &lowerPathHead, const string &lowerPathTail, FileShareInfo &info)
83 {
84     if (lowerPathHead.empty()) {
85         return -EINVAL;
86     }
87 
88     if (lowerPathHead.find(CURRENT_USER_ID_FLAG) != string::npos) {
89         lowerPathHead = lowerPathHead.replace(lowerPathHead.find(CURRENT_USER_ID_FLAG),
90                                               CURRENT_USER_ID_FLAG.length(), info.currentUid_);
91     }
92 
93     if (lowerPathHead.find(PACKAGE_NAME_FLAG) != string::npos) {
94         lowerPathHead = lowerPathHead.replace(lowerPathHead.find(PACKAGE_NAME_FLAG),
95                                               PACKAGE_NAME_FLAG.length(), info.providerBundleName_);
96     }
97 
98     info.providerLowerPath_ = lowerPathHead + lowerPathTail;
99     return 0;
100 }
101 
GetProviderPath(const string & uriStr,int32_t tokenId,FileShareInfo & info)102 static int32_t GetProviderPath(const string &uriStr, int32_t tokenId, FileShareInfo &info)
103 {
104     Uri uri(uriStr);
105     string pathInProvider = uri.GetPath();
106     string::size_type pos = pathInProvider.find(DATA_STORAGE_PATH);
107     if (pos == string::npos) {
108         return -EINVAL;
109     }
110 
111     size_t num = SANDBOX_PATH.size();
112     string lowerPathTail = "", lowerPathHead = "";
113     for (size_t i = 0; i < num; i++) {
114         if (pathInProvider.length() >= SANDBOX_PATH[i].length()) {
115             string sandboxPathTemp = pathInProvider.substr(0, SANDBOX_PATH[i].length());
116             if (sandboxPathTemp == SANDBOX_PATH[i]) {
117                 lowerPathHead = LOWER_PATH[i];
118                 lowerPathTail = pathInProvider.substr(SANDBOX_PATH[i].length());
119                 break;
120             }
121         }
122     }
123 
124     int32_t ret = GetLowerPath(lowerPathHead, lowerPathTail, info);
125     if (ret != 0) {
126         LOGE("Get lower path failed with %{public}d", ret);
127         return ret;
128     }
129 
130     info.providerSandboxPath_ = pathInProvider;
131     return 0;
132 }
133 
GetSharePath(FileShareInfo & info,int32_t flag)134 static void GetSharePath(FileShareInfo &info, int32_t flag)
135 {
136     string shareRPath = DATA_APP_EL2_PATH + info.currentUid_ + SHARE_PATH +info.targetBundleName_ +
137                         SHARE_R_PATH + info.providerBundleName_ + info.providerSandboxPath_;
138     string shareRWPath = DATA_APP_EL2_PATH + info.currentUid_ + SHARE_PATH +info.targetBundleName_ +
139                          SHARE_RW_PATH + info.providerBundleName_ + info.providerSandboxPath_;
140     if ((flag & WRITE_URI_PERMISSION) == WRITE_URI_PERMISSION) {
141         info.sharePath_.push_back(shareRWPath);
142         info.sharePath_.push_back(shareRPath);
143         info.isExist_.push_back(false);
144         info.isExist_.push_back(false);
145     } else if ((flag & READ_URI_PERMISSION) == READ_URI_PERMISSION) {
146         info.sharePath_.push_back(shareRPath);
147         info.isExist_.push_back(false);
148     }
149 }
150 
GetShareFileType(FileShareInfo & info)151 static int32_t GetShareFileType(FileShareInfo &info)
152 {
153     if (IsExistFile(info.providerLowerPath_)) {
154         info.type_ = FILE_TYPE;
155         return 0;
156     } else if (IsExistDir(info.providerLowerPath_)) {
157         info.type_ = DIR_TYPE;
158         return 0;
159     }
160     return -ENOENT;
161 }
162 
GetFileShareInfo(const string & uri,int32_t tokenId,int32_t flag,FileShareInfo & info)163 static int32_t GetFileShareInfo(const string &uri, int32_t tokenId, int32_t flag, FileShareInfo &info)
164 {
165     int32_t ret = 0;
166     ret = GetTargetInfo(tokenId, info.targetBundleName_, info.currentUid_);
167     if (ret != 0) {
168         LOGE("Failed to get target info %{public}d", ret);
169         return ret;
170     }
171 
172     GetProviderBundleName(uri, info.providerBundleName_);
173     ret = GetProviderPath(uri, tokenId, info);
174     if (ret != 0) {
175         LOGE("Failed to get lower path %{public}d", ret);
176         return ret;
177     }
178 
179     ret = GetShareFileType(info);
180     if (ret != 0) {
181         LOGE("Failed to get share file type %{public}d", ret);
182         return ret;
183     }
184     GetSharePath(info, flag);
185     return 0;
186 }
187 
MakeDir(const string & path)188 static bool MakeDir(const string &path)
189 {
190     string::size_type index = 0;
191     string subPath;
192     do {
193         index = path.find('/', index + 1);
194         if (index == string::npos) {
195             subPath = path;
196         } else {
197             subPath = path.substr(0, index);
198         }
199 
200         if (access(subPath.c_str(), 0) != 0) {
201             if (mkdir(subPath.c_str(), DIR_MODE) != 0) {
202                 LOGE("Failed to make dir with %{public}d", errno);
203                 return false;
204             }
205         }
206     } while (index != string::npos);
207 
208     return true;
209 }
210 
RemoveDir(const string & path)211 static bool RemoveDir(const string& path)
212 {
213     stack<string> dirs, delDirs;
214     dirs.push(path);
215     while (dirs.size() > 0) {
216         string curPath = dirs.top();
217         dirs.pop();
218         DIR *curDir = opendir(curPath.c_str());
219         struct dirent *ptr = readdir(curDir);
220         while (ptr != nullptr) {
221             string subPath = curPath + "/" + string(ptr->d_name);
222             if (ptr->d_type == DT_DIR && strcmp(ptr->d_name, ".") != 0 &&
223                 strcmp(ptr->d_name, "..") != 0) {
224                 dirs.push(subPath);
225                 delDirs.push(subPath);
226             } else if (ptr->d_type != DT_DIR && remove(subPath.c_str()) != 0) {
227                 umount2(subPath.c_str(), MNT_DETACH);
228                 remove(subPath.c_str());
229                 LOGE("Failed to remove dir with %{public}d", errno);
230             }
231             ptr = readdir(curDir);
232         }
233         closedir(curDir);
234     }
235 
236     while (delDirs.size() > 0) {
237         string curPath = delDirs.top();
238         if (remove(curPath.c_str()) != 0) {
239             LOGE("Failed to remove dir with %{public}d", errno);
240         }
241         delDirs.pop();
242     }
243 
244     return true;
245 }
246 
DeleteDir(const string & path)247 static bool DeleteDir(const string &path)
248 {
249     if (IsExistDir(path)) {
250         return RemoveDir(path);
251     }
252     return false;
253 }
254 
PreparePreShareDir(FileShareInfo & info)255 static int32_t PreparePreShareDir(FileShareInfo &info)
256 {
257     for (size_t i = 0; i < info.sharePath_.size(); i++) {
258         if (access(info.sharePath_[i].c_str(), F_OK) != 0) {
259             string sharePathDir = info.sharePath_[i];
260             size_t posLast = info.sharePath_[i].find_last_of("/");
261             sharePathDir = info.sharePath_[i].substr(0, posLast);
262             if (!MakeDir(sharePathDir.c_str())) {
263                 LOGE("Make dir failed with %{public}d", errno);
264                 return -errno;
265             }
266         } else {
267             LOGE("File %{public}s already exists", info.sharePath_[i].c_str());
268             info.isExist_[i] = true;
269         }
270     }
271     return 0;
272 }
273 
CreateShareFile(const string & uri,int32_t tokenId,int32_t flag)274 int32_t FileShare::CreateShareFile(const string &uri, int32_t tokenId, int32_t flag)
275 {
276     FileShareInfo info;
277     int32_t ret = GetFileShareInfo(uri, tokenId, flag, info);
278     if (ret != 0) {
279         LOGE("Failed to get FileShareInfo with %{public}d", ret);
280         return ret;
281     }
282 
283     if ((ret = PreparePreShareDir(info)) != 0) {
284         LOGE("PreparePreShareDir failed");
285         return ret;
286     }
287 
288     for (size_t i = 0; i < info.sharePath_.size(); i++) {
289         if (info.isExist_[i]) {
290             continue;
291         }
292 
293         if (info.type_ == FILE_TYPE) {
294             if ((ret = creat(info.sharePath_[i].c_str(), FILE_MODE)) < 0) {
295                 LOGE("Create file failed with %{public}d", errno);
296                 return -errno;
297             }
298             close(ret);
299         } else if (mkdir(info.sharePath_[i].c_str(), DIR_MODE) != 0) {
300             LOGE("Create dir failed with %{public}d", errno);
301             return -errno;
302         }
303 
304         if (mount(info.providerLowerPath_.c_str(), info.sharePath_[i].c_str(),
305                   nullptr, MS_BIND, nullptr) != 0) {
306             LOGE("Mount failed with %{public}d", errno);
307             return -errno;
308         }
309     }
310     LOGI("Create Share File Successfully!");
311     return 0;
312 }
313 
UmountDelUris(vector<string> sharePathList,string currentUid,string bundleNameSelf)314 static void UmountDelUris(vector<string> sharePathList, string currentUid, string bundleNameSelf)
315 {
316     for (size_t i = 0; i < sharePathList.size(); i++) {
317         Uri uri(sharePathList[i]);
318         string path = uri.GetPath();
319         string bundleName = uri.GetAuthority();
320         string delRPath = DATA_APP_EL2_PATH + currentUid + SHARE_PATH + bundleNameSelf + SHARE_R_PATH +
321                           bundleName + path;
322         string delRWPath = DATA_APP_EL2_PATH + currentUid + SHARE_PATH + bundleNameSelf + SHARE_RW_PATH +
323                            bundleName + path;
324         if (access(delRPath.c_str(), F_OK) == 0) {
325             if (umount2(delRPath.c_str(), MNT_DETACH) != 0) {
326                 LOGE("UmountdelRPath, umount failed with %{public}d", errno);
327             }
328         }
329         if (access(delRWPath.c_str(), F_OK) == 0) {
330             if (umount2(delRWPath.c_str(), MNT_DETACH) != 0) {
331                 LOGE("UmountdelRWPath, umount failed with %{public}d", errno);
332             }
333         }
334     }
335 }
336 
DeleteShareFile(int32_t tokenId,vector<string> sharePathList)337 int32_t FileShare::DeleteShareFile(int32_t tokenId, vector<string> sharePathList)
338 {
339     string bundleName, currentUid;
340     int32_t ret = GetTargetInfo(tokenId, bundleName, currentUid);
341     if (ret != 0) {
342         LOGE("Failed to delete share file %{public}d", -EINVAL);
343         return -EINVAL;
344     }
345     UmountDelUris(sharePathList, currentUid, bundleName);
346 
347     string sharePath = DATA_APP_EL2_PATH + currentUid + SHARE_PATH + bundleName;
348     if ((access(sharePath.c_str(), F_OK) == 0) && !DeleteDir(sharePath)) {
349         LOGE("Delete dir failed with %{public}d", errno);
350         return -errno;
351     }
352 
353     LOGI("Delete Share File Successfully!");
354     return 0;
355 }
356 } // namespace AppFileService
357 } // namespace OHOS