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 if (this->mediaLibraryOriginalRdb_ == nullptr) {
51 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
52 return 0;
53 }
54 auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
55 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
56 return 0;
57 }
58 return GetInt32Val("count", resultSet);
59 }
60
61 /**
62 * @brief Get Row Count of Photos not in Album.
63 */
GetPhotosRowCountNotInPhotoMap()64 int32_t PhotosClone::GetPhotosRowCountNotInPhotoMap()
65 {
66 std::string querySql = this->SQL_PHOTOS_TABLE_COUNT_NOT_IN_PHOTO_MAP;
67 if (this->mediaLibraryOriginalRdb_ == nullptr) {
68 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
69 return 0;
70 }
71 auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
72 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
73 return 0;
74 }
75 return GetInt32Val("count", resultSet);
76 }
77
78 /**
79 * @brief Query the Photos Info, which is in PhotoAlbum, from the Original MediaLibrary Database.
80 */
GetPhotosInPhotoMap(int32_t offset,int32_t pageSize)81 std::shared_ptr<NativeRdb::ResultSet> PhotosClone::GetPhotosInPhotoMap(int32_t offset, int32_t pageSize)
82 {
83 std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
84 if (this->mediaLibraryOriginalRdb_ == nullptr) {
85 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
86 return nullptr;
87 }
88 return this->mediaLibraryOriginalRdb_->QuerySql(this->SQL_PHOTOS_TABLE_QUERY_IN_PHOTO_MAP, bindArgs);
89 }
90
91 /**
92 * @brief Query the Photos Info, which is not in PhotoAlbum, from the Original MediaLibrary Database.
93 */
GetPhotosNotInPhotoMap(int32_t offset,int32_t pageSize)94 std::shared_ptr<NativeRdb::ResultSet> PhotosClone::GetPhotosNotInPhotoMap(int32_t offset, int32_t pageSize)
95 {
96 std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
97 if (this->mediaLibraryOriginalRdb_ == nullptr) {
98 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
99 return nullptr;
100 }
101 return this->mediaLibraryOriginalRdb_->QuerySql(this->SQL_PHOTOS_TABLE_QUERY_NOT_IN_PHOTO_MAP, bindArgs);
102 }
103
104 /**
105 * @note If the lPath is empty, return '/Pictures/其它' string.
106 * If the lPath is '/Pictures/ScreenShots', return '/Pictures/ScreenShots' string.
107 * Otherwise, return the lPath of the FileInfo.
108 */
FindAlbumInfo(const FileInfo & fileInfo)109 PhotoAlbumDao::PhotoAlbumRowData PhotosClone::FindAlbumInfo(const FileInfo &fileInfo)
110 {
111 PhotoAlbumDao::PhotoAlbumRowData albumInfo;
112 std::string lPath = fileInfo.lPath;
113 // Scenario 2, WHEN FileInfo is in hidden album, THEN override lPath to the folder in sourcePath.
114 // Scenario 3, WHEN FileInfo is not belongs to any album, THEN override lPath to the folder in sourcePath.
115 // Note, sourcePath is a sign of the possible scenaio that the file is not in any album.
116 bool islPathMiss = !fileInfo.sourcePath.empty() && (fileInfo.hidden == 1 || fileInfo.recycledTime != 0);
117 islPathMiss = islPathMiss || fileInfo.lPath.empty();
118 if (islPathMiss) {
119 lPath = this->photoAlbumDao_.ParseSourcePathToLPath(fileInfo.sourcePath);
120 MEDIA_INFO_LOG("Media_Restore: fix lPath of album.fileInfo.lPath: %{public}s, "
121 "lPathFromSourcePath: %{public}s, lowercase: %{public}s, FileInfo Object: %{public}s",
122 fileInfo.lPath.c_str(),
123 lPath.c_str(),
124 this->ToLower(lPath).c_str(),
125 this->ToString(fileInfo).c_str());
126 }
127 // Scenario 1, WHEN FileInfo is in /Pictures/Screenshots and Video type, THEN redirect to /Pictures/Screenrecords
128 if (this->ToLower(lPath) == this->ToLower(AlbumPlugin::LPATH_SCREEN_SHOTS) &&
129 fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
130 albumInfo = this->photoAlbumDao_.BuildAlbumInfoOfRecorders();
131 albumInfo = this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
132 MEDIA_INFO_LOG("Media_Restore: screenshots redirect to screenrecords, fileInfo.lPath: %{public}s, "
133 "lPath: %{public}s, Object: %{public}s, albumInfo: %{public}s",
134 fileInfo.lPath.c_str(),
135 lPath.c_str(),
136 this->ToString(fileInfo).c_str(),
137 this->photoAlbumDao_.ToString(albumInfo).c_str());
138 return albumInfo;
139 }
140 albumInfo = this->photoAlbumDao_.BuildAlbumInfoByLPath(lPath);
141 return this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
142 }
143
144 /**
145 * @brief Find the lPath of the PhotoAlbum related to Photos from target database.
146 */
FindlPath(const FileInfo & fileInfo)147 std::string PhotosClone::FindlPath(const FileInfo &fileInfo)
148 {
149 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
150 return albumInfo.lPath;
151 }
152
153 /**
154 * @brief Find the albumId of the PhotoAlbum related to Photos from target database.
155 */
FindAlbumId(const FileInfo & fileInfo)156 int32_t PhotosClone::FindAlbumId(const FileInfo &fileInfo)
157 {
158 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
159 return albumInfo.albumId;
160 }
161
162 /**
163 * @brief Find the packageName of the PhotoAlbum related to Photos from target database.
164 */
FindPackageName(const FileInfo & fileInfo)165 std::string PhotosClone::FindPackageName(const FileInfo &fileInfo)
166 {
167 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
168 // Only provide the package name of the SOURCE album.
169 if (albumInfo.albumType != static_cast<int32_t>(PhotoAlbumType::SOURCE) ||
170 albumInfo.albumSubType != static_cast<int32_t>(PhotoAlbumSubType::SOURCE_GENERIC)) {
171 return "";
172 }
173 return albumInfo.albumName;
174 }
175
176 /**
177 * @brief Find the bundleName of the PhotoAlbum related to Photos from target database.
178 */
FindBundleName(const FileInfo & fileInfo)179 std::string PhotosClone::FindBundleName(const FileInfo &fileInfo)
180 {
181 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
182 // Only provide the bundle name of the SOURCE album.
183 if (albumInfo.albumType != static_cast<int32_t>(PhotoAlbumType::SOURCE) ||
184 albumInfo.albumSubType != static_cast<int32_t>(PhotoAlbumSubType::SOURCE_GENERIC)) {
185 return "";
186 }
187 return albumInfo.bundleName;
188 }
189
FindDuplicateBurstKey()190 std::vector<PhotosDao::PhotosRowData> PhotosClone::FindDuplicateBurstKey()
191 {
192 std::vector<PhotosDao::PhotosRowData> result;
193 std::string querySql = this->SQL_PHOTOS_TABLE_BURST_KEY_DUPLICATE_QUERY;
194 int rowCount = 0;
195 int offset = 0;
196 int pageSize = 200;
197 do {
198 std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
199 if (this->mediaLibraryOriginalRdb_ == nullptr) {
200 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
201 break;
202 }
203 auto resultSet = this->mediaLibraryTargetRdb_->QuerySql(querySql, bindArgs);
204 if (resultSet == nullptr) {
205 MEDIA_ERR_LOG("Query resultSql is null.");
206 break;
207 }
208 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
209 PhotosDao::PhotosRowData info;
210 info.burstKey = GetStringVal("burst_key", resultSet);
211 info.ownerAlbumId = GetInt32Val("owner_album_id", resultSet);
212 result.emplace_back(info);
213 }
214 // Check if there are more rows to fetch.
215 resultSet->GetRowCount(rowCount);
216 offset += pageSize;
217 } while (rowCount > 0);
218 return result;
219 }
220
FindPhotoQuality(const FileInfo & fileInfo)221 int32_t PhotosClone::FindPhotoQuality(const FileInfo &fileInfo)
222 {
223 if (fileInfo.photoQuality == 1 && fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
224 return 0;
225 }
226 return fileInfo.photoQuality;
227 }
228
ToString(const std::vector<NativeRdb::ValueObject> & values)229 std::string PhotosClone::ToString(const std::vector<NativeRdb::ValueObject> &values)
230 {
231 std::vector<std::string> result;
232 for (auto &value : values) {
233 std::string str;
234 value.GetString(str);
235 result.emplace_back(str + ", ");
236 }
237 return std::accumulate(result.begin(), result.end(), std::string());
238 }
239
240 /**
241 * @brief generate a uuid
242 *
243 * @return std::string uuid with 32 characters
244 */
GenerateUuid()245 std::string PhotosClone::GenerateUuid()
246 {
247 uuid_t uuid;
248 uuid_generate(uuid);
249 char str[UUID_STR_LENGTH] = {};
250 uuid_unparse(uuid, str);
251 return str;
252 }
253
254 /**
255 * @brief Fix Duplicate burst_key in Photos, which is used in different PhotoAlbum.
256 */
FixDuplicateBurstKeyInDifferentAlbum(std::atomic<uint64_t> & totalNumber)257 int32_t PhotosClone::FixDuplicateBurstKeyInDifferentAlbum(std::atomic<uint64_t> &totalNumber)
258 {
259 std::vector<PhotosDao::PhotosRowData> duplicateBurstKeyList = this->FindDuplicateBurstKey();
260 totalNumber += static_cast<uint64_t>(duplicateBurstKeyList.size());
261 MEDIA_INFO_LOG("Media_Restore: onProcess Update otherTotalNumber_: %{public}lld", (long long)totalNumber);
262 std::string executeSql = this->SQL_PHOTOS_TABLE_BURST_KEY_UPDATE;
263 for (auto &info : duplicateBurstKeyList) {
264 if (info.burstKey.empty()) {
265 continue;
266 }
267 std::string burstKeyNew = this->GenerateUuid();
268 std::vector<NativeRdb::ValueObject> bindArgs = {burstKeyNew, info.ownerAlbumId, info.burstKey};
269 MEDIA_INFO_LOG("Media_Restore: executeSql = %{public}s, bindArgs=%{public}s",
270 executeSql.c_str(),
271 this->ToString(bindArgs).c_str());
272 if (this->mediaLibraryOriginalRdb_ == nullptr) {
273 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
274 break;
275 }
276 int32_t ret = this->mediaLibraryTargetRdb_->ExecuteSql(executeSql, bindArgs);
277 if (ret != NativeRdb::E_OK) {
278 MEDIA_ERR_LOG("Media_Restore: FixDuplicateBurstKeyInDifferentAlbum failed,"
279 " ret=%{public}d, sql=%{public}s, bindArgs=%{public}s",
280 ret,
281 executeSql.c_str(),
282 this->ToString(bindArgs).c_str());
283 }
284 }
285 return 0;
286 }
287
FindSourcePath(const FileInfo & fileInfo)288 std::string PhotosClone::FindSourcePath(const FileInfo &fileInfo)
289 {
290 if (fileInfo.lPath.empty()) {
291 return fileInfo.sourcePath;
292 }
293 if (!fileInfo.sourcePath.empty()) {
294 return fileInfo.sourcePath;
295 }
296 if (fileInfo.hidden == 0 && fileInfo.recycledTime == 0) {
297 return fileInfo.sourcePath;
298 }
299 return this->SOURCE_PATH_PREFIX + fileInfo.lPath + "/" + fileInfo.displayName;
300 }
301
302 /**
303 * @brief Get Row Count of Photos No Need Migrate.
304 */
GetNoNeedMigrateCount()305 int32_t PhotosClone::GetNoNeedMigrateCount()
306 {
307 std::string querySql = this->SQL_PHOTOS_TABLE_COUNT_NO_NEED_MIGRATE;
308 if (this->mediaLibraryOriginalRdb_ == nullptr) {
309 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
310 return 0;
311 }
312 auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
313 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
314 return 0;
315 }
316 return GetInt32Val("count", resultSet);
317 }
318 } // namespace OHOS::Media