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 ¬ifyData)
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 }