1 /*
2 * Copyright (c) 2024 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 "key_backup.h"
17
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <thread>
21
22 #include "storage_service_errno.h"
23 #include "storage_service_log.h"
24 #include "unique_fd.h"
25 #include "utils/storage_radar.h"
26
27 namespace OHOS {
28 namespace StorageDaemon {
29 constexpr uint32_t INVALID_LOOP_NUM = 0xFFFFFFFF;
30 constexpr uint8_t BACK_MAX_RETRY_TIME = 3;
31 constexpr uint16_t BACK_RETRY_INTERVAL_MS = 50 * 1000;
32
33 constexpr const char *BACKUP_NAME = "_bak";
34 struct FileNode {
35 std::string baseName;
36 std::string origFile;
37 std::string backFile;
38 bool isSame;
39 };
40
CreateBackup(const std::string & from,const std::string & to,bool removeOld)41 void KeyBackup::CreateBackup(const std::string &from, const std::string &to, bool removeOld)
42 {
43 LOGI("create backup from: %{public}s to: %{public}s removeOld: %{public}d",
44 from.c_str(), to.c_str(), removeOld ? 1 : 0);
45 if (access(from.c_str(), 0) != 0) {
46 LOGE("from path s not exist, path is %{public}s", from.c_str());
47 return;
48 }
49
50 if (access(to.c_str(), 0) == 0) {
51 if (removeOld) {
52 if (RemoveNode(to) != 0) {
53 LOGE("faled to remove to: %{public}s", to.c_str());
54 }
55 }
56 } else {
57 int32_t ret = MkdirParentWithRetry(to, DEFAULT_DIR_PERM);
58 if (ret != 0) {
59 LOGE("CreateBackup failed, path is %{public}s", to.c_str());
60 return;
61 }
62 }
63 CheckAndCopyFiles(from, to);
64 }
65
RemoveNode(const std::string & pathName)66 int32_t KeyBackup::RemoveNode(const std::string &pathName)
67 {
68 LOGI("remove node pathName %{public}s", pathName.c_str());
69 struct stat st;
70 if (lstat(pathName.c_str(), &st) < 0) {
71 return (errno == ENOENT) ? 0 : -1;
72 }
73
74 if (!S_ISDIR(st.st_mode)) {
75 CleanFile(pathName);
76 return remove(pathName.c_str());
77 }
78
79 DIR *dir = opendir(pathName.c_str());
80 if (dir == nullptr) {
81 return -1;
82 }
83
84 struct dirent *de = nullptr;
85 bool rmSubNodeFail = false;
86 errno = 0;
87 while ((de = readdir(dir)) != nullptr) {
88 if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) {
89 continue;
90 }
91 std::string dn = pathName + "/" + std::string(de->d_name);
92 if (RemoveNode(dn) < 0) {
93 rmSubNodeFail = true;
94 break;
95 }
96 errno = 0;
97 }
98
99 if (errno < 0 || rmSubNodeFail) {
100 closedir(dir);
101 return -1;
102 }
103
104 if (closedir(dir) < 0) {
105 return -1;
106 }
107 return rmdir(pathName.c_str());
108 }
109
TryRestoreKey(const std::shared_ptr<BaseKey> & baseKey,const UserAuth & auth)110 int32_t KeyBackup::TryRestoreKey(const std::shared_ptr<BaseKey> &baseKey, const UserAuth &auth)
111 {
112 if (baseKey == nullptr) {
113 LOGE("basekey is nullptr");
114 return -1;
115 }
116 std::string keyDir = baseKey->GetDir();
117 std::string backupDir;
118 GetBackupDir(keyDir, backupDir);
119 if (baseKey->DoRestoreKey(auth, keyDir + PATH_LATEST) == E_OK) {
120 std::thread fixFileThread([this, keyDir, backupDir]() { CheckAndFixFiles(keyDir, backupDir); });
121 fixFileThread.detach();
122 LOGI("Restore by main key success !");
123 return 0;
124 }
125 LOGE("origKey failed, try backupKey");
126 if (baseKey->DoRestoreKey(auth, backupDir + PATH_LATEST) == E_OK) {
127 CheckAndFixFiles(backupDir, keyDir);
128 LOGI("Restore by back key success !");
129 return 0;
130 }
131
132 LOGE("origKey failed, backupKey failed, so mix key");
133 return -1;
134 }
135
TryRestoreUeceKey(const std::shared_ptr<BaseKey> & baseKey,const UserAuth & auth,KeyBlob & planKey,KeyBlob & decryptedKey)136 int32_t KeyBackup::TryRestoreUeceKey(const std::shared_ptr<BaseKey> &baseKey,
137 const UserAuth &auth,
138 KeyBlob &planKey,
139 KeyBlob &decryptedKey)
140 {
141 if (baseKey == nullptr) {
142 LOGE("basekey is nullptr");
143 return -1;
144 }
145 std::string keyDir = baseKey->GetDir();
146 std::string backupDir;
147 GetBackupDir(keyDir, backupDir);
148 auto ret = baseKey->DecryptKeyBlob(auth, keyDir + PATH_LATEST, planKey, decryptedKey);
149 if (ret == E_OK) {
150 CheckAndFixFiles(keyDir, backupDir);
151 LOGI("Restore uece by main key success !");
152 return 0;
153 }
154 LOGE("origKey failed, try backupKey");
155 ret = baseKey->DecryptKeyBlob(auth, backupDir + PATH_LATEST, planKey, decryptedKey);
156 if (ret == E_OK) {
157 CheckAndFixFiles(backupDir, keyDir);
158 LOGI("Restore uece by back key success !");
159 return 0;
160 }
161
162 LOGE("origKey failed, backupKey failed, so mix key");
163 return -1;
164 }
165
GetBackupDir(std::string & origDir,std::string & backupDir)166 int32_t KeyBackup::GetBackupDir(std::string &origDir, std::string &backupDir)
167 {
168 LOGI("get backup dir origDir %{public}s", origDir.c_str());
169 if (origDir == DEVICE_EL1_DIR) {
170 backupDir = std::string(DEVICE_EL1_DIR) + BACKUP_NAME;
171 LOGI("backup dir is: %{public}s", backupDir.c_str());
172 return 0;
173 }
174
175 auto slashIndex = origDir.rfind("/");
176 if (slashIndex == std::string::npos || slashIndex == 0) {
177 return -1;
178 }
179 std::string prefixStr = origDir.substr(0, slashIndex);
180 std::string endStr = origDir.substr(slashIndex);
181 backupDir = prefixStr + BACKUP_NAME + endStr;
182 LOGI("backup dir is: %{public}s", backupDir.c_str());
183 return 0;
184 }
185
ListAndCheckDir(std::string & origDir)186 void KeyBackup::ListAndCheckDir(std::string &origDir)
187 {
188 LOGI("list and check dir %{public}s", origDir.c_str());
189 if (access(origDir.c_str(), F_OK) == 0) {
190 return;
191 }
192 LOGW("list and check dir origDir is not exist %{public}s", origDir.c_str());
193 std::string backupDir;
194 int32_t ret = GetBackupDir(origDir, backupDir);
195 if (ret != 0) {
196 LOGE("list and check dir failed %{public}s", origDir.c_str());
197 return;
198 }
199 if (access(backupDir.c_str(), F_OK) == 0) {
200 LOGW("list and check dir origDir: %{public}s backupDir: %{public}s", origDir.c_str(), backupDir.c_str());
201 ret = MkdirParent(origDir, DEFAULT_DIR_PERM);
202 if (ret != 0) {
203 return;
204 }
205 CheckAndCopyFiles(backupDir, origDir);
206 }
207 return;
208 }
209
DoResotreKeyMix(std::shared_ptr<BaseKey> & baseKey,const UserAuth & auth,const std::string & keyDir,const std::string & backupDir)210 int32_t KeyBackup::DoResotreKeyMix(std::shared_ptr<BaseKey> &baseKey, const UserAuth &auth, const std::string &keyDir,
211 const std::string &backupDir)
212 {
213 std::string origKeyDir = keyDir + PATH_LATEST;
214 std::string backupKeyDir = backupDir + PATH_LATEST;
215 std::vector<struct FileNode> fileList;
216 uint32_t diffNum = 0;
217 int32_t ret = GetFileList(origKeyDir, backupKeyDir, fileList, diffNum);
218 if (ret != 0 || diffNum <= 1) {
219 LOGE("get file list failed or diffNum too least, ret: %{public}d, diffNum: %{public}d", ret, diffNum);
220 return E_ERR;
221 }
222
223 std::string tempKeyDir;
224 ret = CopySameFilesToTempDir(backupKeyDir, tempKeyDir, fileList);
225 if (ret != 0) {
226 return false;
227 }
228
229 diffNum = fileList.size();
230 uint32_t loopNum = GetLoopMaxNum(diffNum);
231 if (loopNum == INVALID_LOOP_NUM) {
232 RemoveNode(tempKeyDir);
233 return E_ERR;
234 }
235 for (uint32_t i = 0; i <= loopNum; i++) {
236 LOGI("try mix key files to decrypt i: %{public}d loopNum: %{public}d", i, loopNum);
237 ret = CopyMixFilesToTempDir(diffNum, i, tempKeyDir, fileList);
238 if (ret != 0) {
239 LOGE("copy mix files to temp dir failed");
240 continue;
241 }
242 if (baseKey == nullptr) {
243 LOGE("basekey is nullptr");
244 return E_ERR;
245 }
246 if (baseKey->DoRestoreKey(auth, tempKeyDir) == E_OK) {
247 LOGI("mix key files descrpt succ, fix orig and backup");
248 CheckAndFixFiles(tempKeyDir, origKeyDir);
249 CheckAndFixFiles(tempKeyDir, backupKeyDir);
250 RemoveNode(tempKeyDir);
251 return true;
252 }
253 }
254 RemoveNode(tempKeyDir);
255 return E_ERR;
256 }
257
GetFileList(const std::string & origDir,const std::string & backDir,std::vector<struct FileNode> & fileList,uint32_t diffNum)258 int32_t KeyBackup::GetFileList(const std::string &origDir, const std::string &backDir,
259 std::vector<struct FileNode> &fileList, uint32_t diffNum)
260 {
261 LOGI("get file list origDir: %{public}s backDir: %{public}s", origDir.c_str(), backDir.c_str());
262 DIR *dir = opendir(origDir.c_str());
263 if (dir == nullptr) {
264 LOGE("fail to open %{public}s", origDir.c_str());
265 return -1;
266 }
267 struct dirent *de = nullptr;
268 while ((de = readdir(dir)) != nullptr) {
269 AddOrigFileToList(std::string(de->d_name), origDir, fileList);
270 }
271 closedir(dir);
272 dir = nullptr;
273
274 dir = opendir(backDir.c_str());
275 if (dir == nullptr) {
276 LOGE("fail to open %{public}s", backDir.c_str());
277 return -1;
278 }
279 while ((de = readdir(dir)) != nullptr) {
280 AddBackupFileToList(std::string(de->d_name), backDir, fileList);
281 }
282 closedir(dir);
283 dir = nullptr;
284
285 diffNum = GetDiffFilesNum(fileList);
286 LOGI("get file list origDir: %{public}s backDir: %{public}s diffNum: %{public}d",
287 origDir.c_str(), backDir.c_str(), diffNum);
288 return 0;
289 }
290
IsRegFile(const std::string & filePath)291 bool KeyBackup::IsRegFile(const std::string &filePath)
292 {
293 struct stat st;
294 if (lstat(filePath.c_str(), &st) < 0) {
295 LOGE("lstat failed %{public}s", filePath.c_str());
296 return false;
297 }
298
299 if (!S_ISREG(st.st_mode)) {
300 LOGE("filePath is not reg file %{public}s", filePath.c_str());
301 return false;
302 }
303 return true;
304 }
305
AddOrigFileToList(const std::string & fileName,const std::string & origDir,std::vector<struct FileNode> & fileList)306 void KeyBackup::AddOrigFileToList(const std::string &fileName, const std::string &origDir,
307 std::vector<struct FileNode> &fileList)
308 {
309 if (fileName.compare("..") == 0 || fileName.compare(".") == 0) {
310 return;
311 }
312
313 std::string filePath = origDir + "/" + fileName;
314 if (!IsRegFile(filePath)) {
315 return;
316 }
317
318 struct FileNode fl;
319 fl.baseName = fileName;
320 fl.origFile = filePath;
321 fl.backFile = "";
322 fl.isSame = false;
323 fileList.push_back(fl);
324 return;
325 }
326
AddBackupFileToList(const std::string & fileName,const std::string & backDir,std::vector<struct FileNode> & fileList)327 void KeyBackup::AddBackupFileToList(const std::string &fileName, const std::string &backDir,
328 std::vector<struct FileNode> &fileList)
329 {
330 if (fileName.compare("..") == 0 || fileName.compare(".") == 0) {
331 return;
332 }
333
334 std::string filePath = backDir + "/" + fileName;
335 if (!IsRegFile(filePath)) {
336 return;
337 }
338
339 for (auto iter = fileList.begin(); iter != fileList.end(); ++iter) {
340 if (iter->baseName.compare(fileName) == 0) {
341 iter->backFile = backDir + "/" + fileName;
342 if (CompareFile(iter->origFile, iter->backFile) == 0) {
343 iter->isSame = true;
344 }
345 return;
346 }
347 }
348
349 struct FileNode fl;
350 fl.baseName = fileName;
351 fl.origFile = "";
352 fl.backFile = filePath;
353 fl.isSame = false;
354 fileList.push_back(fl);
355 return;
356 }
357
GetDiffFilesNum(const std::vector<struct FileNode> & fileList)358 uint32_t KeyBackup::GetDiffFilesNum(const std::vector<struct FileNode> &fileList)
359 {
360 uint32_t diffNum = 0;
361 for (auto iter = fileList.begin(); iter != fileList.end(); ++iter) {
362 LOGI("fileList contain origFile: %{public}s, backupFile: %{public}s, isSame: %{public}d, fileName: %{public}s",
363 iter->origFile.c_str(), iter->backFile.c_str(), iter->isSame ? 0 : 1, iter->baseName.c_str());
364 if (!iter->isSame) {
365 diffNum++;
366 }
367 }
368 LOGI("diff files num %{public}d", diffNum);
369 return diffNum;
370 }
371
CopySameFilesToTempDir(const std::string & backupDir,std::string & tempDir,std::vector<struct FileNode> & fileList)372 int32_t KeyBackup::CopySameFilesToTempDir(const std::string &backupDir, std::string &tempDir,
373 std::vector<struct FileNode> &fileList)
374 {
375 LOGI("copy same files to temp dir, backupDir: %{public}s tempDir: %{public}s", backupDir.c_str(), tempDir.c_str());
376 int32_t ret = CreateTempDirForMixFiles(backupDir, tempDir);
377 if (ret != 0) {
378 return -1;
379 }
380
381 for (auto iter = fileList.begin(); iter != fileList.end();) {
382 if (iter->isSame || iter->backFile.empty()) {
383 ret = CheckAndCopyOneFile(iter->origFile, tempDir + "/" + iter->baseName);
384 if (ret != 0) {
385 RemoveNode(tempDir);
386 return -1;
387 }
388 iter = fileList.erase(iter);
389 } else if (iter->origFile.empty()) {
390 ret = CheckAndCopyOneFile(iter->backFile, tempDir + "/" + iter->baseName);
391 if (ret != 0) {
392 RemoveNode(tempDir);
393 return -1;
394 }
395 iter = fileList.erase(iter);
396 } else {
397 ++iter;
398 }
399 }
400 return 0;
401 }
402
CreateTempDirForMixFiles(const std::string & backupDir,std::string & tempDir)403 int32_t KeyBackup::CreateTempDirForMixFiles(const std::string &backupDir, std::string &tempDir)
404 {
405 auto pos = backupDir.rfind("/");
406 std::string parentDir = backupDir.substr(0, pos);
407 tempDir = parentDir + "/temp";
408
409 RemoveNode(tempDir);
410 int32_t ret = HandleCopyDir(backupDir, tempDir);
411 if (ret != 0) {
412 LOGE("create temp dir for mix files failed, ret: %{public}d, tempDir: %{public}s", ret, tempDir.c_str());
413 } else {
414 LOGI("create temp dir for mix files success, tempDir: %{public}s", tempDir.c_str());
415 }
416 return ret;
417 }
418
GetLoopMaxNum(uint32_t diffNum)419 uint32_t KeyBackup::GetLoopMaxNum(uint32_t diffNum)
420 {
421 if (diffNum > MAX_FILE_NUM) {
422 LOGE("there are too many different files, diffNum: %{public}d", diffNum);
423 return INVALID_LOOP_NUM;
424 }
425
426 const double fileNum = 2;
427 return static_cast<uint32_t>(pow(fileNum, diffNum) - 1);
428 }
429
CopyMixFilesToTempDir(uint32_t diffNum,uint32_t num,const std::string & tempDir,const std::vector<struct FileNode> & fileList)430 int32_t KeyBackup::CopyMixFilesToTempDir(uint32_t diffNum, uint32_t num, const std::string &tempDir,
431 const std::vector<struct FileNode> &fileList)
432 {
433 for (uint32_t i = 0; i < diffNum; i++) {
434 std::string from;
435 if (num & (1UL << i)) {
436 from = fileList[i].backFile;
437 } else {
438 from = fileList[i].origFile;
439 }
440 std::string to = tempDir + "/" + fileList[i].baseName;
441 if (CheckAndCopyOneFile(from, to) != 0) {
442 return -1;
443 }
444 }
445 return 0;
446 }
447
CheckAndFixFiles(const std::string & from,const std::string & to)448 void KeyBackup::CheckAndFixFiles(const std::string &from, const std::string &to)
449 {
450 LOGI("check fix files from: %{public}s to: %{public}s", from.c_str(), to.c_str());
451 CreateBackup(from, to, false);
452 }
453
FsyncFile(const std::string & dirName)454 void KeyBackup::FsyncFile(const std::string &dirName)
455 {
456 LOGI("sync directory dirName %{public}s", dirName.c_str());
457 std::string realPath;
458 if (!GetRealPath(dirName, realPath)) {
459 return;
460 }
461
462 UniqueFd fd(open(realPath.c_str(), O_RDONLY | O_CLOEXEC));
463 if (fd < 0) {
464 LOGE("failed to open %{public}s", realPath.c_str());
465 return;
466 }
467
468 auto ret = fsync(fd);
469 if (ret == -1) {
470 if (errno == EROFS || errno == EINVAL) {
471 LOGE("file system does not support sync, dirName: %{public}s", realPath.c_str());
472 } else {
473 StorageService::StorageRadar::ReportUserManager("KeyBackup::FsyncFile", 0, ret, "dirName=" + dirName);
474 LOGE("sync failed: %{public}s", realPath.c_str());
475 }
476 }
477 return;
478 }
479
MkdirParentWithRetry(const std::string & pathName,mode_t mode)480 int32_t KeyBackup::MkdirParentWithRetry(const std::string &pathName, mode_t mode)
481 {
482 int32_t ret = MkdirParent(pathName, DEFAULT_DIR_PERM);
483 if (ret == 0) {
484 LOGI("succeed");
485 return 0;
486 }
487 LOGE("CreateBackup failed start retry, path is %{public}s", pathName.c_str());
488 for (int i = 0; i < BACK_MAX_RETRY_TIME; ++i) {
489 usleep(BACK_RETRY_INTERVAL_MS);
490 ret = MkdirParent(pathName, DEFAULT_DIR_PERM);
491 LOGE("CreateBackup has retry %{public}d times, retryRet %{public}d", i, ret);
492 if (ret == 0) {
493 break;
494 }
495 }
496 return ret;
497 }
498
MkdirParent(const std::string & pathName,mode_t mode)499 int32_t KeyBackup::MkdirParent(const std::string &pathName, mode_t mode)
500 {
501 LOGI("mkdir parent dirName %{public}s", pathName.c_str());
502 std::string::size_type pos = 0;
503 pos = pathName.find("/", pos + 1);
504 while (pos != std::string::npos) {
505 std::string dirName = pathName.substr(0, pos);
506 if (access(dirName.c_str(), F_OK) != 0) {
507 if (mkdir(dirName.c_str(), mode) < 0) {
508 LOGE("mkdr dir %{public}s failed", dirName.c_str());
509 return -1;
510 }
511 }
512 pos = pathName.find("/", pos + 1);
513 }
514
515 return 0;
516 }
517
CleanFile(const std::string & path)518 void KeyBackup::CleanFile(const std::string &path)
519 {
520 LOGI("clean file path %{public}s", path.c_str());
521 std::string realPath;
522 if (!GetRealPath(path, realPath)) {
523 return;
524 }
525 FILE *f = fopen(realPath.c_str(), "w");
526 if (f == nullptr) {
527 LOGE("open %s failed", realPath.c_str());
528 return;
529 }
530 int fd = fileno(f);
531 if (fd < 0) {
532 LOGE("open %{public}s failed", realPath.c_str());
533 (void)fclose(f);
534 return;
535 }
536
537 int len = lseek(fd, 0, SEEK_END);
538 std::string data(len, '\0');
539
540 lseek(fd, 0, SEEK_SET);
541 if (write(fd, data.c_str(), data.size()) < 0) {
542 LOGE("failed to write file %{public}s", realPath.c_str());
543 }
544 if (fsync(fd) == -1) {
545 LOGE("failed to sync file %{public}s", realPath.c_str());
546 }
547 (void)fclose(f);
548 return;
549 }
550
CheckAndCopyFiles(const std::string & from,const std::string & to)551 void KeyBackup::CheckAndCopyFiles(const std::string &from, const std::string &to)
552 {
553 LOGI("check and copy files from: %{public}s to: %{public}s", from.c_str(), to.c_str());
554 struct stat st;
555 if (lstat(from.c_str(), &st) < 0) {
556 LOGE("lstat file failed, %{public}s", from.c_str());
557 return;
558 }
559
560 if (S_ISREG(st.st_mode)) {
561 CheckAndCopyOneFile(from, to);
562 return;
563 } else if (!S_ISDIR(st.st_mode)) {
564 LOGE("file: %{public}s is not reg file or dir, skip it", from.c_str());
565 return;
566 }
567
568 int32_t ret = HandleCopyDir(from, to);
569 if (ret != 0) {
570 LOGE("CheckAndCopyFiles failed start retry, path is %{public}s", to.c_str());
571 for (int i = 0; i < BACK_MAX_RETRY_TIME; ++i) {
572 usleep(BACK_RETRY_INTERVAL_MS);
573 ret = HandleCopyDir(from, to);
574 LOGE("CheckAndCopyFiles has retry %{public}d times, retryRet %{public}d", i, ret);
575 if (ret == 0) {
576 break;
577 }
578 }
579 }
580 DIR *dir = opendir(from.c_str());
581 if (dir == nullptr) {
582 LOGE("open dr failed, %{public}s", from.c_str());
583 return;
584 }
585
586 struct dirent *de = nullptr;
587 while ((de = readdir(dir)) != nullptr) {
588 if (strcmp(de->d_name, "..") == 0 || strcmp(de->d_name, ".") == 0) {
589 continue;
590 }
591 std::string dfrom = from + "/" + de->d_name;
592 std::string dto = to + "/" + de->d_name;
593 CheckAndCopyFiles(dfrom, dto);
594 }
595
596 if (closedir(dir) < 0) {
597 LOGE("close dir failed, %{public}s", from.c_str());
598 }
599 }
600
HandleCopyDir(const std::string & from,const std::string & to)601 int32_t KeyBackup::HandleCopyDir(const std::string &from, const std::string &to)
602 {
603 struct FileAttr attr;
604 int32_t ret = mkdir(to.c_str(), DEFAULT_DIR_PERM);
605 if (ret && errno != EEXIST) {
606 LOGE("mkdir dir %{public}s failed", to.c_str());
607 return -1;
608 }
609
610 if (GetAttr(from, attr) == 0) {
611 SetAttr(to, attr);
612 }
613 return 0;
614 }
615
CheckAndCopyOneFile(const std::string & srcFile,const std::string & dstFile)616 int32_t KeyBackup::CheckAndCopyOneFile(const std::string &srcFile, const std::string &dstFile)
617 {
618 LOGI("check and copy one file srcFile: %{public}s dstFile: %{public}s", srcFile.c_str(), dstFile.c_str());
619 std::string srcData;
620 if (!ReadFileToString(srcFile, srcData)) {
621 LOGE("failed to read srcFile %{public}s", srcFile.c_str());
622 return -1;
623 }
624
625 std::string dstData;
626 if (!ReadFileToString(dstFile, dstData)) {
627 LOGE("failed to read dstFile %{public}s", dstFile.c_str());
628 }
629
630 if (srcData.compare(dstData) == 0) {
631 return 0;
632 }
633
634 if (!WriteStringToFile(srcData, dstFile)) {
635 LOGE("failed to write dstFile file: %{public}s", dstFile.c_str());
636 return -1;
637 }
638
639 struct FileAttr attr;
640 if (GetAttr(srcFile, attr) == 0) {
641 SetAttr(dstFile, attr);
642 }
643 FsyncFile(dstFile);
644 LOGW("copy srcFile: %{public}s dstFile file %{public}s succ", srcFile.c_str(), dstFile.c_str());
645 return 0;
646 }
647
ReadFileToString(const std::string & filePath,std::string & content)648 bool KeyBackup::ReadFileToString(const std::string &filePath, std::string &content)
649 {
650 std::string realPath;
651 if (!GetRealPath(filePath, realPath)) {
652 return false;
653 }
654 FILE *f = fopen(realPath.c_str(), "r");
655 if (f == nullptr) {
656 LOGE("%s realpath failed", realPath.c_str());
657 return false;
658 }
659 int fd = fileno(f);
660 if (fd < 0) {
661 LOGE("%{public}s realpath failed", realPath.c_str());
662 (void)fclose(f);
663 return false;
664 }
665 struct stat sb {};
666 if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
667 content.resize(sb.st_size);
668 }
669
670 ssize_t remaining = sb.st_size;
671 bool readStatus = true;
672 char* p = const_cast<char*>(content.data());
673
674 while (remaining > 0) {
675 ssize_t n = read(fd, p, remaining);
676 if (n < 0) {
677 readStatus = false;
678 break;
679 }
680 p += n;
681 remaining -= n;
682 }
683 (void)fclose(f);
684 return readStatus;
685 }
686
GetRealPath(const std::string & path,std::string & realPath)687 bool KeyBackup::GetRealPath(const std::string &path, std::string &realPath)
688 {
689 char resolvedPath[PATH_MAX] = { 0 };
690 if (path.size() > PATH_MAX || !realpath(path.c_str(), resolvedPath)) {
691 LOGE("%{public}s realpath failed", path.c_str());
692 return false;
693 }
694 realPath = std::string(resolvedPath);
695 return true;
696 }
697
WriteStringToFd(int fd,const std::string & content)698 bool KeyBackup::WriteStringToFd(int fd, const std::string &content)
699 {
700 const char *p = content.data();
701 size_t remaining = content.size();
702 while (remaining > 0) {
703 ssize_t n = write(fd, p, remaining);
704 if (n == -1) {
705 return false;
706 }
707 p += n;
708 remaining -= n;
709 }
710 return true;
711 }
712
WriteStringToFile(const std::string & payload,const std::string & fileName)713 bool KeyBackup::WriteStringToFile(const std::string &payload, const std::string &fileName)
714 {
715 UniqueFd fd(open(fileName.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, DEFAULT_WRITE_FILE_PERM));
716 if (fd < 0) {
717 LOGE("open file failed, %{public}s", fileName.c_str());
718 return false;
719 }
720 if (!WriteStringToFd(fd, payload)) {
721 LOGE("failed to write file, %{public}s", fileName.c_str());
722 unlink(fileName.c_str());
723 return false;
724 }
725
726 auto ret = fsync(fd);
727 if (ret == -1) {
728 if (errno == EROFS || errno == EINVAL) {
729 LOGE("file system does not support sync, fileName: %{public}s", fileName.c_str());
730 } else {
731 std::string extraData = "payload=" + payload + ", fileName=" + fileName;
732 StorageService::StorageRadar::ReportUserManager("KeyBackup::FsyncFile::fsync", 0, ret, extraData);
733 LOGE("sync failed: %{public}s", fileName.c_str());
734 unlink(fileName.c_str());
735 return false;
736 }
737 }
738 return true;
739 }
740
CompareFile(const std::string & fileA,const std::string fileB)741 int32_t KeyBackup::CompareFile(const std::string &fileA, const std::string fileB)
742 {
743 std::string dataA;
744 if (!ReadFileToString(fileA, dataA)) {
745 LOGE("failed to read from %{public}s", fileA.c_str());
746 return -1;
747 }
748
749 std::string dataB;
750 if (!ReadFileToString(fileB, dataB)) {
751 LOGE("failed to read from %{public}s", fileB.c_str());
752 return -1;
753 }
754
755 return dataA.compare(dataB);
756 }
757
GetAttr(const std::string & path,struct FileAttr & attr)758 int32_t KeyBackup::GetAttr(const std::string &path, struct FileAttr &attr)
759 {
760 struct stat st;
761 if (lstat(path.c_str(), &st) < 0) {
762 return (errno == ENOENT) ? 0 : -1;
763 }
764
765 attr.uid = st.st_uid;
766 attr.gid = st.st_gid;
767 attr.mode = st.st_mode;
768 return 0;
769 }
770
SetAttr(const std::string & path,struct FileAttr & attr)771 int32_t KeyBackup::SetAttr(const std::string &path, struct FileAttr &attr)
772 {
773 int32_t ret = lchown(path.c_str(), attr.uid, attr.gid);
774 if (ret != 0) {
775 LOGE("lchown failed path: %{public}s, uid: %{public}d, gid: %{public}d", path.c_str(), attr.uid, attr.gid);
776 return ret;
777 }
778
779 ret = chmod(path.c_str(), attr.mode);
780 if (ret != 0) {
781 LOGE("chmod failed, path: %{public}s, mode: %{public}d", path.c_str(), attr.mode);
782 return ret;
783 }
784
785 return ret;
786 }
787 } // namespace StorageDaemon
788 } // namespace HOHS