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