1 /*
2 * Copyright (c) 2021-2025 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 #include "account_file_operator.h"
16 #include <cerrno>
17 #include <cstdio>
18 #include <fcntl.h>
19 #include <fstream>
20 #include <shared_mutex>
21 #include <sstream>
22 #include <string>
23 #include <sys/file.h>
24 #include <sys/ioctl.h>
25 #include <sys/stat.h>
26 #include <sys/statvfs.h>
27 #include <sys/types.h>
28 #include <thread>
29 #include <unistd.h>
30 #include "account_log_wrapper.h"
31 #include "directory_ex.h"
32 #include "account_hisysevent_adapter.h"
33 #include "json_utils.h"
34 namespace OHOS {
35 namespace AccountSA {
36 namespace {
37 #ifdef ENABLE_FILE_WATCHER
38 constexpr char ACCOUNT_INFO_DIGEST_FILE_PATH[] = "account_info_digest.json";
39 #endif // ENABLE_FILE_WATCHER
40 const long MAX_FILE_SIZE = 16 * 1024 * 1024; // 16MB
41 const unsigned long long BUFF_FILE_SIZE = 50 * 1024 * 1024; // 50MB
42 const uint32_t RETRY_TIMES = 3;
43 const uint32_t RETRY_SLEEP_MS = 5;
44 #define HMFS_MONITOR_FL 0x00000002
45 #define HMFS_IOCTL_HW_GET_FLAGS _IOR(0XF5, 70, unsigned int)
46 #define HMFS_IOCTL_HW_SET_FLAGS _IOR(0XF5, 71, unsigned int)
47 const uint64_t FDSAN_DIR_TAG = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_DIRECTORY, 0xC01B00);
48 static std::map<std::string, std::shared_ptr<Utils::RWLock>> g_rwLockMap;
49 static std::mutex g_rwLockMapMutex;
50 const char OPERATION_LOG_ERROR[] = "errLog";
51 const int32_t RELEASE_COUNT = 2;
52 } // namespace
53
FileExists(const std::string & path)54 static bool FileExists(const std::string &path)
55 {
56 uint32_t retryCount = 0;
57 while (retryCount < RETRY_TIMES) {
58 struct stat buf = {};
59 if (stat(path.c_str(), &buf) == 0) {
60 return S_ISREG(buf.st_mode);
61 }
62 if (errno != ENOENT) {
63 ACCOUNT_LOGE("Stat %{public}s failed, errno=%{public}d. Retrying...", path.c_str(), errno);
64 std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_SLEEP_MS));
65 retryCount++;
66 } else {
67 return false;
68 }
69 }
70 std::string errMsg = "Stat " + path + " with retry failed.";
71 REPORT_OS_ACCOUNT_FAIL(0, OPERATION_LOG_ERROR, ENOENT, errMsg);
72 return false;
73 }
74
~FileTransaction()75 FileTransaction::~FileTransaction()
76 {
77 ReleaseAction();
78 }
79
TryEraseTransaction(const std::string & path)80 static void TryEraseTransaction(const std::string &path)
81 {
82 std::lock_guard<std::mutex> lock(g_rwLockMapMutex);
83 auto iter = g_rwLockMap.find(path);
84 if (iter == g_rwLockMap.end()) {
85 return;
86 }
87 // if count == 2, it is only handled by map and one transaction. need release.
88 if (iter->second.use_count() == RELEASE_COUNT) {
89 g_rwLockMap.erase(iter);
90 }
91 }
92
BeginWriteTransaction()93 ErrCode FileTransaction::BeginWriteTransaction()
94 {
95 if (isOpenTransaction_) {
96 ACCOUNT_LOGE("Transaction already started.");
97 return ERR_ACCOUNT_COMMON_FILE_TRANSACTION_FAILED;
98 }
99 rwlock_->LockWrite();
100 isOpenTransaction_ = true;
101 std::string tempFilePath = GetTempFilePath();
102 std::string folderPath = tempFilePath.substr(0, tempFilePath.rfind('/'));
103 AccountFileOperator tempFileOperator;
104 if (!tempFileOperator.IsExistDir(folderPath)) {
105 ErrCode errCode = tempFileOperator.CreateDir(folderPath);
106 if (errCode != ERR_OK) {
107 ACCOUNT_LOGE("Failed to create dir, str = %{public}s errCode %{public}d.", folderPath.c_str(), errCode);
108 rwlock_->UnLockWrite();
109 return errCode;
110 }
111 }
112 FILE *tempFile = fopen(tempFilePath.c_str(), "wb");
113 if (tempFile == nullptr) {
114 ACCOUNT_LOGE("Failed to open %{public}s, errno %{public}d.", tempFilePath.c_str(), errno);
115 rwlock_->UnLockWrite();
116 return ERR_ACCOUNT_COMMON_FILE_OPEN_FAILED;
117 }
118 (void)fclose(tempFile);
119 return ERR_OK;
120 }
121
ForceUnlock()122 void FileTransaction::ForceUnlock()
123 {
124 if (!isOpenTransaction_) {
125 ACCOUNT_LOGE("Transaction not started.");
126 return;
127 }
128 rwlock_->UnLockWrite();
129 isOpenTransaction_ = false;
130 return;
131 }
132
Rollback()133 ErrCode FileTransaction::Rollback()
134 {
135 if (!isOpenTransaction_) {
136 return ERR_OK;
137 }
138 ErrCode ret = DeleteTempFile();
139 if (ret != ERR_OK) {
140 ACCOUNT_LOGE("Delete temp file failed, ret = %{public}d.", ret);
141 }
142 ForceUnlock();
143 return ret;
144 }
145
EndTransaction()146 ErrCode FileTransaction::EndTransaction()
147 {
148 if (!isOpenTransaction_) {
149 return ERR_OK;
150 }
151 if (isWriteSuccessOnce_) {
152 ErrCode ret = SwapFileNames();
153 if (ret != ERR_OK) {
154 ACCOUNT_LOGE("SwapFileNames failed.");
155 return ret;
156 }
157 }
158 // if file delete not ok, return ok, write is success.
159 ErrCode ret = DeleteTempFile();
160 if (ret != ERR_OK) {
161 ACCOUNT_LOGE("Delete temp file failed, ret = %{public}d.", ret);
162 return ret;
163 }
164 ForceUnlock();
165 return ERR_OK;
166 }
167
WriteFile(const std::string & path,const std::string & content)168 static ErrCode WriteFile(const std::string &path, const std::string &content)
169 {
170 FILE *fp = fopen(path.c_str(), "wb");
171 if (fp == nullptr) {
172 ACCOUNT_LOGE("Failed to open %{public}s, errno = %{public}d.", path.c_str(), errno);
173 return ERR_ACCOUNT_COMMON_FILE_OPEN_FAILED;
174 }
175 int fd = fileno(fp);
176 do {
177 flock(fd, LOCK_EX);
178 size_t num = fwrite(content.c_str(), sizeof(char), content.length(), fp);
179 if (num != content.length()) {
180 ACCOUNT_LOGE("Failed to fwrite %{public}s, errno = %{public}d.", path.c_str(), errno);
181 break;
182 }
183 if (fflush(fp) != 0) {
184 ACCOUNT_LOGE("Failed to fflush %{public}s, errno = %{public}d.", path.c_str(), errno);
185 break;
186 }
187 if (fsync(fd) != 0) {
188 ACCOUNT_LOGE("Failed to fsync %{public}s, errno = %{public}d.", path.c_str(), errno);
189 break;
190 }
191 flock(fd, LOCK_UN);
192 (void)fclose(fp);
193 // change mode
194 if (!ChangeModeFile(path, S_IRUSR | S_IWUSR)) {
195 ACCOUNT_LOGW("Failed to change mode for file %{public}s, errno = %{public}d.", path.c_str(), errno);
196 return ERR_OHOSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR;
197 }
198 return ERR_OK;
199 } while (0);
200 flock(fd, LOCK_UN);
201 (void)fclose(fp);
202 return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
203 }
204
WriteFile(const std::string & content)205 ErrCode FileTransaction::WriteFile(const std::string &content)
206 {
207 if (!isOpenTransaction_) {
208 ACCOUNT_LOGE("Transaction not started.");
209 return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
210 }
211 std::string tempFilePath = GetTempFilePath();
212 ErrCode err = AccountSA::WriteFile(tempFilePath, content);
213 if (err != ERR_OK) {
214 ACCOUNT_LOGE("Write file failed.");
215 return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
216 }
217 isWriteSuccessOnce_ = true;
218 return ERR_OK;
219 }
220
ReadFile(const std::string & path,std::string & content)221 static ErrCode ReadFile(const std::string &path, std::string &content)
222 {
223 if (!FileExists(path)) {
224 ACCOUNT_LOGE("cannot find file, path = %{public}s", path.c_str());
225 return ERR_OSACCOUNT_SERVICE_FILE_FIND_FILE_ERROR;
226 }
227 FILE *fp = fopen(path.c_str(), "rb");
228 if (fp == nullptr) {
229 ACCOUNT_LOGE("Cannot open file %{public}s, errno %{public}d.", path.c_str(), errno);
230 return ERR_ACCOUNT_COMMON_FILE_OPEN_FAILED;
231 }
232 int fd = fileno(fp);
233 flock(fd, LOCK_SH);
234 (void)fseek(fp, 0, SEEK_END);
235 long fileSize = ftell(fp);
236 if ((fileSize < 0) || (fileSize > MAX_FILE_SIZE)) {
237 ACCOUNT_LOGE("The file(%{public}s) size is invalid, errno %{public}d.", path.c_str(), errno);
238 flock(fd, LOCK_UN);
239 (void)fclose(fp);
240 return ERR_ACCOUNT_COMMON_FILE_READ_FAILED;
241 }
242 rewind(fp);
243 std::unique_ptr<char[]> buffer = std::make_unique<char[]>(fileSize);
244 size_t retSize = fread(buffer.get(), sizeof(char), fileSize, fp);
245 if (static_cast<long>(retSize) != fileSize) {
246 ACCOUNT_LOGE("Fail to read file %{public}s", path.c_str());
247 flock(fd, LOCK_UN);
248 (void)fclose(fp);
249 return ERR_ACCOUNT_COMMON_FILE_READ_FAILED;
250 }
251 content = std::string(buffer.get(), retSize);
252 flock(fd, LOCK_UN);
253 (void)fclose(fp);
254 return ERR_OK;
255 }
256
ReadFile(std::string & content)257 ErrCode FileTransaction::ReadFile(std::string &content)
258 {
259 return AccountSA::ReadFile(path_, content);
260 }
261
IsTempFileExist()262 bool FileTransaction::IsTempFileExist()
263 {
264 return FileExists(GetTempFilePath());
265 }
266
IsTempFileExist(const std::string & path)267 bool FileTransaction::IsTempFileExist(const std::string &path)
268 {
269 return FileExists(GetTempFilePath(path));
270 }
271
DeleteTempFile()272 ErrCode FileTransaction::DeleteTempFile()
273 {
274 bool delFlag = false;
275 std::string tempFilePath = GetTempFilePath();
276 uint32_t i = 0;
277 do {
278 delFlag = OHOS::RemoveFile(tempFilePath);
279 if (delFlag) {
280 break;
281 }
282 i++;
283 std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_SLEEP_MS));
284 } while (i <= RETRY_TIMES);
285 if (!delFlag) {
286 int32_t err = errno;
287 ACCOUNT_LOGE("DeleteTempFile failed, path %{public}s, errno %{public}d.", tempFilePath.c_str(), err);
288 std::string errMsg = "DeleteTempFile failed, path " + tempFilePath + ", errno " + std::to_string(err);
289 REPORT_OS_ACCOUNT_FAIL(0, OPERATION_LOG_ERROR, err, errMsg);
290 return ERR_OSACCOUNT_SERVICE_FILE_DELE_ERROR;
291 }
292 return ERR_OK;
293 }
294
GetTempFilePath(const std::string & path)295 std::string FileTransaction::GetTempFilePath(const std::string &path)
296 {
297 return path + ".tmp";
298 }
299
GetTempFilePath() const300 std::string FileTransaction::GetTempFilePath() const
301 {
302 return GetTempFilePath(path_);
303 }
304
SwapFileNames()305 ErrCode FileTransaction::SwapFileNames()
306 {
307 std::string tempFileName = GetTempFilePath();
308
309 bool isTempFileExist = FileExists(tempFileName);
310 if (!isTempFileExist) {
311 ACCOUNT_LOGI("Temp file does not exist, path = %{public}s.", tempFileName.c_str());
312 return ERR_OK;
313 }
314 bool isTargetFileExist = FileExists(path_);
315 uint32_t mode = RENAME_NOREPLACE;
316 if (isTargetFileExist) {
317 if (!ChangeModeFile(path_, S_IRUSR | S_IWUSR)) {
318 ACCOUNT_LOGW("Failed to change mode for file %{public}s, errno = %{public}d.", path_.c_str(), errno);
319 return ERR_OHOSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR;
320 }
321 mode = RENAME_EXCHANGE;
322 }
323 for (uint32_t i = 0; i <= RETRY_TIMES; i++) {
324 int32_t ret = renameat2(AT_FDCWD, tempFileName.c_str(), 0, path_.c_str(), mode);
325 if (ret == ERR_OK) {
326 return ERR_OK;
327 }
328 if ((ret != ERR_OK) && (errno != EAGAIN)) {
329 int32_t err = errno;
330 ACCOUNT_LOGE("Failed to swap file names, errno = %{public}d, errMsg = %{public}s", err, strerror(err));
331 std::string errMsg = "Failed to swap file " + tempFileName + " and " +
332 path_ + ", errMsg = %{public}s" + strerror(err);
333 REPORT_OS_ACCOUNT_FAIL(0, OPERATION_LOG_ERROR, err, errMsg);
334 return ERR_ACCOUNT_COMMON_FILE_SWAP_FAILED;
335 }
336 std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_SLEEP_MS));
337 }
338 std::string errMsg =
339 "Failed to swap file " + tempFileName + " and " + path_ + ", with retry";
340 REPORT_OS_ACCOUNT_FAIL(0, OPERATION_LOG_ERROR, EAGAIN, errMsg);
341 return ERR_ACCOUNT_COMMON_FILE_SWAP_FAILED;
342 }
343
ReleaseAction()344 void FileTransaction::ReleaseAction()
345 {
346 if (isOpenTransaction_) {
347 this->Rollback();
348 }
349 TryEraseTransaction(path_);
350 rwlock_ = nullptr;
351 }
352
GetPath() const353 std::string FileTransaction::GetPath() const
354 {
355 return path_;
356 }
357
AccountFileOperator()358 AccountFileOperator::AccountFileOperator() {}
359
~AccountFileOperator()360 AccountFileOperator::~AccountFileOperator() {}
361
CreateDir(const std::string & path,mode_t mode)362 ErrCode AccountFileOperator::CreateDir(const std::string &path, mode_t mode)
363 {
364 ACCOUNT_LOGI("Start creating a directory");
365 std::unique_lock<std::shared_timed_mutex> lock(fileLock_);
366 if (!OHOS::ForceCreateDirectory(path)) {
367 ACCOUNT_LOGE("failed to create %{public}s, errno %{public}d.", path.c_str(), errno);
368 return ERR_OSACCOUNT_SERVICE_FILE_CREATE_DIR_ERROR;
369 }
370 SetDirDelFlags(path);
371 bool createFlag = OHOS::ChangeModeDirectory(path, mode);
372 if (!createFlag) {
373 ACCOUNT_LOGE("failed to change mode for %{public}s, errno %{public}d.", path.c_str(), errno);
374 return ERR_OSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR;
375 }
376
377 return ERR_OK;
378 }
379
DeleteDirOrFile(const std::string & path)380 ErrCode AccountFileOperator::DeleteDirOrFile(const std::string &path)
381 {
382 if (IsExistDir(path)) {
383 return DeleteDir(path);
384 }
385 if (IsExistFile(path)) {
386 return DeleteFile(path);
387 }
388 ACCOUNT_LOGI("Dir or file does not exist, path %{public}s.", path.c_str());
389 return ERR_OK;
390 }
391
DeleteDir(const std::string & path)392 ErrCode AccountFileOperator::DeleteDir(const std::string &path)
393 {
394 std::unique_lock<std::shared_timed_mutex> lock(fileLock_);
395 bool delFlag = false;
396 delFlag = OHOS::ForceRemoveDirectory(path);
397 if (!delFlag) {
398 ACCOUNT_LOGE("DeleteDirOrFile failed, path %{public}s errno %{public}d.", path.c_str(), errno);
399 return ERR_OSACCOUNT_SERVICE_FILE_DELE_ERROR;
400 }
401 #ifdef ENABLE_FILE_WATCHER
402 SetValidDeleteFileOperationFlag(path, true);
403 #endif // ENABLE_FILE_WATCHER
404 return ERR_OK;
405 }
406
DeleteFile(const std::string & path)407 ErrCode AccountFileOperator::DeleteFile(const std::string &path)
408 {
409 std::unique_lock<std::shared_timed_mutex> lock(fileLock_);
410 bool delFlag = false;
411 delFlag = OHOS::RemoveFile(path);
412 if (!delFlag) {
413 ACCOUNT_LOGE("DeleteDirOrFile failed, path %{public}s errno %{public}d.", path.c_str(), errno);
414 return ERR_OSACCOUNT_SERVICE_FILE_DELE_ERROR;
415 }
416 #ifdef ENABLE_FILE_WATCHER
417 SetValidDeleteFileOperationFlag(path, true);
418 #endif // ENABLE_FILE_WATCHER
419 return ERR_OK;
420 }
421
422 #ifdef ENABLE_FILE_WATCHER
SetValidModifyFileOperationFlag(const std::string & fileName,bool flag)423 void AccountFileOperator::SetValidModifyFileOperationFlag(const std::string &fileName, bool flag)
424 {
425 if (fileName.find(ACCOUNT_INFO_DIGEST_FILE_PATH) != std::string::npos) { // ignore digest file record
426 return;
427 }
428 if (!flag) {
429 validModifyFileOperationFlag_.erase(
430 std::remove(validModifyFileOperationFlag_.begin(), validModifyFileOperationFlag_.end(), fileName),
431 validModifyFileOperationFlag_.end());
432 return;
433 }
434 if (std::find(validModifyFileOperationFlag_.begin(), validModifyFileOperationFlag_.end(), fileName) ==
435 validModifyFileOperationFlag_.end()) {
436 validModifyFileOperationFlag_.emplace_back(fileName);
437 }
438 }
439
GetValidModifyFileOperationFlag(const std::string & fileName)440 bool AccountFileOperator::GetValidModifyFileOperationFlag(const std::string &fileName)
441 {
442 for (auto iter : validModifyFileOperationFlag_) {
443 if (iter == fileName) {
444 return true;
445 }
446 }
447 return false;
448 }
449
SetValidDeleteFileOperationFlag(const std::string & fileName,bool flag)450 void AccountFileOperator::SetValidDeleteFileOperationFlag(const std::string &fileName, bool flag)
451 {
452 if (!flag) {
453 validDeleteFileOperationFlag_.erase(
454 std::remove(validDeleteFileOperationFlag_.begin(), validDeleteFileOperationFlag_.end(), fileName),
455 validDeleteFileOperationFlag_.end());
456 return;
457 }
458 validDeleteFileOperationFlag_.emplace_back(fileName);
459 }
460
GetValidDeleteFileOperationFlag(const std::string & fileName)461 bool AccountFileOperator::GetValidDeleteFileOperationFlag(const std::string &fileName)
462 {
463 for (auto iter : validDeleteFileOperationFlag_) {
464 if (fileName.find(iter) != std::string::npos) {
465 return true;
466 }
467 }
468 return false;
469 }
470 #endif // ENABLE_FILE_WATCHER
471
IsDataStorageSufficient(const unsigned long long reqFreeBytes)472 static bool IsDataStorageSufficient(const unsigned long long reqFreeBytes)
473 {
474 struct statvfs diskInfo;
475 int ret = statvfs("/data", &diskInfo);
476 if (ret != 0) {
477 ACCOUNT_LOGE("Get disk info failed, ret=%{public}d, errno=%{public}d.", ret, errno);
478 return false;
479 }
480
481 unsigned long long freeBytes =
482 static_cast<unsigned long long>(diskInfo.f_bsize) * static_cast<unsigned long long>(diskInfo.f_bavail);
483 bool isSufficient = (freeBytes > reqFreeBytes + BUFF_FILE_SIZE);
484 if (!isSufficient) {
485 ACCOUNT_LOGE("Data storage is insufficient, freeBytes=%{public}llu, reqFreeBytes=%{public}llu.", freeBytes,
486 reqFreeBytes);
487 }
488 return isSufficient;
489 }
490
SetDirDelFlags(const std::string & dirpath)491 bool AccountFileOperator::SetDirDelFlags(const std::string &dirpath)
492 {
493 char realPath[PATH_MAX] = {0};
494 if (realpath(dirpath.c_str(), realPath) == nullptr) {
495 ACCOUNT_LOGE("Failed to get realpath");
496 return false;
497 }
498 int32_t fd = open(realPath, O_DIRECTORY);
499 if (fd < 0) {
500 ACCOUNT_LOGE("Failed to open dir, errno: %{public}d", errno);
501 return false;
502 }
503 fdsan_exchange_owner_tag(fd, 0, FDSAN_DIR_TAG);
504 unsigned int flags = 0;
505 int32_t ret = ioctl(fd, HMFS_IOCTL_HW_GET_FLAGS, &flags);
506 if (ret < 0) {
507 fdsan_close_with_tag(fd, FDSAN_DIR_TAG);
508 ACCOUNT_LOGE("Failed to get flags, errno: %{public}d", errno);
509 return false;
510 }
511 if (flags & HMFS_MONITOR_FL) {
512 fdsan_close_with_tag(fd, FDSAN_DIR_TAG);
513 ACCOUNT_LOGE("Delete control flag is already set");
514 return false;
515 }
516 flags |= HMFS_MONITOR_FL;
517 ret = ioctl(fd, HMFS_IOCTL_HW_SET_FLAGS, &flags);
518 if (ret < 0) {
519 fdsan_close_with_tag(fd, FDSAN_DIR_TAG);
520 ACCOUNT_LOGE("Failed to set flags, errno: %{public}d", errno);
521 return false;
522 }
523 fdsan_close_with_tag(fd, FDSAN_DIR_TAG);
524 return true;
525 }
526
InputFileByPathAndContentWithTransaction(const std::string & path,const std::string & content)527 ErrCode AccountFileOperator::InputFileByPathAndContentWithTransaction(
528 const std::string &path, const std::string &content)
529 {
530 if (!IsDataStorageSufficient(content.length())) {
531 return ERR_ACCOUNT_COMMON_DATA_NO_SPACE;
532 }
533 std::unique_lock<std::shared_timed_mutex> lock(fileLock_);
534 auto transaction = GetFileTransaction(path);
535 if (transaction == nullptr) {
536 ACCOUNT_LOGE("GetFileTransaction failed, get nullptr.");
537 return ERR_ACCOUNT_COMMON_INSUFFICIENT_MEMORY_ERROR;
538 }
539 ErrCode errCode = transaction->BeginWriteTransaction();
540 if (errCode != ERR_OK) {
541 ACCOUNT_LOGE("BeginWriteTransaction failed, result = %{public}d", errCode);
542 return errCode;
543 }
544 errCode = transaction->WriteFile(content);
545 if (errCode != ERR_OK) {
546 ACCOUNT_LOGE("WriteFile failed, result = %{public}d", errCode);
547 return errCode;
548 }
549 errCode = transaction->EndTransaction();
550 if (errCode != ERR_OK) {
551 ACCOUNT_LOGE("EndTransaction failed, result = %{public}d", errCode);
552 }
553 return errCode;
554 }
555
InputFileByPathAndContent(const std::string & path,const std::string & content)556 ErrCode AccountFileOperator::InputFileByPathAndContent(const std::string &path, const std::string &content)
557 {
558 std::string str = path;
559 str.erase(str.rfind('/'));
560 if (!IsExistDir(str)) {
561 ErrCode errCode = CreateDir(str);
562 if (errCode != ERR_OK) {
563 ACCOUNT_LOGE("failed to create dir, str = %{public}s errCode %{public}d.", str.c_str(), errCode);
564 return errCode;
565 }
566 }
567 if (!IsDataStorageSufficient(content.length())) {
568 return ERR_ACCOUNT_COMMON_DATA_NO_SPACE;
569 }
570 std::unique_lock<std::shared_timed_mutex> lock(fileLock_);
571 #ifdef ENABLE_FILE_WATCHER
572 SetValidModifyFileOperationFlag(path, true);
573 #endif // ENABLE_FILE_WATCHER
574 ErrCode ret = WriteFile(path, content);
575 if (ret != ERR_OK) {
576 ACCOUNT_LOGE("WriteFile failed, path = %{public}s.", path.c_str());
577 #ifdef ENABLE_FILE_WATCHER
578 SetValidModifyFileOperationFlag(path, false);
579 #endif // ENABLE_FILE_WATCHER
580 }
581 return ret;
582 }
583
GetFileContentByPath(const std::string & path,std::string & content)584 ErrCode AccountFileOperator::GetFileContentByPath(const std::string &path, std::string &content)
585 {
586 if (!IsExistFile(path)) {
587 ACCOUNT_LOGE("cannot find file, path = %{public}s", path.c_str());
588 return ERR_OSACCOUNT_SERVICE_FILE_FIND_FILE_ERROR;
589 }
590 std::shared_lock<std::shared_timed_mutex> lock(fileLock_);
591 ErrCode ret = ReadFile(path, content);
592 if (ret != ERR_OK) {
593 ACCOUNT_LOGE("Failed to read file, path = %{public}s, ret = %{public}d", path.c_str(), ret);
594 }
595 return ret;
596 }
597
IsExistFile(const std::string & path)598 bool AccountFileOperator::IsExistFile(const std::string &path)
599 {
600 if (path.empty()) {
601 ACCOUNT_LOGE("Path is empty.");
602 return false;
603 }
604 std::shared_lock<std::shared_timed_mutex> lock(fileLock_);
605 return FileExists(path);
606 }
607
CheckFileExistence(const std::string & path)608 ErrCode AccountFileOperator::CheckFileExistence(const std::string &path)
609 {
610 if (path.empty()) {
611 ACCOUNT_LOGE("Path is empty.");
612 return ERR_ACCOUNT_COMMON_INVALID_PARAMETER;
613 }
614 std::shared_lock<std::shared_timed_mutex> lock(fileLock_);
615 uint32_t retryCount = 0;
616 while (retryCount < RETRY_TIMES) {
617 struct stat buf = {};
618 if (stat(path.c_str(), &buf) == 0) {
619 if (S_ISREG(buf.st_mode)) {
620 return ERR_OK;
621 }
622 ACCOUNT_LOGE("S_ISREG failed, errno=%{public}d.", errno);
623 return ERR_ACCOUNT_COMMON_FILE_OTHER_ERROR;
624 }
625 if (errno != ENOENT) {
626 ACCOUNT_LOGE("Stat %{public}s failed, errno=%{public}d. Retrying...", path.c_str(), errno);
627 std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_SLEEP_MS));
628 retryCount++;
629 } else {
630 ACCOUNT_LOGE("Stat %{public}s failed, errno=%{public}d.", path.c_str(), errno);
631 return ERR_ACCOUNT_COMMON_FILE_NOT_EXIST;
632 }
633 }
634 return ERR_ACCOUNT_COMMON_FILE_OTHER_ERROR;
635 }
636
IsJsonFormat(const std::string & path)637 bool AccountFileOperator::IsJsonFormat(const std::string &path)
638 {
639 std::string content;
640 if (GetFileContentByPath(path, content) != ERR_OK) {
641 return false;
642 }
643
644 auto jsonData = CreateJsonFromString(content);
645 if (jsonData == nullptr || !IsStructured(jsonData)) {
646 ACCOUNT_LOGE("File %{public}s is invalid json format, size: %{public}zu", path.c_str(), content.size());
647 return false;
648 }
649 return true;
650 }
651
IsJsonFileReady(const std::string & path)652 bool AccountFileOperator::IsJsonFileReady(const std::string &path)
653 {
654 return IsExistFile(path) && IsJsonFormat(path);
655 }
656
IsExistDir(const std::string & path)657 bool AccountFileOperator::IsExistDir(const std::string &path)
658 {
659 if (path.empty()) {
660 return false;
661 }
662 std::shared_lock<std::shared_timed_mutex> lock(fileLock_);
663 struct stat buf = {};
664 if (stat(path.c_str(), &buf) != 0) {
665 ACCOUNT_LOGE("Stat %{public}s failed, errno=%{public}d", path.c_str(), errno);
666 return false;
667 }
668
669 return S_ISDIR(buf.st_mode);
670 }
671
GetFileTransaction(const std::string & path)672 TransactionShared AccountFileOperator::GetFileTransaction(const std::string &path)
673 {
674 auto shared_lock = GetRWLock(path);
675 auto ret = std::make_shared<FileTransaction>(path, shared_lock);
676 return ret;
677 }
678
GetRWLock(const std::string & path)679 std::shared_ptr<Utils::RWLock> AccountFileOperator::GetRWLock(const std::string &path)
680 {
681 std::lock_guard<std::mutex> lock(g_rwLockMapMutex);
682 auto iter = g_rwLockMap.find(path);
683 if (iter != g_rwLockMap.end()) {
684 return iter->second;
685 }
686 std::shared_ptr<Utils::RWLock> rwlock = std::make_shared<Utils::RWLock>();
687 g_rwLockMap.emplace(path, rwlock);
688 return rwlock;
689 }
690 } // namespace AccountSA
691 } // namespace OHOS
692