• 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 
16 #include "sandbox_helper.h"
17 
18 #include <iomanip>
19 #include <sstream>
20 #include <unordered_set>
21 #include <vector>
22 
23 #include "log.h"
24 #include "json_utils.h"
25 #include "uri.h"
26 
27 using namespace std;
28 
29 namespace OHOS {
30 namespace AppFileService {
31 namespace {
32     const string PACKAGE_NAME_FLAG = "<PackageName>";
33     const string CURRENT_USER_ID_FLAG = "<currentUserId>";
34     const string PHYSICAL_PATH_KEY = "src-path";
35     const string SANDBOX_PATH_KEY = "sandbox-path";
36     const string MOUNT_PATH_MAP_KEY = "mount-path-map";
37     const string SANDBOX_JSON_FILE_PATH = "/etc/app_file_service/file_share_sandbox.json";
38     const std::string SHAER_PATH_HEAD = "/mnt/hmdfs/";
39     const std::string SHAER_PATH_MID = "/account/merge_view/files/";
40     const string FILE_MANAGER_URI_HEAD = "/storage/";
41     const string FILE_MANAGER_AUTHORITY = "docs";
42     const string DLP_MANAGER_BUNDLE_NAME = "com.ohos.dlpmanager";
43     const string FUSE_URI_HEAD = "/mnt/data/fuse";
44     const string BACKFLASH = "/";
45     const string MEDIA = "media";
46     const int ASSET_IN_BUCKET_NUM_MAX = 1000;
47     const int ASSET_DIR_START_NUM = 16;
48 }
49 
50 struct MediaUriInfo {
51     string mediaType;
52     string fileId;
53     string realName;
54     string displayName;
55 };
56 
57 std::unordered_map<std::string, std::string> SandboxHelper::sandboxPathMap_;
58 std::mutex SandboxHelper::mapMutex_;
59 
Encode(const string & uri)60 string SandboxHelper::Encode(const string &uri)
61 {
62     const unordered_set<char> uriCompentsSet = {
63         ';', ',', '/', '?', ':', '@', '&',
64         '=', '+', '$', '-', '_', '.', '!',
65         '~', '*', '(', ')', '#', '\''
66     };
67     const int32_t encodeLen = 2;
68     ostringstream outPutStream;
69     outPutStream.fill('0');
70     outPutStream << std::hex;
71 
72     for (unsigned char tmpChar : uri) {
73         if (std::isalnum(tmpChar) || uriCompentsSet.find(tmpChar) != uriCompentsSet.end()) {
74             outPutStream << tmpChar;
75         } else {
76             outPutStream << std::uppercase;
77             outPutStream << '%' << std::setw(encodeLen) << static_cast<unsigned int>(tmpChar);
78             outPutStream << std::nouppercase;
79         }
80     }
81 
82     return outPutStream.str();
83 }
84 
Decode(const string & uri)85 string SandboxHelper::Decode(const string &uri)
86 {
87     std::ostringstream outPutStream;
88     const int32_t encodeLen = 2;
89     size_t index = 0;
90     while (index < uri.length()) {
91         if (uri[index] == '%') {
92             int hex = 0;
93             std::istringstream inputStream(uri.substr(index + 1, encodeLen));
94             inputStream >> std::hex >> hex;
95             outPutStream << static_cast<char>(hex);
96             index += encodeLen + 1;
97         } else {
98             outPutStream << uri[index];
99             index++;
100         }
101     }
102 
103     return outPutStream.str();
104 }
105 
GetLowerPath(string & lowerPathHead,const string & lowerPathTail,const string & userId,const string & bundleName)106 static string GetLowerPath(string &lowerPathHead, const string &lowerPathTail,
107                            const string &userId, const string &bundleName)
108 {
109     if (lowerPathHead.find(CURRENT_USER_ID_FLAG) != string::npos) {
110         lowerPathHead = lowerPathHead.replace(lowerPathHead.find(CURRENT_USER_ID_FLAG),
111                                               CURRENT_USER_ID_FLAG.length(), userId);
112     }
113 
114     if (lowerPathHead.find(PACKAGE_NAME_FLAG) != string::npos) {
115         lowerPathHead = lowerPathHead.replace(lowerPathHead.find(PACKAGE_NAME_FLAG),
116                                               PACKAGE_NAME_FLAG.length(), bundleName);
117     }
118 
119     return lowerPathHead + lowerPathTail;
120 }
121 
GetSandboxPathMap()122 bool SandboxHelper::GetSandboxPathMap()
123 {
124     lock_guard<mutex> lock(mapMutex_);
125     if (sandboxPathMap_.size() > 0) {
126         return true;
127     }
128 
129     nlohmann::json jsonObj;
130     int ret = JsonUtils::GetJsonObjFromPath(jsonObj, SANDBOX_JSON_FILE_PATH);
131     if (ret != 0) {
132         LOGE("Get json object failed from %{public}s with %{public}d", SANDBOX_JSON_FILE_PATH.c_str(), ret);
133         return false;
134     }
135 
136     if (jsonObj.find(MOUNT_PATH_MAP_KEY) == jsonObj.end()) {
137         LOGE("Json object find mount path map failed");
138         return false;
139     }
140 
141     nlohmann::json mountPathMap = jsonObj[MOUNT_PATH_MAP_KEY];
142     for (size_t i = 0; i < mountPathMap.size(); i++) {
143         string srcPath = mountPathMap[i][PHYSICAL_PATH_KEY];
144         string sandboxPath = mountPathMap[i][SANDBOX_PATH_KEY];
145         sandboxPathMap_[sandboxPath] = srcPath;
146     }
147 
148     if (sandboxPathMap_.size() == 0) {
149         return false;
150     }
151 
152     return true;
153 }
154 
GetPathSuffix(const std::string & path,string & pathSuffix)155 static int32_t GetPathSuffix(const std::string &path, string &pathSuffix)
156 {
157     size_t pos = path.rfind('.');
158     if (pos != string::npos) {
159         pathSuffix = path.substr(pos);
160         return 0;
161     }
162     return -EINVAL;
163 }
164 
CalAssetBucket(const int32_t & fileId)165 static int32_t CalAssetBucket(const int32_t &fileId)
166 {
167     int32_t bucketNum = 0;
168     if (fileId < 0) {
169         LOGE("input fileId %{private}d is invalid", fileId);
170         return -EINVAL;
171     }
172 
173     int32_t start = ASSET_DIR_START_NUM;
174     int32_t divider = ASSET_DIR_START_NUM;
175     while (fileId > start * ASSET_IN_BUCKET_NUM_MAX) {
176         divider = start;
177         start <<= 1;
178     }
179 
180     int32_t fileIdRemainder = fileId % divider;
181     if (fileIdRemainder == 0) {
182         bucketNum = start + fileIdRemainder;
183     } else {
184         bucketNum = (start - divider) + fileIdRemainder;
185     }
186     return bucketNum;
187 }
188 
GetFileIdFromFileName(const std::string & fileName)189 static int32_t GetFileIdFromFileName(const std::string &fileName)
190 {
191     size_t pos = fileName.find_last_of('_');
192     if (pos == std::string::npos || pos == fileName.size() - 1) {
193         return -EINVAL;
194     }
195 
196     std::string idStr = fileName.substr(pos + 1);
197     if (!std::all_of(idStr.begin(), idStr.end(), ::isdigit)) {
198         return -EINVAL;
199     }
200 
201     return std::stoi(idStr);
202 }
203 
GetBucketNum(const std::string & fileName)204 static int32_t GetBucketNum(const std::string &fileName)
205 {
206     int32_t fileId = GetFileIdFromFileName(fileName);
207     if (fileId < 0) {
208         LOGE("GetFileIdFromFileName failed with %{public}s", fileName.c_str());
209         return fileId;
210     }
211     return CalAssetBucket(fileId);
212 }
213 
ParseMediaSandboxPath(const string & sandboxPath,MediaUriInfo & mediaUriInfo)214 static void ParseMediaSandboxPath(const string &sandboxPath, MediaUriInfo &mediaUriInfo)
215 {
216     string path = sandboxPath;
217     std::replace(path.begin(), path.end(), '/', ' ');
218     stringstream ss;
219     ss << path;
220     ss >> mediaUriInfo.mediaType >> mediaUriInfo.fileId >> mediaUriInfo.realName >> mediaUriInfo.displayName;
221 }
222 
GetMediaPhysicalPath(const std::string & sandboxPath,const std::string & userId,std::string & physicalPath)223 static int32_t GetMediaPhysicalPath(const std::string &sandboxPath, const std::string &userId,
224                                     std::string &physicalPath)
225 {
226     MediaUriInfo mediaUriInfo;
227     ParseMediaSandboxPath(sandboxPath, mediaUriInfo);
228 
229     int32_t bucketNum = GetBucketNum(mediaUriInfo.realName);
230     if (bucketNum < 0) {
231         return -EINVAL;
232     }
233 
234     std::string mediaSuffix;
235     if (GetPathSuffix(sandboxPath, mediaSuffix) != 0) {
236         LOGE("GetPathSuffix failed");
237         return -EINVAL;
238     }
239 
240     physicalPath = SHAER_PATH_HEAD + userId + SHAER_PATH_MID + mediaUriInfo.mediaType +
241                    BACKFLASH + to_string(bucketNum) + BACKFLASH + mediaUriInfo.realName + mediaSuffix;
242     return 0;
243 }
244 
GetPhysicalPath(const std::string & fileUri,const std::string & userId,std::string & physicalPath)245 int32_t SandboxHelper::GetPhysicalPath(const std::string &fileUri, const std::string &userId,
246                                        std::string &physicalPath)
247 {
248     Uri uri(fileUri);
249     string bundleName = uri.GetAuthority();
250     string sandboxPath = uri.GetPath();
251 
252     if (bundleName == MEDIA) {
253         return GetMediaPhysicalPath(sandboxPath, userId, physicalPath);
254     }
255 
256     if ((sandboxPath.find(FILE_MANAGER_URI_HEAD) == 0 && bundleName != FILE_MANAGER_AUTHORITY) ||
257         (sandboxPath.find(FUSE_URI_HEAD) == 0 && bundleName != DLP_MANAGER_BUNDLE_NAME)) {
258         return -EINVAL;
259     }
260 
261     if (!GetSandboxPathMap()) {
262         LOGE("GetSandboxPathMap failed");
263         return -EINVAL;
264     }
265 
266     string lowerPathTail = "";
267     string lowerPathHead = "";
268     string::size_type curPrefixMatchLen = 0;
269     for (auto it = sandboxPathMap_.begin(); it != sandboxPathMap_.end(); it++) {
270         string sandboxPathPrefix = it->first;
271         string::size_type prefixMatchLen = sandboxPathPrefix.length();
272         if (sandboxPath.length() >= prefixMatchLen) {
273             string sandboxPathTemp = sandboxPath.substr(0, prefixMatchLen);
274             if (sandboxPathTemp == sandboxPathPrefix && curPrefixMatchLen <= prefixMatchLen) {
275                 curPrefixMatchLen = prefixMatchLen;
276                 lowerPathHead = it->second;
277                 lowerPathTail = sandboxPath.substr(prefixMatchLen);
278             }
279         }
280     }
281 
282     if (lowerPathHead == "") {
283         LOGE("lowerPathHead is invalid");
284         return -EINVAL;
285     } else {
286         physicalPath = GetLowerPath(lowerPathHead, lowerPathTail, userId, bundleName);
287         return 0;
288     }
289 }
290 
CheckValidPath(const std::string & filePath)291 bool SandboxHelper::CheckValidPath(const std::string &filePath)
292 {
293     if (filePath.empty() || filePath.size() >= PATH_MAX) {
294         return false;
295     }
296 
297     char realPath[PATH_MAX]{'\0'};
298     if (realpath(filePath.c_str(), realPath) != nullptr &&
299         strncmp(realPath, filePath.c_str(), filePath.size()) == 0) {
300         return true;
301     } else {
302         return false;
303     }
304 }
305 } // namespace AppFileService
306 } // namespace OHOS
307 
308