• 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 "cloud_file_utils.h"
16 #include <ctime>
17 #include <fcntl.h>
18 #include <filesystem>
19 #include <sys/xattr.h>
20 #include <sys/ioctl.h>
21 #include <unistd.h>
22 #include "utils_log.h"
23 namespace OHOS {
24 namespace FileManagement {
25 namespace CloudDisk {
26 using namespace std;
27 namespace {
28     static const string LOCAL_PATH_DATA_SERVICE_EL2 = "/data/service/el2/";
29     static const string LOCAL_PATH_HMDFS_CLOUD_DATA = "/hmdfs/cloud/data/";
30     static const string CLOUD_FILE_CLOUD_ID_XATTR = "user.cloud.cloudid";
31     static const uint32_t CLOUD_ID_MIN_SIZE = 3;
32     static const uint32_t CLOUD_ID_BUCKET_MID_TIMES = 2;
33     static const uint32_t CLOUD_ID_BUCKET_MAX_SIZE = 32;
34     static const int64_t SECOND_TO_MILLISECOND = 1e3;
35     static const int64_t MILLISECOND_TO_NANOSECOND = 1e6;
36     static const uint64_t DELTA_DISK = 0x9E3779B9;
37     static const uint64_t HMDFS_HASH_COL_BIT_DISK = (0x1ULL) << 63;
38 }
39 
40 constexpr unsigned HMDFS_IOC = 0xf2;
41 constexpr unsigned WRITEOPEN_CMD = 0x02;
42 constexpr unsigned CLOUD_ENABLE_CMD = 0x0b;
43 #define HMDFS_IOC_GET_WRITEOPEN_CNT _IOR(HMDFS_IOC, WRITEOPEN_CMD, uint32_t)
44 #define HMDFS_IOC_SET_CLOUD_GENERATION _IOR(HMDFS_IOC, CLOUD_ENABLE_CMD, uint32_t)
45 const string CloudFileUtils::TMP_SUFFIX = ".temp.download";
46 
IsDotDotdot(const std::string & name)47 bool CloudFileUtils::IsDotDotdot(const std::string &name)
48 {
49     return name == "." || name == "..";
50 }
51 
Str2HashBuf(const char * msg,size_t len,uint32_t * buf,int num)52 void CloudFileUtils::Str2HashBuf(const char *msg, size_t len, uint32_t *buf, int num)
53 {
54     const int32_t shift8 = 8;
55     const int32_t shift16 = 16;
56     const int32_t three = 3;
57     const int32_t mod = 4;
58     uint32_t pad = static_cast<uint32_t>(len) | (static_cast<uint32_t>(len) << shift8);
59     pad |= pad << shift16;
60 
61     uint32_t val = pad;
62     len = std::min(len, static_cast<size_t>(num * sizeof(int)));
63     for (uint32_t i = 0; i < len; i++) {
64         if ((i % sizeof(int)) == 0) {
65             val = pad;
66         }
67         uint8_t c = static_cast<uint8_t>(tolower(msg[i]));
68         val = c + (val << shift8);
69         if ((i % mod) == three) {
70             *buf++ = val;
71             val = pad;
72             num--;
73         }
74     }
75     if (--num >= 0) {
76         *buf++ = val;
77     }
78     while (--num >= 0) {
79         *buf++ = pad;
80     }
81 }
82 
TeaTransform(uint32_t buf[4],uint32_t const in[])83 void CloudFileUtils::TeaTransform(uint32_t buf[4], uint32_t const in[]) __attribute__((no_sanitize(
84     "unsigned-integer-overflow")))
85 {
86     int n = 16;
87     uint32_t a = in[0];
88     uint32_t b = in[1];
89     uint32_t c = in[2];
90     uint32_t d = in[3];
91     uint32_t b0 = buf[0];
92     uint32_t b1 = buf[1];
93     uint32_t sum = 0;
94     const int32_t LEFT_SHIFT = 4;
95     const int32_t RIGHT_SHIFT = 5;
96     do {
97         sum += DELTA_DISK;
98         b0 += ((b1 << LEFT_SHIFT) + a) ^ (b1 + sum) ^ ((b1 >> RIGHT_SHIFT) + b);
99         b1 += ((b0 << LEFT_SHIFT) + c) ^ (b0 + sum) ^ ((b0 >> RIGHT_SHIFT) + d);
100     } while (--n);
101 
102     buf[0] += b0;
103     buf[1] += b1;
104 }
105 
DentryHash(const std::string & inputStr)106 uint32_t CloudFileUtils::DentryHash(const std::string &inputStr)
107 {
108     if (IsDotDotdot(inputStr)) {
109         return 0;
110     }
111     constexpr int inLen = 8;
112     constexpr int bufLen = 4;
113     uint32_t in[inLen];
114     uint32_t buf[bufLen] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
115     auto len = inputStr.length();
116     constexpr decltype(len) hashWidth = 16;
117     const char *p = inputStr.c_str();
118 
119     bool loopFlag = true;
120     while (loopFlag) {
121         Str2HashBuf(p, len, in, bufLen);
122         TeaTransform(buf, in);
123 
124         if (len <= hashWidth) {
125             break;
126         }
127         p += hashWidth;
128         len -= hashWidth;
129     };
130     uint32_t hash = buf[0];
131     uint32_t hmdfsHash = hash & ~HMDFS_HASH_COL_BIT_DISK;
132     return hmdfsHash;
133 }
134 
GetBucketId(string cloudId)135 uint32_t CloudFileUtils::GetBucketId(string cloudId)
136 {
137     size_t size = cloudId.size();
138     if (size < CLOUD_ID_MIN_SIZE) {
139         return 0;
140     }
141 
142     char first = cloudId[0];
143     char last = cloudId[size - 1];
144     char middle = cloudId[size / CLOUD_ID_BUCKET_MID_TIMES];
145     return (first + last + middle) % CLOUD_ID_BUCKET_MAX_SIZE;
146 }
147 
Timespec2Milliseconds(const struct timespec & time)148 int64_t CloudFileUtils::Timespec2Milliseconds(const struct timespec &time)
149 {
150     return time.tv_sec * SECOND_TO_MILLISECOND + time.tv_nsec / MILLISECOND_TO_NANOSECOND;
151 }
152 
GetLocalBucketPath(string cloudId,string bundleName,int32_t userId)153 string CloudFileUtils::GetLocalBucketPath(string cloudId, string bundleName, int32_t userId)
154 {
155     string baseDir = LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
156                      LOCAL_PATH_HMDFS_CLOUD_DATA + bundleName + "/";
157     uint32_t bucketId = GetBucketId(cloudId);
158     string bucketPath = baseDir + to_string(bucketId);
159     return bucketPath;
160 }
161 
GetLocalFilePath(string cloudId,string bundleName,int32_t userId)162 string CloudFileUtils::GetLocalFilePath(string cloudId, string bundleName, int32_t userId)
163 {
164     return GetLocalBucketPath(cloudId, bundleName, userId) + "/" + cloudId;
165 }
166 
GetPathWithoutTmp(const string & path)167 string CloudFileUtils::GetPathWithoutTmp(const string &path)
168 {
169     string ret = path;
170     if (EndsWith(path, TMP_SUFFIX)) {
171         ret = path.substr(0, path.length() - TMP_SUFFIX.length());
172     }
173     return ret;
174 }
175 
EndsWith(const string & fullString,const string & ending)176 bool CloudFileUtils::EndsWith(const string &fullString, const string &ending)
177 {
178     if (fullString.length() >= ending.length()) {
179         return (!fullString.compare(fullString.length() - ending.length(),
180                                     ending.length(),
181                                     ending));
182     }
183     return false;
184 }
185 
GetCloudId(const string & path)186 string CloudFileUtils::GetCloudId(const string &path)
187 {
188     auto idSize = getxattr(path.c_str(), CLOUD_FILE_CLOUD_ID_XATTR.c_str(), nullptr, 0);
189     if (idSize <= 0) {
190         return "";
191     }
192     char cloudId[idSize + 1];
193     idSize = getxattr(path.c_str(), CLOUD_FILE_CLOUD_ID_XATTR.c_str(), cloudId, idSize);
194     if (idSize <= 0) {
195         return "";
196     }
197     return string(cloudId);
198 }
199 
CheckIsCloud(const string & key)200 bool CloudFileUtils::CheckIsCloud(const string &key)
201 {
202     return key == CLOUD_CLOUD_ID_XATTR;
203 }
204 
CheckIsCloudLocation(const string & key)205 bool CloudFileUtils::CheckIsCloudLocation(const string &key)
206 {
207     return key == CLOUD_FILE_LOCATION;
208 }
209 
CheckIsHmdfsPermission(const string & key)210 bool CloudFileUtils::CheckIsHmdfsPermission(const string &key)
211 {
212     return key == HMDFS_PERMISSION_XATTR;
213 }
214 
CheckIsCloudRecycle(const string & key)215 bool CloudFileUtils::CheckIsCloudRecycle(const string &key)
216 {
217     return key == CLOUD_CLOUD_RECYCLE_XATTR;
218 }
219 
CheckIsFavorite(const string & key)220 bool CloudFileUtils::CheckIsFavorite(const string &key)
221 {
222     return key == IS_FAVORITE_XATTR;
223 }
224 
CheckIsTimeRecycled(const string & key)225 bool CloudFileUtils::CheckIsTimeRecycled(const string &key)
226 {
227     return key == CLOUD_TIME_RECYCLED;
228 }
229 
CheckIsHasLCD(const string & key)230 bool CloudFileUtils::CheckIsHasLCD(const string &key)
231 {
232     return key == CLOUD_HAS_LCD;
233 }
234 
CheckIsHasTHM(const string & key)235 bool CloudFileUtils::CheckIsHasTHM(const string &key)
236 {
237     return key == CLOUD_HAS_THM;
238 }
239 
CheckFileStatus(const string & key)240 bool CloudFileUtils::CheckFileStatus(const string &key)
241 {
242     return key == IS_FILE_STATUS_XATTR;
243 }
244 
LocalWriteOpen(const string & dfsPath)245 bool CloudFileUtils::LocalWriteOpen(const string &dfsPath)
246 {
247     unique_ptr<char[]> absPath = make_unique<char[]>(PATH_MAX + 1);
248     if (realpath(dfsPath.c_str(), absPath.get()) == nullptr) {
249         return false;
250     }
251     string realPath = absPath.get();
252     char resolvedPath[PATH_MAX] = {'\0'};
253     char *realPaths = realpath(realPath.c_str(), resolvedPath);
254     if (realPaths == NULL) {
255         LOGE("realpath failed");
256         return false;
257     }
258     int fd = open(realPaths, O_RDONLY);
259     if (fd < 0) {
260         LOGE("open failed, errno:%{public}d", errno);
261         return false;
262     }
263     uint32_t writeOpenCnt = 0;
264     int ret = ioctl(fd, HMDFS_IOC_GET_WRITEOPEN_CNT, &writeOpenCnt);
265     close(fd);
266     if (ret < 0) {
267         LOGE("ioctl failed, errno:%{public}d", errno);
268         return false;
269     }
270 
271     return writeOpenCnt != 0;
272 }
273 
ClearCache(const string & dfsPath)274 bool CloudFileUtils::ClearCache(const string &dfsPath)
275 {
276     auto resolvedPath = realpath(dfsPath.c_str(), NULL);
277     if (resolvedPath == NULL) {
278         LOGE("realpath failed");
279         return false;
280     }
281     int fd = open(resolvedPath, O_RDONLY);
282     free(resolvedPath);
283     if (fd < 0) {
284         LOGE("open failed, errno:%{public}d", errno);
285         return false;
286     }
287     int ret = ioctl(fd, HMDFS_IOC_SET_CLOUD_GENERATION);
288     if (ret < 0) {
289         LOGE("ioctl failed, errno:%{public}d", errno);
290         close(fd);
291         return false;
292     }
293     close(fd);
294     return true;
295 }
296 
GetRealPath(const string & path)297 string CloudFileUtils::GetRealPath(const string &path)
298 {
299     filesystem::path tempPath(path);
300     filesystem::path realPath{};
301     for (const auto& component : tempPath) {
302         if (component == ".") {
303             continue;
304         } else if (component == "..") {
305             realPath = realPath.parent_path();
306         } else {
307             realPath /= component;
308         }
309     }
310     return realPath.string();
311 }
312 } // namespace CloudDisk
313 } // namespace FileManagement
314 } // namespace OHOS
315