1 /*
2 * Copyright (C) 2021 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 #define MLOG_TAG "SmartAlbum"
16
17 #include "medialibrary_smartalbum_map_operations.h"
18
19 #include "datashare_predicates.h"
20 #include "datashare_result_set.h"
21 #include "fetch_result.h"
22 #include "medialibrary_common_utils.h"
23 #include "medialibrary_data_manager.h"
24 #include "medialibrary_dir_operations.h"
25 #include "medialibrary_errno.h"
26 #include "medialibrary_file_operations.h"
27 #include "medialibrary_notify.h"
28 #include "medialibrary_object_utils.h"
29 #include "medialibrary_smartalbum_operations.h"
30 #include "media_file_utils.h"
31 #include "media_log.h"
32 #include "media_smart_album_column.h"
33 #include "media_smart_map_column.h"
34 #include "rdb_utils.h"
35 #include "result_set_utils.h"
36
37 using namespace std;
38 using namespace OHOS::NativeRdb;
39 using namespace OHOS::DataShare;
40 using namespace OHOS::RdbDataShareAdapter;
41
42 namespace OHOS {
43 namespace Media {
44 using ChangeType = AAFwk::ChangeInfo::ChangeType;
45 static const std::string HASH_COLLISION_SUFFIX = "(1)";
46 static const std::string ASSET_RECYCLE_SUFFIX = "-copy";
47 static const std::string DIR_RECYCLE_SUFFIX = "_recycle";
48 const std::string RECYCLE_DIR = ".recycle/";
49 constexpr int64_t ONEDAY_TO_SEC = 60 * 60 * 24;
50 constexpr int32_t HASH_COLLISION_MAX_TRY = 10;
51 std::atomic<bool> MediaLibrarySmartAlbumMapOperations::isInterrupt_ = false;
52 mutex MediaLibrarySmartAlbumMapOperations::g_opMutex;
53
MakeSuffixPathName(const string & assetPath)54 static string MakeSuffixPathName(const string &assetPath)
55 {
56 string outSuffixPath;
57 size_t extensionIndex = assetPath.rfind(".");
58 if (extensionIndex != string::npos) {
59 string extension = assetPath.substr(extensionIndex);
60 string noExtensionPath = assetPath.substr(0, extensionIndex);
61 outSuffixPath = noExtensionPath + ASSET_RECYCLE_SUFFIX + extension;
62 } else {
63 outSuffixPath = assetPath + ASSET_RECYCLE_SUFFIX;
64 }
65 MEDIA_DEBUG_LOG("outSuffixPath = %{private}s", outSuffixPath.c_str());
66 return outSuffixPath;
67 }
68
QueryAgeingTrashFiles()69 static shared_ptr<NativeRdb::ResultSet> QueryAgeingTrashFiles()
70 {
71 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
72 CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, nullptr, "UniStore is nullptr");
73
74 MediaLibraryCommand querySmartAlbumCmd(OperationObject::SMART_ALBUM, OperationType::QUERY);
75 querySmartAlbumCmd.GetAbsRdbPredicates()->EqualTo(SMARTALBUM_DB_ID, to_string(TRASH_ALBUM_ID_VALUES));
76 auto resultSet = uniStore->Query(querySmartAlbumCmd, { SMARTALBUM_DB_EXPIRED_TIME });
77 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, nullptr, "Failed to query rdb");
78
79 CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK, nullptr, "Failed to query rdb");
80 auto recycleDays = GetInt32Val(SMARTALBUM_DB_EXPIRED_TIME, resultSet);
81 resultSet.reset();
82
83 int64_t dateAgeing = MediaFileUtils::UTCTimeMilliSeconds();
84 string strAgeingQueryCondition = MEDIA_DATA_DB_DATE_TRASHED + "> 0" + " AND " + to_string(dateAgeing) + " - " +
85 MEDIA_DATA_DB_DATE_TRASHED + " > " + to_string(recycleDays * ONEDAY_TO_SEC * MSEC_TO_SEC);
86 MEDIA_INFO_LOG("StrAgeingQueryCondition = %{private}s", strAgeingQueryCondition.c_str());
87
88 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_ASSET, OperationType::QUERY);
89 cmd.GetAbsRdbPredicates()->SetWhereClause(strAgeingQueryCondition);
90 return MediaLibraryObjectUtils::QueryWithCondition(cmd, {});
91 }
92
HandleAgingOperation(shared_ptr<int> countPtr)93 int32_t MediaLibrarySmartAlbumMapOperations::HandleAgingOperation(shared_ptr<int> countPtr)
94 {
95 auto resultSet = QueryAgeingTrashFiles();
96 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR, "Failed to query ageing trash files");
97
98 int32_t count = 0;
99 CHECK_AND_RETURN_RET_LOG(resultSet->GetRowCount(count) == NativeRdb::E_OK, E_HAS_DB_ERROR,
100 "Get query result count failed");
101 if (count == 0) {
102 MEDIA_INFO_LOG("Have no ageing trash file");
103 return E_SUCCESS;
104 }
105
106 auto fetchFileResult = make_shared<FetchResult<FileAsset>>();
107 for (int32_t row = 0; row < count; row++) {
108 if (MediaLibrarySmartAlbumMapOperations::GetInterrupt()) {
109 MEDIA_INFO_LOG("recieve interrupt, stop aging");
110 return E_ERR;
111 }
112
113 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetObjectFromRdb(resultSet, row);
114 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_HAS_DB_ERROR, "Get fileAsset failed");
115 int32_t errCode;
116 if (fileAsset->GetIsTrash() == TRASHED_ASSET) {
117 errCode = MediaLibraryObjectUtils::DeleteFileObj(move(fileAsset));
118 } else if (fileAsset->GetIsTrash() == TRASHED_DIR) {
119 errCode = MediaLibraryObjectUtils::DeleteDirObj(move(fileAsset));
120 } else {
121 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_ASSET, OperationType::DELETE);
122 errCode = MediaLibraryObjectUtils::DeleteInfoByIdInDb(cmd, to_string(fileAsset->GetId()));
123 }
124 CHECK_AND_RETURN_RET_LOG(errCode >= 0, errCode, "Failed to delete during trash aging: %{public}d", errCode);
125 }
126 if (countPtr != nullptr) {
127 *countPtr = count;
128 }
129 return E_SUCCESS;
130 }
131
GetAssetRecycle(const int32_t assetId,string & filePath,string & outTrashDirPath)132 static string GetAssetRecycle(const int32_t assetId, string &filePath, string &outTrashDirPath)
133 {
134 auto dirQuerySetMap = MediaLibraryDataManager::GetDirQuerySetMap();
135 for (pair<string, DirAsset> dirPair : dirQuerySetMap) {
136 DirAsset dirAsset = dirPair.second;
137 string rootPath = ROOT_MEDIA_DIR + dirAsset.GetDirectory();
138 if (filePath.find(rootPath) == 0) {
139 string trashDirPath = rootPath + RECYCLE_DIR;
140 return trashDirPath;
141 }
142 }
143 return "";
144 }
145
MakeRecycleDisplayName(const int32_t assetId,const string & trashDirPath,string & outRecyclePath)146 static int32_t MakeRecycleDisplayName(const int32_t assetId, const string &trashDirPath, string &outRecyclePath)
147 {
148 shared_ptr<FileAsset> fileAsset = MediaLibraryObjectUtils::GetFileAssetFromId(to_string(assetId));
149 if (fileAsset == nullptr) {
150 MEDIA_ERR_LOG("Failed to get asset, assetId = %{public}d", assetId);
151 return E_GET_ASSET_FAIL;
152 }
153 string hashDisplayName;
154 string name = to_string(fileAsset->GetId()) + fileAsset->GetRelativePath() + fileAsset->GetDisplayName();
155 int32_t errorCode = MediaLibraryCommonUtils::GenKeySHA256(name, hashDisplayName);
156 if (errorCode != E_OK) {
157 MEDIA_ERR_LOG("Failed to genKey, err: %{public}d", errorCode);
158 return E_MAKE_HASHNAME_FAIL;
159 }
160 string extension;
161 outRecyclePath = trashDirPath + hashDisplayName;
162 if (fileAsset->GetMediaType() != MEDIA_TYPE_ALBUM) {
163 size_t extensionIndex = fileAsset->GetDisplayName().rfind(".");
164 if (extensionIndex != string::npos) {
165 extension = fileAsset->GetDisplayName().substr(extensionIndex);
166 }
167 outRecyclePath += extension;
168 MEDIA_INFO_LOG("Asset outRecyclePath = %{private}s", outRecyclePath.c_str());
169 }
170 int32_t suffixTime = 0;
171 while (MediaLibraryObjectUtils::IsColumnValueExist(outRecyclePath, MEDIA_DATA_DB_RECYCLE_PATH)) {
172 if (suffixTime > HASH_COLLISION_MAX_TRY) {
173 MEDIA_ERR_LOG("Reach max hash collision times");
174 errorCode = E_MAKE_HASHNAME_FAIL;
175 break;
176 }
177 name += HASH_COLLISION_SUFFIX;
178 errorCode = MediaLibraryCommonUtils::GenKeySHA256(name, hashDisplayName);
179 if (errorCode != E_OK) {
180 MEDIA_ERR_LOG("Failed to genKey, err: %{public}d", errorCode);
181 return E_MAKE_HASHNAME_FAIL;
182 }
183 outRecyclePath = trashDirPath + hashDisplayName;
184 if (!extension.empty()) {
185 outRecyclePath += extension;
186 }
187 suffixTime++;
188 }
189 return errorCode;
190 }
191
UpdateChildRecycleInfoInDb(const int32_t assetId)192 static int32_t UpdateChildRecycleInfoInDb(const int32_t assetId)
193 {
194 ValuesBucket values;
195 values.PutLong(MEDIA_DATA_DB_DATE_TRASHED, 0);
196 values.PutInt(MEDIA_DATA_DB_IS_TRASH, 0);
197 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_ASSET, OperationType::UPDATE, values);
198 return MediaLibraryObjectUtils::ModifyInfoByIdInDb(cmd, to_string(assetId));
199 }
200
RecycleChildAssetsInfoUtil(const int32_t parentId)201 static int32_t RecycleChildAssetsInfoUtil(const int32_t parentId)
202 {
203 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
204 CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "UniStore is nullptr");
205
206 MediaLibraryCommand queryCmd(OperationObject::FILESYSTEM_ASSET, OperationType::QUERY);
207 queryCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_PARENT_ID, to_string(parentId))->And()->
208 EqualTo(MEDIA_DATA_DB_IS_TRASH, to_string(TRASHED_DIR_CHILD));
209 auto resultSet = uniStore->Query(queryCmd, { MEDIA_DATA_DB_ID, MEDIA_DATA_DB_MEDIA_TYPE });
210 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR, "QueryResultSet is nullptr");
211
212 int32_t errCode = E_SUCCESS;
213 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
214 int32_t fileId = GetInt32Val(MEDIA_DATA_DB_ID, resultSet);
215 errCode = UpdateChildRecycleInfoInDb(fileId);
216 CHECK_AND_RETURN_RET_LOG(errCode > 0, errCode, "Failed to UpdateChildRecycleInfoInDb");
217
218 if (GetInt32Val(MEDIA_DATA_DB_MEDIA_TYPE, resultSet) == MEDIA_TYPE_ALBUM) {
219 errCode = RecycleChildAssetsInfoUtil(fileId);
220 CHECK_AND_RETURN_RET_LOG(errCode >= 0, errCode, "Failed to RecycleChildAssetsInfoUtil");
221 }
222 }
223 return errCode;
224 }
225
GetNewPath(const string & path,const string & srcRelPath,const string & newRelPath)226 static string GetNewPath(const string &path, const string &srcRelPath, const string &newRelPath)
227 {
228 if ((path.find(srcRelPath) != 0) && (path.find(ROOT_MEDIA_DIR + srcRelPath) != 0)) {
229 return "";
230 }
231 string newPath = newRelPath;
232 if (path.find(ROOT_MEDIA_DIR) != string::npos) {
233 newPath = ROOT_MEDIA_DIR + newPath;
234 }
235 newPath += path.substr(path.find(srcRelPath) + srcRelPath.length());
236 return newPath;
237 }
238
RecycleChildSameNameInfoUtil(const int32_t parentId,const string & srcRelPath,const string & newRelPath,bool isFirstLevel)239 static int32_t RecycleChildSameNameInfoUtil(const int32_t parentId, const string &srcRelPath, const string &newRelPath,
240 bool isFirstLevel)
241 {
242 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
243 CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "UniStore is nullptr");
244
245 MediaLibraryCommand queryCmd(OperationObject::FILESYSTEM_ASSET, OperationType::QUERY);
246 queryCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_PARENT_ID, to_string(parentId));
247 vector<string> columns = { MEDIA_DATA_DB_ID, MEDIA_DATA_DB_FILE_PATH, MEDIA_DATA_DB_MEDIA_TYPE,
248 MEDIA_DATA_DB_IS_TRASH, MEDIA_DATA_DB_RECYCLE_PATH, MEDIA_DATA_DB_RELATIVE_PATH };
249 auto result = uniStore->Query(queryCmd, columns);
250 CHECK_AND_RETURN_RET_LOG(result != nullptr, E_HAS_DB_ERROR, "Failed to obtain value from database");
251
252 int32_t count = -1;
253 CHECK_AND_RETURN_RET(result->GetRowCount(count) == NativeRdb::E_OK, E_HAS_DB_ERROR);
254 for (int32_t i = 0; i < count; i++) {
255 CHECK_AND_RETURN_RET(result->GoToNextRow() == NativeRdb::E_OK, E_HAS_DB_ERROR);
256 ValuesBucket values;
257 string relativePath = GetStringVal(MEDIA_DATA_DB_RELATIVE_PATH, result);
258 values.PutString(MEDIA_DATA_DB_RELATIVE_PATH, GetNewPath(relativePath, srcRelPath, newRelPath));
259
260 int32_t mediaType = GetInt32Val(MEDIA_DATA_DB_MEDIA_TYPE, result);
261 if (isFirstLevel && (mediaType != MEDIA_TYPE_ALBUM)) {
262 string newParentName = newRelPath;
263 // delete the final '/' in relative_path
264 newParentName.pop_back();
265 newParentName = MediaLibraryDataManagerUtils::GetDisPlayNameFromPath(newParentName);
266 values.PutString(MEDIA_DATA_DB_BUCKET_NAME, newParentName);
267 }
268
269 // Update recycle_path for TRASHED_ASSET and TRASHED_DIR, update data for TRASHED_DIR_CHILD.
270 int32_t isTrash = GetInt32Val(MEDIA_DATA_DB_IS_TRASH, result);
271 if (isTrash == TRASHED_DIR_CHILD) {
272 string path = GetStringVal(MEDIA_DATA_DB_FILE_PATH, result);
273 values.PutString(MEDIA_DATA_DB_FILE_PATH, GetNewPath(path, srcRelPath, newRelPath));
274 } else {
275 string recyclePath = GetStringVal(MEDIA_DATA_DB_RECYCLE_PATH, result);
276 values.PutString(MEDIA_DATA_DB_RECYCLE_PATH, GetNewPath(recyclePath, srcRelPath, newRelPath));
277 }
278
279 int32_t fileId = GetInt32Val(MEDIA_DATA_DB_ID, result);
280 MediaLibraryCommand updateCmd(OperationObject::FILESYSTEM_ASSET, OperationType::UPDATE, values);
281 updateCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, to_string(fileId));
282 int32_t changedRows = -1;
283 auto ret = uniStore->Update(updateCmd, changedRows);
284 if ((ret != NativeRdb::E_OK) || (changedRows <= 0)) {
285 MEDIA_ERR_LOG("Update DB failed. Ret: %{public}d. Update fileId: %{public}d", ret, fileId);
286 return E_HAS_DB_ERROR;
287 }
288
289 if (mediaType == MEDIA_TYPE_ALBUM) {
290 ret = RecycleChildSameNameInfoUtil(fileId, srcRelPath, newRelPath, false);
291 CHECK_AND_RETURN_RET_LOG(ret == E_SUCCESS, E_HAS_DB_ERROR, "Update DB failed. fileId: %{public}d", fileId);
292 }
293 }
294 return E_SUCCESS;
295 }
296
RecycleDir(const shared_ptr<FileAsset> & fileAsset)297 static int32_t RecycleDir(const shared_ptr<FileAsset> &fileAsset)
298 {
299 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
300 CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "UniStore is nullptr");
301
302 ValuesBucket values;
303 int32_t parentId = MediaLibraryObjectUtils::CreateDirWithPath(ROOT_MEDIA_DIR +
304 MediaFileUtils::AddDocsToRelativePath(fileAsset->GetRelativePath()));
305 if (parentId != fileAsset->GetParent()) {
306 values.PutInt(MEDIA_DATA_DB_PARENT_ID, parentId);
307 }
308
309 bool hasSameName = false;
310 string assetPath = fileAsset->GetRecyclePath();
311 while (MediaLibraryObjectUtils::IsFileExistInDb(assetPath)) {
312 hasSameName = true;
313 assetPath = assetPath + DIR_RECYCLE_SUFFIX;
314 }
315
316 if (!MediaFileUtils::RenameDir(fileAsset->GetPath(), assetPath)) {
317 if (errno == ENAMETOOLONG) {
318 return -ENAMETOOLONG;
319 }
320 return E_RENAME_DIR_FAIL;
321 }
322
323 if (hasSameName) {
324 fileAsset->SetRecyclePath(assetPath);
325 // update dir info
326 string newName = MediaLibraryDataManagerUtils::GetDisPlayNameFromPath(assetPath);
327 values.PutString(MEDIA_DATA_DB_NAME, newName);
328 values.PutString(MEDIA_DATA_DB_TITLE, newName);
329 values.PutString(MEDIA_DATA_DB_RECYCLE_PATH, assetPath);
330
331 // update child info
332 string srcRelPath = fileAsset->GetRelativePath() + fileAsset->GetDisplayName() + "/";
333 string newRelPath = fileAsset->GetRelativePath() + newName + "/";
334 RecycleChildSameNameInfoUtil(fileAsset->GetId(), srcRelPath, newRelPath, true);
335 }
336
337 if (!values.IsEmpty()) {
338 MediaLibraryCommand updateCmd(OperationObject::FILESYSTEM_ASSET, OperationType::UPDATE, values);
339 updateCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, to_string(fileAsset->GetId()));
340 int32_t changedRows = -1;
341 return uniStore->Update(updateCmd, changedRows);
342 }
343
344 return E_SUCCESS;
345 }
346
UpdateRecycleInfoInDb(const int32_t assetId,const string & realPath)347 static int32_t UpdateRecycleInfoInDb(const int32_t assetId, const string &realPath)
348 {
349 ValuesBucket values;
350 values.PutString(MEDIA_DATA_DB_FILE_PATH, realPath);
351 values.PutString(MEDIA_DATA_DB_RECYCLE_PATH, "");
352 values.PutLong(MEDIA_DATA_DB_DATE_TRASHED, 0);
353 values.PutInt(MEDIA_DATA_DB_IS_TRASH, 0);
354 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_ASSET, OperationType::UPDATE, values);
355 return MediaLibraryObjectUtils::ModifyInfoByIdInDb(cmd, to_string(assetId));
356 }
357
RecycleDirAssetsInfoUtil(const shared_ptr<FileAsset> & fileAsset)358 static int32_t RecycleDirAssetsInfoUtil(const shared_ptr<FileAsset> &fileAsset)
359 {
360 if (!MediaFileUtils::IsDirectory(fileAsset->GetPath())) {
361 MEDIA_ERR_LOG("recycle dir is not exists");
362 return E_RECYCLE_FILE_IS_NULL;
363 }
364
365 auto errorCode = RecycleDir(fileAsset);
366 CHECK_AND_RETURN_RET_LOG(errorCode == E_SUCCESS, errorCode, "Failed to RecycleDir");
367
368 errorCode = RecycleChildAssetsInfoUtil(fileAsset->GetId());
369 CHECK_AND_RETURN_RET_LOG(errorCode >= 0, errorCode, "Failed to recycleChildAssetsInfoUtil");
370
371 string dirRealPath = fileAsset->GetRecyclePath();
372 return UpdateRecycleInfoInDb(fileAsset->GetId(), dirRealPath);
373 }
374
RecycleFile(const shared_ptr<FileAsset> & fileAsset)375 static int32_t RecycleFile(const shared_ptr<FileAsset> &fileAsset)
376 {
377 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
378 CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "UniStore is nullptr");
379
380 ValuesBucket values;
381 int32_t parentId = MediaLibraryObjectUtils::CreateDirWithPath(ROOT_MEDIA_DIR +
382 MediaFileUtils::AddDocsToRelativePath(fileAsset->GetRelativePath()));
383 if (parentId != fileAsset->GetParent()) {
384 values.PutInt(MEDIA_DATA_DB_PARENT_ID, parentId);
385 values.PutInt(MEDIA_DATA_DB_BUCKET_ID, parentId);
386 }
387
388 bool hasSameName = false;
389 string assetPath = fileAsset->GetRecyclePath();
390 while (MediaLibraryObjectUtils::IsFileExistInDb(assetPath)) {
391 hasSameName = true;
392 assetPath = MakeSuffixPathName(assetPath);
393 }
394
395 if (!MediaFileUtils::MoveFile(fileAsset->GetPath(), assetPath)) {
396 if (errno == ENAMETOOLONG) {
397 return -ENAMETOOLONG;
398 }
399 return E_RENAME_FILE_FAIL;
400 }
401 MediaLibraryObjectUtils::InvalidateThumbnail(to_string(fileAsset->GetId()));
402
403 if (hasSameName) {
404 fileAsset->SetRecyclePath(assetPath);
405 string newName = MediaLibraryDataManagerUtils::GetDisPlayNameFromPath(assetPath);
406 values.PutString(MEDIA_DATA_DB_NAME, newName);
407 values.PutString(MEDIA_DATA_DB_RECYCLE_PATH, assetPath);
408 MediaType mediaType = fileAsset->GetMediaType();
409 if ((mediaType != MEDIA_TYPE_VIDEO) && (mediaType != MEDIA_TYPE_AUDIO)) {
410 values.PutString(MEDIA_DATA_DB_TITLE, newName);
411 }
412 }
413
414 if (!values.IsEmpty()) {
415 MediaLibraryCommand updateCmd(OperationObject::FILESYSTEM_ASSET, OperationType::UPDATE, values);
416 updateCmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, to_string(fileAsset->GetId()));
417 int32_t changedRows = -1;
418 return uniStore->Update(updateCmd, changedRows);
419 }
420
421 return E_SUCCESS;
422 }
423
RecycleFileAssetsInfoUtil(const shared_ptr<FileAsset> & fileAsset)424 static int32_t RecycleFileAssetsInfoUtil(const shared_ptr<FileAsset> &fileAsset)
425 {
426 string recyclePath = fileAsset->GetPath();
427 if (!MediaFileUtils::IsFileExists(recyclePath)) {
428 MEDIA_ERR_LOG("RecycleFile is null, fileid = %{private}d", fileAsset->GetId());
429 return E_RECYCLE_FILE_IS_NULL;
430 }
431
432 int32_t errorCode = RecycleFile(fileAsset);
433 CHECK_AND_RETURN_RET_LOG(errorCode >= 0, errorCode, "Failed to recycleFile");
434
435 string fileRealPath = fileAsset->GetRecyclePath();
436 return UpdateRecycleInfoInDb(fileAsset->GetId(), fileRealPath);
437 }
438
RemoveTrashAssetsInfoUtil(const int32_t fileAssetId)439 static int32_t RemoveTrashAssetsInfoUtil(const int32_t fileAssetId)
440 {
441 shared_ptr<FileAsset> fileAsset = MediaLibraryObjectUtils::GetFileAssetFromId(to_string(fileAssetId));
442 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_GET_ASSET_FAIL, "fileAsset is nullptr, assetId: %{public}d",
443 fileAssetId);
444
445 int32_t ret = 0;
446 if (fileAsset->GetMediaType() != MEDIA_TYPE_ALBUM) {
447 ret = RecycleFileAssetsInfoUtil(fileAsset);
448 } else {
449 ret = RecycleDirAssetsInfoUtil(fileAsset);
450 }
451 return ret;
452 }
453
UpdateFavoriteAssetsInfoUtil(const int32_t fileAssetId,const bool isFavorites)454 static int32_t UpdateFavoriteAssetsInfoUtil(const int32_t fileAssetId, const bool isFavorites)
455 {
456 ValuesBucket values;
457 values.PutInt(MEDIA_DATA_DB_IS_FAV, isFavorites ? 1 : 0);
458 MEDIA_INFO_LOG("Update asset %{public}d favorite to %{public}d", fileAssetId, isFavorites ? 1 : 0);
459 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_ASSET, OperationType::UPDATE, values);
460 return MediaLibraryObjectUtils::ModifyInfoByIdInDb(cmd, to_string(fileAssetId));
461 }
462
HandleRemoveAssetOperation(const int32_t albumId,const int32_t childFileAssetId,MediaLibraryCommand & cmd)463 int32_t MediaLibrarySmartAlbumMapOperations::HandleRemoveAssetOperation(const int32_t albumId,
464 const int32_t childFileAssetId, MediaLibraryCommand &cmd)
465 {
466 lock_guard<mutex> guard(g_opMutex);
467 int32_t errorCode = E_SUCCESS;
468 if (albumId == TRASH_ALBUM_ID_VALUES) {
469 errorCode = RemoveTrashAssetsInfoUtil(childFileAssetId);
470 } else if (albumId == FAVOURITE_ALBUM_ID_VALUES) {
471 errorCode = UpdateFavoriteAssetsInfoUtil(childFileAssetId, false);
472 }
473 CHECK_AND_RETURN_RET_LOG(errorCode >= 0, errorCode, "Failed to handleRemoveAssetOperations");
474 cmd.GetAbsRdbPredicates()->EqualTo(SMARTALBUMMAP_DB_ALBUM_ID, to_string(albumId))->And()->
475 EqualTo(SMARTALBUMMAP_DB_CHILD_ASSET_ID, to_string(childFileAssetId));
476 return MediaLibraryObjectUtils::DeleteInfoByIdInDb(cmd);
477 }
478
UpdateChildTrashInfoInDb(const int32_t assetId,const int64_t trashDate)479 static int32_t UpdateChildTrashInfoInDb(const int32_t assetId, const int64_t trashDate)
480 {
481 ValuesBucket values;
482 values.PutLong(MEDIA_DATA_DB_DATE_TRASHED, trashDate);
483 values.PutInt(MEDIA_DATA_DB_IS_TRASH, TRASHED_DIR_CHILD);
484 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_ASSET, OperationType::UPDATE, values);
485 return MediaLibraryObjectUtils::ModifyInfoByIdInDb(cmd, to_string(assetId));
486 }
487
TrashChildAssetsInfoUtil(const int32_t parentId,const int64_t & trashDate)488 static int32_t TrashChildAssetsInfoUtil(const int32_t parentId, const int64_t &trashDate)
489 {
490 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
491 CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "UniStore is nullptr");
492
493 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_ASSET, OperationType::QUERY);
494 string parentPath = MediaLibraryObjectUtils::GetPathByIdFromDb(to_string(parentId));
495 cmd.GetAbsRdbPredicates()->Like(MEDIA_DATA_DB_FILE_PATH, parentPath + "/%")->And()->
496 EqualTo(MEDIA_DATA_DB_IS_TRASH, to_string(NOT_TRASHED));
497
498 auto result = uniStore->Query(cmd, { MEDIA_DATA_DB_ID });
499 CHECK_AND_RETURN_RET_LOG(result != nullptr, E_HAS_DB_ERROR, "QueryResultSet is nullptr");
500
501 auto count = 0;
502 CHECK_AND_RETURN_RET_LOG(result->GetRowCount(count) == NativeRdb::E_OK, E_HAS_DB_ERROR,
503 "Get query result count failed");
504 if (count == 0) {
505 MEDIA_INFO_LOG("Have no child assets");
506 return E_SUCCESS;
507 }
508
509 while (result->GoToNextRow() == NativeRdb::E_OK) {
510 auto ret = UpdateChildTrashInfoInDb(GetInt32Val(MEDIA_DATA_DB_ID, result), trashDate);
511 CHECK_AND_RETURN_RET_LOG(ret >= 0, ret, "Failed to updateChildTrashInfoInDb");
512 }
513 return E_SUCCESS;
514 }
515
UpdateTrashInfoInDb(const int32_t assetId,const int64_t trashDate,string & recyclePath,const string & oldPath,const uint32_t trashType)516 static int32_t UpdateTrashInfoInDb(const int32_t assetId, const int64_t trashDate, string &recyclePath,
517 const string &oldPath, const uint32_t trashType)
518 {
519 ValuesBucket values;
520 values.PutString(MEDIA_DATA_DB_FILE_PATH, recyclePath);
521 values.PutString(MEDIA_DATA_DB_RECYCLE_PATH, oldPath);
522 values.PutLong(MEDIA_DATA_DB_DATE_TRASHED, trashDate);
523 values.PutInt(MEDIA_DATA_DB_IS_TRASH, trashType);
524 MediaLibraryCommand cmd(OperationObject::FILESYSTEM_ASSET, OperationType::UPDATE, values);
525 return MediaLibraryObjectUtils::ModifyInfoByIdInDb(cmd, to_string(assetId));
526 }
527
TrashDirAssetsInfoUtil(const int32_t assetId)528 static int32_t TrashDirAssetsInfoUtil(const int32_t assetId)
529 {
530 string oldPath = MediaLibraryObjectUtils::GetPathByIdFromDb(to_string(assetId));
531 string trashDirPath = GetAssetRecycle(assetId, oldPath, trashDirPath);
532 CHECK_AND_RETURN_RET_LOG(!trashDirPath.empty(), E_CHECK_ROOT_DIR_FAIL, "Failed to get recycle dir");
533 if (!MediaFileUtils::IsDirectory(trashDirPath)) {
534 if (!MediaFileUtils::CreateDirectory(trashDirPath)) {
535 MEDIA_ERR_LOG("TrashDirPath create failed");
536 return E_CREATE_TRASHDIR_FAIL;
537 }
538 }
539 string recyclePath;
540 auto errorCode = MakeRecycleDisplayName(assetId, trashDirPath, recyclePath);
541 CHECK_AND_RETURN_RET_LOG(errorCode == E_SUCCESS, errorCode, "Failed to makeRecycleDisplayName");
542 if (!MediaFileUtils::RenameDir(oldPath, recyclePath)) {
543 return E_MODIFY_DATA_FAIL;
544 }
545 int64_t trashDate = MediaFileUtils::UTCTimeMilliSeconds();
546 errorCode = TrashChildAssetsInfoUtil(assetId, trashDate);
547 CHECK_AND_RETURN_RET_LOG(errorCode == E_SUCCESS, errorCode, "Failed to trashChildAssetsInfoUtil");
548 return UpdateTrashInfoInDb(assetId, trashDate, recyclePath, oldPath, TRASHED_DIR);
549 }
550
TrashFileAssetsInfoUtil(const int32_t assetId)551 static int32_t TrashFileAssetsInfoUtil(const int32_t assetId)
552 {
553 string oldPath = MediaLibraryObjectUtils::GetPathByIdFromDb(to_string(assetId));
554 string trashDirPath = GetAssetRecycle(assetId, oldPath, trashDirPath);
555 CHECK_AND_RETURN_RET_LOG(!trashDirPath.empty(), E_CHECK_ROOT_DIR_FAIL, "Failed to get recycle dir");
556 if (!MediaFileUtils::IsDirectory(trashDirPath)) {
557 if (!MediaFileUtils::CreateDirectory(trashDirPath)) {
558 MEDIA_ERR_LOG("TrashDirPath create failed");
559 return E_CREATE_TRASHDIR_FAIL;
560 }
561 }
562 string recyclePath;
563 auto errorCode = MakeRecycleDisplayName(assetId, trashDirPath, recyclePath);
564 CHECK_AND_RETURN_RET_LOG(errorCode == E_SUCCESS, errorCode, "Failed to make recycle display name");
565 errorCode = MediaFileUtils::ModifyAsset(oldPath, recyclePath);
566 CHECK_AND_RETURN_RET_LOG(errorCode == E_SUCCESS, errorCode, "Failed to modifyAsset");
567 MediaLibraryObjectUtils::InvalidateThumbnail(to_string(assetId));
568 int64_t trashDate = MediaFileUtils::UTCTimeSeconds();
569 return UpdateTrashInfoInDb(assetId, trashDate, recyclePath, oldPath, TRASHED_ASSET);
570 }
571
InsertTrashAssetsInfoUtil(const int32_t fileAssetId)572 static int32_t InsertTrashAssetsInfoUtil(const int32_t fileAssetId)
573 {
574 shared_ptr<FileAsset> fileAsset = MediaLibraryObjectUtils::GetFileAssetFromId(to_string(fileAssetId));
575 if (fileAsset == nullptr) {
576 MEDIA_ERR_LOG("FileAsset is nullptr");
577 return E_GET_ASSET_FAIL;
578 }
579 if (fileAsset->GetDateTrashed() != 0) {
580 return E_IS_RECYCLED;
581 }
582 if (fileAsset->GetMediaType() != MEDIA_TYPE_ALBUM) {
583 return TrashFileAssetsInfoUtil(fileAssetId);
584 } else {
585 return TrashDirAssetsInfoUtil(fileAssetId);
586 }
587 }
588
HandleAddAssetOperation(const int32_t albumId,const int32_t childFileAssetId,const int32_t childAlbumId,MediaLibraryCommand & cmd)589 int32_t MediaLibrarySmartAlbumMapOperations::HandleAddAssetOperation(const int32_t albumId,
590 const int32_t childFileAssetId, const int32_t childAlbumId, MediaLibraryCommand &cmd)
591 {
592 MEDIA_DEBUG_LOG("HandleAddAssetOperations albumId = %{public}d, childFileAssetId = %{public}d",
593 albumId, childFileAssetId);
594 lock_guard<mutex> guard(g_opMutex);
595 int32_t errorCode = E_SUCCESS;
596 if (albumId == TRASH_ALBUM_ID_VALUES) {
597 errorCode = InsertTrashAssetsInfoUtil(childFileAssetId);
598 } else if (albumId == FAVOURITE_ALBUM_ID_VALUES) {
599 errorCode = UpdateFavoriteAssetsInfoUtil(childFileAssetId, true);
600 }
601 CHECK_AND_RETURN_RET_LOG(errorCode >= 0, errorCode, "Failed to handleAddAssetOperations");
602 if (childAlbumId != DEFAULT_ALBUMID) {
603 if (!MediaLibraryObjectUtils::IsParentSmartAlbum(albumId, true)) {
604 MEDIA_ERR_LOG("Child can not add smart album");
605 return E_CHILD_CAN_NOT_ADD_SMARTALBUM;
606 }
607 }
608 if (childFileAssetId != DEFAULT_ASSETID) {
609 if (MediaLibraryObjectUtils::IsParentSmartAlbum(albumId)) {
610 MEDIA_ERR_LOG("Parent can not add assets");
611 return E_PARENT_CAN_NOT_ADDASSETS;
612 }
613 }
614 return MediaLibraryObjectUtils::InsertInDb(cmd);
615 }
616
HandleSmartAlbumMapOperation(MediaLibraryCommand & cmd)617 int32_t MediaLibrarySmartAlbumMapOperations::HandleSmartAlbumMapOperation(MediaLibraryCommand &cmd)
618 {
619 ValueObject valueObject;
620 ValuesBucket values = cmd.GetValueBucket();
621 int32_t albumId = DEFAULT_ALBUMID;
622 if (values.GetObject(SMARTALBUMMAP_DB_ALBUM_ID, valueObject)) {
623 valueObject.GetInt(albumId);
624 }
625 CHECK_AND_RETURN_RET_LOG(MediaLibraryObjectUtils::IsSmartAlbumExistInDb(albumId),
626 E_SMARTALBUM_IS_NOT_EXISTED, "Failed to get smartAlbumId");
627 int32_t childAssetId = DEFAULT_ASSETID;
628 int32_t childAlbumId = DEFAULT_ALBUMID;
629 if (values.GetObject(SMARTALBUMMAP_DB_CHILD_ASSET_ID, valueObject)) {
630 valueObject.GetInt(childAssetId);
631 }
632 if (values.GetObject(SMARTALBUMMAP_DB_CHILD_ALBUM_ID, valueObject)) {
633 valueObject.GetInt(childAlbumId);
634 }
635 // childAssetId and childAlbumId only one has value
636 if ((childAlbumId == DEFAULT_ALBUMID) && (childAssetId == DEFAULT_ASSETID)) {
637 MEDIA_ERR_LOG("GetObject failed");
638 return E_GET_VALUEBUCKET_FAIL;
639 }
640 if (childAlbumId != DEFAULT_ALBUMID) {
641 CHECK_AND_RETURN_RET_LOG(MediaLibraryObjectUtils::IsSmartAlbumExistInDb(childAlbumId),
642 E_SMARTALBUM_IS_NOT_EXISTED, "Failed to get childAlbumId");
643 }
644 if (childAssetId != DEFAULT_ASSETID) {
645 CHECK_AND_RETURN_RET_LOG(MediaLibraryObjectUtils::IsAssetExistInDb(childAssetId,
646 true), E_GET_ASSET_FAIL, "Failed to get childAssetId");
647 }
648 MEDIA_INFO_LOG("childAssetId = %{public}d , childAlbumId = %{public}d", childAssetId, childAlbumId);
649 int32_t errCode = E_ERR;
650 switch (cmd.GetOprnType()) {
651 case OperationType::CREATE:
652 errCode = HandleAddAssetOperation(albumId, childAssetId, childAlbumId, cmd);
653 break;
654 case OperationType::DELETE:
655 errCode = HandleRemoveAssetOperation(albumId, childAssetId, cmd);
656 break;
657 case OperationType::AGING:
658 errCode = HandleAgingOperation();
659 break;
660 default:
661 MEDIA_WARN_LOG("Unknown operation type %{private}d", cmd.GetOprnType());
662 break;
663 }
664 return errCode;
665 }
666
SetInterrupt(bool interrupt)667 void MediaLibrarySmartAlbumMapOperations::SetInterrupt(bool interrupt)
668 {
669 isInterrupt_ = interrupt;
670 }
671
GetInterrupt()672 bool MediaLibrarySmartAlbumMapOperations::GetInterrupt()
673 {
674 return isInterrupt_.load();
675 }
676 } // namespace Media
677 } // namespace OHOS
678