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