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 
16 #define MLOG_TAG "MediaLibraryOthersCloneRestore"
17 
18 #include "others_clone_restore.h"
19 
20 #include <securec.h>
21 #include <dirent.h>
22 
23 #include "album_plugin_config.h"
24 #include "backup_database_utils.h"
25 #include "backup_file_utils.h"
26 #include "datashare_abs_result_set.h"
27 #include "directory_ex.h"
28 #include "ffrt.h"
29 #include "ffrt_inner.h"
30 #include "medialibrary_db_const.h"
31 #include "medialibrary_errno.h"
32 #include "media_file_utils.h"
33 #include "media_file_uri.h"
34 #include "media_log.h"
35 #include "media_scanner.h"
36 #include "medialibrary_rdb_transaction.h"
37 
38 namespace OHOS {
39 namespace Media {
40 const int PHONE_FIRST_NUMBER = 105;
41 const int PHONE_SECOND_NUMBER = 80;
42 const int PHONE_THIRD_NUMBER = 104;
43 const int PHONE_FOURTH_NUMBER = 111;
44 const int PHONE_FIFTH_NUMBER = 110;
45 const int PHONE_SIXTH_NUMBER = 101;
46 const int QUERY_NUMBER = 200;
47 constexpr int32_t MAX_CLONE_THREAD_NUM = 2;
48 constexpr int64_t SECONDS_LEVEL_LIMIT = 1e10;
49 const std::string I_PHONE_LPATH = "/Pictures/";
50 const std::string PHONE_TYPE = "type";
51 const std::string PHONE_DEVICE_TYPE = "deviceType";
52 const std::string PHONE_DETAIL = "detail";
53 const std::string PHOTO_DB_NAME = "photo_MediaInfo.db";
54 const std::string VIDEO_DB_NAME = "video_MediaInfo.db";
55 const std::string OTHER_CLONE_FILE_ROOT_PATH = "/storage/media/local/files/.backup/restore";
56 const std::string OTHER_CLONE_DB_PATH = "/storage/media/local/files/.backup/restore/storage/emulated/0/";
57 const std::string OTHER_CLONE_FILE_PATH = "/storage/media/local/files/.backup/restore/storage/emulated/";
58 const std::string OTHER_CLONE_DISPLAYNAME = "primaryStr";
59 const std::string OTHER_CLONE_DATA = "_data";
60 const std::string OTHER_CLONE_MODIFIED = "date_modified";
61 const std::string OTHER_CLONE_TAKEN = "datetaken";
62 const std::string OTHER_MUSIC_ROOT_PATH = "/storage/emulated/0/";
63 
GetPhoneName()64 static std::string GetPhoneName()
65 {
66     int arr[] = { PHONE_FIRST_NUMBER, PHONE_SECOND_NUMBER, PHONE_THIRD_NUMBER, PHONE_FOURTH_NUMBER, PHONE_FIFTH_NUMBER,
67         PHONE_SIXTH_NUMBER };
68     int len = sizeof(arr) / sizeof(arr[0]);
69     std::string phoneName = "";
70     for (int i = 0; i < len; i++) {
71         phoneName += static_cast<char>(arr[i]);
72     }
73     return phoneName;
74 }
75 
OthersCloneRestore(int32_t sceneCode,const std::string & mediaAppName,const std::string & bundleInfo)76 OthersCloneRestore::OthersCloneRestore(int32_t sceneCode, const std::string &mediaAppName,
77     const std::string &bundleInfo)
78 {
79     sceneCode_ = sceneCode;
80     mediaAppName_ = mediaAppName;
81     if (sceneCode_ == I_PHONE_CLONE_RESTORE) {
82         nlohmann::json jsonObj = nlohmann::json::parse(bundleInfo, nullptr, false);
83         if (jsonObj.is_discarded()) {
84             MEDIA_ERR_LOG("parse json failed");
85             clonePhoneName_ = GetPhoneName();
86             return;
87         }
88         for (auto &obj : jsonObj) {
89             if (obj.contains(PHONE_TYPE) && obj.at(PHONE_TYPE) == PHONE_DEVICE_TYPE) {
90                 clonePhoneName_ = obj.at(PHONE_DETAIL);
91             }
92         }
93         if (clonePhoneName_.empty()) {
94             MEDIA_ERR_LOG("read json error");
95             clonePhoneName_ = GetPhoneName();
96         }
97     }
98     MEDIA_INFO_LOG("Use ffrt without escape");
99 }
100 
CloneInfoPushBack(std::vector<CloneDbInfo> & pushInfos,std::vector<CloneDbInfo> & popInfos)101 void OthersCloneRestore::CloneInfoPushBack(std::vector<CloneDbInfo> &pushInfos, std::vector<CloneDbInfo> &popInfos)
102 {
103     std::lock_guard<std::mutex> guard(cloneMutex_);
104     for (auto &info : popInfos) {
105         pushInfos.push_back(info);
106     }
107 }
108 
HandleSelectBatch(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,int32_t offset,int32_t sceneCode,std::vector<CloneDbInfo> & mediaDbInfo)109 void OthersCloneRestore::HandleSelectBatch(std::shared_ptr<NativeRdb::RdbStore> mediaRdb, int32_t offset,
110     int32_t sceneCode, std::vector<CloneDbInfo> &mediaDbInfo)
111 {
112     MEDIA_INFO_LOG("start handle clone batch, offset: %{public}d", offset);
113     if (mediaRdb == nullptr) {
114         MEDIA_ERR_LOG("rdb is nullptr, Maybe init failed.");
115         return;
116     }
117     std::string queryExternalMayClonePhoto;
118     if (sceneCode == I_PHONE_CLONE_RESTORE) {
119         queryExternalMayClonePhoto = "SELECT primaryStr, date_modified, datetaken FROM mediainfo LIMIT " +
120             std::to_string(offset) + ", " + std::to_string(QUERY_NUMBER);
121     } else {
122         queryExternalMayClonePhoto = "SELECT _data, date_modified, datetaken FROM mediainfo LIMIT " +
123             std::to_string(offset) + ", " + std::to_string(QUERY_NUMBER);
124     }
125     auto resultSet = mediaRdb->QuerySql(queryExternalMayClonePhoto);
126     if (resultSet == nullptr) {
127         MEDIA_ERR_LOG("Query resultSql is null.");
128         return;
129     }
130     std::vector<CloneDbInfo> infos;
131     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
132         CloneDbInfo tmpDbInfo;
133         if (sceneCode == I_PHONE_CLONE_RESTORE) {
134             tmpDbInfo.displayName = GetStringVal(OTHER_CLONE_DISPLAYNAME, resultSet);
135             tmpDbInfo.dateModified = GetDoubleVal(OTHER_CLONE_MODIFIED, resultSet);
136             tmpDbInfo.dateTaken = GetDoubleVal(OTHER_CLONE_TAKEN, resultSet);
137         } else {
138             tmpDbInfo.data = GetStringVal(OTHER_CLONE_DATA, resultSet);
139             tmpDbInfo.dateModified = static_cast<double>(GetInt64Val(OTHER_CLONE_MODIFIED, resultSet));
140             tmpDbInfo.dateTaken = static_cast<double>(GetInt64Val(OTHER_CLONE_TAKEN, resultSet));
141         }
142         infos.push_back(tmpDbInfo);
143     };
144     CloneInfoPushBack(mediaDbInfo, infos);
145 }
146 
GetCloneDbInfos(const std::string & dbName,std::vector<CloneDbInfo> & mediaDbInfo)147 void OthersCloneRestore::GetCloneDbInfos(const std::string &dbName, std::vector<CloneDbInfo> &mediaDbInfo)
148 {
149     std::string dbPath = OTHER_CLONE_DB_PATH + dbName;
150     if (access(dbPath.c_str(), F_OK) != 0) {
151         MEDIA_ERR_LOG("Init rdb not exists, dbName = %{public}s", dbName.c_str());
152         return;
153     }
154     std::shared_ptr<NativeRdb::RdbStore> mediaRdb;
155     int32_t initErr = BackupDatabaseUtils::InitDb(mediaRdb, dbName, dbPath, mediaAppName_, false);
156     if (mediaRdb == nullptr) {
157         MEDIA_ERR_LOG("Init rdb fail, dbName = %{public}s, err = %{public}d", dbName.c_str(), initErr);
158         return;
159     }
160 
161     std::string selectTotalCloneMediaNumber = "SELECT count(1) AS count FROM mediainfo";
162     int32_t totalNumber = BackupDatabaseUtils::QueryInt(mediaRdb, selectTotalCloneMediaNumber, CUSTOM_COUNT);
163     MEDIA_INFO_LOG("dbName = %{public}s, totalNumber = %{public}d", dbName.c_str(), totalNumber);
164     ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_CLONE_THREAD_NUM);
165     for (int32_t offset = 0; offset < totalNumber; offset += QUERY_NUMBER) {
166         ffrt::submit([this, mediaRdb, offset, &mediaDbInfo]() {
167             HandleSelectBatch(mediaRdb, offset, sceneCode_, mediaDbInfo);
168             }, { &offset }, {}, ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
169     }
170     ffrt::wait();
171 }
172 
Init(const std::string & backupRetoreDir,const std::string & upgradeFilePath,bool isUpgrade)173 int32_t OthersCloneRestore::Init(const std::string &backupRetoreDir, const std::string &upgradeFilePath, bool isUpgrade)
174 {
175     if (BaseRestore::Init() != E_OK) {
176         MEDIA_ERR_LOG("GetBackupInfo init failed");
177         return E_FAIL;
178     }
179     if (mediaLibraryRdb_ == nullptr) {
180         MEDIA_ERR_LOG("GetBackupInfo Rdbstore is null");
181         return E_FAIL;
182     }
183     int64_t startGetInfo = MediaFileUtils::UTCTimeMilliSeconds();
184     GetCloneDbInfos(AUDIO_DB_NAME, audioDbInfo_);
185     GetCloneDbInfos(PHOTO_DB_NAME, photoDbInfo_);
186     GetCloneDbInfos(VIDEO_DB_NAME, photoDbInfo_);
187     int64_t startCurrent = MediaFileUtils::UTCTimeMilliSeconds();
188     int32_t err = GetAllfilesInCurrentDir(backupRestoreDir_);
189     if (err != E_OK) {
190         MEDIA_ERR_LOG("get all files err %{public}d", err);
191         return err;
192     }
193     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
194     MEDIA_INFO_LOG("GetCloneDb cost %{public}ld, recursively getting all files cost %{public}ld, phonesize:%{public}d, \
195         audiosize:%{public}d", (long)(startCurrent - startGetInfo), (long)(end - startCurrent),
196         (int)photoInfos_.size(), (int)audioInfos_.size());
197     this->photoAlbumDao_.SetMediaLibraryRdb(this->mediaLibraryRdb_);
198     this->photosRestore_.OnStart(this->mediaLibraryRdb_, nullptr);
199     MEDIA_INFO_LOG("Init end");
200     return E_OK;
201 }
202 
GetInsertValue(const FileInfo & fileInfo,const std::string & newPath,int32_t sourceType)203 NativeRdb::ValuesBucket OthersCloneRestore::GetInsertValue(const FileInfo &fileInfo, const std::string &newPath,
204     int32_t sourceType)
205 {
206     NativeRdb::ValuesBucket values;
207     values.PutString(MediaColumn::MEDIA_FILE_PATH, newPath);
208     values.PutString(MediaColumn::MEDIA_TITLE, fileInfo.title);
209     values.PutString(MediaColumn::MEDIA_NAME, fileInfo.displayName);
210     // use owner_album_id to mark the album id which the photo is in.
211     values.PutInt(PhotoColumn::PHOTO_OWNER_ALBUM_ID, fileInfo.ownerAlbumId);
212     // only SOURCE album has package_name and owner_package.
213     values.PutString(MediaColumn::MEDIA_PACKAGE_NAME, fileInfo.packageName);
214     values.PutString(MediaColumn::MEDIA_OWNER_PACKAGE, fileInfo.bundleName);
215     if (fileInfo.dateTaken != 0) {
216         values.PutLong(MediaColumn::MEDIA_DATE_TAKEN, fileInfo.dateTaken);
217         values.PutLong(MediaColumn::MEDIA_DATE_ADDED, fileInfo.dateTaken);
218     }
219     if (fileInfo.dateModified != 0) {
220         values.PutLong(MediaColumn::MEDIA_DATE_MODIFIED, fileInfo.dateModified);
221     }
222     return values;
223 }
224 
ParseSourcePathToPath(const std::string & sourcePath,const std::string & prefix)225 static std::string ParseSourcePathToPath(const std::string &sourcePath, const std::string &prefix)
226 {
227     size_t startPos = sourcePath.find(prefix);
228     std::string result = sourcePath;
229     if (startPos != std::string::npos) {
230         startPos += prefix.length();
231         result = sourcePath.substr(startPos, sourcePath.size() - startPos);
232     }
233     return result;
234 }
235 
SetFileInfosInCurrentDir(const std::string & file,struct stat & statInfo)236 void OthersCloneRestore::SetFileInfosInCurrentDir(const std::string &file, struct stat &statInfo)
237 {
238     FileInfo tmpInfo;
239     tmpInfo.filePath = file;
240     tmpInfo.displayName = ExtractFileName(file);
241     tmpInfo.title = BackupFileUtils::GetFileTitle(tmpInfo.displayName);
242     tmpInfo.fileType = MediaFileUtils::GetMediaType(tmpInfo.displayName);
243     tmpInfo.fileSize = statInfo.st_size;
244     tmpInfo.dateModified = MediaFileUtils::Timespec2Millisecond(statInfo.st_mtim);
245     if (tmpInfo.fileType  == MediaType::MEDIA_TYPE_IMAGE || tmpInfo.fileType  == MediaType::MEDIA_TYPE_VIDEO) {
246         UpDateFileModifiedTime(tmpInfo);
247         photoInfos_.emplace_back(tmpInfo);
248     } else if (tmpInfo.fileType  == MediaType::MEDIA_TYPE_AUDIO) {
249         UpDateFileModifiedTime(tmpInfo);
250         tmpInfo.relativePath = ParseSourcePathToPath(tmpInfo.filePath, OTHER_MUSIC_ROOT_PATH);
251         if (tmpInfo.relativePath == tmpInfo.filePath) {
252             tmpInfo.relativePath = ParseSourcePathToPath(tmpInfo.filePath, OTHER_CLONE_FILE_ROOT_PATH);
253         }
254         audioInfos_.emplace_back(tmpInfo);
255     } else {
256         tmpInfo.fileType = MediaFileUtils::GetMediaTypeNotSupported(tmpInfo.displayName);
257         if (tmpInfo.fileType  == MediaType::MEDIA_TYPE_IMAGE || tmpInfo.fileType  == MediaType::MEDIA_TYPE_VIDEO) {
258             UpDateFileModifiedTime(tmpInfo);
259             photoInfos_.emplace_back(tmpInfo);
260             MEDIA_WARN_LOG("Not supported media %{public}s", BackupFileUtils::GarbleFilePath(file, sceneCode_).c_str());
261         } else {
262             MEDIA_WARN_LOG("Not supported file %{public}s", BackupFileUtils::GarbleFilePath(file, sceneCode_).c_str());
263         }
264     }
265 }
266 
UpDateFileModifiedTime(FileInfo & fileInfo)267 void OthersCloneRestore::UpDateFileModifiedTime(FileInfo &fileInfo)
268 {
269     auto pathMatch = [displayName {fileInfo.displayName}, filePath {fileInfo.filePath},
270         sceneCode {sceneCode_}](const auto &info) {
271         if (sceneCode == I_PHONE_CLONE_RESTORE) {
272             return info.displayName == displayName;
273         } else {
274             return info.data == ParseSourcePathToPath(filePath, OTHER_CLONE_FILE_ROOT_PATH);
275         }
276     };
277     CloneDbInfo info;
278     if (fileInfo.fileType == MediaType::MEDIA_TYPE_AUDIO) {
279         auto it = std::find_if(audioDbInfo_.begin(), audioDbInfo_.end(), pathMatch);
280         if (it != audioDbInfo_.end()) {
281             info.dateModified = it->dateModified;
282             info.dateTaken = it->dateTaken;
283         } else {
284             return;
285         }
286     } else if (fileInfo.fileType  == MediaType::MEDIA_TYPE_IMAGE || fileInfo.fileType  == MediaType::MEDIA_TYPE_VIDEO) {
287         auto it = std::find_if(photoDbInfo_.begin(), photoDbInfo_.end(), pathMatch);
288         if (it != photoDbInfo_.end()) {
289             info.dateModified = it->dateModified;
290             info.dateTaken = it->dateTaken;
291         } else {
292             auto it = std::find_if(audioDbInfo_.begin(), audioDbInfo_.end(), pathMatch);
293             if (it != audioDbInfo_.end()) {
294                 MEDIA_WARN_LOG("find video in audio info map %{public}s", fileInfo.displayName.c_str());
295                 info.dateModified = it->dateModified;
296                 info.dateTaken = it->dateTaken;
297             }
298         }
299     } else {
300         MEDIA_WARN_LOG("Not supported file %{public}s", fileInfo.displayName.c_str());
301         return;
302     }
303     if (info.dateModified < SECONDS_LEVEL_LIMIT) {
304         info.dateModified = info.dateModified * static_cast<double>(MSEC_TO_SEC);
305     }
306     if (info.dateTaken < SECONDS_LEVEL_LIMIT) {
307         info.dateTaken = info.dateTaken * static_cast<double>(MSEC_TO_SEC);
308     }
309     fileInfo.dateModified = static_cast<int64_t>(info.dateModified);
310     fileInfo.dateTaken = static_cast<int64_t>(info.dateTaken);
311     BackupFileUtils::ModifyFile(fileInfo.filePath, fileInfo.dateModified / MSEC_TO_SEC);
312 }
313 
GetAllfilesInCurrentDir(const std::string & path)314 int32_t OthersCloneRestore::GetAllfilesInCurrentDir(const std::string &path)
315 {
316     int err = E_OK;
317     DIR *dirPath = nullptr;
318     struct dirent *currentFile = nullptr;
319     size_t len = path.length();
320     struct stat statInfo;
321 
322     if (len >= FILENAME_MAX - 1) {
323         return ERR_INCORRECT_PATH;
324     }
325     auto fName = (char *)calloc(FILENAME_MAX, sizeof(char));
326     if (fName == nullptr) {
327         return ERR_MEM_ALLOC_FAIL;
328     }
329     if (strcpy_s(fName, FILENAME_MAX, path.c_str()) != ERR_SUCCESS) {
330         FREE_MEMORY_AND_SET_NULL(fName);
331         return ERR_MEM_ALLOC_FAIL;
332     }
333     fName[len++] = '/';
334     if ((dirPath = opendir(path.c_str())) == nullptr) {
335         FREE_MEMORY_AND_SET_NULL(fName);
336         MEDIA_ERR_LOG("Failed to opendir %{private}s, errno %{private}d", path.c_str(), errno);
337         return ERR_NOT_ACCESSIBLE;
338     }
339 
340     while ((currentFile = readdir(dirPath)) != nullptr) {
341         if (!strcmp(currentFile->d_name, ".") || !strcmp(currentFile->d_name, "..")) {
342             continue;
343         }
344         if (strncpy_s(fName + len, FILENAME_MAX - len, currentFile->d_name, FILENAME_MAX - len)) {
345             MEDIA_ERR_LOG("Failed to copy file name %{private}s ", fName);
346             continue;
347         }
348         if (lstat(fName, &statInfo) == -1) {
349             MEDIA_ERR_LOG("Failed to get info of directory %{private}s ", fName);
350             continue;
351         }
352         std::string currentPath = fName;
353         if (S_ISDIR(statInfo.st_mode)) {
354             (void)GetAllfilesInCurrentDir(currentPath);
355         } else if (S_ISREG(statInfo.st_mode)) {
356             SetFileInfosInCurrentDir(fName, statInfo);
357         } else {
358             MEDIA_INFO_LOG("Not directory or regular file, name is %{private}s", fName);
359         }
360     }
361     closedir(dirPath);
362     dirPath = nullptr;
363     FREE_MEMORY_AND_SET_NULL(fName);
364     return err;
365 }
366 
HandleInsertBatch(int32_t offset)367 void OthersCloneRestore::HandleInsertBatch(int32_t offset)
368 {
369     int32_t totalNumber = std::min(static_cast<int32_t>(photoInfos_.size()),
370         static_cast<int32_t>(offset + QUERY_NUMBER));
371     vector<FileInfo> insertInfos;
372     for (offset; offset < totalNumber; offset++) {
373         FileInfo info = photoInfos_[offset];
374         if (info.fileType != MediaType::MEDIA_TYPE_IMAGE && info.fileType != MediaType::MEDIA_TYPE_VIDEO) {
375             MEDIA_WARN_LOG("photo info error : %{public}s", info.displayName.c_str());
376             continue;
377         }
378         UpdateAlbumInfo(info);
379         insertInfos.push_back(info);
380     }
381     InsertPhoto(insertInfos);
382 }
383 
RestorePhoto()384 void OthersCloneRestore::RestorePhoto()
385 {
386     if (!photoInfos_.size()) {
387         MEDIA_INFO_LOG("photo infos size zero");
388         return;
389     }
390     std::vector<FileInfo> fileInfos;
391     totalNumber_ += photoInfos_.size();
392     RestoreAlbum(photoInfos_);
393     unsigned long pageSize = 200;
394     vector<FileInfo> insertInfos;
395     int32_t totalNumber = static_cast<int32_t>(photoInfos_.size());
396     ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_CLONE_THREAD_NUM);
397     for (int32_t offset = 0; offset < totalNumber; offset += QUERY_NUMBER) {
398         ffrt::submit([this, offset]() {
399             HandleInsertBatch(offset);
400             }, { &offset }, {}, ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
401     }
402     ffrt::wait();
403 }
404 
InsertPhoto(std::vector<FileInfo> & fileInfos)405 void OthersCloneRestore::InsertPhoto(std::vector<FileInfo> &fileInfos)
406 {
407     int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
408     vector<NativeRdb::ValuesBucket> values = BaseRestore::GetInsertValues(sceneCode_, fileInfos, SourceType::PHOTOS);
409     int64_t startInsert = MediaFileUtils::UTCTimeMilliSeconds();
410     int64_t rowNum = 0;
411     int32_t errCode = BatchInsertWithRetry(PhotoColumn::PHOTOS_TABLE, values, rowNum);
412     if (errCode != E_OK) {
413         MEDIA_ERR_LOG("BatchInsert fail err %{public}d", errCode);
414         UpdateFailedFiles(fileInfos, RestoreError::INSERT_FAILED);
415         return;
416     }
417 
418     int64_t startMove = MediaFileUtils::UTCTimeMilliSeconds();
419     migrateDatabaseNumber_ += rowNum;
420     int32_t fileMoveCount = 0;
421     int32_t videoFileMoveCount = 0;
422     MoveMigrateFile(fileInfos, fileMoveCount, videoFileMoveCount, sceneCode_);
423     int64_t startUpdate = MediaFileUtils::UTCTimeMilliSeconds();
424     UpdatePhotosByFileInfoMap(mediaLibraryRdb_, fileInfos);
425     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
426     MEDIA_INFO_LOG("generate values cost %{public}ld, insert %{public}ld assets cost %{public}ld"
427         ", and move %{public}ld files (%{public}ld + %{public}ld) cost %{public}ld. update cost %{public}ld",
428         (long)(startInsert - start), (long)rowNum, (long)(startMove - startInsert),
429         (long)fileMoveCount, (long)(fileMoveCount - videoFileMoveCount),
430         (long)videoFileMoveCount, (long)(startUpdate - startMove), (long)(end - startUpdate));
431 }
432 
NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)433 bool OthersCloneRestore::NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> &fileInfos,
434     NeedQueryMap &needQueryMap)
435 {
436     return true;
437 }
438 
RestoreAudio()439 void OthersCloneRestore::RestoreAudio()
440 {
441     MEDIA_INFO_LOG("restore audio");
442     if (sceneCode_ == I_PHONE_CLONE_RESTORE) {
443         MEDIA_INFO_LOG("No need move audio");
444         return;
445     }
446     if (!audioInfos_.size()) {
447         MEDIA_INFO_LOG("audio infos size zero");
448         return;
449     }
450     audioTotalNumber_ += audioInfos_.size();
451     int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
452     InsertAudio(sceneCode_, audioInfos_);
453     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
454     MEDIA_INFO_LOG("generate values cost %{public}ld, insert audio %{public}ld",
455         (long)(end - start), (long)audioTotalNumber_);
456 }
457 
HandleRestData()458 void OthersCloneRestore::HandleRestData()
459 {
460     MEDIA_INFO_LOG("Start to handle rest data in native.");
461     RestoreThumbnail();
462 }
463 
ParseSourcePathToLPath(int32_t sceneCode,const std::string & filePath)464 static std::string ParseSourcePathToLPath(int32_t sceneCode, const std::string &filePath)
465 {
466     std::string lPath = filePath;
467     std::string source = OTHER_CLONE_FILE_PATH;
468     auto findPos = lPath.find(source);
469     if (findPos != std::string::npos) {
470         lPath.replace(lPath.find(source), source.length(), "");
471     } else {
472         MEDIA_WARN_LOG("find other clone path error path: %{public}s",
473             BackupFileUtils::GarbleFilePath(filePath, sceneCode).c_str());
474         source = OTHER_CLONE_FILE_ROOT_PATH;
475         findPos = lPath.find(source);
476         if (findPos != std::string::npos) {
477             lPath.replace(lPath.find(source), source.length(), "");
478         }
479     }
480     std::size_t startPos = lPath.find_first_of(FILE_SEPARATOR);
481     if (startPos != std::string::npos) {
482         lPath = lPath.substr(startPos);
483     }
484     std::size_t pos = lPath.find_last_of(FILE_SEPARATOR);
485     if (pos != std::string::npos) {
486         lPath = lPath.substr(0, pos);
487     } else {
488         MEDIA_WARN_LOG("find error path is: %{public}s",
489             BackupFileUtils::GarbleFilePath(filePath, sceneCode).c_str());
490         lPath = FILE_SEPARATOR;
491     }
492     if (lPath.empty()) {
493         MEDIA_WARN_LOG("find path is empty: %{public}s",
494             BackupFileUtils::GarbleFilePath(filePath, sceneCode).c_str());
495         lPath = FILE_SEPARATOR;
496     }
497     return lPath;
498 }
499 
AddGalleryAlbum(std::vector<PhotoAlbumRestore::GalleryAlbumRowData> & galleryAlbumInfos,const std::string & lPath)500 static void AddGalleryAlbum(std::vector<PhotoAlbumRestore::GalleryAlbumRowData> &galleryAlbumInfos,
501     const std::string &lPath)
502 {
503     auto pathMatch = [lPath {lPath}](const auto &galleryAlbumInfo) {
504         return galleryAlbumInfo.lPath == lPath;
505     };
506     auto it = std::find_if(galleryAlbumInfos.begin(), galleryAlbumInfos.end(), pathMatch);
507     if (it != galleryAlbumInfos.end()) {
508         return;
509     }
510 
511     PhotoAlbumRestore::GalleryAlbumRowData galleryAlbum;
512     std::size_t pos = lPath.find_last_of(FILE_SEPARATOR);
513     if (pos != std::string::npos) {
514         galleryAlbum.albumName = lPath.substr(pos + 1);
515     } else {
516         galleryAlbum.albumName = lPath;
517     }
518     galleryAlbum.lPath = lPath;
519     galleryAlbum.priority = 1;
520     galleryAlbumInfos.emplace_back(galleryAlbum);
521 }
522 
ParseResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info,std::string dbName)523 bool OthersCloneRestore::ParseResultSet(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info,
524     std::string dbName)
525 {
526     return true;
527 }
528 
ParseResultSetForAudio(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info)529 bool OthersCloneRestore::ParseResultSetForAudio(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info)
530 {
531     return true;
532 }
533 
RestoreAlbum(std::vector<FileInfo> & fileInfos)534 void OthersCloneRestore::RestoreAlbum(std::vector<FileInfo> &fileInfos)
535 {
536     std::vector<PhotoAlbumDao::PhotoAlbumRowData> albumInfos = this->photoAlbumDao_.GetPhotoAlbums();
537     std::vector<PhotoAlbumRestore::GalleryAlbumRowData> galleryAlbumInfos;
538     if (sceneCode_ == I_PHONE_CLONE_RESTORE) {
539         PhotoAlbumRestore::GalleryAlbumRowData galleryAlbum;
540         galleryAlbum.albumName = clonePhoneName_;
541         galleryAlbum.bundleName = clonePhoneName_;
542         galleryAlbum.lPath = I_PHONE_LPATH + clonePhoneName_;
543         galleryAlbum.priority = 1;
544         galleryAlbumInfos.emplace_back(galleryAlbum);
545     } else if (sceneCode_ == OTHERS_PHONE_CLONE_RESTORE) {
546         for (auto &info : fileInfos) {
547             info.lPath = ParseSourcePathToLPath(sceneCode_, info.filePath);
548             AddGalleryAlbum(galleryAlbumInfos, info.lPath);
549         }
550     }
551     std::vector<PhotoAlbumDao::PhotoAlbumRowData> albumInfosToRestore =
552         photoAlbumRestore_.GetAlbumsToRestore(albumInfos, galleryAlbumInfos);
553     auto ret =  photoAlbumDao_.RestoreAlbums(albumInfosToRestore);
554     if (ret != NativeRdb::E_OK) {
555         MEDIA_ERR_LOG("Failed to RestoreAlbums : %{public}d", ret);
556     }
557 }
558 
HasSameFileForDualClone(FileInfo & fileInfo)559 bool OthersCloneRestore::HasSameFileForDualClone(FileInfo &fileInfo)
560 {
561     PhotosDao::PhotosRowData rowData = this->photosRestore_.FindSameFile(fileInfo);
562     int32_t fileId = rowData.fileId;
563     std::string cloudPath = rowData.data;
564     if (fileId <= 0 || cloudPath.empty()) {
565         return false;
566     }
567     fileInfo.isNew = false;
568     fileInfo.fileIdNew = fileId;
569     fileInfo.cloudPath = cloudPath;
570     bool isInCloud = rowData.cleanFlag == 1 && rowData.position == static_cast<int32_t>(PhotoPositionType::CLOUD);
571     // If the file was in cloud previously, only require update flags.
572     if (fileId > 0 && isInCloud) {
573         fileInfo.updateMap["clean_flag"] = "0";
574         fileInfo.updateMap["position"] = to_string(static_cast<int32_t>(PhotoPositionType::LOCAL_AND_CLOUD));
575         return false;
576     }
577     fileInfo.needMove = false;
578     return true;
579 }
580 
ToLower(const std::string & str)581 static std::string ToLower(const std::string &str)
582 {
583     std::string lowerStr;
584     std::transform(
585         str.begin(), str.end(), std::back_inserter(lowerStr), [](unsigned char c) { return std::tolower(c); });
586     return lowerStr;
587 }
588 
FindAlbumInfo(FileInfo & fileInfo)589 PhotoAlbumDao::PhotoAlbumRowData OthersCloneRestore::FindAlbumInfo(FileInfo &fileInfo)
590 {
591     PhotoAlbumDao::PhotoAlbumRowData albumInfo;
592     if (fileInfo.lPath.empty()) {
593         MEDIA_ERR_LOG("others clone lPath is empty, path: %{public}s",
594             BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode_).c_str());
595         return albumInfo;
596     }
597     if (ToLower(fileInfo.lPath) == ToLower(AlbumPlugin::LPATH_SCREEN_SHOTS) &&
598         fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
599         albumInfo = this->photoAlbumDao_.BuildAlbumInfoOfRecorders();
600         albumInfo = this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
601         MEDIA_INFO_LOG(
602             "others clone: screenshots redirect to screenrecords, path: %{public}s",
603             BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode_).c_str());
604         fileInfo.lPath = AlbumPlugin::LPATH_SCREEN_RECORDS;
605         return albumInfo;
606     }
607     albumInfo = this->photoAlbumDao_.GetPhotoAlbum(fileInfo.lPath);
608     if (albumInfo.lPath.empty()) {
609         MEDIA_ERR_LOG("others clone: albumInfo is empty, path: %{public}s",
610             BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode_).c_str());
611     }
612     return albumInfo;
613 }
614 
UpdateAlbumInfo(FileInfo & info)615 void OthersCloneRestore::UpdateAlbumInfo(FileInfo &info)
616 {
617     if (sceneCode_ == I_PHONE_CLONE_RESTORE) {
618         PhotoAlbumDao::PhotoAlbumRowData albumInfo = photoAlbumDao_.GetPhotoAlbum(I_PHONE_LPATH + clonePhoneName_);
619         info.lPath = I_PHONE_LPATH + clonePhoneName_;
620         info.mediaAlbumId = albumInfo.albumId;
621         info.ownerAlbumId = albumInfo.albumId;
622         info.packageName = clonePhoneName_;
623         info.bundleName = clonePhoneName_;
624     } else if (sceneCode_ == OTHERS_PHONE_CLONE_RESTORE) {
625         PhotoAlbumDao::PhotoAlbumRowData albumInfo = FindAlbumInfo(info);
626         info.mediaAlbumId = albumInfo.albumId;
627         info.ownerAlbumId = albumInfo.albumId;
628     }
629 }
630 
AnalyzeSource()631 void OthersCloneRestore::AnalyzeSource()
632 {
633     MEDIA_INFO_LOG("analyze source later");
634 }
635 
636 } // namespace Media
637 } // namespace OHOS
638