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