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