• 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 
23 #include "fuse_ioctl.h"
24 #include "utils_log.h"
25 
26 namespace OHOS {
27 namespace FileManagement {
28 namespace CloudDisk {
29 using namespace std;
30 using namespace CloudFile;
31 namespace {
32     static const string LOCAL_PATH_DATA_SERVICE_EL2 = "/data/service/el2/";
33     static const string LOCAL_PATH_HMDFS_CLOUD_DATA = "/hmdfs/cloud/data/";
34     static const string LOCAL_PATH_HMDFS_CLOUD_CACHE = "/hmdfs/cache/cloud_cache";
35     static const string CLOUDDISK_CACHE_DIR = "/disk_drivekit_cache/";
36     static const string CLOUD_FILE_CLOUD_ID_XATTR = "user.cloud.cloudid";
37     static const uint32_t CLOUD_ID_MIN_SIZE = 3;
38     static const uint32_t CLOUD_ID_BUCKET_MID_TIMES = 2;
39     static const uint32_t CLOUD_ID_BUCKET_MAX_SIZE = 32;
40     static const int64_t SECOND_TO_MILLISECOND = 1e3;
41     static const int64_t MILLISECOND_TO_NANOSECOND = 1e6;
42     static const uint64_t DELTA_DISK = 0x9E3779B9;
43     static const uint64_t HMDFS_HASH_COL_BIT_DISK = (0x1ULL) << 63;
44 }
45 
46 const string CloudFileUtils::TMP_SUFFIX = ".temp.download";
47 
IsDotDotdot(const std::string & name)48 bool CloudFileUtils::IsDotDotdot(const std::string &name)
49 {
50     return name == "." || name == "..";
51 }
52 
Str2HashBuf(const char * msg,size_t len,uint32_t * buf,int num)53 void CloudFileUtils::Str2HashBuf(const char *msg, size_t len, uint32_t *buf, int num)
54 {
55     const int32_t shift8 = 8;
56     const int32_t shift16 = 16;
57     const int32_t three = 3;
58     const int32_t mod = 4;
59     uint32_t pad = static_cast<uint32_t>(len) | (static_cast<uint32_t>(len) << shift8);
60     pad |= pad << shift16;
61 
62     uint32_t val = pad;
63     len = std::min(len, static_cast<size_t>(num * sizeof(int)));
64     for (uint32_t i = 0; i < len; i++) {
65         if ((i % sizeof(int)) == 0) {
66             val = pad;
67         }
68         uint8_t c = static_cast<uint8_t>(tolower(msg[i]));
69         val = c + (val << shift8);
70         if ((i % mod) == three) {
71             *buf++ = val;
72             val = pad;
73             num--;
74         }
75     }
76     if (--num >= 0) {
77         *buf++ = val;
78     }
79     while (--num >= 0) {
80         *buf++ = pad;
81     }
82 }
83 
TeaTransform(uint32_t buf[4],uint32_t const in[])84 void CloudFileUtils::TeaTransform(uint32_t buf[4], uint32_t const in[]) __attribute__((no_sanitize(
85     "unsigned-integer-overflow")))
86 {
87     int n = 16;
88     uint32_t a = in[0];
89     uint32_t b = in[1];
90     uint32_t c = in[2];
91     uint32_t d = in[3];
92     uint32_t b0 = buf[0];
93     uint32_t b1 = buf[1];
94     uint32_t sum = 0;
95     const int32_t LEFT_SHIFT = 4;
96     const int32_t RIGHT_SHIFT = 5;
97     do {
98         sum += DELTA_DISK;
99         b0 += ((b1 << LEFT_SHIFT) + a) ^ (b1 + sum) ^ ((b1 >> RIGHT_SHIFT) + b);
100         b1 += ((b0 << LEFT_SHIFT) + c) ^ (b0 + sum) ^ ((b0 >> RIGHT_SHIFT) + d);
101     } while (--n);
102 
103     buf[0] += b0;
104     buf[1] += b1;
105 }
106 
DentryHash(const std::string & inputStr)107 uint32_t CloudFileUtils::DentryHash(const std::string &inputStr)
108 {
109     if (IsDotDotdot(inputStr)) {
110         return 0;
111     }
112     constexpr int inLen = 8;
113     constexpr int bufLen = 4;
114     uint32_t in[inLen];
115     uint32_t buf[bufLen] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
116     auto len = inputStr.length();
117     constexpr decltype(len) hashWidth = 16;
118     const char *p = inputStr.c_str();
119 
120     bool loopFlag = true;
121     while (loopFlag) {
122         Str2HashBuf(p, len, in, bufLen);
123         TeaTransform(buf, in);
124 
125         if (len <= hashWidth) {
126             break;
127         }
128         p += hashWidth;
129         len -= hashWidth;
130     };
131     uint32_t hash = buf[0];
132     uint32_t hmdfsHash = hash & ~HMDFS_HASH_COL_BIT_DISK;
133     return hmdfsHash;
134 }
135 
GetBucketId(string cloudId)136 uint32_t CloudFileUtils::GetBucketId(string cloudId)
137 {
138     size_t size = cloudId.size();
139     if (size < CLOUD_ID_MIN_SIZE) {
140         return 0;
141     }
142 
143     char first = cloudId[0];
144     char last = cloudId[size - 1];
145     char middle = cloudId[size / CLOUD_ID_BUCKET_MID_TIMES];
146     return (first + last + middle) % CLOUD_ID_BUCKET_MAX_SIZE;
147 }
148 
Timespec2Milliseconds(const struct timespec & time)149 int64_t CloudFileUtils::Timespec2Milliseconds(const struct timespec &time)
150 {
151     return time.tv_sec * SECOND_TO_MILLISECOND + time.tv_nsec / MILLISECOND_TO_NANOSECOND;
152 }
153 
GetLocalBaseDir(string bundleName,int32_t userId)154 string CloudFileUtils::GetLocalBaseDir(string bundleName, int32_t userId)
155 {
156     string baseDir = LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
157                      LOCAL_PATH_HMDFS_CLOUD_DATA + bundleName + "/";
158     return baseDir;
159 }
160 
GetLocalBucketPath(string cloudId,string bundleName,int32_t userId)161 string CloudFileUtils::GetLocalBucketPath(string cloudId, string bundleName, int32_t userId)
162 {
163     string baseDir = GetLocalBaseDir(bundleName, userId);
164     uint32_t bucketId = GetBucketId(cloudId);
165     string bucketPath = baseDir + to_string(bucketId);
166     return bucketPath;
167 }
168 
GetLocalDKCachePath(string cloudId,string bundleName,int32_t userId)169 string CloudFileUtils::GetLocalDKCachePath(string cloudId, string bundleName, int32_t userId)
170 {
171     string baseDir = LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) + LOCAL_PATH_HMDFS_CLOUD_CACHE +
172                      CLOUDDISK_CACHE_DIR + bundleName + "/";
173     uint32_t bucketId = GetBucketId(cloudId);
174     string cachePath = baseDir + to_string(bucketId) + "/" + cloudId;
175     return cachePath;
176 }
177 
GetLocalFilePath(string cloudId,string bundleName,int32_t userId)178 string CloudFileUtils::GetLocalFilePath(string cloudId, string bundleName, int32_t userId)
179 {
180     return GetLocalBucketPath(cloudId, bundleName, userId) + "/" + cloudId;
181 }
182 
GetPathWithoutTmp(const string & path)183 string CloudFileUtils::GetPathWithoutTmp(const string &path)
184 {
185     string ret = path;
186     if (EndsWith(path, TMP_SUFFIX)) {
187         ret = path.substr(0, path.length() - TMP_SUFFIX.length());
188     }
189     return ret;
190 }
191 
EndsWith(const string & fullString,const string & ending)192 bool CloudFileUtils::EndsWith(const string &fullString, const string &ending)
193 {
194     if (fullString.length() >= ending.length()) {
195         return (!fullString.compare(fullString.length() - ending.length(),
196                                     ending.length(),
197                                     ending));
198     }
199     return false;
200 }
201 
GetCloudId(const string & path)202 string CloudFileUtils::GetCloudId(const string &path)
203 {
204     auto idSize = getxattr(path.c_str(), CLOUD_FILE_CLOUD_ID_XATTR.c_str(), nullptr, 0);
205     if (idSize <= 0) {
206         return "";
207     }
208     char cloudId[idSize + 1];
209     idSize = getxattr(path.c_str(), CLOUD_FILE_CLOUD_ID_XATTR.c_str(), cloudId, idSize);
210     if (idSize <= 0) {
211         return "";
212     }
213     return string(cloudId);
214 }
215 
CheckIsCloud(const string & key)216 bool CloudFileUtils::CheckIsCloud(const string &key)
217 {
218     return key == CLOUD_CLOUD_ID_XATTR;
219 }
220 
CheckIsCloudLocation(const string & key)221 bool CloudFileUtils::CheckIsCloudLocation(const string &key)
222 {
223     return key == CLOUD_FILE_LOCATION;
224 }
225 
CheckIsHmdfsPermission(const string & key)226 bool CloudFileUtils::CheckIsHmdfsPermission(const string &key)
227 {
228     return key == HMDFS_PERMISSION_XATTR;
229 }
230 
CheckIsCloudRecycle(const string & key)231 bool CloudFileUtils::CheckIsCloudRecycle(const string &key)
232 {
233     return key == CLOUD_CLOUD_RECYCLE_XATTR;
234 }
235 
CheckIsFavorite(const string & key)236 bool CloudFileUtils::CheckIsFavorite(const string &key)
237 {
238     return key == IS_FAVORITE_XATTR;
239 }
240 
CheckIsTimeRecycled(const string & key)241 bool CloudFileUtils::CheckIsTimeRecycled(const string &key)
242 {
243     return key == CLOUD_TIME_RECYCLED;
244 }
245 
CheckIsHasLCD(const string & key)246 bool CloudFileUtils::CheckIsHasLCD(const string &key)
247 {
248     return key == CLOUD_HAS_LCD;
249 }
250 
CheckIsHasTHM(const string & key)251 bool CloudFileUtils::CheckIsHasTHM(const string &key)
252 {
253     return key == CLOUD_HAS_THM;
254 }
255 
CheckFileStatus(const string & key)256 bool CloudFileUtils::CheckFileStatus(const string &key)
257 {
258     return key == IS_FILE_STATUS_XATTR;
259 }
260 
CheckIsRecyclePath(const string & key)261 bool CloudFileUtils::CheckIsRecyclePath(const string &key)
262 {
263     return key == CLOUD_RECYCLE_PATH;
264 }
265 
LocalWriteOpen(const string & dfsPath)266 bool CloudFileUtils::LocalWriteOpen(const string &dfsPath)
267 {
268     unique_ptr<char[]> absPath = make_unique<char[]>(PATH_MAX + 1);
269     if (realpath(dfsPath.c_str(), absPath.get()) == nullptr) {
270         return false;
271     }
272     string realPath = absPath.get();
273     char resolvedPath[PATH_MAX] = {'\0'};
274     char *realPaths = realpath(realPath.c_str(), resolvedPath);
275     if (realPaths == NULL) {
276         LOGE("realpath failed");
277         return false;
278     }
279     std::FILE *file = fopen(realPaths, "r");
280     if (file == nullptr) {
281         LOGE("fopen failed, errno:%{public}d", errno);
282         return false;
283     }
284     int fd = fileno(file);
285     /*
286      * In the implementation of fopen, if the contained fd < 0, reutrn nullptr.
287      * There is no case where the fd < 0 when the pointer is non-null.
288      * This is to judge the exception where the file carrying the fd has been closed.
289      * In such cases, fclose is not needed.
290      */
291     if (fd < 0) {
292         LOGE("get fd failed, errno:%{public}d", errno);
293         return false;
294     }
295     uint32_t writeOpenCnt = 0;
296     int ret = ioctl(fd, HMDFS_IOC_GET_WRITEOPEN_CNT, &writeOpenCnt);
297     if (ret < 0) {
298         LOGE("ioctl failed, errno:%{public}d", errno);
299         if (fclose(file)) {
300             LOGE("fclose failed, errno:%{public}d", errno);
301         }
302         return false;
303     }
304 
305     if (fclose(file)) {
306         LOGE("fclose failed, errno:%{public}d", errno);
307         return false;
308     }
309     return writeOpenCnt != 0;
310 }
311 
ClearHmdfsCache(const string & dfsPath)312 static bool ClearHmdfsCache(const string &dfsPath)
313 {
314     char resolvedPath[PATH_MAX];
315     if (realpath(dfsPath.c_str(), resolvedPath) == nullptr) {
316         LOGE("realpath failed");
317         return false;
318     }
319     std::FILE *file = fopen(resolvedPath, "r");
320     if (file == nullptr) {
321         LOGE("fopen failed, errno:%{public}d", errno);
322         return false;
323     }
324     int fd = fileno(file);
325     /*
326      * In the implementation of fopen, if the contained fd < 0, reutrn nullptr.
327      * There is no case where the fd < 0 when the pointer is non-null.
328      * This is to judge the exception where the file carrying the fd has been closed.
329      * In such cases, fclose is not needed.
330      */
331     if (fd < 0) {
332         LOGE("get fd failed, errno:%{public}d", errno);
333         return false;
334     }
335     int ret = ioctl(fd, HMDFS_IOC_SET_CLOUD_GENERATION);
336     if (ret < 0) {
337         LOGE("ioctl failed, errno:%{public}d", errno);
338         if (fclose(file)) {
339             LOGE("fclose failed, errno:%{public}d", errno);
340         }
341         return false;
342     }
343     if (fclose(file)) {
344         LOGE("fclose failed, errno:%{public}d", errno);
345         return false;
346     }
347     return true;
348 }
349 
ClearCloudCache(const string & cloudPath)350 static bool ClearCloudCache(const string &cloudPath)
351 {
352     char resolvedPath[PATH_MAX];
353     if (realpath(cloudPath.c_str(), resolvedPath) == nullptr) {
354         LOGE("realpath failed");
355         return false;
356     }
357 
358     int fd = open(resolvedPath, O_RDONLY | O_DIRECTORY);
359     if (fd == -1) {
360         LOGE("open failed %{public}d", errno);
361         return false;
362     }
363     int ret = ioctl(fd, HMDFS_IOC_CLEAN_CACHE_DAEMON);
364     if (ret < 0) {
365         LOGE("ioctl failed, errno:%{public}d", errno);
366         close(fd);
367         return false;
368     }
369 
370     close(fd);
371     return true;
372 }
373 
ClearCache(const string & dfsPath,const string & cloudPath)374 bool CloudFileUtils::ClearCache(const string &dfsPath, const string &cloudPath)
375 {
376     if (!ClearHmdfsCache(dfsPath)) {
377         return false;
378     }
379 
380     if (!ClearCloudCache(cloudPath)) {
381         return false;
382     }
383 
384     return true;
385 }
386 
GetRealPath(const string & path)387 string CloudFileUtils::GetRealPath(const string &path)
388 {
389     filesystem::path tempPath(path);
390     filesystem::path realPath{};
391     for (const auto& component : tempPath) {
392         if (component == ".") {
393             continue;
394         } else if (component == "..") {
395             realPath = realPath.parent_path();
396         } else {
397             realPath /= component;
398         }
399     }
400     return realPath.string();
401 }
402 } // namespace CloudDisk
403 } // namespace FileManagement
404 } // namespace OHOS
405