• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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