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