• 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 #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