1 /*
2 * Copyright (c) 2023 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 <ctime>
19 #include <sys/stat.h>
20 #include <sstream>
21
22 #include "clouddisk_sync_helper.h"
23 #include "clouddisk_rdb_utils.h"
24 #include "clouddisk_type_const.h"
25 #include "file_column.h"
26 #include "rdb_errno.h"
27 #include "rdb_sql_utils.h"
28 #include "utils_log.h"
29 #include "dfs_error.h"
30 #include "mimetype_utils.h"
31
32 namespace OHOS::FileManagement::CloudDisk {
33 using namespace std;
34 using namespace OHOS::NativeRdb;
35 using namespace CloudSync;
36 using namespace OHOS::Media;
37
38 static constexpr int32_t LOOKUP_QUERY_LIMIT = 1;
39
CloudSyncTriggerFunc(const std::vector<std::string> & args)40 static const std::string CloudSyncTriggerFunc(const std::vector<std::string> &args)
41 {
42 size_t size = args.size();
43 if (size != ARGS_SIZE) {
44 LOGE("CloudSyncTriggerFunc args size error, %{public}zu", size);
45 return "";
46 }
47 int32_t userId = std::strtol(args[ARG_USER_ID].c_str(), nullptr, 0);
48 string bundleName = args[ARG_BUNDLE_NAME];
49 LOGD("begin cloud sync trigger, bundleName: %{public}s, userId: %{public}d", bundleName.c_str(), userId);
50 CloudDiskSyncHelper::GetInstance().RegisterTriggerSync(bundleName, userId);
51 return "";
52 }
53
CloudDiskRdbStore(const std::string & bundleName,const int32_t & userId)54 CloudDiskRdbStore::CloudDiskRdbStore(const std::string &bundleName, const int32_t &userId)
55 : bundleName_(bundleName), userId_(userId)
56 {
57 RdbInit();
58 MimeTypeUtils::InitMimeTypeMap();
59 }
60
~CloudDiskRdbStore()61 CloudDiskRdbStore::~CloudDiskRdbStore()
62 {
63 Stop();
64 }
65
RdbInit()66 int32_t CloudDiskRdbStore::RdbInit()
67 {
68 LOGI("Init rdb store, userId_ = %{private}d, bundleName_ = %{private}s", userId_, bundleName_.c_str());
69 string baseDir = DATA_SERVICE_EL1_PUBLIC_CLOUDFILE;
70 string customDir = baseDir.append(to_string(userId_)).append("/").append(bundleName_);
71 string name = CLOUD_DISK_DATABASE_NAME;
72 int32_t errCode = 0;
73 string databasePath = RdbSqlUtils::GetDefaultDatabasePath(customDir, CLOUD_DISK_DATABASE_NAME, errCode);
74 if (errCode != NativeRdb::E_OK) {
75 LOGE("Create Default Database Path is failed, errCode = %{public}d", errCode);
76 return E_PATH;
77 }
78 config_.SetName(move(name));
79 config_.SetPath(move(databasePath));
80 config_.SetScalarFunction("cloud_sync_func", ARGS_SIZE, CloudSyncTriggerFunc);
81 errCode = 0;
82 CloudDiskDataCallBack rdbDataCallBack;
83 rdbStore_ = RdbHelper::GetRdbStore(config_, CLOUD_DISK_RDB_VERSION, rdbDataCallBack, errCode);
84 if (rdbStore_ == nullptr) {
85 LOGE("GetRdbStore is failed, userId_ = %{private}d, bundleName_ = %{private}s, errCode = %{public}d",
86 userId_, bundleName_.c_str(), errCode);
87 return E_RDB;
88 }
89 return E_OK;
90 }
91
Stop()92 void CloudDiskRdbStore::Stop()
93 {
94 if (rdbStore_ == nullptr) {
95 return;
96 }
97 rdbStore_ = nullptr;
98 }
99
GetRaw()100 shared_ptr<RdbStore> CloudDiskRdbStore::GetRaw()
101 {
102 return rdbStore_;
103 }
104
LookUp(const std::string & parentCloudId,const std::string & fileName,CloudDiskFileInfo & info)105 int32_t CloudDiskRdbStore::LookUp(const std::string &parentCloudId,
106 const std::string &fileName, CloudDiskFileInfo &info)
107 {
108 RDBPTR_IS_NULLPTR(rdbStore_);
109 if (fileName.empty() || parentCloudId.empty()) {
110 LOGE("look up parameters is invalid");
111 return E_INVAL_ARG;
112 }
113 AbsRdbPredicates lookUpPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
114 lookUpPredicates
115 .EqualTo(FileColumn::PARENT_CLOUD_ID, parentCloudId)->And()
116 ->EqualTo(FileColumn::FILE_NAME, fileName)->And()->EqualTo(FileColumn::FILE_TIME_RECYCLED, "0")->And()
117 ->NotEqualTo(FileColumn::DIRTY_TYPE, to_string(static_cast<int32_t>(DirtyType::TYPE_DELETED)));
118 lookUpPredicates.Limit(LOOKUP_QUERY_LIMIT);
119 auto resultSet = rdbStore_->QueryByStep(lookUpPredicates, FileColumn::FILE_SYSTEM_QUERY_COLUMNS);
120 int32_t ret = CloudDiskRdbUtils::ResultSetToFileInfo(move(resultSet), info);
121 if (ret != E_OK) {
122 LOGE("lookup file info is failed, ret %{public}d", ret);
123 return E_RDB;
124 }
125 return E_OK;
126 }
127
GetAttr(const std::string & cloudId,CloudDiskFileInfo & info)128 int32_t CloudDiskRdbStore::GetAttr(const std::string &cloudId, CloudDiskFileInfo &info)
129 {
130 RDBPTR_IS_NULLPTR(rdbStore_);
131 if (cloudId.empty() || cloudId == "rootId") {
132 LOGE("getAttr parameter is invalid");
133 return E_INVAL_ARG;
134 }
135 AbsRdbPredicates getAttrPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
136 getAttrPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
137 auto resultSet = rdbStore_->QueryByStep(getAttrPredicates, FileColumn::FILE_SYSTEM_QUERY_COLUMNS);
138 int32_t ret = CloudDiskRdbUtils::ResultSetToFileInfo(move(resultSet), info);
139 if (ret != E_OK) {
140 LOGE("get file attr is failed, ret %{public}d", ret);
141 return E_RDB;
142 }
143 return E_OK;
144 }
145
ReadDir(const std::string & cloudId,vector<CloudDiskFileInfo> & infos)146 int32_t CloudDiskRdbStore::ReadDir(const std::string &cloudId, vector<CloudDiskFileInfo> &infos)
147 {
148 RDBPTR_IS_NULLPTR(rdbStore_);
149 CLOUDID_IS_NULL(cloudId);
150 AbsRdbPredicates readDirPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
151 readDirPredicates.EqualTo(FileColumn::PARENT_CLOUD_ID, cloudId)
152 ->And()->EqualTo(FileColumn::FILE_TIME_RECYCLED, "0")->And()
153 ->NotEqualTo(FileColumn::DIRTY_TYPE, to_string(static_cast<int32_t>(DirtyType::TYPE_DELETED)));
154 auto resultSet = rdbStore_->QueryByStep(readDirPredicates, { FileColumn::FILE_NAME, FileColumn::IS_DIRECTORY });
155 int32_t ret = CloudDiskRdbUtils::ResultSetToFileInfos(move(resultSet), infos);
156 if (ret != E_OK) {
157 LOGE("read directory is failed, ret %{public}d", ret);
158 return E_RDB;
159 }
160 return E_OK;
161 }
162
GetFileExtension(const std::string & fileName,std::string & extension)163 static int32_t GetFileExtension(const std::string &fileName, std::string &extension)
164 {
165 size_t dotIndex = fileName.rfind(".");
166 if (dotIndex != string::npos) {
167 extension = fileName.substr(dotIndex + 1);
168 return E_OK;
169 }
170 LOGE("Failed to obtain file extension");
171 return E_INVAL_ARG;
172 }
173
GetFileTypeFromMimeType(const std::string & mimeType)174 static int32_t GetFileTypeFromMimeType(const std::string &mimeType)
175 {
176 size_t pos = mimeType.find_first_of("/");
177 if (pos == string::npos) {
178 LOGE("Invalid mime type: %{public}s", mimeType.c_str());
179 return E_INVAL_ARG;
180 }
181 string prefix = mimeType.substr(0, pos);
182 if (prefix == "audio") {
183 return static_cast<int32_t>(FileType::FILE_TYPE_AUDIO);
184 } else if (prefix == "image") {
185 return static_cast<int32_t>(FileType::FILE_TYPE_IMAGE);
186 } else if (prefix == "video") {
187 return static_cast<int32_t>(FileType::FILE_TYPE_VIDEO);
188 } else if (prefix == "text") {
189 return static_cast<int32_t>(FileType::FILE_TYPE_TEXT);
190 }
191 return static_cast<int32_t>(FileType::FILE_TYPE_APPLICATION);
192 }
193
Timespec2Milliseconds(const struct timespec & time)194 static int64_t Timespec2Milliseconds(const struct timespec &time)
195 {
196 return time.tv_sec * SECOND_TO_MILLISECOND + time.tv_nsec / MILLISECOND_TO_NANOSECOND;
197 }
198
FillFileType(const std::string & fileName,ValuesBucket & fileInfo)199 static void FillFileType(const std::string &fileName, ValuesBucket &fileInfo)
200 {
201 string extension;
202 if (!GetFileExtension(fileName, extension)) {
203 fileInfo.PutString(FileColumn::FILE_CATEGORY, extension);
204 string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension);
205 fileInfo.PutString(FileColumn::MIME_TYPE, mimeType);
206 int32_t fileType = GetFileTypeFromMimeType(mimeType);
207 fileInfo.PutInt(FileColumn::FILE_TYPE, fileType);
208 }
209 }
210
UTCTimeMilliSeconds()211 static int64_t UTCTimeMilliSeconds()
212 {
213 struct timespec t;
214 clock_gettime(CLOCK_REALTIME, &t);
215 return t.tv_sec * SECOND_TO_MILLISECOND + t.tv_nsec / MILLISECOND_TO_NANOSECOND;
216 }
217
CreateFile(const std::string & fileName,const std::string & filePath,ValuesBucket & fileInfo)218 static int32_t CreateFile(const std::string &fileName, const std::string &filePath, ValuesBucket &fileInfo)
219 {
220 struct stat statInfo {};
221 int32_t ret = stat(filePath.c_str(), &statInfo);
222 if (ret) {
223 LOGE("filePath %{private}s is invalid", filePath.c_str());
224 return E_PATH;
225 }
226 fileInfo.PutInt(FileColumn::IS_DIRECTORY, FILE);
227 fileInfo.PutLong(FileColumn::FILE_SIZE, statInfo.st_size);
228 fileInfo.PutLong(FileColumn::FILE_TIME_EDITED, Timespec2Milliseconds(statInfo.st_mtim));
229 fileInfo.PutLong(FileColumn::META_TIME_EDITED, Timespec2Milliseconds(statInfo.st_mtim));
230 FillFileType(fileName, fileInfo);
231 return E_OK;
232 }
233
Create(const std::string & cloudId,const std::string & parentCloudId,const std::string & fileName)234 int32_t CloudDiskRdbStore::Create(const std::string &cloudId, const std::string &parentCloudId,
235 const std::string &fileName)
236 {
237 RDBPTR_IS_NULLPTR(rdbStore_);
238 ValuesBucket fileInfo;
239 if (cloudId.empty() || parentCloudId.empty() || fileName.empty()) {
240 LOGE("create parameter is invalid");
241 return E_INVAL_ARG;
242 }
243 fileInfo.PutString(FileColumn::CLOUD_ID, cloudId);
244 fileInfo.PutString(FileColumn::FILE_NAME, fileName);
245 fileInfo.PutLong(FileColumn::FILE_TIME_ADDED, UTCTimeMilliSeconds());
246 fileInfo.PutString(FileColumn::PARENT_CLOUD_ID, parentCloudId);
247 fileInfo.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_NO_NEED_UPLOAD));
248 fileInfo.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::NEW));
249 string filePath = CloudFileUtils::GetLocalFilePath(cloudId, bundleName_, userId_);
250 if (CreateFile(fileName, filePath, fileInfo)) {
251 LOGE("file path is invalid, cannot create file record");
252 return E_PATH;
253 }
254 int64_t outRowId = 0;
255 int32_t ret = rdbStore_->Insert(outRowId, FileColumn::FILES_TABLE, fileInfo);
256 if (ret != E_OK) {
257 LOGE("insert new file record in DB is failed, ret = %{public}d", ret);
258 return ret;
259 }
260 return E_OK;
261 }
262
MkDir(const std::string & cloudId,const std::string & parentCloudId,const std::string & directoryName)263 int32_t CloudDiskRdbStore::MkDir(const std::string &cloudId, const std::string &parentCloudId,
264 const std::string &directoryName)
265 {
266 RDBPTR_IS_NULLPTR(rdbStore_);
267 ValuesBucket dirInfo;
268 if (cloudId.empty() || parentCloudId.empty() || directoryName.empty()) {
269 LOGE("make directory parameter is invalid");
270 return E_INVAL_ARG;
271 }
272 dirInfo.PutString(FileColumn::CLOUD_ID, cloudId);
273 dirInfo.PutString(FileColumn::FILE_NAME, directoryName);
274 dirInfo.PutLong(FileColumn::FILE_TIME_ADDED, UTCTimeMilliSeconds());
275 dirInfo.PutLong(FileColumn::FILE_TIME_EDITED, UTCTimeMilliSeconds());
276 dirInfo.PutLong(FileColumn::META_TIME_EDITED, UTCTimeMilliSeconds());
277 dirInfo.PutInt(FileColumn::IS_DIRECTORY, DIRECTORY);
278 dirInfo.PutString(FileColumn::PARENT_CLOUD_ID, parentCloudId);
279 dirInfo.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::NEW));
280 int64_t outRowId = 0;
281 int32_t ret = rdbStore_->Insert(outRowId, FileColumn::FILES_TABLE, dirInfo);
282 if (ret != E_OK) {
283 LOGE("insert new directory record in DB is failed, ret = %{public}d", ret);
284 return ret;
285 }
286 return E_OK;
287 }
288
Write(const std::string & cloudId)289 int32_t CloudDiskRdbStore::Write(const std::string &cloudId)
290 {
291 RDBPTR_IS_NULLPTR(rdbStore_);
292 if (cloudId.empty() || cloudId == "rootId") {
293 LOGE("write parameter is invalid");
294 return E_INVAL_ARG;
295 }
296 string filePath = CloudFileUtils::GetLocalFilePath(cloudId, bundleName_, userId_);
297 struct stat statInfo {};
298 int32_t ret = stat(filePath.c_str(), &statInfo);
299 if (ret) {
300 LOGE("filePath %{private}s is invalid", filePath.c_str());
301 return E_PATH;
302 }
303 CloudDiskFileInfo info;
304 if (GetAttr(cloudId, info)) {
305 LOGE("get write cloudId info in DB fail");
306 return E_RDB;
307 }
308 int32_t position = static_cast<int32_t>(info.location);
309 ValuesBucket write;
310 write.PutLong(FileColumn::FILE_SIZE, statInfo.st_size);
311 write.PutLong(FileColumn::FILE_TIME_EDITED, Timespec2Milliseconds(statInfo.st_mtim));
312 write.PutLong(FileColumn::META_TIME_EDITED, Timespec2Milliseconds(statInfo.st_mtim));
313 write.PutLong(FileColumn::FILE_TIME_VISIT, Timespec2Milliseconds(statInfo.st_atim));
314 if (position != LOCAL) {
315 write.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_FDIRTY));
316 write.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::UPDATE));
317 } else {
318 write.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_NEW));
319 }
320 int32_t changedRows = -1;
321 vector<ValueObject> bindArgs;
322 bindArgs.emplace_back(cloudId);
323 ret = rdbStore_->Update(changedRows, FileColumn::FILES_TABLE, write,
324 FileColumn::CLOUD_ID + " = ?", bindArgs);
325 if (ret != E_OK) {
326 LOGE("write file record in DB fail, ret %{public}d", ret);
327 return E_RDB;
328 }
329 return E_OK;
330 }
331
GetXAttr(const std::string & cloudId,const std::string & key,std::string & value)332 int32_t CloudDiskRdbStore::GetXAttr(const std::string &cloudId, const std::string &key, std::string &value)
333 {
334 RDBPTR_IS_NULLPTR(rdbStore_);
335 if (cloudId.empty() || cloudId == "rootId" || key != CLOUD_FILE_LOCATION) {
336 LOGE("getxattr parameter is invalid");
337 return E_INVAL_ARG;
338 }
339 AbsRdbPredicates getXAttrPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
340 getXAttrPredicates.EqualTo(FileColumn::CLOUD_ID, cloudId);
341 auto resultSet = rdbStore_->QueryByStep(getXAttrPredicates, { FileColumn::POSITION });
342 if (resultSet == nullptr) {
343 LOGE("get nullptr getxattr result");
344 return E_RDB;
345 }
346 if (resultSet->GoToNextRow() != E_OK) {
347 LOGE("getxattr result set go to next row failed");
348 return E_RDB;
349 }
350 int32_t position;
351 CloudDiskRdbUtils::GetInt(FileColumn::POSITION, position, resultSet);
352 value = to_string(position);
353 return E_OK;
354 }
355
SetXAttr(const std::string & cloudId,const std::string & key,const std::string & value)356 int32_t CloudDiskRdbStore::SetXAttr(const std::string &cloudId, const std::string &key, const std::string &value)
357 {
358 RDBPTR_IS_NULLPTR(rdbStore_);
359 if (cloudId.empty() || cloudId == "rootId" || key != CLOUD_FILE_LOCATION) {
360 LOGE("setxattr parameter is invalid");
361 return E_INVAL_ARG;
362 }
363 int32_t val = -1;
364 istringstream transfer(value);
365 transfer >> val;
366 if (val != LOCAL && val != CLOUD && val != LOCAL_AND_CLOUD) {
367 LOGE("setxattr unknown value");
368 return E_INVAL_ARG;
369 }
370 ValuesBucket setXAttr;
371 setXAttr.PutInt(FileColumn::POSITION, val);
372 int32_t changedRows = -1;
373 vector<ValueObject> bindArgs;
374 bindArgs.emplace_back(cloudId);
375 int32_t ret = rdbStore_->Update(changedRows, FileColumn::FILES_TABLE, setXAttr,
376 FileColumn::CLOUD_ID + " = ?", bindArgs);
377 if (ret != E_OK) {
378 LOGE("set xAttr location fail, ret %{public}d", ret);
379 return E_RDB;
380 }
381 return E_OK;
382 }
383
FileRename(ValuesBucket & values,const int32_t & position,const std::string & newFileName)384 static void FileRename(ValuesBucket &values, const int32_t &position, const std::string &newFileName)
385 {
386 values.PutString(FileColumn::FILE_NAME, newFileName);
387 FillFileType(newFileName, values);
388 if (position != LOCAL) {
389 values.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_MDIRTY));
390 values.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::RENAME));
391 }
392 }
393
FileMove(ValuesBucket & values,const int32_t & position,const std::string & newParentCloudId)394 static void FileMove(ValuesBucket &values, const int32_t &position, const std::string &newParentCloudId)
395 {
396 values.PutString(FileColumn::PARENT_CLOUD_ID, newParentCloudId);
397 if (position != LOCAL) {
398 values.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_MDIRTY));
399 values.PutLong(FileColumn::OPERATE_TYPE, static_cast<int64_t>(OperationType::MOVE));
400 }
401 }
402
Rename(const std::string & oldParentCloudId,const std::string & oldFileName,const std::string & newParentCloudId,const std::string & newFileName)403 int32_t CloudDiskRdbStore::Rename(const std::string &oldParentCloudId, const std::string &oldFileName,
404 const std::string &newParentCloudId, const std::string &newFileName)
405 {
406 RDBPTR_IS_NULLPTR(rdbStore_);
407 if (oldParentCloudId.empty() || oldFileName.empty() || newParentCloudId.empty() || newFileName.empty()) {
408 LOGE("rename parameters is invalid");
409 return E_INVAL_ARG;
410 }
411 CloudDiskFileInfo info;
412 if (LookUp(oldParentCloudId, oldFileName, info)) {
413 LOGE("get rename cloudId info in DB fail");
414 return E_RDB;
415 }
416 string cloudId = info.cloudId;
417 int32_t position = static_cast<int32_t>(info.location);
418 if (oldFileName == newFileName && oldParentCloudId == newParentCloudId) {
419 LOGI("the rename parameter is same as old");
420 return E_OK;
421 }
422 ValuesBucket rename;
423 rename.PutLong(FileColumn::META_TIME_EDITED, UTCTimeMilliSeconds());
424 if (oldFileName != newFileName && oldParentCloudId == newParentCloudId) {
425 FileRename(rename, position, newFileName);
426 }
427 if (oldFileName == newFileName && oldParentCloudId != newParentCloudId) {
428 FileMove(rename, position, newParentCloudId);
429 }
430 int32_t changedRows = -1;
431 vector<ValueObject> bindArgs;
432 bindArgs.emplace_back(cloudId);
433 int32_t ret = rdbStore_->Update(changedRows, FileColumn::FILES_TABLE, rename,
434 FileColumn::CLOUD_ID + " = ?", bindArgs);
435 if (ret != E_OK) {
436 LOGE("rename file fail, ret %{public}d", ret);
437 return E_RDB;
438 }
439 return E_OK;
440 }
441
UnlinkSynced(const std::string & cloudId)442 int32_t CloudDiskRdbStore::UnlinkSynced(const std::string &cloudId)
443 {
444 RDBPTR_IS_NULLPTR(rdbStore_);
445 CLOUDID_IS_NULL(cloudId);
446 int32_t changedRows = -1;
447 ValuesBucket updateValue;
448 vector<string> whereArgs = {cloudId};
449 updateValue.PutInt(FileColumn::DIRTY_TYPE, static_cast<int32_t>(DirtyType::TYPE_DELETED));
450 int32_t ret = rdbStore_
451 ->Update(changedRows, FileColumn::FILES_TABLE, updateValue, FileColumn::CLOUD_ID + " = ?", whereArgs);
452 if (ret != E_OK) {
453 LOGE("unlink synced directory fail, ret %{public}d", ret);
454 return E_RDB;
455 }
456 return E_OK;
457 }
458
UnlinkLocal(const std::string & cloudId)459 int32_t CloudDiskRdbStore::UnlinkLocal(const std::string &cloudId)
460 {
461 RDBPTR_IS_NULLPTR(rdbStore_);
462 CLOUDID_IS_NULL(cloudId);
463 int32_t changedRows = -1;
464 vector<string> whereArgs = {cloudId};
465 int32_t ret = rdbStore_
466 ->Delete(changedRows, FileColumn::FILES_TABLE, FileColumn::CLOUD_ID + " = ?", whereArgs);
467 if (ret != E_OK) {
468 LOGE("unlink local directory fail, ret %{public}d", ret);
469 return E_RDB;
470 }
471 return E_OK;
472 }
473
Unlink(const std::string & parentCloudId,const std::string & fileName,string & unlinkCloudId)474 int32_t CloudDiskRdbStore::Unlink(const std::string &parentCloudId, const std::string &fileName, string &unlinkCloudId)
475 {
476 RDBPTR_IS_NULLPTR(rdbStore_);
477 if (parentCloudId.empty() || fileName.empty()) {
478 LOGE("Unlink parameters is invalid");
479 return E_INVAL_ARG;
480 }
481 AbsRdbPredicates unlinkPredicates = AbsRdbPredicates(FileColumn::FILES_TABLE);
482 unlinkPredicates
483 .EqualTo(FileColumn::PARENT_CLOUD_ID, parentCloudId)->And()
484 ->EqualTo(FileColumn::FILE_NAME, fileName)->And()->EqualTo(FileColumn::FILE_TIME_RECYCLED, "0")->And()
485 ->NotEqualTo(FileColumn::DIRTY_TYPE, to_string(static_cast<int32_t>(DirtyType::TYPE_DELETED)));
486 auto resultSet =
487 rdbStore_->QueryByStep(unlinkPredicates,
488 {FileColumn::CLOUD_ID, FileColumn::IS_DIRECTORY, FileColumn::POSITION});
489 if (resultSet == nullptr) {
490 LOGE("unlink result set is nullptr");
491 return E_RDB;
492 }
493 if (resultSet->GoToNextRow() != E_OK) {
494 LOGW("not need to unlink");
495 return E_OK;
496 }
497 string cloudId;
498 CloudDiskRdbUtils::GetString(FileColumn::CLOUD_ID, cloudId, resultSet);
499 int32_t isDirectory;
500 CloudDiskRdbUtils::GetInt(FileColumn::IS_DIRECTORY, isDirectory, resultSet);
501 int32_t position;
502 CloudDiskRdbUtils::GetInt(FileColumn::POSITION, position, resultSet);
503 vector<ValueObject> bindArgs;
504 bindArgs.emplace_back(cloudId);
505 if (position == CLOUD) {
506 RETURN_ON_ERR(UnlinkSynced(cloudId));
507 return E_OK;
508 } else if (position == LOCAL) {
509 RETURN_ON_ERR(UnlinkLocal(cloudId));
510 } else {
511 RETURN_ON_ERR(UnlinkSynced(cloudId));
512 }
513 if (isDirectory == FILE) {
514 unlinkCloudId = cloudId;
515 }
516 return E_OK;
517 }
518
GenCloudSyncTriggerFuncParams(RdbStore & store,std::string & userId,std::string & bundleName)519 static void GenCloudSyncTriggerFuncParams(RdbStore &store, std::string &userId, std::string &bundleName)
520 {
521 string databasePath = store.GetPath();
522 string str = "cloudfile/";
523 size_t startPos = databasePath.find(str);
524 size_t endPos = databasePath.find("/rdb");
525 if (startPos != std::string::npos && endPos != std::string::npos) {
526 startPos += str.size();
527 string tempStr = databasePath.substr(startPos, endPos - startPos);
528 size_t pos = tempStr.find('/');
529 if (pos != std::string::npos) {
530 userId = tempStr.substr(0, pos);
531 bundleName = tempStr.substr(pos + 1);
532 LOGI("generate CloudSyncTriggerFunc parameters success, userId: %{public}s, bundleName: %{public}s",
533 userId.c_str(), bundleName.c_str());
534 return;
535 }
536 }
537 LOGE("generate CloudSyncTriggerFunc parameters fail");
538 return;
539 }
540
CreateFolderTriggerSync(RdbStore & store)541 static const std::string &CreateFolderTriggerSync(RdbStore &store)
542 {
543 string userId;
544 string bundleName;
545 GenCloudSyncTriggerFuncParams(store, userId, bundleName);
546 static const string CREATE_FOLDERS_NEW_CLOUD_SYNC =
547 "CREATE TRIGGER folders_new_cloud_sync_trigger AFTER INSERT ON " + FileColumn::FILES_TABLE +
548 " FOR EACH ROW WHEN new.isDirectory == 1 AND new.dirty_type == " +
549 std::to_string(static_cast<int32_t>(DirtyType::TYPE_NEW)) +
550 " BEGIN SELECT cloud_sync_func(" + "'" + userId + "', " + "'" + bundleName + "'); END;";
551 return CREATE_FOLDERS_NEW_CLOUD_SYNC;
552 }
553
UpdateFileTriggerSync(RdbStore & store)554 static const std::string &UpdateFileTriggerSync(RdbStore &store)
555 {
556 string userId;
557 string bundleName;
558 GenCloudSyncTriggerFuncParams(store, userId, bundleName);
559 static const string CREATE_FILES_UPDATE_CLOUD_SYNC =
560 "CREATE TRIGGER files_update_cloud_sync_trigger AFTER UPDATE ON " + FileColumn::FILES_TABLE +
561 " FOR EACH ROW WHEN OLD.dirty_type IN (0,1,2,3) AND new.dirty_type IN (2,3)" +
562 " BEGIN SELECT cloud_sync_func(" + "'" + userId + "', " + "'" + bundleName + "'); END;";
563 return CREATE_FILES_UPDATE_CLOUD_SYNC;
564 }
565
DeleteFileTriggerSync(RdbStore & store)566 static const std::string &DeleteFileTriggerSync(RdbStore &store)
567 {
568 string userId;
569 string bundleName;
570 GenCloudSyncTriggerFuncParams(store, userId, bundleName);
571 static const string CREATE_FILES_DELETE_CLOUD_SYNC =
572 "CREATE TRIGGER files_delete_cloud_sync_trigger AFTER UPDATE ON " + FileColumn::FILES_TABLE +
573 " FOR EACH ROW WHEN OLD.dirty_type IN (0,2,3) AND new.dirty_type == " +
574 std::to_string(static_cast<int32_t>(DirtyType::TYPE_DELETED)) +
575 " BEGIN SELECT cloud_sync_func(" + "'" + userId + "', " + "'" + bundleName + "'); END;";
576 return CREATE_FILES_DELETE_CLOUD_SYNC;
577 }
578
LocalFileTriggerSync(RdbStore & store)579 static const std::string &LocalFileTriggerSync(RdbStore &store)
580 {
581 string userId;
582 string bundleName;
583 GenCloudSyncTriggerFuncParams(store, userId, bundleName);
584 static const string CREATE_FILES_LOCAL_CLOUD_SYNC =
585 "CREATE TRIGGER files_local_cloud_sync_trigger AFTER UPDATE ON " + FileColumn::FILES_TABLE +
586 " FOR EACH ROW WHEN OLD.dirty_type IN (1,6) AND new.dirty_type == " +
587 std::to_string(static_cast<int32_t>(DirtyType::TYPE_NEW)) +
588 " BEGIN SELECT cloud_sync_func(" + "'" + userId + "', " + "'" + bundleName + "'); END;";
589 return CREATE_FILES_LOCAL_CLOUD_SYNC;
590 }
591
ExecuteSql(RdbStore & store)592 static int32_t ExecuteSql(RdbStore &store)
593 {
594 static const vector<string> onCreateSqlStrs = {
595 FileColumn::CREATE_FILE_TABLE,
596 CreateFolderTriggerSync(store),
597 UpdateFileTriggerSync(store),
598 FileColumn::CREATE_PARENT_CLOUD_ID_INDEX,
599 DeleteFileTriggerSync(store),
600 LocalFileTriggerSync(store),
601 };
602 for (const string& sqlStr : onCreateSqlStrs) {
603 if (store.ExecuteSql(sqlStr) != NativeRdb::E_OK) {
604 return NativeRdb::E_ERROR;
605 }
606 }
607 return NativeRdb::E_OK;
608 }
609
OnCreate(RdbStore & store)610 int32_t CloudDiskDataCallBack::OnCreate(RdbStore &store)
611 {
612 if (ExecuteSql(store) != NativeRdb::E_OK) {
613 return NativeRdb::E_ERROR;
614 }
615 return NativeRdb::E_OK;
616 }
617
VersionAddParentCloudIdIndex(RdbStore & store)618 static void VersionAddParentCloudIdIndex(RdbStore &store)
619 {
620 const string executeSqlStr = FileColumn::CREATE_PARENT_CLOUD_ID_INDEX;
621 int32_t ret = store.ExecuteSql(executeSqlStr);
622 if (ret != NativeRdb::E_OK) {
623 LOGE("add parent cloud id index fail, err %{public}d", ret);
624 }
625 }
626
VersionFixFileTrigger(RdbStore & store)627 static void VersionFixFileTrigger(RdbStore &store)
628 {
629 const string dropFilesUpdateTrigger = "DROP TRIGGER IF EXISTS files_update_cloud_sync_trigger";
630 if (store.ExecuteSql(dropFilesUpdateTrigger) != NativeRdb::E_OK) {
631 LOGE("drop files_update_cloud_sync_trigger fail");
632 }
633 const string addUpdateFileTrigger = UpdateFileTriggerSync(store);
634 int32_t ret = store.ExecuteSql(addUpdateFileTrigger);
635 if (ret != NativeRdb::E_OK) {
636 LOGE("add update file trigger fail, err %{public}d", ret);
637 }
638 const string addDeleteFileTrigger = DeleteFileTriggerSync(store);
639 ret = store.ExecuteSql(addDeleteFileTrigger);
640 if (ret != NativeRdb::E_OK) {
641 LOGE("add delete file trigger fail, err %{public}d", ret);
642 }
643 const string addLocalFileTrigger = LocalFileTriggerSync(store);
644 ret = store.ExecuteSql(addLocalFileTrigger);
645 if (ret != NativeRdb::E_OK) {
646 LOGE("add local file trigger fail, err %{public}d", ret);
647 }
648 }
649
VersionFixCreateAndLocalTrigger(RdbStore & store)650 static void VersionFixCreateAndLocalTrigger(RdbStore &store)
651 {
652 const string dropFilesCreateTrigger = "DROP TRIGGER IF EXISTS files_new_cloud_sync_trigger";
653 if (store.ExecuteSql(dropFilesCreateTrigger) != NativeRdb::E_OK) {
654 LOGE("drop files_new_cloud_sync_trigger fail");
655 }
656 const string dropFilesLocalTrigger = "DROP TRIGGER IF EXISTS files_local_cloud_sync_trigger";
657 if (store.ExecuteSql(dropFilesLocalTrigger) != NativeRdb::E_OK) {
658 LOGE("drop files_local_cloud_sync_trigger fail");
659 }
660 const string addLocalFileTrigger = LocalFileTriggerSync(store);
661 int32_t ret = store.ExecuteSql(addLocalFileTrigger);
662 if (ret != NativeRdb::E_OK) {
663 LOGE("add local file trigger fail, err %{public}d", ret);
664 }
665 const string addCreateFolderTrigger = CreateFolderTriggerSync(store);
666 ret = store.ExecuteSql(addCreateFolderTrigger);
667 if (ret != NativeRdb::E_OK) {
668 LOGE("add create folder trigger fail, err %{public}d", ret);
669 }
670 }
671
OnUpgrade(RdbStore & store,int32_t oldVersion,int32_t newVersion)672 int32_t CloudDiskDataCallBack::OnUpgrade(RdbStore &store, int32_t oldVersion, int32_t newVersion)
673 {
674 LOGD("OnUpgrade old:%d, new:%d", oldVersion, newVersion);
675 if (oldVersion < VERSION_ADD_PARENT_CLOUD_ID_INDEX) {
676 VersionAddParentCloudIdIndex(store);
677 }
678 if (oldVersion < VERSION_FIX_FILE_TRIGGER) {
679 VersionFixFileTrigger(store);
680 }
681 if (oldVersion < VERSION_FIX_CREATE_AND_LOCAL_TRIGGER) {
682 VersionFixCreateAndLocalTrigger(store);
683 }
684 return NativeRdb::E_OK;
685 }
686 }