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