• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 #include "photos_clone.h"
16 
17 #include <uuid.h>
18 #include <numeric>
19 
20 #include "rdb_store.h"
21 #include "result_set_utils.h"
22 #include "photo_album_dao.h"
23 #include "backup_const.h"
24 #include "media_log.h"
25 #include "album_plugin_config.h"
26 #include "userfile_manager_types.h"
27 
28 namespace OHOS::Media {
ToString(const FileInfo & fileInfo)29 std::string PhotosClone::ToString(const FileInfo &fileInfo)
30 {
31     return "FileInfo[ fileId: " + std::to_string(fileInfo.fileIdOld) + ", displayName: " + fileInfo.displayName +
32            ", bundleName: " + fileInfo.bundleName + ", lPath: " + fileInfo.lPath +
33            ", size: " + std::to_string(fileInfo.fileSize) + ", fileType: " + std::to_string(fileInfo.fileType) + " ]";
34 }
35 
ToLower(const std::string & str)36 std::string PhotosClone::ToLower(const std::string &str)
37 {
38     std::string lowerStr;
39     std::transform(
40         str.begin(), str.end(), std::back_inserter(lowerStr), [](unsigned char c) { return std::tolower(c); });
41     return lowerStr;
42 }
43 
44 /**
45  * @brief Get Row Count of Photos in Album.
46  */
GetPhotosRowCountInPhotoMap()47 int32_t PhotosClone::GetPhotosRowCountInPhotoMap()
48 {
49     std::string querySql = this->SQL_PHOTOS_TABLE_COUNT_IN_PHOTO_MAP;
50     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, 0,
51         "Media_Restore: mediaLibraryOriginalRdb_ is null.");
52     auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
53     CHECK_AND_RETURN_RET(resultSet != nullptr, 0);
54     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
55         resultSet->Close();
56         return 0;
57     }
58     int32_t count = GetInt32Val("count", resultSet);
59     return count;
60 }
61 
62 /**
63  * @brief Get Row Count of Cloud Photos in Album.
64  */
GetCloudPhotosRowCountInPhotoMap()65 int32_t PhotosClone::GetCloudPhotosRowCountInPhotoMap()
66 {
67     std::string querySql = this->SQL_CLOUD_PHOTOS_TABLE_COUNT_IN_PHOTO_MAP;
68     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, 0,
69         "singleCloud Media_Restore: mediaLibraryOriginalRdb_ is null.");
70     auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
71     CHECK_AND_RETURN_RET(resultSet != nullptr, 0);
72     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
73         resultSet->Close();
74         return 0;
75     }
76     int32_t count = GetInt32Val("count", resultSet);
77     return count;
78 }
79 
80 /**
81  * @brief Get Row Count of Photos not in Album.
82  */
GetPhotosRowCountNotInPhotoMap()83 int32_t PhotosClone::GetPhotosRowCountNotInPhotoMap()
84 {
85     std::string querySql = this->SQL_PHOTOS_TABLE_COUNT_NOT_IN_PHOTO_MAP;
86     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, 0,
87         "Media_Restore: mediaLibraryOriginalRdb_ is null.");
88     auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
89     CHECK_AND_RETURN_RET(resultSet != nullptr, 0);
90     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
91         resultSet->Close();
92         return 0;
93     }
94     int32_t count = GetInt32Val("count", resultSet);
95     return count;
96 }
97 
98 /**
99  * @brief Get Row Count of Cloud Photos not in Album.
100  */
GetCloudPhotosRowCountNotInPhotoMap()101 int32_t PhotosClone::GetCloudPhotosRowCountNotInPhotoMap()
102 {
103     std::string querySql = this->SQL_CLOUD_PHOTOS_TABLE_COUNT_NOT_IN_PHOTO_MAP;
104     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, 0,
105         "singleCloud Media_Restore: mediaLibraryOriginalRdb_ is null.");
106     auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
107     CHECK_AND_RETURN_RET(resultSet != nullptr, 0);
108     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
109         resultSet->Close();
110         return 0;
111     }
112     int32_t count = GetInt32Val("count", resultSet);
113     return count;
114 }
115 
116 /**
117  * @brief Query the Photos Info, which is in PhotoAlbum, from the Original MediaLibrary Database.
118  */
GetPhotosInPhotoMap(int32_t offset,int32_t pageSize)119 std::shared_ptr<NativeRdb::ResultSet> PhotosClone::GetPhotosInPhotoMap(int32_t offset, int32_t pageSize)
120 {
121     std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
122     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, nullptr,
123         "Media_Restore: mediaLibraryOriginalRdb_ is null.");
124     return this->mediaLibraryOriginalRdb_->QuerySql(this->SQL_PHOTOS_TABLE_QUERY_IN_PHOTO_MAP, bindArgs);
125 }
126 
127 /**
128  * @brief Query the Cloud Photos Info, which is in PhotoAlbum, from the Original MediaLibrary Database.
129  */
GetCloudPhotosInPhotoMap(int32_t offset,int32_t pageSize)130 std::shared_ptr<NativeRdb::ResultSet> PhotosClone::GetCloudPhotosInPhotoMap(int32_t offset, int32_t pageSize)
131 {
132     std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
133     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, nullptr,
134         "singleCloud Media_Restore: mediaLibraryOriginalRdb_ is null.");
135     return this->mediaLibraryOriginalRdb_->QuerySql(this->SQL_CLOUD_PHOTOS_TABLE_QUERY_IN_PHOTO_MAP, bindArgs);
136 }
137 
138 /**
139  * @brief Query the Photos Info, which is not in PhotoAlbum, from the Original MediaLibrary Database.
140  */
GetPhotosNotInPhotoMap(int32_t offset,int32_t pageSize)141 std::shared_ptr<NativeRdb::ResultSet> PhotosClone::GetPhotosNotInPhotoMap(int32_t offset, int32_t pageSize)
142 {
143     std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
144     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, nullptr,
145         "Media_Restore: mediaLibraryOriginalRdb_ is null.");
146     return this->mediaLibraryOriginalRdb_->QuerySql(this->SQL_PHOTOS_TABLE_QUERY_NOT_IN_PHOTO_MAP, bindArgs);
147 }
148 
149 /**
150  * @brief Query the Cloud Photos Info, which is not in PhotoAlbum, from the Original MediaLibrary Database.
151  */
GetCloudPhotosNotInPhotoMap(int32_t offset,int32_t pageSize)152 std::shared_ptr<NativeRdb::ResultSet> PhotosClone::GetCloudPhotosNotInPhotoMap(int32_t offset, int32_t pageSize)
153 {
154     std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
155     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, nullptr,
156         "singleCloud Media_Restore: mediaLibraryOriginalRdb_ is null.");
157     return this->mediaLibraryOriginalRdb_->QuerySql(this->SQL_CLOUD_PHOTOS_TABLE_QUERY_NOT_IN_PHOTO_MAP, bindArgs);
158 }
159 
160 /**
161  * @note If the lPath is empty, return '/Pictures/其它' string.
162  *      If the lPath is '/Pictures/ScreenShots', return '/Pictures/ScreenShots' string.
163  *      Otherwise, return the lPath of the FileInfo.
164  */
FindAlbumInfo(const FileInfo & fileInfo)165 PhotoAlbumDao::PhotoAlbumRowData PhotosClone::FindAlbumInfo(const FileInfo &fileInfo)
166 {
167     PhotoAlbumDao::PhotoAlbumRowData albumInfo;
168     std::string lPath = fileInfo.lPath;
169     // Scenario 2, WHEN FileInfo is in hidden album, THEN override lPath to the folder in sourcePath.
170     // Scenario 3, WHEN FileInfo is not belongs to any album, THEN override lPath to the folder in sourcePath.
171     // Note, sourcePath is a sign of the possible scenaio that the file is not in any album.
172     bool islPathMiss = !fileInfo.sourcePath.empty() && (fileInfo.hidden == 1 || fileInfo.recycledTime != 0);
173     islPathMiss = islPathMiss || fileInfo.lPath.empty();
174     if (islPathMiss) {
175         lPath = this->photoAlbumDao_.ParseSourcePathToLPath(fileInfo.sourcePath);
176         MEDIA_INFO_LOG("Media_Restore: fix lPath of album.fileInfo.lPath: %{public}s, "
177                        "lPathFromSourcePath: %{public}s, lowercase: %{public}s, FileInfo Object: %{public}s",
178             fileInfo.lPath.c_str(),
179             lPath.c_str(),
180             this->ToLower(lPath).c_str(),
181             this->ToString(fileInfo).c_str());
182     }
183     // Scenario 1, WHEN FileInfo is in /Pictures/Screenshots and Video type, THEN redirect to /Pictures/Screenrecords
184     if (this->ToLower(lPath) == this->ToLower(AlbumPlugin::LPATH_SCREEN_SHOTS) &&
185         fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
186         albumInfo = this->photoAlbumDao_.BuildAlbumInfoOfRecorders();
187         albumInfo = this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
188         MEDIA_INFO_LOG("Media_Restore: screenshots redirect to screenrecords, fileInfo.lPath: %{public}s, "
189                        "lPath: %{public}s, Object: %{public}s, albumInfo: %{public}s",
190             fileInfo.lPath.c_str(),
191             lPath.c_str(),
192             this->ToString(fileInfo).c_str(),
193             this->photoAlbumDao_.ToString(albumInfo).c_str());
194         return albumInfo;
195     }
196     return BuildAlbumInfoByCondition(fileInfo, lPath);
197 }
198 
BuildAlbumInfoByCondition(const FileInfo & fileInfo,const std::string & lPath)199 PhotoAlbumDao::PhotoAlbumRowData PhotosClone::BuildAlbumInfoByCondition(const FileInfo &fileInfo,
200     const std::string &lPath)
201 {
202     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->photoAlbumDao_.BuildAlbumInfoByLPath(lPath);
203     if (fileInfo.hidden == 0 && fileInfo.recycledTime == 0) {
204         return this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
205     }
206     return this->photoAlbumDao_.GetOrCreatePhotoAlbumForClone(albumInfo);
207 }
208 
209 /**
210  * @brief Find the lPath of the PhotoAlbum related to Photos from target database.
211  */
FindlPath(const FileInfo & fileInfo)212 std::string PhotosClone::FindlPath(const FileInfo &fileInfo)
213 {
214     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
215     return albumInfo.lPath;
216 }
217 
218 /**
219  * @brief Find the albumId of the PhotoAlbum related to Photos from target database.
220  */
FindAlbumId(const FileInfo & fileInfo)221 int32_t PhotosClone::FindAlbumId(const FileInfo &fileInfo)
222 {
223     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
224     bool cond = albumInfo.albumId > static_cast<int32_t>(PhotoAlbumId::DEFAULT) ||
225         (fileInfo.hidden == 0 && fileInfo.recycledTime == 0);
226     CHECK_AND_RETURN_RET(!cond, albumInfo.albumId);
227     return fileInfo.recycledTime != 0 ? static_cast<int32_t>(PhotoAlbumId::TRASH) :
228         static_cast<int32_t>(PhotoAlbumId::HIDDEN);
229 }
230 
231 /**
232  * @brief Find the packageName of the PhotoAlbum related to Photos from target database.
233  */
FindPackageName(const FileInfo & fileInfo)234 std::string PhotosClone::FindPackageName(const FileInfo &fileInfo)
235 {
236     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
237     // Only provide the package name of the existing SOURCE album.
238     CHECK_AND_RETURN_RET(albumInfo.IsValidSourceAlbum(), "");
239     return albumInfo.albumName;
240 }
241 
242 /**
243  * @brief Find the bundleName of the PhotoAlbum related to Photos from target database.
244  */
FindBundleName(const FileInfo & fileInfo)245 std::string PhotosClone::FindBundleName(const FileInfo &fileInfo)
246 {
247     PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
248     // Only provide the bundle name of the existing SOURCE album.
249     CHECK_AND_RETURN_RET(albumInfo.IsValidSourceAlbum(), "");
250     return albumInfo.bundleName;
251 }
252 
FindDuplicateBurstKey()253 std::vector<PhotosDao::PhotosRowData> PhotosClone::FindDuplicateBurstKey()
254 {
255     std::vector<PhotosDao::PhotosRowData> result;
256     std::string querySql = this->SQL_PHOTOS_TABLE_BURST_KEY_DUPLICATE_QUERY;
257     int rowCount = 0;
258     int offset = 0;
259     int pageSize = 200;
260     do {
261         std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
262         CHECK_AND_BREAK_ERR_LOG(this->mediaLibraryOriginalRdb_ != nullptr,
263             "Media_Restore: mediaLibraryOriginalRdb_ is null.");
264         auto resultSet = this->mediaLibraryTargetRdb_->QuerySql(querySql, bindArgs);
265         CHECK_AND_BREAK_ERR_LOG(resultSet != nullptr, "Query resultSql is null.");
266         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
267             PhotosDao::PhotosRowData info;
268             info.burstKey = GetStringVal("burst_key", resultSet);
269             info.ownerAlbumId = GetInt32Val("owner_album_id", resultSet);
270             result.emplace_back(info);
271         }
272         // Check if there are more rows to fetch.
273         resultSet->GetRowCount(rowCount);
274         offset += pageSize;
275         resultSet->Close();
276     } while (rowCount > 0);
277     return result;
278 }
279 
FindPhotoQuality(const FileInfo & fileInfo)280 int32_t PhotosClone::FindPhotoQuality(const FileInfo &fileInfo)
281 {
282     CHECK_AND_RETURN_RET(fileInfo.photoQuality != 1, 0);
283     return fileInfo.photoQuality;
284 }
285 
ToString(const std::vector<NativeRdb::ValueObject> & values)286 std::string PhotosClone::ToString(const std::vector<NativeRdb::ValueObject> &values)
287 {
288     std::vector<std::string> result;
289     for (auto &value : values) {
290         std::string str;
291         value.GetString(str);
292         result.emplace_back(str + ", ");
293     }
294     return std::accumulate(result.begin(), result.end(), std::string());
295 }
296 
297 /**
298  * @brief generate a uuid
299  *
300  * @return std::string uuid with 32 characters
301  */
GenerateUuid()302 std::string PhotosClone::GenerateUuid()
303 {
304     uuid_t uuid;
305     uuid_generate(uuid);
306     char str[UUID_STR_LENGTH] = {};
307     uuid_unparse(uuid, str);
308     return str;
309 }
310 
311 /**
312  * @brief Fix Duplicate burst_key in Photos, which is used in different PhotoAlbum.
313  */
FixDuplicateBurstKeyInDifferentAlbum(std::atomic<uint64_t> & totalNumber)314 int32_t PhotosClone::FixDuplicateBurstKeyInDifferentAlbum(std::atomic<uint64_t> &totalNumber)
315 {
316     std::vector<PhotosDao::PhotosRowData> duplicateBurstKeyList = this->FindDuplicateBurstKey();
317     totalNumber += static_cast<uint64_t>(duplicateBurstKeyList.size());
318     MEDIA_INFO_LOG("Media_Restore: onProcess Update otherTotalNumber_: %{public}lld", (long long)totalNumber);
319     std::string executeSql = this->SQL_PHOTOS_TABLE_BURST_KEY_UPDATE;
320     for (auto &info : duplicateBurstKeyList) {
321         CHECK_AND_CONTINUE(!info.burstKey.empty());
322         std::string burstKeyNew = this->GenerateUuid();
323         std::vector<NativeRdb::ValueObject> bindArgs = {burstKeyNew, info.ownerAlbumId, info.burstKey};
324         MEDIA_INFO_LOG("Media_Restore: executeSql = %{public}s, bindArgs=%{public}s",
325             executeSql.c_str(),
326             this->ToString(bindArgs).c_str());
327         CHECK_AND_BREAK_ERR_LOG(this->mediaLibraryOriginalRdb_ != nullptr,
328             "Media_Restore: mediaLibraryOriginalRdb_ is null.");
329         int32_t ret = this->mediaLibraryTargetRdb_->ExecuteSql(executeSql, bindArgs);
330         CHECK_AND_PRINT_LOG(ret == NativeRdb::E_OK,
331             "Media_Restore: FixDuplicateBurstKeyInDifferentAlbum failed,"
332             " ret=%{public}d, sql=%{public}s, bindArgs=%{public}s",
333             ret, executeSql.c_str(), this->ToString(bindArgs).c_str());
334     }
335     return 0;
336 }
337 
FindSourcePath(const FileInfo & fileInfo)338 std::string PhotosClone::FindSourcePath(const FileInfo &fileInfo)
339 {
340     CHECK_AND_RETURN_RET(!fileInfo.lPath.empty(), fileInfo.sourcePath);
341     CHECK_AND_RETURN_RET(fileInfo.sourcePath.empty(), fileInfo.sourcePath);
342     bool cond = (fileInfo.hidden == 0 && fileInfo.recycledTime == 0);
343     CHECK_AND_RETURN_RET(!cond, fileInfo.sourcePath);
344     return this->SOURCE_PATH_PREFIX + fileInfo.lPath + "/" + fileInfo.displayName;
345 }
346 
347 /**
348  * @brief Get Row Count of Photos No Need Migrate.
349  */
GetNoNeedMigrateCount()350 int32_t PhotosClone::GetNoNeedMigrateCount()
351 {
352     std::string querySql = this->SQL_PHOTOS_TABLE_COUNT_NO_NEED_MIGRATE;
353     CHECK_AND_RETURN_RET_LOG(this->mediaLibraryOriginalRdb_ != nullptr, 0,
354         "Media_Restore: mediaLibraryOriginalRdb_ is null.");
355     auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
356     CHECK_AND_RETURN_RET(resultSet != nullptr, 0);
357     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
358         resultSet->Close();
359         return 0;
360     }
361     int32_t count = GetInt32Val("count", resultSet);
362     return count;
363 }
364 }  // namespace OHOS::Media