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 "clouddisk_rdbstore.h"
17 
18 #include <cinttypes>
19 #include <ctime>
20 #include <sys/stat.h>
21 #include <sstream>
22 #include <functional>
23 
24 #include "cloud_pref_impl.h"
25 #include "clouddisk_db_const.h"
26 #include "clouddisk_notify.h"
27 #include "clouddisk_notify_utils.h"
28 #include "clouddisk_rdb_transaction.h"
29 #include "clouddisk_rdb_utils.h"
30 #include "clouddisk_sync_helper.h"
31 #include "clouddisk_type_const.h"
32 #include "dfs_error.h"
33 #include "file_column.h"
34 #include "ffrt_inner.h"
35 #include "nlohmann/json.hpp"
36 #include "parameter.h"
37 #include "parameters.h"
38 #include "rdb_errno.h"
39 #include "rdb_sql_utils.h"
40 #include "utils_log.h"
41 
42 namespace OHOS::FileManagement::CloudDisk {
43 using namespace std;
44 using namespace OHOS::NativeRdb;
45 using namespace CloudSync;
46 
47 enum XATTR_CODE {
48     ERROR_CODE = -1,
49     CLOUD_LOCATION = 1,
50     CLOUD_RECYCLE,
51     IS_FAVORITE,
52     FILE_SYNC_STATUS,
53     IS_EXT_ATTR
54 };
55 static constexpr int32_t LOOKUP_QUERY_LIMIT = 1;
56 static constexpr int32_t CHECK_QUERY_LIMIT = 2000;
57 static const uint32_t SET_STATE = 1;
58 static const uint32_t CANCEL_STATE = 0;
59 static const uint32_t MAX_FILE_NAME_SIZE = 246;
60 static const uint32_t MAX_QUERY_TIMES = 1024;
61 static const uint32_t STAT_MODE_DIR = 0771;
62 static const uint32_t STAT_MODE_REG = 0660;
63 const string BUNDLENAME_FLAG = "<BundleName>";
64 const string CLOUDDISK_URI_PREFIX = "file://<BundleName>/data/storage/el2/cloud";
65 const string BACKFLASH = "/";
66 static const string RECYCLE_FILE_NAME = ".trash";
67 static const string ROOT_CLOUD_ID = "rootId";
68 static const std::string FILEMANAGER_KEY = "persist.kernel.bundle_name.filemanager";
69 
CloudSyncTriggerFunc(const std::vector<std::string> & args)70 static const std::string CloudSyncTriggerFunc(const std::vector<std::string> &args)
71 {
72     size_t size = args.size();
73     if (size != ARGS_SIZE) {
74         LOGE("CloudSyncTriggerFunc args size error, %{public}zu", size);
75         return "";
76     }
77     int32_t userId = std::strtol(args[ARG_USER_ID].c_str(), nullptr, 0);
78     string bundleName = args[ARG_BUNDLE_NAME];
79     LOGD("begin cloud sync trigger, bundleName: %{public}s, userId: %{public}d", bundleName.c_str(), userId);
80     return "";
81 }
82 
CloudDiskRdbStore(const std::string & bundleName,const int32_t & userId)83 CloudDiskRdbStore::CloudDiskRdbStore(const std::string &bundleName, const int32_t &userId)
84     : bundleName_(bundleName), userId_(userId)
85 {
86     RdbInit();
87 }
88 
~CloudDiskRdbStore()89 CloudDiskRdbStore::~CloudDiskRdbStore()
90 {
91     Stop();
92 }
93 
ReBuildDatabase(const string & databasePath)94 int32_t CloudDiskRdbStore::ReBuildDatabase(const string &databasePath)
95 {
96     LOGI("database need to be rebuilded");
97     int32_t errCode = RdbHelper::DeleteRdbStore(databasePath);
98     if (errCode != NativeRdb::E_OK) {
99         LOGE("Delete CloudDisk Database is failed, err = %{public}d", errCode);
100         return errCode;
101     }
102     errCode = 0;
103     CloudDiskDataCallBack rdbDataCallBack;
104     rdbStore_ = RdbHelper::GetRdbStore(config_, CLOUD_DISK_RDB_VERSION, rdbDataCallBack, errCode);
105     if (rdbStore_ == nullptr) {
106         LOGE("ReGetRdbStore is failed, userId_ = %{public}d, bundleName_ = %{public}s, errCode = %{public}d",
107              userId_, bundleName_.c_str(), errCode);
108         return errCode;
109     }
110     DatabaseRestore();
111     return E_OK;
112 }
113 
RdbInit()114 int32_t CloudDiskRdbStore::RdbInit()
115 {
116     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_SERVICE) != 0) {
117         LOGE("wait move error");
118         return EBUSY;
119     }
120     LOGI("Init rdb store, userId_ = %{public}d, bundleName_ = %{public}s", userId_, bundleName_.c_str());
121     string baseDir = "/data/service/el2/" + to_string(userId_) + "/hmdfs/cloudfile_manager/";
122     string customDir = baseDir.append(system::GetParameter(FILEMANAGER_KEY, ""));
123     string name = CLOUD_DISK_DATABASE_NAME;
124     int32_t errCode = 0;
125     string databasePath = RdbSqlUtils::GetDefaultDatabasePath(customDir, CLOUD_DISK_DATABASE_NAME, errCode);
126     if (errCode != NativeRdb::E_OK) {
127         LOGE("Create Default Database Path is failed, errCode = %{public}d", errCode);
128         return E_PATH;
129     }
130     config_.SetName(name);
131     config_.SetPath(databasePath);
132     config_.SetReadConSize(CONNECT_SIZE);
133     config_.SetScalarFunction("cloud_sync_func", ARGS_SIZE, CloudSyncTriggerFunc);
134     errCode = 0;
135     CloudDiskDataCallBack rdbDataCallBack;
136     rdbStore_ = RdbHelper::GetRdbStore(config_, CLOUD_DISK_RDB_VERSION, rdbDataCallBack, errCode);
137     if (rdbStore_ == nullptr) {
138         LOGE("GetRdbStore is failed, userId_ = %{public}d, bundleName_ = %{public}s, errCode = %{public}d",
139              userId_, bundleName_.c_str(), errCode);
140         if (errCode == NativeRdb::E_SQLITE_CORRUPT) {
141             if (ReBuildDatabase(databasePath)) {
142                 LOGE("clouddisk db image is malformed, ReBuild failed");
143             }
144         }
145         return errCode;
146     } else if (errCode == NativeRdb::E_SQLITE_CORRUPT) { DatabaseRestore(); }
147     return E_OK;
148 }
149 
Stop()150 void CloudDiskRdbStore::Stop()
151 {
152     if (rdbStore_ == nullptr) {
153         return;
154     }
155     rdbStore_ = nullptr;
156 }
157 
GetRaw()158 shared_ptr<RdbStore> CloudDiskRdbStore::GetRaw()
159 {
160     return rdbStore_;
161 }
162 
DatabaseRestore()163 void CloudDiskRdbStore::DatabaseRestore()
164 {
165     if (rdbStore_ == nullptr) {
166         LOGE("rdbStore_ is nullptr");
167         return;
168     }
169     LOGI("clouddisk db image is malformed, need to restore");
170     auto fileName = "/data/service/el2/" + to_string(userId_) + "/hmdfs/cloudfile_manager/" +
171         system::GetParameter(FILEMANAGER_KEY, "") + "/backup/clouddisk_backup.db";
172     int32_t ret = -1;
173     if (access(fileName.c_str(), F_OK) == 0) {
174         {
175             lock_guard<mutex> lock(backupMutex_);
176             ret = rdbStore_->Restore(fileName);
177         }
178         if (ret != 0) {
179             LOGE("cloudisk restore failed, ret %{public}d", ret);
180         }
181     } else {
182         LOGE("clouddisk backup db is not exist");
183     }
184 }
185 
LookUp(const std::string & parentCloudId,const std::string & fileName,CloudDiskFileInfo & info)186 int32_t CloudDiskRdbStore::LookUp(const std::string &parentCloudId,
187     const std::string &fileName, CloudDiskFileInfo &info)
188 {
189     RDBPTR_IS_NULLPTR(rdbStore_);
190     if (fileName.empty() || parentCloudId.empty()) {
191         LOGE("look up parameters is invalid");
192         return E_INVAL_ARG;
193     }
194     AbsRdbPredicates lookUpPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
195     lookUpPredicates
196         .EqualTo(FileColumn::PARENT_CLOUD_ID, parentCloudId)->And()
197         ->EqualTo(FileColumn::FILE_NAME, fileName)->And()->EqualTo(FileColumn::FILE_TIME_RECYCLED, "0")->And()
198         ->EqualTo(FileColumn::ROOT_DIRECTORY, bundleName_)->And()
199         ->NotEqualTo(FileColumn::DIRTY_TYPE, to_string(static_cast<int32_t>(DirtyType::TYPE_DELETED)));
200     lookUpPredicates.Limit(LOOKUP_QUERY_LIMIT);
201     auto resultSet = rdbStore_->QueryByStep(lookUpPredicates, FileColumn::FILE_SYSTEM_QUERY_COLUMNS);
202     int32_t ret = CloudDiskRdbUtils::ResultSetToFileInfo(move(resultSet), info);
203     if (ret != E_OK) {
204         LOGE("lookup file info is failed, ret %{public}d", ret);
205         return E_RDB;
206     }
207     return E_OK;
208 }
209 
GetAttr(const std::string & cloudId,CloudDiskFileInfo & info)210 int32_t CloudDiskRdbStore::GetAttr(const std::string &cloudId, CloudDiskFileInfo &info)
211 {
212     RDBPTR_IS_NULLPTR(rdbStore_);
213     if (cloudId.empty() || cloudId == ROOT_CLOUD_ID) {
214         LOGE("getAttr parameter is invalid");
215         return E_INVAL_ARG;
216     }
217     AbsRdbPredicates getAttrPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
218     getAttrPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
219     auto resultSet = rdbStore_->QueryByStep(getAttrPredicates, FileColumn::FILE_SYSTEM_QUERY_COLUMNS);
220     int32_t ret = CloudDiskRdbUtils::ResultSetToFileInfo(move(resultSet), info);
221     if (ret != E_OK) {
222         LOGE("get file attr is failed, ret %{public}d", ret);
223         return E_RDB;
224     }
225     return E_OK;
226 }
227 
SetAttr(const std::string & fileName,const std::string & parentCloudId,const std::string & cloudId,const unsigned long long & size)228 int32_t CloudDiskRdbStore::SetAttr(const std::string &fileName, const std::string &parentCloudId,
229     const std::string &cloudId, const unsigned long long &size)
230 {
231     RDBPTR_IS_NULLPTR(rdbStore_);
232     if (cloudId.empty()) {
233         LOGE("cloudId is empty");
234         return E_INVAL_ARG;
235     }
236     if (cloudId == ROOT_CLOUD_ID) {
237         LOGE("cloudId is rootId");
238         return E_INVAL_ARG;
239     }
240 
241     ValuesBucket setAttr;
242     setAttr.PutLong(FileColumn::FILE_SIZE, static_cast<int64_t>(size));
243     TransactionOperations rdbTransaction(rdbStore_);
244     auto [ret, transaction] = rdbTransaction.Start();
245     if (ret != E_OK) {
246         LOGE("rdbstore begin transaction failed, ret = %{public}d", ret);
247         return ret;
248     }
249     int32_t changedRows = -1;
250     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(FileColumn::FILES_TABLE);
251     predicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
252     std::tie(ret, changedRows) = transaction->Update(setAttr, predicates);
253     if (ret != E_OK) {
254         LOGE("setAttr size fail, ret: %{public}d, changeRow is %{public}d", ret, changedRows);
255         return E_RDB;
256     }
257 
258     MetaBase metaBase(fileName, cloudId);
259     metaBase.size = size;
260     auto callback = [&metaBase] (MetaBase &m) {
261         m.size = metaBase.size;
262     };
263     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId_, bundleName_, parentCloudId);
264     ret = metaFile->DoLookupAndUpdate(fileName, callback);
265     if (ret != E_OK) {
266         LOGE("update new dentry failed, ret = %{public}d", ret);
267         return ret;
268     }
269     rdbTransaction.Finish();
270     return E_OK;
271 }
272 
ReadDir(const std::string & cloudId,vector<CloudDiskFileInfo> & infos)273 int32_t CloudDiskRdbStore::ReadDir(const std::string &cloudId, vector<CloudDiskFileInfo> &infos)
274 {
275     RDBPTR_IS_NULLPTR(rdbStore_);
276     CLOUDID_IS_NULL(cloudId);
277     AbsRdbPredicates readDirPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
278     readDirPredicates.EqualTo(FileColumn::PARENT_CLOUD_ID, cloudId)
279         ->And()->EqualTo(FileColumn::FILE_TIME_RECYCLED, "0")->And()
280         ->EqualTo(FileColumn::ROOT_DIRECTORY, bundleName_)->And()
281         ->NotEqualTo(FileColumn::DIRTY_TYPE, to_string(static_cast<int32_t>(DirtyType::TYPE_DELETED)));
282     auto resultSet = rdbStore_->QueryByStep(readDirPredicates, { FileColumn::FILE_NAME, FileColumn::IS_DIRECTORY });
283     int32_t ret = CloudDiskRdbUtils::ResultSetToFileInfos(move(resultSet), infos);
284     if (ret != E_OK) {
285         LOGE("read directory is failed, ret %{public}d", ret);
286         return E_RDB;
287     }
288     return E_OK;
289 }
290 
GetFileExtension(const std::string & fileName,std::string & extension)291 static int32_t GetFileExtension(const std::string &fileName, std::string &extension)
292 {
293     size_t dotIndex = fileName.rfind(".");
294     if (dotIndex != string::npos) {
295         extension = fileName.substr(dotIndex + 1);
296         return E_OK;
297     }
298     LOGE("Failed to obtain file extension");
299     return E_INVAL_ARG;
300 }
301 
FillFileType(const std::string & fileName,ValuesBucket & fileInfo)302 static void FillFileType(const std::string &fileName, ValuesBucket &fileInfo)
303 {
304     string extension;
305     if (!GetFileExtension(fileName, extension)) {
306         fileInfo.PutString(FileColumn::FILE_CATEGORY, extension);
307     }
308 }
309 
UTCTimeMilliSeconds()310 static int64_t UTCTimeMilliSeconds()
311 {
312     struct timespec t;
313     clock_gettime(CLOCK_REALTIME, &t);
314     return t.tv_sec * SECOND_TO_MILLISECOND + t.tv_nsec / MILLISECOND_TO_NANOSECOND;
315 }
316 
CheckNameForSpace(const std::string & fileName,const int32_t isDir)317 static int32_t CheckNameForSpace(const std::string& fileName, const int32_t isDir)
318 {
319     if (fileName.empty()) {
320         return EINVAL;
321     }
322     if (fileName[0] == ' ') {
323         LOGI("Illegal name");
324         return EINVAL;
325     }
326     if (isDir == DIRECTORY) {
327         if ((fileName.length() >= 1 && fileName[fileName.length() - 1] == ' ') || fileName == RECYCLE_FILE_NAME) {
328             LOGI("Illegal name");
329             return EINVAL;
330         }
331     }
332     return E_OK;
333 }
334 
CheckName(const std::string & fileName)335 static int32_t CheckName(const std::string &fileName)
336 {
337     if (fileName.empty() ||
338         fileName == "." ||
339         fileName == ".." ||
340         fileName.length() > MAX_FILE_NAME_SIZE) {
341         return EINVAL;
342     }
343     std::map<char, bool> illegalCharacter = {
344         {'<', true},
345         {'>', true},
346         {'|', true},
347         {':', true},
348         {'?', true},
349         {'/', true},
350         {'\\', true},
351         {'"', true},
352         {'*', true},
353     };
354     for (char c : fileName) {
355         if (illegalCharacter.find(c) != illegalCharacter.end()) {
356             LOGI("Illegal name");
357             return EINVAL;
358         }
359     }
360     return E_OK;
361 }
362 
CreateFile(const std::string & fileName,const std::string & filePath,ValuesBucket & fileInfo,struct stat * statInfo)363 static int32_t CreateFile(const std::string &fileName, const std::string &filePath, ValuesBucket &fileInfo,
364     struct stat *statInfo)
365 {
366     int32_t ret = stat(filePath.c_str(), statInfo);
367     if (ret) {
368         LOGE("filePath %{private}s is invalid", GetAnonyString(filePath).c_str());
369         return E_PATH;
370     }
371     fileInfo.PutInt(FileColumn::IS_DIRECTORY, FILE);
372     fileInfo.PutLong(FileColumn::FILE_SIZE, statInfo->st_size);
373     fileInfo.PutLong(FileColumn::FILE_TIME_EDITED, CloudFileUtils::Timespec2Milliseconds(statInfo->st_mtim));
374     fileInfo.PutLong(FileColumn::META_TIME_EDITED, CloudFileUtils::Timespec2Milliseconds(statInfo->st_mtim));
375     FillFileType(fileName, fileInfo);
376     return E_OK;
377 }
378 
CreateDentry(MetaBase & metaBase,uint32_t userId,const std::string & bundleName,const std::string & fileName,const std::string & parentCloudId)379 static int32_t CreateDentry(MetaBase &metaBase, uint32_t userId, const std::string &bundleName,
380     const std::string &fileName, const std::string &parentCloudId)
381 {
382     auto callback = [&metaBase] (MetaBase &m) {
383         m.cloudId = metaBase.cloudId;
384         m.atime = metaBase.atime;
385         m.mtime = metaBase.mtime;
386         m.size = metaBase.size;
387         m.mode = metaBase.mode;
388         m.position = metaBase.position;
389         m.fileType = metaBase.fileType;
390         m.noUpload = metaBase.noUpload;
391     };
392     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, parentCloudId);
393     int32_t ret = metaFile->DoLookupAndUpdate(fileName, callback);
394     if (ret != E_OK) {
395         LOGE("update new dentry failed, ret = %{public}d", ret);
396         return ret;
397     }
398     return E_OK;
399 }
400 
UpdateMetabase(MetaBase & metaBase,int64_t fileTimeAdded,struct stat * statInfo)401 static void UpdateMetabase(MetaBase &metaBase, int64_t fileTimeAdded, struct stat *statInfo)
402 {
403     metaBase.atime = static_cast<uint64_t>(fileTimeAdded);
404     metaBase.mtime = static_cast<uint64_t>(CloudFileUtils::Timespec2Milliseconds(statInfo->st_mtim));
405     metaBase.mode = statInfo->st_mode;
406     metaBase.size = static_cast<uint64_t>(statInfo->st_size);
407     metaBase.position = LOCAL;
408     metaBase.fileType = FILE_TYPE_CONTENT;
409 }
410 
HandleCreateValue(ValuesBucket & fileInfo,const std::string & cloudId,const std::string & parentCloudId,const std::string & fileName,const std::string & bundleName)411 static void HandleCreateValue(ValuesBucket &fileInfo, const std::string &cloudId, const std::string &parentCloudId,
412                               const std::string &fileName, const std::string &bundleName)
413 {
414     fileInfo.PutString(FileColumn::CLOUD_ID, cloudId);
415     fileInfo.PutString(FileColumn::FILE_NAME, fileName);
416     fileInfo.PutString(FileColumn::PARENT_CLOUD_ID, parentCloudId);
417     fileInfo.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_NO_NEED_UPLOAD));
418     fileInfo.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::NEW));
419     fileInfo.PutString(FileColumn::ROOT_DIRECTORY, bundleName);
420 }
421 
Create(const std::string & cloudId,const std::string & parentCloudId,const std::string & fileName)422 int32_t CloudDiskRdbStore::Create(const std::string &cloudId, const std::string &parentCloudId,
423     const std::string &fileName)
424 {
425     int32_t ret = CheckName(fileName);
426     if (ret != E_OK) {
427         return ret;
428     }
429     ret = CheckNameForSpace(fileName, FILE);
430     if (ret != E_OK) {
431         return ret;
432     }
433     RDBPTR_IS_NULLPTR(rdbStore_);
434     ValuesBucket fileInfo;
435     if (cloudId.empty() || parentCloudId.empty() || fileName.empty()) {
436         LOGE("create parameter is invalid");
437         return E_INVAL_ARG;
438     }
439     int64_t fileTimeAdded = UTCTimeMilliSeconds();
440     fileInfo.PutLong(FileColumn::FILE_TIME_ADDED, fileTimeAdded);
441     HandleCreateValue(fileInfo, cloudId, parentCloudId, fileName, bundleName_);
442     struct stat statInfo {};
443     string filePath = CloudFileUtils::GetLocalFilePath(cloudId, bundleName_, userId_);
444     if (CreateFile(fileName, filePath, fileInfo, &statInfo)) {
445         LOGE("file path is invalid, cannot create file record");
446         return E_PATH;
447     }
448     TransactionOperations rdbTransaction(rdbStore_);
449     auto [rdbRet, transaction] = rdbTransaction.Start();
450     if (rdbRet != E_OK) {
451         LOGE("rdbstore begin transaction failed, ret = %{public}d", ret);
452         return rdbRet;
453     }
454     int64_t outRowId = 0;
455     std::tie(rdbRet, outRowId) = transaction->Insert(FileColumn::FILES_TABLE, fileInfo);
456     if (rdbRet != E_OK) {
457         LOGE("insert new file record in DB is failed, ret = %{public}d", ret);
458         return rdbRet;
459     }
460     MetaBase metaBase(fileName, cloudId);
461     UpdateMetabase(metaBase, fileTimeAdded, &statInfo);
462     ret = CreateDentry(metaBase, userId_, bundleName_, fileName, parentCloudId);
463     if (ret != E_OK) {
464         LOGE("create new dentry failed, ret = %{public}d", ret);
465         return ret;
466     }
467     rdbTransaction.Finish();
468     return E_OK;
469 }
470 
MkDir(const std::string & cloudId,const std::string & parentCloudId,const std::string & directoryName)471 int32_t CloudDiskRdbStore::MkDir(const std::string &cloudId, const std::string &parentCloudId,
472     const std::string &directoryName)
473 {
474     int32_t ret = CheckName(directoryName);
475     if (ret != E_OK) {
476         return ret;
477     }
478     ret = CheckNameForSpace(directoryName, DIRECTORY);
479     if (ret != E_OK) {
480         return ret;
481     }
482     RDBPTR_IS_NULLPTR(rdbStore_);
483     ValuesBucket dirInfo;
484     if (cloudId.empty() || parentCloudId.empty() || directoryName.empty()) {
485         LOGE("make directory parameter is invalid");
486         return E_INVAL_ARG;
487     }
488     dirInfo.PutString(FileColumn::CLOUD_ID, cloudId);
489     dirInfo.PutString(FileColumn::FILE_NAME, directoryName);
490     int64_t fileTimeAdded = UTCTimeMilliSeconds();
491     dirInfo.PutLong(FileColumn::FILE_TIME_ADDED, fileTimeAdded);
492     int64_t fileTimeEdited = UTCTimeMilliSeconds();
493     dirInfo.PutLong(FileColumn::FILE_TIME_EDITED, fileTimeEdited);
494     int64_t metaTimeEdited = UTCTimeMilliSeconds();
495     dirInfo.PutLong(FileColumn::META_TIME_EDITED, metaTimeEdited);
496     dirInfo.PutInt(FileColumn::IS_DIRECTORY, DIRECTORY);
497     dirInfo.PutString(FileColumn::PARENT_CLOUD_ID, parentCloudId);
498     dirInfo.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::NEW));
499     dirInfo.PutInt(FileColumn::FILE_STATUS, FileStatus::TO_BE_UPLOADED);
500     dirInfo.PutString(FileColumn::ROOT_DIRECTORY, bundleName_);
501     TransactionOperations rdbTransaction(rdbStore_);
502     std::shared_ptr<Transaction> transaction;
503     std::tie(ret, transaction) = rdbTransaction.Start();
504     if (ret != E_OK) {
505         LOGE("rdbstore begin transaction failed, ret = %{public}d", ret);
506         return ret;
507     }
508     int64_t outRowId = 0;
509     std::tie(ret, outRowId) = transaction->Insert(FileColumn::FILES_TABLE, dirInfo);
510     if (ret != E_OK) {
511         LOGE("insert new directory record in DB is failed, ret = %{public}d", ret);
512         return ret;
513     }
514     MetaBase metaBase(directoryName, cloudId);
515     metaBase.atime = static_cast<uint64_t>(fileTimeAdded);
516     metaBase.mtime = static_cast<uint64_t>(fileTimeEdited);
517     metaBase.mode = S_IFDIR | STAT_MODE_DIR;
518     metaBase.position = LOCAL;
519     metaBase.fileType = FILE_TYPE_CONTENT;
520     ret = CreateDentry(metaBase, userId_, bundleName_, directoryName, parentCloudId);
521     if (ret != E_OK) {
522         LOGE("create new dentry failed, ret = %{public}d", ret);
523         return ret;
524     }
525     rdbTransaction.Finish();
526     CloudDiskSyncHelper::GetInstance().RegisterTriggerSync(bundleName_, userId_);
527     return E_OK;
528 }
529 
HandleWriteValue(ValuesBucket & write,int32_t position,struct stat & statInfo)530 static void HandleWriteValue(ValuesBucket &write, int32_t position, struct stat &statInfo)
531 {
532     write.PutLong(FileColumn::FILE_SIZE, statInfo.st_size);
533     write.PutLong(FileColumn::FILE_TIME_EDITED, CloudFileUtils::Timespec2Milliseconds(statInfo.st_mtim));
534     write.PutLong(FileColumn::META_TIME_EDITED, CloudFileUtils::Timespec2Milliseconds(statInfo.st_mtim));
535     write.PutLong(FileColumn::FILE_TIME_VISIT, CloudFileUtils::Timespec2Milliseconds(statInfo.st_atim));
536     write.PutInt(FileColumn::FILE_STATUS, FileStatus::TO_BE_UPLOADED);
537     if (position != LOCAL) {
538         write.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_FDIRTY));
539         write.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::UPDATE));
540     } else {
541         write.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_NEW));
542     }
543 }
544 
WriteUpdateDentry(MetaBase & metaBase,uint32_t userId,const std::string & bundleName,const std::string & fileName,const std::string & parentCloudId)545 static int32_t WriteUpdateDentry(MetaBase &metaBase, uint32_t userId, const std::string &bundleName,
546     const std::string &fileName, const std::string &parentCloudId)
547 {
548     auto callback = [&metaBase] (MetaBase &m) {
549         m.mtime = metaBase.mtime;
550         m.size = metaBase.size;
551     };
552     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, parentCloudId);
553     LOGD("write update dentry start");
554     int32_t ret = metaFile->DoChildUpdate(fileName, callback);
555     if (ret != E_OK) {
556         LOGE("update new dentry failed, ret = %{public}d", ret);
557         return ret;
558     }
559     return ret;
560 }
561 
Write(const std::string & fileName,const std::string & parentCloudId,const std::string & cloudId)562 int32_t CloudDiskRdbStore::Write(const std::string &fileName, const std::string &parentCloudId,
563     const std::string &cloudId)
564 {
565     RDBPTR_IS_NULLPTR(rdbStore_);
566     if (cloudId.empty() || cloudId == ROOT_CLOUD_ID) {
567         LOGE("write parameter is invalid");
568         return E_INVAL_ARG;
569     }
570     TransactionOperations rdbTransaction(rdbStore_);
571     auto [ret, transaction] = rdbTransaction.Start();
572     if (ret != E_OK) {
573         LOGE("rdbstore begin transaction failed, ret = %{public}d", ret);
574         return ret;
575     }
576     string filePath = CloudFileUtils::GetLocalFilePath(cloudId, bundleName_, userId_);
577     struct stat statInfo {};
578     ret = stat(filePath.c_str(), &statInfo);
579     if (ret) {
580         LOGE("filePath %{private}s is invalid", GetAnonyString(filePath).c_str());
581         return E_PATH;
582     }
583     CloudDiskFileInfo info;
584     if (GetAttr(cloudId, info)) {
585         LOGE("get write cloudId info in DB fail");
586         return E_RDB;
587     }
588     int32_t position = static_cast<int32_t>(info.location);
589     ValuesBucket write;
590     HandleWriteValue(write, position, statInfo);
591     int32_t changedRows = -1;
592     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(FileColumn::FILES_TABLE);
593     predicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
594     std::tie(ret, changedRows) = transaction->Update(write, predicates);
595     if (ret != E_OK) {
596         LOGE("write file record in DB fail, ret %{public}d", ret);
597         return E_RDB;
598     }
599     MetaBase metaBase(fileName, cloudId);
600     metaBase.mtime = static_cast<uint64_t>(CloudFileUtils::Timespec2Milliseconds(statInfo.st_mtim));
601     metaBase.size = static_cast<uint64_t>(statInfo.st_size);
602     ret = WriteUpdateDentry(metaBase, userId_, bundleName_, fileName, parentCloudId);
603     if (ret != E_OK) {
604         LOGE("write update dentry failed, ret %{public}d", ret);
605         return E_RDB;
606     }
607     rdbTransaction.Finish();
608     CloudDiskSyncHelper::GetInstance().RegisterTriggerSync(bundleName_, userId_);
609     return E_OK;
610 }
611 
LocationSetXattr(const std::string & name,const std::string & parentCloudId,const std::string & cloudId,const std::string & value)612 int32_t CloudDiskRdbStore::LocationSetXattr(const std::string &name, const std::string &parentCloudId,
613     const std::string &cloudId, const std::string &value)
614 {
615     RDBPTR_IS_NULLPTR(rdbStore_);
616     int32_t val = -1;
617     istringstream transfer(value);
618     transfer >> val;
619     if (val != LOCAL && val != CLOUD && val != LOCAL_AND_CLOUD) {
620         LOGE("setxattr unknown value");
621         return E_INVAL_ARG;
622     }
623     ValuesBucket setXAttr;
624     setXAttr.PutInt(FileColumn::POSITION, val);
625     int32_t changedRows = -1;
626     TransactionOperations rdbTransaction(rdbStore_);
627     auto [ret, transaction] = rdbTransaction.Start();
628     if (ret != E_OK) {
629         LOGE("rdbstore begin transaction failed, ret = %{public}d", ret);
630         return ret;
631     }
632     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(FileColumn::FILES_TABLE);
633     predicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
634     std::tie(ret, changedRows) = transaction->Update(setXAttr, predicates);
635     if (ret != E_OK) {
636         LOGE("set xAttr location fail, ret %{public}d", ret);
637         return E_RDB;
638     }
639     MetaBase metaBase(name, cloudId);
640     auto callback = [&val] (MetaBase &m) {
641         m.position = val;
642     };
643     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId_, bundleName_, parentCloudId);
644     ret = metaFile->DoLookupAndUpdate(name, callback);
645     if (ret != E_OK) {
646         LOGE("update new dentry failed, ret = %{public}d", ret);
647         return ret;
648     }
649     rdbTransaction.Finish();
650     return E_OK;
651 }
652 
GetRowId(const std::string & cloudId,int64_t & rowId)653 int32_t CloudDiskRdbStore::GetRowId(const std::string &cloudId, int64_t &rowId)
654 {
655     RDBPTR_IS_NULLPTR(rdbStore_);
656     CLOUDID_IS_NULL(cloudId);
657     AbsRdbPredicates getRowIdPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
658     getRowIdPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
659     auto resultSet = rdbStore_->QueryByStep(getRowIdPredicates, {FileColumn::ROW_ID});
660     if (resultSet == nullptr) {
661         LOGE("get nullptr result set");
662         return E_RDB;
663     }
664     if (resultSet->GoToNextRow() != E_OK) {
665         LOGE("getRowId result set go to next row failed");
666         return E_RDB;
667     }
668     CloudDiskRdbUtils::GetLong(FileColumn::ROW_ID, rowId, resultSet);
669     return E_OK;
670 }
671 
RecycleSetValue(int32_t val,ValuesBucket & setXAttr,int32_t position)672 static int32_t RecycleSetValue(int32_t val, ValuesBucket &setXAttr, int32_t position)
673 {
674     if (position != LOCAL) {
675         setXAttr.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_MDIRTY));
676     } else {
677         setXAttr.PutInt(FileColumn::OPERATE_TYPE, static_cast<int32_t>(OperationType::NEW));
678     }
679     if (val == 0) {
680         setXAttr.PutInt(FileColumn::OPERATE_TYPE, static_cast<int32_t>(OperationType::RESTORE));
681         setXAttr.PutLong(FileColumn::FILE_TIME_RECYCLED, CANCEL_STATE);
682         setXAttr.PutInt(FileColumn::DIRECTLY_RECYCLED, CANCEL_STATE);
683         setXAttr.PutLong(FileColumn::META_TIME_EDITED, UTCTimeMilliSeconds());
684     } else if (val == 1) {
685         int64_t recycledTime = UTCTimeMilliSeconds();
686         setXAttr.PutInt(FileColumn::OPERATE_TYPE, static_cast<int32_t>(OperationType::DELETE));
687         setXAttr.PutLong(FileColumn::FILE_TIME_RECYCLED, recycledTime);
688         setXAttr.PutInt(FileColumn::DIRECTLY_RECYCLED, SET_STATE);
689         setXAttr.PutLong(FileColumn::META_TIME_EDITED, recycledTime);
690     } else {
691         LOGE("invalid value");
692         return E_RDB;
693     }
694     return E_OK;
695 }
696 
GetParentCloudId(const std::string & cloudId,std::string & parentCloudId)697 int32_t CloudDiskRdbStore::GetParentCloudId(const std::string &cloudId, std::string &parentCloudId)
698 {
699     RDBPTR_IS_NULLPTR(rdbStore_);
700     AbsRdbPredicates getParentCloudIdPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
701     getParentCloudIdPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
702     auto resultSet = rdbStore_->QueryByStep(getParentCloudIdPredicates, { FileColumn::PARENT_CLOUD_ID });
703     if (resultSet == nullptr) {
704         LOGE("get nullptr parentCloudId resultSet");
705         return E_RDB;
706     }
707     if (resultSet->GoToNextRow() != E_OK) {
708         LOGE("get parentCloudId go to next row failed");
709         return E_RDB;
710     }
711     int32_t ret = CloudDiskRdbUtils::GetString(FileColumn::PARENT_CLOUD_ID, parentCloudId, resultSet);
712     if (ret != E_OK) {
713         LOGE("get parent cloudId failed");
714         return ret;
715     }
716     return E_OK;
717 }
718 
RecycleSetXattr(const std::string & name,const std::string & parentCloudId,const std::string & cloudId,const std::string & value)719 int32_t CloudDiskRdbStore::RecycleSetXattr(const std::string &name, const std::string &parentCloudId,
720     const std::string &cloudId, const std::string &value)
721 {
722     RDBPTR_IS_NULLPTR(rdbStore_);
723     bool isNum = std::all_of(value.begin(), value.end(), ::isdigit);
724     if (!isNum) {
725         return EINVAL;
726     }
727     int32_t val = std::stoi(value);
728     int64_t rowId = 0;
729     int32_t position = -1;
730     int32_t changedRows = -1;
731     TransactionOperations rdbTransaction(rdbStore_);
732     auto [ret, transaction] = rdbTransaction.Start();
733     if (ret != E_OK) {
734         LOGE("rdbstore begin transaction failed, ret = %{public}d", ret);
735         return ret;
736     }
737     ret = GetRowIdAndPosition(transaction, cloudId, rowId, position);
738     if (ret != E_OK) {
739         LOGE("get rowId and position fail, ret %{public}d", ret);
740         return E_RDB;
741     }
742     ValuesBucket setXAttr;
743     ret = RecycleSetValue(val, setXAttr, position);
744     if (ret != E_OK) {
745         return ret;
746     }
747     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(FileColumn::FILES_TABLE);
748     predicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
749     std::tie(ret, changedRows) = transaction->Update(setXAttr, predicates);
750     if (ret != E_OK) {
751         LOGE("set xAttr location fail, ret %{public}d", ret);
752         return E_RDB;
753     }
754     if (val == 0) {
755         ret = MetaFileMgr::GetInstance().RemoveFromRecycleDentryfile(userId_, bundleName_, name,
756             parentCloudId, rowId);
757     } else {
758         ret = MetaFileMgr::GetInstance().MoveIntoRecycleDentryfile(userId_, bundleName_, name,
759             parentCloudId, rowId);
760     }
761     if (ret != E_OK) {
762         LOGE("recycle set dentryfile failed, ret = %{public}d", ret);
763         return ret;
764     }
765     rdbTransaction.Finish();
766     CloudDiskSyncHelper::GetInstance().RegisterTriggerSync(bundleName_, userId_);
767     return E_OK;
768 }
769 
GetRowIdAndPosition(shared_ptr<Transaction> transaction,const std::string & cloudId,int64_t & rowId,int32_t & position)770 int32_t CloudDiskRdbStore::GetRowIdAndPosition(shared_ptr<Transaction> transaction,
771     const std::string &cloudId, int64_t &rowId, int32_t &position)
772 {
773     RDBPTR_IS_NULLPTR(rdbStore_);
774     CLOUDID_IS_NULL(cloudId);
775     AbsRdbPredicates getRowIdAndPositionPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
776     getRowIdAndPositionPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
777     auto resultSet =
778         transaction->QueryByStep(getRowIdAndPositionPredicates, {FileColumn::ROW_ID, FileColumn::POSITION});
779     if (resultSet == nullptr) {
780         LOGE("get nullptr result set");
781         return E_RDB;
782     }
783     if (resultSet->GoToNextRow() != E_OK) {
784         LOGE("getRowIdAndPositionPredicates result set go to next row failed");
785         return E_RDB;
786     }
787     int32_t ret = CloudDiskRdbUtils::GetLong(FileColumn::ROW_ID, rowId, resultSet);
788     if (ret != E_OK) {
789         LOGE("get rowId failed");
790         return ret;
791     }
792     ret = CloudDiskRdbUtils::GetInt(FileColumn::POSITION, position, resultSet);
793     if (ret != E_OK) {
794         LOGE("get position failed");
795         return ret;
796     }
797     return E_OK;
798 }
799 
FavoriteSetXattr(const std::string & cloudId,const std::string & value)800 int32_t CloudDiskRdbStore::FavoriteSetXattr(const std::string &cloudId, const std::string &value)
801 {
802     LOGD("favoriteSetXattr, value %{public}s", value.c_str());
803     RDBPTR_IS_NULLPTR(rdbStore_);
804     bool isNum = std::all_of(value.begin(), value.end(), ::isdigit);
805     if (!isNum) {
806         return EINVAL;
807     }
808     int32_t val = std::stoi(value);
809     ValuesBucket setXAttr;
810     if (val == 0) {
811         setXAttr.PutInt(FileColumn::IS_FAVORITE, CANCEL_STATE);
812         setXAttr.PutLong(FileColumn::META_TIME_EDITED, UTCTimeMilliSeconds());
813     } else if (val == 1) {
814         setXAttr.PutInt(FileColumn::IS_FAVORITE, SET_STATE);
815         setXAttr.PutLong(FileColumn::META_TIME_EDITED, UTCTimeMilliSeconds());
816     } else {
817         return E_RDB;
818     }
819     int32_t changedRows = -1;
820     vector<ValueObject> bindArgs;
821     bindArgs.emplace_back(cloudId);
822     int32_t ret = rdbStore_->Update(changedRows, FileColumn::FILES_TABLE, setXAttr,
823         FileColumn::CLOUD_ID + " = ?", bindArgs);
824     if (ret != E_OK) {
825         LOGE("set xAttr location fail, ret %{public}d", ret);
826         return E_RDB;
827     }
828     return E_OK;
829 }
830 
CheckXattr(const std::string & key)831 int32_t CheckXattr(const std::string &key)
832 {
833     if (key == CLOUD_FILE_LOCATION) {
834         return CLOUD_LOCATION;
835     } else if (key == CLOUD_CLOUD_RECYCLE_XATTR) {
836         return CLOUD_RECYCLE;
837     } else if (key == IS_FAVORITE_XATTR) {
838         return IS_FAVORITE;
839     } else if (key == IS_FILE_STATUS_XATTR) {
840         return FILE_SYNC_STATUS;
841     } else if (key == CLOUD_EXT_ATTR) {
842         return IS_EXT_ATTR;
843     } else {
844         return ERROR_CODE;
845     }
846 }
847 
LocationGetXattr(const std::string & name,const std::string & key,std::string & value,const std::string & parentCloudId)848 int32_t CloudDiskRdbStore::LocationGetXattr(const std::string &name, const std::string &key, std::string &value,
849     const std::string &parentCloudId)
850 {
851     if (key != CLOUD_FILE_LOCATION) {
852         LOGE("getxattr parameter is invalid");
853         return E_INVAL_ARG;
854     }
855     MetaBase metaBase(name);
856     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId_, bundleName_, parentCloudId);
857     int32_t ret = metaFile->DoLookup(metaBase);
858     if (ret != E_OK) {
859         LOGE("lookup dentry failed, ret = %{public}d", ret);
860         return ENOENT;
861     }
862     value = std::to_string(metaBase.position);
863     return E_OK;
864 }
865 
FavoriteGetXattr(const std::string & cloudId,const std::string & key,std::string & value)866 int32_t CloudDiskRdbStore::FavoriteGetXattr(const std::string &cloudId, const std::string &key, std::string &value)
867 {
868     RDBPTR_IS_NULLPTR(rdbStore_);
869     if (cloudId.empty() || cloudId == ROOT_CLOUD_ID || key != IS_FAVORITE_XATTR) {
870         LOGE("getxattr parameter is invalid");
871         return E_INVAL_ARG;
872     }
873     AbsRdbPredicates getXAttrPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
874     getXAttrPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
875     auto resultSet = rdbStore_->QueryByStep(getXAttrPredicates, { FileColumn::IS_FAVORITE });
876     if (resultSet == nullptr) {
877         LOGE("get nullptr getxattr result");
878         return E_RDB;
879     }
880     if (resultSet->GoToNextRow() != E_OK) {
881         LOGE("getxattr result set go to next row failed");
882         return E_RDB;
883     }
884     int32_t isFavorite;
885     CloudDiskRdbUtils::GetInt(FileColumn::IS_FAVORITE, isFavorite, resultSet);
886     value = to_string(isFavorite);
887     return E_OK;
888 }
889 
FileStatusGetXattr(const std::string & cloudId,const std::string & key,std::string & value)890 int32_t CloudDiskRdbStore::FileStatusGetXattr(const std::string &cloudId, const std::string &key, std::string &value)
891 {
892     RDBPTR_IS_NULLPTR(rdbStore_);
893     if (cloudId.empty() || cloudId == ROOT_CLOUD_ID || key != IS_FILE_STATUS_XATTR) {
894         LOGE("getxattr parameter is invalid");
895         return E_INVAL_ARG;
896     }
897     AbsRdbPredicates getXAttrPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
898     getXAttrPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
899     auto resultSet = rdbStore_->QueryByStep(getXAttrPredicates, { FileColumn::FILE_STATUS });
900     if (resultSet == nullptr) {
901         LOGE("get nullptr getxattr result");
902         return E_RDB;
903     }
904     if (resultSet->GoToNextRow() != E_OK) {
905         LOGE("getxattr result set go to next row failed");
906         return E_RDB;
907     }
908     int32_t fileStatus;
909     int32_t ret = CloudDiskRdbUtils::GetInt(FileColumn::FILE_STATUS, fileStatus, resultSet);
910     if (ret != E_OK) {
911         LOGE("get file status failed");
912         return ret;
913     }
914     value = to_string(fileStatus);
915     return E_OK;
916 }
917 
GetExtAttrValue(const std::string & cloudId,const std::string & key,std::string & value)918 int32_t CloudDiskRdbStore::GetExtAttrValue(const std::string &cloudId, const std::string &key, std::string &value)
919 {
920     if (cloudId.empty() || cloudId == ROOT_CLOUD_ID || key.empty()) {
921         LOGE("get ext attr value parameter is invalid");
922         return E_INVAL_ARG;
923     }
924 
925     std::string res;
926     int32_t pos = 0;
927     int32_t ret = GetExtAttr(cloudId, res, pos);
928     if (ret != E_OK || res.empty()) {
929         LOGE("get ext attr value res is empty");
930         return E_RDB;
931     }
932 
933     nlohmann::json jsonObj = nlohmann::json::parse(res, nullptr, false);
934     if (jsonObj.is_discarded()) {
935         LOGE("get ext jsonObj parse failed");
936         return E_RDB;
937     }
938 
939     LOGD("GetExtAttrValue, name %{public}s", key.c_str());
940     if (!jsonObj.contains(key) || !jsonObj[key].is_string()) {
941         LOGE("get ext not a string");
942         return E_RDB;
943     }
944 
945     value = jsonObj[key].get<std::string>();
946     return E_OK;
947 }
948 
GetExtAttr(const std::string & cloudId,std::string & value,int32_t & position)949 int32_t CloudDiskRdbStore::GetExtAttr(const std::string &cloudId, std::string &value, int32_t &position)
950 {
951     RDBPTR_IS_NULLPTR(rdbStore_);
952     if (cloudId.empty() || cloudId == ROOT_CLOUD_ID) {
953         LOGE("get ext attr parameter is invalid");
954         return E_INVAL_ARG;
955     }
956     AbsRdbPredicates getAttrPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
957     getAttrPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
958     auto resultSet = rdbStore_->QueryByStep(getAttrPredicates, FileColumn::EXT_ATTR_QUERY_COLUMNS);
959     if (resultSet == nullptr) {
960         LOGE("get nullptr get ext attr result");
961         return E_RDB;
962     }
963     if (resultSet->GoToNextRow() != E_OK) {
964         LOGE("get ext attr result set go to next row failed");
965         return E_RDB;
966     }
967 
968     int32_t ret = CloudDiskRdbUtils::GetString(FileColumn::ATTRIBUTE, value, resultSet);
969     if (ret != E_OK) {
970         LOGE("get ext attr value failed");
971         return ret;
972     }
973 
974     ret = CloudDiskRdbUtils::GetInt(FileColumn::POSITION, position, resultSet);
975     if (ret != E_OK) {
976         LOGE("get location value failed");
977         return ret;
978     }
979 
980     return E_OK;
981 }
982 
GetXAttr(const std::string & cloudId,const std::string & key,std::string & value,const CacheNode & node,const std::string & extAttrKey)983 int32_t CloudDiskRdbStore::GetXAttr(const std::string &cloudId, const std::string &key, std::string &value,
984     const CacheNode &node, const std::string &extAttrKey)
985 {
986     int32_t num = CheckXattr(key);
987     switch (num) {
988         case CLOUD_LOCATION:
989             return LocationGetXattr(node.fileName, key, value, node.parentCloudId);
990             break;
991         case IS_FAVORITE:
992             return FavoriteGetXattr(cloudId, key, value);
993             break;
994         case FILE_SYNC_STATUS:
995             return FileStatusGetXattr(cloudId, key, value);
996             break;
997         case IS_EXT_ATTR:
998             return GetExtAttrValue(cloudId, extAttrKey, value);
999     }
1000 
1001     return E_INVAL_ARG;
1002 }
1003 
ExtAttributeSetValue(const std::string & key,const std::string & value,ValuesBucket & setXAttr,std::string & xattrList,int32_t pos)1004 static int32_t ExtAttributeSetValue(const std::string &key, const std::string &value,
1005     ValuesBucket &setXAttr, std::string &xattrList, int32_t pos)
1006 {
1007     nlohmann::json jsonObj;
1008     if (xattrList.empty()) {
1009         jsonObj = nlohmann::json({{key, value}});
1010     } else {
1011         jsonObj = nlohmann::json::parse(xattrList, nullptr, false);
1012         if (jsonObj.is_discarded()) {
1013             LOGE("ext jsonObj parse failed");
1014             return E_RDB;
1015         }
1016 
1017         jsonObj[key] = value;
1018     }
1019     std::string jsonValue = jsonObj.dump();
1020     setXAttr.PutString(FileColumn::ATTRIBUTE, jsonValue);
1021     if (pos != LOCAL) {
1022         setXAttr.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_MDIRTY));
1023         setXAttr.PutLong(FileColumn::OPERATE_TYPE, static_cast<int32_t>(OperationType::UNKNOWN_TYPE));
1024     }
1025     setXAttr.PutLong(FileColumn::META_TIME_EDITED, UTCTimeMilliSeconds());
1026     return E_OK;
1027 }
1028 
ExtAttributeSetXattr(const std::string & cloudId,const std::string & value,const std::string & key)1029 int32_t CloudDiskRdbStore::ExtAttributeSetXattr(const std::string &cloudId, const std::string &value,
1030     const std::string &key)
1031 {
1032     RDBPTR_IS_NULLPTR(rdbStore_);
1033     ValuesBucket setAttr;
1034     int32_t changedRows = -1;
1035     TransactionOperations rdbTransaction(rdbStore_);
1036     auto [ret, transaction] = rdbTransaction.Start();
1037     if (ret != E_OK) {
1038         LOGE("Ext rdbstore begin transaction failed, ret = %{public}d", ret);
1039         return ret;
1040     }
1041     std::string xattrList;
1042     int32_t pos = 0;
1043     RETURN_ON_ERR(GetExtAttr(cloudId, xattrList, pos));
1044     RETURN_ON_ERR(ExtAttributeSetValue(key, value, setAttr, xattrList, pos));
1045     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(FileColumn::FILES_TABLE);
1046     predicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
1047     std::tie(ret, changedRows) = transaction->Update(setAttr, predicates);
1048     if (ret != E_OK) {
1049         LOGE("ext attr location fail, ret %{public}d", ret);
1050         return E_RDB;
1051     }
1052     rdbTransaction.Finish();
1053     CloudDiskSyncHelper::GetInstance().RegisterTriggerSync(bundleName_, userId_);
1054     return E_OK;
1055 }
1056 
SetXAttr(const std::string & cloudId,const std::string & key,const std::string & value,const std::string & name,const std::string & parentCloudId)1057 int32_t CloudDiskRdbStore::SetXAttr(const std::string &cloudId, const std::string &key, const std::string &value,
1058     const std::string &name, const std::string &parentCloudId)
1059 {
1060     int32_t num = CheckXattr(key);
1061     switch (num) {
1062         case CLOUD_LOCATION:
1063             return LocationSetXattr(name, parentCloudId, cloudId, value);
1064             break;
1065         case CLOUD_RECYCLE:
1066             return RecycleSetXattr(name, parentCloudId, cloudId, value);
1067             break;
1068         case IS_FAVORITE:
1069             return FavoriteSetXattr(cloudId, value);
1070             break;
1071         case IS_EXT_ATTR:
1072             return ExtAttributeSetXattr(cloudId, value, name);
1073     }
1074 
1075     return E_INVAL_ARG;
1076 }
1077 
FileRename(ValuesBucket & values,const int32_t & position,const std::string & newFileName)1078 static void FileRename(ValuesBucket &values, const int32_t &position, const std::string &newFileName)
1079 {
1080     values.PutString(FileColumn::FILE_NAME, newFileName);
1081     values.PutInt(FileColumn::FILE_STATUS, FileStatus::TO_BE_UPLOADED);
1082     FillFileType(newFileName, values);
1083     if (position != LOCAL) {
1084         values.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_MDIRTY));
1085         values.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::RENAME));
1086     }
1087 }
1088 
FileMove(ValuesBucket & values,const int32_t & position,const std::string & newParentCloudId)1089 static void FileMove(ValuesBucket &values, const int32_t &position, const std::string &newParentCloudId)
1090 {
1091     values.PutString(FileColumn::PARENT_CLOUD_ID, newParentCloudId);
1092     values.PutInt(FileColumn::FILE_STATUS, FileStatus::TO_BE_UPLOADED);
1093     if (position != LOCAL) {
1094         values.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_MDIRTY));
1095         values.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::MOVE));
1096     }
1097 }
1098 
FileMoveAndRename(ValuesBucket & values,const int32_t & position,const std::string & newParentCloudId,const std::string & newFileName)1099 static void FileMoveAndRename(ValuesBucket &values, const int32_t &position, const std::string &newParentCloudId,
1100     const std::string &newFileName)
1101 {
1102     values.PutString(FileColumn::PARENT_CLOUD_ID, newParentCloudId);
1103     values.PutString(FileColumn::FILE_NAME, newFileName);
1104     values.PutInt(FileColumn::FILE_STATUS, FileStatus::TO_BE_UPLOADED);
1105     FillFileType(newFileName, values);
1106     if (position != LOCAL) {
1107         values.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_MDIRTY));
1108         values.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::MOVE));
1109     }
1110 }
1111 
HandleRenameValue(ValuesBucket & rename,int32_t position,const CacheNode & oldNode,const CacheNode & newNode)1112 static void HandleRenameValue(ValuesBucket &rename, int32_t position, const CacheNode &oldNode,
1113     const CacheNode &newNode)
1114 {
1115     string oldParentCloudId = oldNode.parentCloudId;
1116     string oldFileName = oldNode.fileName;
1117     string newParentCloudId = newNode.parentCloudId;
1118     string newFileName = newNode.fileName;
1119     rename.PutLong(FileColumn::META_TIME_EDITED, UTCTimeMilliSeconds());
1120     if (oldFileName != newFileName && oldParentCloudId == newParentCloudId) {
1121         FileRename(rename, position, newFileName);
1122     }
1123     if (oldFileName == newFileName && oldParentCloudId != newParentCloudId) {
1124         FileMove(rename, position, newParentCloudId);
1125     }
1126     if (oldFileName != newFileName && oldParentCloudId != newParentCloudId) {
1127         FileMoveAndRename(rename, position, newParentCloudId, newFileName);
1128     }
1129 }
1130 
Rename(const std::string & oldParentCloudId,const std::string & oldFileName,const std::string & newParentCloudId,const std::string & newFileName)1131 int32_t CloudDiskRdbStore::Rename(const std::string &oldParentCloudId, const std::string &oldFileName,
1132     const std::string &newParentCloudId, const std::string &newFileName)
1133 {
1134     int32_t ret = CheckName(newFileName);
1135     if (ret != E_OK) {
1136         return ret;
1137     }
1138     RDBPTR_IS_NULLPTR(rdbStore_);
1139     if (oldParentCloudId.empty() || oldFileName.empty() || newParentCloudId.empty() || newFileName.empty()) {
1140         LOGE("rename parameters is invalid");
1141         return E_INVAL_ARG;
1142     }
1143     MetaBase metaBase(oldFileName);
1144     auto oldMetaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId_, bundleName_, oldParentCloudId);
1145     ret = oldMetaFile->DoLookup(metaBase);
1146     if (ret != E_OK) {
1147         LOGE("lookup dentry failed, ret = %{public}d", ret);
1148         return EINVAL;
1149     }
1150     ret = CheckNameForSpace(newFileName, S_ISDIR(metaBase.mode));
1151     if (ret != E_OK) {
1152         return ret;
1153     }
1154     ValuesBucket rename;
1155     CacheNode newNode = {.parentCloudId = newParentCloudId, .fileName = newFileName};
1156     CacheNode oldNode = {.parentCloudId = oldParentCloudId, .fileName = oldFileName};
1157     HandleRenameValue(rename, metaBase.position, oldNode, newNode);
1158     vector<ValueObject> bindArgs;
1159     bindArgs.emplace_back(metaBase.cloudId);
1160     auto newMetaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId_, bundleName_, newParentCloudId);
1161     ret = oldMetaFile->DoRename(metaBase, newFileName, newMetaFile);
1162     if (ret != E_OK) {
1163         LOGE("rename dentry failed, ret = %{public}d", ret);
1164         return EINVAL;
1165     }
1166     function<void()> rdbUpdate = [this, rename, bindArgs] {
1167         int32_t changedRows = -1;
1168         int32_t ret = rdbStore_ ->Update(changedRows, FileColumn::FILES_TABLE, rename,
1169                                          FileColumn::CLOUD_ID + " = ?", bindArgs);
1170         if (ret != E_OK) {
1171             LOGE("rename file fail, ret %{public}d", ret);
1172         }
1173         CloudDiskSyncHelper::GetInstance().RegisterTriggerSync(bundleName_, userId_);
1174     };
1175     ffrt::thread(rdbUpdate).detach();
1176     return E_OK;
1177 }
1178 
GetHasChild(const std::string & cloudId,bool & hasChild)1179 int32_t CloudDiskRdbStore::GetHasChild(const std::string &cloudId, bool &hasChild)
1180 {
1181     RDBPTR_IS_NULLPTR(rdbStore_);
1182     CLOUDID_IS_NULL(cloudId);
1183     AbsRdbPredicates readDirPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
1184     readDirPredicates.EqualTo(FileColumn::PARENT_CLOUD_ID, cloudId)
1185         ->And()->EqualTo(FileColumn::FILE_TIME_RECYCLED, "0")->And()
1186         ->NotEqualTo(FileColumn::DIRTY_TYPE, to_string(static_cast<int32_t>(DirtyType::TYPE_DELETED)));
1187     auto resultSet = rdbStore_->QueryByStep(readDirPredicates, {FileColumn::FILE_NAME});
1188     if (resultSet == nullptr) {
1189         LOGE("get nullptr result set");
1190         return E_RDB;
1191     }
1192     if (resultSet->GoToNextRow() == E_OK) {
1193         hasChild = true;
1194     } else {
1195         hasChild = false;
1196     }
1197     return E_OK;
1198 }
1199 
UnlinkSynced(const std::string & cloudId)1200 int32_t CloudDiskRdbStore::UnlinkSynced(const std::string &cloudId)
1201 {
1202     RDBPTR_IS_NULLPTR(rdbStore_);
1203     CLOUDID_IS_NULL(cloudId);
1204     int32_t changedRows = -1;
1205     ValuesBucket updateValue;
1206     vector<string> whereArgs = {cloudId};
1207     updateValue.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_DELETED));
1208     int32_t ret = rdbStore_->Update(changedRows, FileColumn::FILES_TABLE, updateValue, FileColumn::CLOUD_ID + " = ?",
1209         whereArgs);
1210     if (ret != E_OK) {
1211         LOGE("unlink synced directory fail, ret %{public}d", ret);
1212         return E_RDB;
1213     }
1214     return E_OK;
1215 }
1216 
UnlinkLocal(const std::string & cloudId)1217 int32_t CloudDiskRdbStore::UnlinkLocal(const std::string &cloudId)
1218 {
1219     RDBPTR_IS_NULLPTR(rdbStore_);
1220     CLOUDID_IS_NULL(cloudId);
1221     int32_t changedRows = -1;
1222     vector<string> whereArgs = {cloudId};
1223     int32_t ret = rdbStore_->Delete(changedRows, FileColumn::FILES_TABLE, FileColumn::CLOUD_ID + " = ?", whereArgs);
1224     if (ret != E_OK) {
1225         LOGE("unlink local directory fail, ret %{public}d", ret);
1226         return E_RDB;
1227     }
1228     return E_OK;
1229 }
1230 
Unlink(const std::string & cloudId,const int32_t & noUpload)1231 int32_t CloudDiskRdbStore::Unlink(const std::string &cloudId, const int32_t &noUpload)
1232 {
1233     RDBPTR_IS_NULLPTR(rdbStore_);
1234     if (cloudId.empty() || cloudId == ROOT_CLOUD_ID) {
1235         LOGE("Unlink parameters is invalid");
1236         return E_INVAL_ARG;
1237     }
1238     if (noUpload == NO_UPLOAD) {
1239         RETURN_ON_ERR(UnlinkLocal(cloudId));
1240     } else {
1241         RETURN_ON_ERR(UnlinkSynced(cloudId));
1242     }
1243     CloudDiskSyncHelper::GetInstance().RegisterTriggerSync(bundleName_, userId_);
1244     return E_OK;
1245 }
1246 
GetDirtyType(const std::string & cloudId,int32_t & dirtyType)1247 int32_t CloudDiskRdbStore::GetDirtyType(const std::string &cloudId, int32_t &dirtyType)
1248 {
1249     AbsRdbPredicates predicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
1250     predicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
1251     auto resultSet = rdbStore_->QueryByStep(predicates, {FileColumn::DIRTY_TYPE});
1252     if (resultSet == nullptr) {
1253         LOGE("get null result");
1254         return E_RDB;
1255     }
1256     if (resultSet->GoToNextRow() != E_OK) {
1257         LOGE("get current node resultSet fail");
1258         return E_RDB;
1259     }
1260 
1261     int32_t ret = CloudDiskRdbUtils::GetInt(FileColumn::DIRTY_TYPE, dirtyType, resultSet);
1262     if (ret != E_OK) {
1263         LOGE("get file status fail");
1264         return ret;
1265     }
1266     return E_OK;
1267 }
1268 
GetCurNode(const std::string & cloudId,CacheNode & curNode)1269 int32_t CloudDiskRdbStore::GetCurNode(const std::string &cloudId, CacheNode &curNode)
1270 {
1271     RDBPTR_IS_NULLPTR(rdbStore_);
1272     if (cloudId.empty() || cloudId == ROOT_CLOUD_ID) {
1273         LOGE("parameter invalid");
1274         return E_INVAL_ARG;
1275     }
1276     AbsRdbPredicates predicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
1277     predicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
1278     auto resultSet = rdbStore_->QueryByStep(
1279         predicates, {FileColumn::PARENT_CLOUD_ID, FileColumn::IS_DIRECTORY, FileColumn::FILE_NAME});
1280     if (resultSet == nullptr) {
1281         LOGE("get null result");
1282         return E_RDB;
1283     }
1284     if (resultSet->GoToNextRow() != E_OK) {
1285         LOGE("get current node resultSet fail");
1286         return E_RDB;
1287     }
1288     RowEntity rowEntity;
1289     if (resultSet->GetRow(rowEntity) != E_OK) {
1290         LOGE("result set to file info get row failed");
1291         return E_RDB;
1292     }
1293 
1294     int32_t isDirectory;
1295     rowEntity.Get(FileColumn::PARENT_CLOUD_ID).GetString(curNode.parentCloudId);
1296     rowEntity.Get(FileColumn::FILE_NAME).GetString(curNode.fileName);
1297     rowEntity.Get(FileColumn::IS_DIRECTORY).GetInt(isDirectory);
1298     curNode.isDir = isDirectory ? "directory" : "file";
1299 
1300     return E_OK;
1301 }
1302 
GetParentNode(const std::string parentCloudId,std::string & nextCloudId,std::string & fileName)1303 int32_t CloudDiskRdbStore::GetParentNode(const std::string parentCloudId, std::string &nextCloudId,
1304     std::string &fileName)
1305 {
1306     RDBPTR_IS_NULLPTR(rdbStore_);
1307     if (parentCloudId.empty()) {
1308         LOGE("parameter invalid");
1309         return E_INVAL_ARG;
1310     }
1311     AbsRdbPredicates predicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
1312     predicates.EqualTo(FileColumn::CLOUD_ID, parentCloudId);
1313     auto resultSet = rdbStore_->QueryByStep(predicates, {FileColumn::PARENT_CLOUD_ID, FileColumn::FILE_NAME});
1314     if (resultSet == nullptr) {
1315         LOGE("get null result");
1316         return E_RDB;
1317     }
1318     if (resultSet->GoToNextRow() != E_OK) {
1319         LOGE("get current node resultSet fail");
1320         return E_RDB;
1321     }
1322     RowEntity rowEntity;
1323     if (resultSet->GetRow(rowEntity) != E_OK) {
1324         LOGE("result set to file info get row failed");
1325         return E_RDB;
1326     }
1327     rowEntity.Get(FileColumn::PARENT_CLOUD_ID).GetString(nextCloudId);
1328     rowEntity.Get(FileColumn::FILE_NAME).GetString(fileName);
1329     return E_OK;
1330 }
1331 
GetUriFromDB(const std::string & parentCloudId,std::string & uri)1332 int32_t CloudDiskRdbStore::GetUriFromDB(const std::string &parentCloudId, std::string &uri)
1333 {
1334     string realPrefix = CLOUDDISK_URI_PREFIX;
1335     realPrefix.replace(realPrefix.find(BUNDLENAME_FLAG), BUNDLENAME_FLAG.length(), bundleName_);
1336     if (parentCloudId.empty() || parentCloudId == rootId_ || parentCloudId == ROOT_CLOUD_ID) {
1337         uri = realPrefix + BACKFLASH + uri;
1338         return E_OK;
1339     }
1340 
1341     string nextCloudId;
1342     string fileName;
1343     int32_t ret = GetParentNode(parentCloudId, nextCloudId, fileName);
1344     if (ret != E_OK) {
1345         LOGI("get parentnode fail, parentCloudId: %{public}s", parentCloudId.c_str());
1346         return ret;
1347     }
1348     uri = fileName + BACKFLASH + uri;
1349     uint32_t queryTimes = 0;
1350     while (nextCloudId != ROOT_CLOUD_ID) {
1351         ret = GetParentNode(nextCloudId, nextCloudId, fileName);
1352         if (ret != E_OK) {
1353             return E_OK;
1354         }
1355         uri = fileName + BACKFLASH + uri;
1356         queryTimes++;
1357         if (uri.length() > PATH_MAX || queryTimes > MAX_QUERY_TIMES) {
1358             return E_INVAL_ARG;
1359         }
1360     }
1361     uri = realPrefix + BACKFLASH + uri;
1362     return E_OK;
1363 }
1364 
GetNotifyUri(const CacheNode & cacheNode,std::string & uri)1365 int32_t CloudDiskRdbStore::GetNotifyUri(const CacheNode &cacheNode, std::string &uri)
1366 {
1367     int32_t ret = CheckRootIdValid();
1368     if (ret != E_OK) {
1369         LOGE("rootId is invalid");
1370         return ret;
1371     }
1372     ret = CloudDiskNotifyUtils::GetUriFromCache(bundleName_, rootId_, cacheNode, uri);
1373     if (ret == E_OK) {
1374         return ret;
1375     }
1376     LOGD("get uri from cache fail, name: %{public}s", GetAnonyString(cacheNode.fileName).c_str());
1377     uri = cacheNode.fileName;
1378     ret = GetUriFromDB(cacheNode.parentCloudId, uri);
1379     if (ret == E_OK) {
1380         return ret;
1381     }
1382     LOGI("get uri from db fail, name: %{public}s", GetAnonyString(cacheNode.fileName).c_str());
1383     return ret;
1384 }
1385 
GetNotifyData(const CacheNode & cacheNode,NotifyData & notifyData)1386 int32_t CloudDiskRdbStore::GetNotifyData(const CacheNode &cacheNode, NotifyData &notifyData)
1387 {
1388     int32_t ret = GetNotifyUri(cacheNode, notifyData.uri);
1389     if (ret == E_OK) {
1390         notifyData.isDir = cacheNode.isDir == "directory";
1391     }
1392     return ret;
1393 }
1394 
CheckRootIdValid()1395 int32_t CloudDiskRdbStore::CheckRootIdValid()
1396 {
1397     if (!rootId_.empty()) {
1398         return E_OK;
1399     }
1400     CloudPrefImpl cloudPrefImpl(userId_, bundleName_, FileColumn::FILES_TABLE);
1401     cloudPrefImpl.GetString(ROOT_CLOUD_ID, rootId_);
1402     if (rootId_.empty()) {
1403         LOGE("get rootId fail");
1404         return E_INVAL_ARG;
1405     }
1406     LOGI("load rootis succ, rootId: %{public}s", rootId_.c_str());
1407     return E_OK;
1408 }
1409 
GenCloudSyncTriggerFuncParams(RdbStore & store,std::string & userId,std::string & bundleName)1410 static void GenCloudSyncTriggerFuncParams(RdbStore &store, std::string &userId, std::string &bundleName)
1411 {
1412     string databasePath = store.GetPath();
1413     string str = "cloudfile/";
1414     size_t startPos = databasePath.find(str);
1415     size_t endPos = databasePath.find("/rdb");
1416     if (startPos != std::string::npos && endPos != std::string::npos) {
1417         startPos += str.size();
1418         string tempStr = databasePath.substr(startPos, endPos - startPos);
1419         size_t pos = tempStr.find('/');
1420         if (pos != std::string::npos) {
1421             userId = tempStr.substr(0, pos);
1422             bundleName = tempStr.substr(pos + 1);
1423             LOGI("generate CloudSyncTriggerFunc parameters success, userId: %{public}s, bundleName: %{public}s",
1424                 userId.c_str(), bundleName.c_str());
1425             return;
1426         }
1427     }
1428     LOGE("generate CloudSyncTriggerFunc parameters fail");
1429     return;
1430 }
1431 
CreateFolderTriggerSync(RdbStore & store)1432 static const std::string &CreateFolderTriggerSync(RdbStore &store)
1433 {
1434     string userId;
1435     string bundleName;
1436     GenCloudSyncTriggerFuncParams(store, userId, bundleName);
1437     static const string CREATE_FOLDERS_NEW_CLOUD_SYNC =
1438         "CREATE TRIGGER folders_new_cloud_sync_trigger AFTER INSERT ON " + FileColumn::FILES_TABLE +
1439         " FOR EACH ROW WHEN new.isDirectory == 1 AND new.dirty_type == " +
1440         std::to_string(static_cast<int32_t>(DirtyType::TYPE_NEW)) +
1441         " BEGIN SELECT cloud_sync_func(" + "'" + userId + "', " + "'" + bundleName + "'); END;";
1442     return CREATE_FOLDERS_NEW_CLOUD_SYNC;
1443 }
1444 
UpdateFileTriggerSync(RdbStore & store)1445 static const std::string &UpdateFileTriggerSync(RdbStore &store)
1446 {
1447     string userId;
1448     string bundleName;
1449     GenCloudSyncTriggerFuncParams(store, userId, bundleName);
1450     static const string CREATE_FILES_UPDATE_CLOUD_SYNC =
1451         "CREATE TRIGGER files_update_cloud_sync_trigger AFTER UPDATE ON " + FileColumn::FILES_TABLE +
1452         " FOR EACH ROW WHEN OLD.dirty_type IN (0,1,2,3) AND new.dirty_type IN (2,3)" +
1453         " AND OLD.meta_time_edited != new.meta_time_edited" +
1454         " BEGIN SELECT cloud_sync_func(" + "'" + userId + "', " + "'" + bundleName + "'); END;";
1455     return CREATE_FILES_UPDATE_CLOUD_SYNC;
1456 }
1457 
DeleteFileTriggerSync(RdbStore & store)1458 static const std::string &DeleteFileTriggerSync(RdbStore &store)
1459 {
1460     string userId;
1461     string bundleName;
1462     GenCloudSyncTriggerFuncParams(store, userId, bundleName);
1463     static const string CREATE_FILES_DELETE_CLOUD_SYNC =
1464         "CREATE TRIGGER files_delete_cloud_sync_trigger AFTER UPDATE ON " + FileColumn::FILES_TABLE +
1465         " FOR EACH ROW WHEN OLD.dirty_type IN (0,2,3) AND new.dirty_type == " +
1466         std::to_string(static_cast<int32_t>(DirtyType::TYPE_DELETED)) +
1467         " BEGIN SELECT cloud_sync_func(" + "'" + userId + "', " + "'" + bundleName + "'); END;";
1468     return CREATE_FILES_DELETE_CLOUD_SYNC;
1469 }
1470 
LocalFileTriggerSync(RdbStore & store)1471 static const std::string &LocalFileTriggerSync(RdbStore &store)
1472 {
1473     string userId;
1474     string bundleName;
1475     GenCloudSyncTriggerFuncParams(store, userId, bundleName);
1476     static const string CREATE_FILES_LOCAL_CLOUD_SYNC =
1477         "CREATE TRIGGER files_local_cloud_sync_trigger AFTER UPDATE ON " + FileColumn::FILES_TABLE +
1478         " FOR EACH ROW WHEN OLD.dirty_type IN (1,6) AND new.dirty_type == " +
1479         std::to_string(static_cast<int32_t>(DirtyType::TYPE_NEW)) +
1480         " AND OLD.file_status NOT IN (0,1) AND new.file_status NOT IN (1,2)" +
1481         " BEGIN SELECT cloud_sync_func(" + "'" + userId + "', " + "'" + bundleName + "'); END;";
1482     return CREATE_FILES_LOCAL_CLOUD_SYNC;
1483 }
1484 
ExecuteSql(RdbStore & store)1485 static int32_t ExecuteSql(RdbStore &store)
1486 {
1487     static const vector<string> onCreateSqlStrs = {
1488         FileColumn::CREATE_FILE_TABLE,
1489         FileColumn::CREATE_PARENT_CLOUD_ID_INDEX,
1490     };
1491     for (const string& sqlStr : onCreateSqlStrs) {
1492         if (store.ExecuteSql(sqlStr) != NativeRdb::E_OK) {
1493             return NativeRdb::E_ERROR;
1494         }
1495     }
1496     return NativeRdb::E_OK;
1497 }
1498 
OnCreate(RdbStore & store)1499 int32_t CloudDiskDataCallBack::OnCreate(RdbStore &store)
1500 {
1501     if (ExecuteSql(store) != NativeRdb::E_OK) {
1502         return NativeRdb::E_ERROR;
1503     }
1504     return NativeRdb::E_OK;
1505 }
1506 
VersionAddParentCloudIdIndex(RdbStore & store)1507 static void VersionAddParentCloudIdIndex(RdbStore &store)
1508 {
1509     const string executeSqlStr = FileColumn::CREATE_PARENT_CLOUD_ID_INDEX;
1510     int32_t ret = store.ExecuteSql(executeSqlStr);
1511     if (ret != NativeRdb::E_OK) {
1512         LOGE("add parent cloud id index fail, err %{public}d", ret);
1513     }
1514 }
1515 
VersionFixFileTrigger(RdbStore & store)1516 static void VersionFixFileTrigger(RdbStore &store)
1517 {
1518     const string dropFilesUpdateTrigger = "DROP TRIGGER IF EXISTS files_update_cloud_sync_trigger";
1519     if (store.ExecuteSql(dropFilesUpdateTrigger) != NativeRdb::E_OK) {
1520         LOGE("drop files_update_cloud_sync_trigger fail");
1521     }
1522     const string addUpdateFileTrigger = UpdateFileTriggerSync(store);
1523     int32_t ret = store.ExecuteSql(addUpdateFileTrigger);
1524     if (ret != NativeRdb::E_OK) {
1525         LOGE("add update file trigger fail, err %{public}d", ret);
1526     }
1527     const string addDeleteFileTrigger = DeleteFileTriggerSync(store);
1528     ret = store.ExecuteSql(addDeleteFileTrigger);
1529     if (ret != NativeRdb::E_OK) {
1530         LOGE("add delete file trigger fail, err %{public}d", ret);
1531     }
1532     const string addLocalFileTrigger = LocalFileTriggerSync(store);
1533     ret = store.ExecuteSql(addLocalFileTrigger);
1534     if (ret != NativeRdb::E_OK) {
1535         LOGE("add local file trigger fail, err %{public}d", ret);
1536     }
1537 }
1538 
VersionFixCreateAndLocalTrigger(RdbStore & store)1539 static void VersionFixCreateAndLocalTrigger(RdbStore &store)
1540 {
1541     const string dropFilesCreateTrigger = "DROP TRIGGER IF EXISTS files_new_cloud_sync_trigger";
1542     if (store.ExecuteSql(dropFilesCreateTrigger) != NativeRdb::E_OK) {
1543         LOGE("drop files_new_cloud_sync_trigger fail");
1544     }
1545     const string dropFilesLocalTrigger = "DROP TRIGGER IF EXISTS files_local_cloud_sync_trigger";
1546     if (store.ExecuteSql(dropFilesLocalTrigger) != NativeRdb::E_OK) {
1547         LOGE("drop files_local_cloud_sync_trigger fail");
1548     }
1549     const string addLocalFileTrigger = LocalFileTriggerSync(store);
1550     int32_t ret = store.ExecuteSql(addLocalFileTrigger);
1551     if (ret != NativeRdb::E_OK) {
1552         LOGE("add local file trigger fail, err %{public}d", ret);
1553     }
1554     const string addCreateFolderTrigger = CreateFolderTriggerSync(store);
1555     ret = store.ExecuteSql(addCreateFolderTrigger);
1556     if (ret != NativeRdb::E_OK) {
1557         LOGE("add create folder trigger fail, err %{public}d", ret);
1558     }
1559 }
1560 
VersionAddFileStatusAndErrorCode(RdbStore & store)1561 static void VersionAddFileStatusAndErrorCode(RdbStore &store)
1562 {
1563     const string addIsFavorite = FileColumn::ADD_IS_FAVORITE;
1564     int32_t ret = store.ExecuteSql(addIsFavorite);
1565     if (ret != NativeRdb::E_OK) {
1566         LOGE("add is_favorite fail, err %{public}d", ret);
1567     }
1568 }
1569 
VersionAddFileStatus(RdbStore & store)1570 static void VersionAddFileStatus(RdbStore &store)
1571 {
1572     const string addFileStatus = FileColumn::ADD_FILE_STATUS;
1573     int32_t ret = store.ExecuteSql(addFileStatus);
1574     if (ret != NativeRdb::E_OK) {
1575         LOGE("add file_status fail, err %{public}d", ret);
1576     }
1577 }
1578 
VersionSetFileStatusDefault(RdbStore & store)1579 static void VersionSetFileStatusDefault(RdbStore &store)
1580 {
1581     const string setFileStatus = FileColumn::SET_FILE_STATUS_DEFAULT;
1582     int32_t ret = store.ExecuteSql(setFileStatus);
1583     if (ret != NativeRdb::E_OK) {
1584         LOGE("set file_status fail, err %{public}d", ret);
1585     }
1586 }
1587 
VersionFixSyncMetatimeTrigger(RdbStore & store)1588 static void VersionFixSyncMetatimeTrigger(RdbStore &store)
1589 {
1590     const string dropFilesUpdateTrigger = "DROP TRIGGER IF EXISTS files_update_cloud_sync_trigger";
1591     if (store.ExecuteSql(dropFilesUpdateTrigger) != NativeRdb::E_OK) {
1592         LOGE("drop files_update_cloud_sync_trigger fail");
1593     }
1594     const string addUpdateFileTrigger = UpdateFileTriggerSync(store);
1595     int32_t ret = store.ExecuteSql(addUpdateFileTrigger);
1596     if (ret != NativeRdb::E_OK) {
1597         LOGE("add update file trigger fail, err %{public}d", ret);
1598     }
1599 }
1600 
VersionFixRetryTrigger(RdbStore & store)1601 static void VersionFixRetryTrigger(RdbStore &store)
1602 {
1603     const string dropFilesLocalTrigger = "DROP TRIGGER IF EXISTS files_local_cloud_sync_trigger";
1604     if (store.ExecuteSql(dropFilesLocalTrigger) != NativeRdb::E_OK) {
1605         LOGE("drop local file trigger fail");
1606     }
1607     const string addFilesLocalTrigger = LocalFileTriggerSync(store);
1608     int32_t ret = store.ExecuteSql(addFilesLocalTrigger);
1609     if (ret != NativeRdb::E_OK) {
1610         LOGE("add local file trigger fail, err %{public}d", ret);
1611     }
1612 }
1613 
VersionRemoveCloudSyncFuncTrigger(RdbStore & store)1614 static void VersionRemoveCloudSyncFuncTrigger(RdbStore &store)
1615 {
1616     const string dropNewFolderTrigger = "DROP TRIGGER IF EXISTS folders_new_cloud_sync_trigger";
1617     if (store.ExecuteSql(dropNewFolderTrigger) != NativeRdb::E_OK) {
1618         LOGE("drop folders_new_cloud_sync_trigger fail");
1619     }
1620     const string dropUpdateFileTrigger = "DROP TRIGGER IF EXISTS files_update_cloud_sync_trigger";
1621     if (store.ExecuteSql(dropUpdateFileTrigger) != NativeRdb::E_OK) {
1622         LOGE("drop files_update_cloud_sync_trigger fail");
1623     }
1624     const string dropFileDeleteTrigger = "DROP TRIGGER IF EXISTS files_delete_cloud_sync_trigger";
1625     if (store.ExecuteSql(dropFileDeleteTrigger) != NativeRdb::E_OK) {
1626         LOGE("drop files_delete_cloud_sync_trigger fail");
1627     }
1628     const string dropFileLocalTrigger = "DROP TRIGGER IF EXISTS files_local_cloud_sync_trigger";
1629     if (store.ExecuteSql(dropFileLocalTrigger) != NativeRdb::E_OK) {
1630         LOGE("drop files_local_cloud_sync_trigger fail");
1631     }
1632 }
1633 
GetMetaBaseData(CloudDiskFileInfo & info,const shared_ptr<ResultSet> resultSet)1634 static int32_t GetMetaBaseData(CloudDiskFileInfo &info, const shared_ptr<ResultSet> resultSet)
1635 {
1636     RETURN_ON_ERR(CloudDiskRdbUtils::GetString(FileColumn::CLOUD_ID, info.cloudId, resultSet));
1637     RETURN_ON_ERR(CloudDiskRdbUtils::GetString(FileColumn::FILE_NAME, info.name, resultSet));
1638     int32_t isDir = 0;
1639     RETURN_ON_ERR(CloudDiskRdbUtils::GetInt(FileColumn::IS_DIRECTORY, isDir, resultSet));
1640     info.IsDirectory = static_cast<bool>(isDir);
1641     int32_t position = 0;
1642     RETURN_ON_ERR(CloudDiskRdbUtils::GetInt(FileColumn::POSITION, position, resultSet));
1643     info.location = static_cast<uint32_t>(position);
1644     int64_t atime = 0;
1645     RETURN_ON_ERR(CloudDiskRdbUtils::GetLong(FileColumn::FILE_TIME_ADDED, atime, resultSet));
1646     info.atime = static_cast<uint64_t>(atime);
1647     int64_t mtime = 0;
1648     RETURN_ON_ERR(CloudDiskRdbUtils::GetLong(FileColumn::FILE_TIME_EDITED, mtime, resultSet));
1649     info.mtime = static_cast<uint64_t>(mtime);
1650     int64_t size = 0;
1651     RETURN_ON_ERR(CloudDiskRdbUtils::GetLong(FileColumn::FILE_SIZE, size, resultSet));
1652     info.size = static_cast<uint64_t>(size);
1653     int64_t rowId = 0;
1654     RETURN_ON_ERR(CloudDiskRdbUtils::GetLong(FileColumn::ROW_ID, rowId, resultSet));
1655     info.rowId = static_cast<uint64_t>(rowId);
1656     return E_OK;
1657 }
1658 
GetUserIdAndBundleName(RdbStore & store,uint32_t & userId,string & bundleName)1659 static int32_t GetUserIdAndBundleName(RdbStore &store, uint32_t &userId, string &bundleName)
1660 {
1661     string userIdStr;
1662     GenCloudSyncTriggerFuncParams(store, userIdStr, bundleName);
1663     bool isValid = std::all_of(userIdStr.begin(), userIdStr.end(), ::isdigit);
1664     if (!isValid) {
1665         LOGE("invalid user Id");
1666         return E_INVAL_ARG;
1667     }
1668     userId = static_cast<uint32_t>(std::stoi(userIdStr));
1669     return E_OK;
1670 }
1671 
GenerateDentryRecursively(RdbStore & store,const string & parentCloudId)1672 static int32_t GenerateDentryRecursively(RdbStore &store, const string &parentCloudId)
1673 {
1674     LOGD("Generate dentry recursively parentCloudId:%{public}s", parentCloudId.c_str());
1675     uint32_t userId;
1676     string bundleName;
1677     RETURN_ON_ERR(GetUserIdAndBundleName(store, userId, bundleName));
1678     AbsRdbPredicates lookUpPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
1679     lookUpPredicates.EqualTo(FileColumn::PARENT_CLOUD_ID, parentCloudId)
1680         ->And()->EqualTo(FileColumn::FILE_TIME_RECYCLED, "0");
1681     int32_t rowCount = 0;
1682     uint64_t offset = 0;
1683     do {
1684         lookUpPredicates.Limit(offset, CHECK_QUERY_LIMIT);
1685         auto resultSet = store.Query(lookUpPredicates, FileColumn::FILE_SYSTEM_QUERY_COLUMNS);
1686         if (resultSet == nullptr) {
1687             LOGE("failed to get result set at offset:%{public}" PRIu64 "", offset);
1688             continue;
1689         }
1690         int32_t ret = resultSet->GetRowCount(rowCount);
1691         if (ret != E_OK || rowCount < 0) {
1692             LOGE("failed to get row count at offset:%{public}" PRIu64 ", ret: %{public}d", offset, ret);
1693             continue;
1694         }
1695         if (rowCount == 0) {
1696             return E_OK;
1697         }
1698         CloudDiskFileInfo info;
1699         while (resultSet->GoToNextRow() == 0) {
1700             RETURN_ON_ERR(GetMetaBaseData(info, resultSet));
1701             MetaBase metaBase(info.name);
1702             auto callback = [info] (MetaBase &m) {
1703                 m.cloudId = info.cloudId;
1704                 m.atime = info.atime;
1705                 m.mtime = info.mtime;
1706                 m.size = info.size;
1707                 m.mode = (info.IsDirectory) ? (S_IFDIR | STAT_MODE_DIR) : (S_IFREG | STAT_MODE_REG);
1708                 m.position = info.location;
1709                 m.fileType = FILE_TYPE_CONTENT;
1710             };
1711             auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, parentCloudId);
1712             ret = metaFile->DoLookupAndUpdate(info.name, callback);
1713             if (ret != E_OK) {
1714                 LOGE("insert new dentry failed, ret = %{public}d", ret);
1715                 return ret;
1716             }
1717             if (info.IsDirectory) {RETURN_ON_ERR(GenerateDentryRecursively(store, info.cloudId));}
1718         }
1719         offset += CHECK_QUERY_LIMIT;
1720     } while (rowCount != 0);
1721     return E_OK;
1722 }
1723 
GenerateRecycleDentryRecursively(RdbStore & store)1724 static int32_t GenerateRecycleDentryRecursively(RdbStore &store)
1725 {
1726     uint32_t userId;
1727     string bundleName;
1728     RETURN_ON_ERR(GetUserIdAndBundleName(store, userId, bundleName));
1729     AbsRdbPredicates lookUpPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
1730     lookUpPredicates.NotEqualTo(FileColumn::FILE_TIME_RECYCLED, "0");
1731     int32_t rowCount = 0;
1732     uint64_t offset = 0;
1733     do {
1734         lookUpPredicates.Limit(offset, CHECK_QUERY_LIMIT);
1735         auto resultSet = store.Query(lookUpPredicates, FileColumn::FILE_SYSTEM_QUERY_COLUMNS);
1736         if (resultSet == nullptr) {
1737             LOGE("failed to get result set at offset:%{public}" PRIu64 "", offset);
1738             continue;
1739         }
1740         int32_t ret = resultSet->GetRowCount(rowCount);
1741         if (ret != E_OK || rowCount < 0) {
1742             LOGE("failed to get row count at offset:%{public}" PRIu64 ", ret: %{public}d", offset, ret);
1743             continue;
1744         }
1745         if (rowCount == 0) {
1746             return E_OK;
1747         }
1748         CloudDiskFileInfo info;
1749         while (resultSet->GoToNextRow() == 0) {
1750             RETURN_ON_ERR(GetMetaBaseData(info, resultSet));
1751             string uniqueName = info.name + "_" + std::to_string(info.rowId);
1752             MetaBase metaBase(uniqueName);
1753             auto callback = [info] (MetaBase &m) {
1754                 m.cloudId = info.cloudId;
1755                 m.atime = info.atime;
1756                 m.mtime = info.mtime;
1757                 m.size = info.size;
1758                 m.mode = (info.IsDirectory) ? (S_IFDIR | STAT_MODE_DIR) : (S_IFREG | STAT_MODE_REG);
1759                 m.position = info.location;
1760                 m.fileType = FILE_TYPE_CONTENT;
1761             };
1762             RETURN_ON_ERR(MetaFileMgr::GetInstance().CreateRecycleDentry(userId, bundleName));
1763             auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(userId, bundleName, RECYCLE_CLOUD_ID);
1764             ret = metaFile->DoLookupAndUpdate(uniqueName, callback);
1765             if (ret != E_OK) {
1766                 LOGE("insert new dentry failed, ret = %{public}d", ret);
1767                 return ret;
1768             }
1769         }
1770         offset += CHECK_QUERY_LIMIT;
1771     } while (rowCount != 0);
1772     return E_OK;
1773 }
1774 
VersionAddCheckFlag(RdbStore & store)1775 static void VersionAddCheckFlag(RdbStore &store)
1776 {
1777     const string addCheckFlag = FileColumn::ADD_CHECK_FLAG;
1778     int32_t ret = store.ExecuteSql(addCheckFlag);
1779     if (ret != NativeRdb::E_OK) {
1780         LOGE("add check_flag fail, ret = %{public}d", ret);
1781     }
1782     ret = GenerateDentryRecursively(store, ROOT_CLOUD_ID);
1783     if (ret != E_OK) {
1784         LOGE("failed to generate dentry recursively, ret = %{public}d", ret);
1785     }
1786     ret = GenerateRecycleDentryRecursively(store);
1787     if (ret != E_OK) {
1788         LOGE("failed to generate recycle ndentry recursively, ret = %{public}d", ret);
1789     }
1790 }
1791 
VersionAddRootDirectory(RdbStore & store)1792 static void VersionAddRootDirectory(RdbStore &store)
1793 {
1794     const string addRootDirectory = "ALTER Table " + FileColumn::FILES_TABLE +
1795         " ADD COLUMN " + FileColumn::ROOT_DIRECTORY + " TEXT";
1796     int32_t ret = store.ExecuteSql(addRootDirectory);
1797     if (ret != NativeRdb::E_OK) {
1798         LOGE("add root_directory fail, ret = %{public}d", ret);
1799     }
1800     ValuesBucket rootDirectory;
1801     rootDirectory.PutString(FileColumn::ROOT_DIRECTORY, system::GetParameter(FILEMANAGER_KEY, ""));
1802     int32_t changedRows = -1;
1803     vector<ValueObject> bindArgs;
1804     ret = store.Update(changedRows, FileColumn::FILES_TABLE, rootDirectory, "", bindArgs);
1805     if (ret != NativeRdb::E_OK) {
1806         LOGE("set root_directory fail, err %{public}d", ret);
1807     }
1808 }
1809 
VersionAddAttribute(RdbStore & store)1810 static void VersionAddAttribute(RdbStore &store)
1811 {
1812     const string attrbute = FileColumn::ADD_ATTRIBUTE;
1813     int32_t ret = store.ExecuteSql(attrbute);
1814     if (ret != NativeRdb::E_OK) {
1815         LOGE("add attrbute fail, ret = %{public}d", ret);
1816     }
1817 }
1818 
OnUpgrade(RdbStore & store,int32_t oldVersion,int32_t newVersion)1819 int32_t CloudDiskDataCallBack::OnUpgrade(RdbStore &store, int32_t oldVersion, int32_t newVersion)
1820 {
1821     LOGD("OnUpgrade old:%d, new:%d", oldVersion, newVersion);
1822     if (oldVersion < VERSION_ADD_PARENT_CLOUD_ID_INDEX) {
1823         VersionAddParentCloudIdIndex(store);
1824     }
1825     if (oldVersion < VERSION_FIX_FILE_TRIGGER) {
1826         VersionFixFileTrigger(store);
1827     }
1828     if (oldVersion < VERSION_FIX_CREATE_AND_LOCAL_TRIGGER) {
1829         VersionFixCreateAndLocalTrigger(store);
1830     }
1831     if (oldVersion < VERSION_ADD_STATUS_ERROR_FAVORITE) {
1832         VersionAddFileStatusAndErrorCode(store);
1833     }
1834     if (oldVersion < VERSION_ADD_FILE_STATUS) {
1835         VersionAddFileStatus(store);
1836     }
1837     if (oldVersion < VERSION_SET_FILE_STATUS_DEFAULT) {
1838         VersionSetFileStatusDefault(store);
1839     }
1840     if (oldVersion < VERSION_ADD_CHECK_FLAG) {
1841         VersionAddCheckFlag(store);
1842     }
1843     if (oldVersion < VERSION_ADD_ROOT_DIRECTORY) {
1844         VersionAddRootDirectory(store);
1845     }
1846     if (oldVersion < VERSION_FIX_SYNC_METATIME_TRIGGER) {
1847         VersionFixSyncMetatimeTrigger(store);
1848     }
1849     if (oldVersion < VERSION_FIX_RETRY_TRIGGER) {
1850         VersionFixRetryTrigger(store);
1851     }
1852 
1853     if (oldVersion < VERSION_REMOVE_CLOUD_SYNC_FUNC_TRIGGER) {
1854         VersionRemoveCloudSyncFuncTrigger(store);
1855     }
1856 
1857     if (oldVersion < VERSION_ADD_ATTRIBUTE) {
1858         VersionAddAttribute(store);
1859     }
1860     return NativeRdb::E_OK;
1861 }
1862 }