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