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