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 #define HMDFS_IOC_GET_WRITEOPEN_CNT _IOR(HMDFS_IOC, WRITEOPEN_CMD, uint32_t)
43 const string CloudFileUtils::TMP_SUFFIX = ".temp.download";
44
IsDotDotdot(const std::string & name)45 bool CloudFileUtils::IsDotDotdot(const std::string &name)
46 {
47 return name == "." || name == "..";
48 }
49
Str2HashBuf(const char * msg,size_t len,uint32_t * buf,int num)50 void CloudFileUtils::Str2HashBuf(const char *msg, size_t len, uint32_t *buf, int num)
51 {
52 const int32_t shift8 = 8;
53 const int32_t shift16 = 16;
54 const int32_t three = 3;
55 const int32_t mod = 4;
56 uint32_t pad = static_cast<uint32_t>(len) | (static_cast<uint32_t>(len) << shift8);
57 pad |= pad << shift16;
58
59 uint32_t val = pad;
60 len = std::min(len, static_cast<size_t>(num * sizeof(int)));
61 for (uint32_t i = 0; i < len; i++) {
62 if ((i % sizeof(int)) == 0) {
63 val = pad;
64 }
65 uint8_t c = static_cast<uint8_t>(tolower(msg[i]));
66 val = c + (val << shift8);
67 if ((i % mod) == three) {
68 *buf++ = val;
69 val = pad;
70 num--;
71 }
72 }
73 if (--num >= 0) {
74 *buf++ = val;
75 }
76 while (--num >= 0) {
77 *buf++ = pad;
78 }
79 }
80
TeaTransform(uint32_t buf[4],uint32_t const in[])81 void CloudFileUtils::TeaTransform(uint32_t buf[4], uint32_t const in[]) __attribute__((no_sanitize(
82 "unsigned-integer-overflow")))
83 {
84 int n = 16;
85 uint32_t a = in[0];
86 uint32_t b = in[1];
87 uint32_t c = in[2];
88 uint32_t d = in[3];
89 uint32_t b0 = buf[0];
90 uint32_t b1 = buf[1];
91 uint32_t sum = 0;
92 const int32_t LEFT_SHIFT = 4;
93 const int32_t RIGHT_SHIFT = 5;
94 do {
95 sum += DELTA_DISK;
96 b0 += ((b1 << LEFT_SHIFT) + a) ^ (b1 + sum) ^ ((b1 >> RIGHT_SHIFT) + b);
97 b1 += ((b0 << LEFT_SHIFT) + c) ^ (b0 + sum) ^ ((b0 >> RIGHT_SHIFT) + d);
98 } while (--n);
99
100 buf[0] += b0;
101 buf[1] += b1;
102 }
103
DentryHash(const std::string & inputStr)104 uint32_t CloudFileUtils::DentryHash(const std::string &inputStr)
105 {
106 if (IsDotDotdot(inputStr)) {
107 return 0;
108 }
109 constexpr int inLen = 8;
110 constexpr int bufLen = 4;
111 uint32_t in[inLen];
112 uint32_t buf[bufLen] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
113 auto len = inputStr.length();
114 constexpr decltype(len) hashWidth = 16;
115 const char *p = inputStr.c_str();
116
117 bool loopFlag = true;
118 while (loopFlag) {
119 Str2HashBuf(p, len, in, bufLen);
120 TeaTransform(buf, in);
121
122 if (len <= hashWidth) {
123 break;
124 }
125 p += hashWidth;
126 len -= hashWidth;
127 };
128 uint32_t hash = buf[0];
129 uint32_t hmdfsHash = hash & ~HMDFS_HASH_COL_BIT_DISK;
130 return hmdfsHash;
131 }
132
GetBucketId(string cloudId)133 uint32_t CloudFileUtils::GetBucketId(string cloudId)
134 {
135 size_t size = cloudId.size();
136 if (size < CLOUD_ID_MIN_SIZE) {
137 return 0;
138 }
139
140 char first = cloudId[0];
141 char last = cloudId[size - 1];
142 char middle = cloudId[size / CLOUD_ID_BUCKET_MID_TIMES];
143 return (first + last + middle) % CLOUD_ID_BUCKET_MAX_SIZE;
144 }
145
Timespec2Milliseconds(const struct timespec & time)146 int64_t CloudFileUtils::Timespec2Milliseconds(const struct timespec &time)
147 {
148 return time.tv_sec * SECOND_TO_MILLISECOND + time.tv_nsec / MILLISECOND_TO_NANOSECOND;
149 }
150
GetLocalBucketPath(string cloudId,string bundleName,int32_t userId)151 string CloudFileUtils::GetLocalBucketPath(string cloudId, string bundleName, int32_t userId)
152 {
153 string baseDir = LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
154 LOCAL_PATH_HMDFS_CLOUD_DATA + bundleName + "/";
155 uint32_t bucketId = GetBucketId(cloudId);
156 string bucketPath = baseDir + to_string(bucketId);
157 return bucketPath;
158 }
159
GetLocalFilePath(string cloudId,string bundleName,int32_t userId)160 string CloudFileUtils::GetLocalFilePath(string cloudId, string bundleName, int32_t userId)
161 {
162 return GetLocalBucketPath(cloudId, bundleName, userId) + "/" + cloudId;
163 }
164
GetPathWithoutTmp(const string & path)165 string CloudFileUtils::GetPathWithoutTmp(const string &path)
166 {
167 string ret = path;
168 if (EndsWith(path, TMP_SUFFIX)) {
169 ret = path.substr(0, path.length() - TMP_SUFFIX.length());
170 }
171 return ret;
172 }
173
EndsWith(const string & fullString,const string & ending)174 bool CloudFileUtils::EndsWith(const string &fullString, const string &ending)
175 {
176 if (fullString.length() >= ending.length()) {
177 return (!fullString.compare(fullString.length() - ending.length(),
178 ending.length(),
179 ending));
180 }
181 return false;
182 }
183
GetCloudId(const string & path)184 string CloudFileUtils::GetCloudId(const string &path)
185 {
186 auto idSize = getxattr(path.c_str(), CLOUD_FILE_CLOUD_ID_XATTR.c_str(), nullptr, 0);
187 if (idSize <= 0) {
188 return "";
189 }
190 char cloudId[idSize + 1];
191 idSize = getxattr(path.c_str(), CLOUD_FILE_CLOUD_ID_XATTR.c_str(), cloudId, idSize);
192 if (idSize <= 0) {
193 return "";
194 }
195 return string(cloudId);
196 }
197
CheckIsCloud(const string & key)198 bool CloudFileUtils::CheckIsCloud(const string &key)
199 {
200 return key == CLOUD_CLOUD_ID_XATTR;
201 }
202
CheckIsCloudLocation(const string & key)203 bool CloudFileUtils::CheckIsCloudLocation(const string &key)
204 {
205 return key == CLOUD_FILE_LOCATION;
206 }
207
CheckIsHmdfsPermission(const string & key)208 bool CloudFileUtils::CheckIsHmdfsPermission(const string &key)
209 {
210 return key == HMDFS_PERMISSION_XATTR;
211 }
212
CheckIsCloudRecycle(const string & key)213 bool CloudFileUtils::CheckIsCloudRecycle(const string &key)
214 {
215 return key == CLOUD_CLOUD_RECYCLE_XATTR;
216 }
217
CheckIsFavorite(const string & key)218 bool CloudFileUtils::CheckIsFavorite(const string &key)
219 {
220 return key == IS_FAVORITE_XATTR;
221 }
222
CheckFileStatus(const string & key)223 bool CloudFileUtils::CheckFileStatus(const string &key)
224 {
225 return key == IS_FILE_STATUS_XATTR;
226 }
227
LocalWriteOpen(const string & dfsPath)228 bool CloudFileUtils::LocalWriteOpen(const string &dfsPath)
229 {
230 unique_ptr<char[]> absPath = make_unique<char[]>(PATH_MAX + 1);
231 if (realpath(dfsPath.c_str(), absPath.get()) == nullptr) {
232 return false;
233 }
234 string realPath = absPath.get();
235 char resolvedPath[PATH_MAX] = {'\0'};
236 char *realPaths = realpath(realPath.c_str(), resolvedPath);
237 if (realPaths == NULL) {
238 LOGE("realpath failed");
239 return false;
240 }
241 int fd = open(realPaths, O_RDONLY);
242 if (fd < 0) {
243 LOGE("open failed, errno:%{public}d", errno);
244 return false;
245 }
246 uint32_t writeOpenCnt = 0;
247 int ret = ioctl(fd, HMDFS_IOC_GET_WRITEOPEN_CNT, &writeOpenCnt);
248 close(fd);
249 if (ret < 0) {
250 LOGE("ioctl failed, errno:%{public}d", errno);
251 return false;
252 }
253
254 return writeOpenCnt != 0;
255 }
256 } // namespace CloudDisk
257 } // namespace FileManagement
258 } // namespace OHOS
259