• 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 
16 #define MLOG_TAG "MediaLibraryOthersCloneRestore"
17 
18 #include "others_clone_restore.h"
19 
20 #include <securec.h>
21 #include <dirent.h>
22 #include <regex>
23 #include <charconv>
24 
25 #include "album_plugin_config.h"
26 #include "backup_const_column.h"
27 #include "backup_database_utils.h"
28 #include "backup_file_utils.h"
29 #include "datashare_abs_result_set.h"
30 #include "database_report.h"
31 #include "directory_ex.h"
32 #include "ffrt.h"
33 #include "ffrt_inner.h"
34 #include "medialibrary_db_const.h"
35 #include "medialibrary_errno.h"
36 #include "media_file_utils.h"
37 #include "media_file_uri.h"
38 #include "media_log.h"
39 #include "media_scanner.h"
40 #include "medialibrary_rdb_transaction.h"
41 #include "upgrade_restore_task_report.h"
42 
43 namespace OHOS {
44 namespace Media {
45 const int BASE32_CHAR_BITS = 5;
46 const int BASE32_BYTE_BITS = 8;
47 const int PRE_ALLOC_PHOTOMAP_VECTOR = 100000;
48 const int PRE_ALLOC_AUDIOMAP_VECTOR = 10000;
49 const int PRE_ALLOC_PHOTO_VECTOR = 10000;
50 const int PRE_ALLOC_AUDIO_VECTOR = 1000;
51 const int BATCHES_CHUNK_NUMBER = 5000;
52 const int PHONE_FIRST_NUMBER = 105;
53 const int PHONE_SECOND_NUMBER = 80;
54 const int PHONE_THIRD_NUMBER = 104;
55 const int PHONE_FOURTH_NUMBER = 111;
56 const int PHONE_FIFTH_NUMBER = 110;
57 const int PHONE_SIXTH_NUMBER = 101;
58 const int QUERY_NUMBER = 200;
59 const int STRONG_ASSOCIATION_ENABLE = 1;
60 constexpr int32_t MAX_CLONE_THREAD_NUM = 2;
61 const int32_t I_PHONE_DYNAMIC_VIDEO_TYPE = 13;
62 constexpr int64_t SECONDS_LEVEL_LIMIT = 1e10;
63 const size_t EXTRADATA_LEN = 60;
64 const std::string I_PHONE_LPATH = "/Pictures/";
65 const std::string PHONE_TYPE = "type";
66 const std::string PHONE_DEVICE_TYPE = "deviceType";
67 const std::string PHONE_DETAIL = "detail";
68 const std::string PHOTO_DB_NAME = "photo_MediaInfo.db";
69 const std::string PHOTO_SD_MEDIA_INFO_DB_NAME = "photo_sd_MediaInfo.db";
70 const std::string VIDEO_DB_NAME = "video_MediaInfo.db";
71 const std::string VIDEO_SD_MEDIA_INFO_DB_NAME = "video_sd_MediaInfo.db";
72 const std::string OTHER_CLONE_FILE_ROOT_PATH = "/storage/media/local/files/.backup/restore";
73 const std::string LITE_CLONE_SD_FILE_PATH = "/storage/media/local/files/.backup/restore/storage/";
74 const std::string OTHER_CLONE_DB_PATH = "/storage/media/local/files/.backup/restore/storage/emulated/0/";
75 const std::string I_PHONE_IMAGE_FILE_PATH = "/storage/media/local/files/.backup/restore/";
76 const std::string I_PHONE_DYNAMIC_IMAGE = "_DYNAMIC";
77 const std::string I_PHONE_DYNAMIC_VIDEO = "_DYNAMIC.MOV";
78 const std::string I_PHONE_VIDEO_FILE_PATH = "/storage/media/local/files/.backup/restore/storage/emulated/";
79 const std::string OTHER_CLONE_FILE_PATH = "/storage/media/local/files/.backup/restore/storage/emulated/";
80 const std::string OTHER_CLONE_DISPLAYNAME = "primaryStr";
81 const std::string OTHER_CLONE_DATA = "_data";
82 const std::string OTHER_CLONE_MODIFIED = "date_modified";
83 const std::string OTHER_CLONE_TAKEN = "datetaken";
84 const std::string OTHER_CLONE_LATITUDE = "latitude";
85 const std::string OTHER_CLONE_LONGITUDE = "longitude";
86 const std::string OTHER_MUSIC_ROOT_PATH = "/storage/emulated/0/";
87 
88 static constexpr uint32_t CHAR_ARRAY_LENGTH = 5;
89 static constexpr uint32_t ASCII_CHAR_LENGTH = 8;
90 static constexpr uint32_t DECODE_NAME_IDX = 4;
91 static constexpr uint32_t DECODE_SURFIX_IDX = 5;
92 static constexpr uint32_t DECODE_TIME_IDX = 3;
93 static constexpr uint32_t IOS_BURST_CODE_LEN = 19;
94 
GetPhoneName()95 static std::string GetPhoneName()
96 {
97     int arr[] = { PHONE_FIRST_NUMBER, PHONE_SECOND_NUMBER, PHONE_THIRD_NUMBER, PHONE_FOURTH_NUMBER, PHONE_FIFTH_NUMBER,
98         PHONE_SIXTH_NUMBER };
99     int len = sizeof(arr) / sizeof(arr[0]);
100     std::string phoneName = "";
101     for (int i = 0; i < len; i++) {
102         phoneName += static_cast<char>(arr[i]);
103     }
104     return phoneName;
105 }
106 
OthersCloneRestore(int32_t sceneCode,const std::string & mediaAppName,const std::string & bundleInfo)107 OthersCloneRestore::OthersCloneRestore(int32_t sceneCode, const std::string &mediaAppName,
108     const std::string &bundleInfo)
109 {
110     sceneCode_ = sceneCode;
111     mediaAppName_ = mediaAppName;
112     if (sceneCode_ == I_PHONE_CLONE_RESTORE) {
113         nlohmann::json jsonObj = nlohmann::json::parse(bundleInfo, nullptr, false);
114         if (jsonObj.is_discarded()) {
115             MEDIA_ERR_LOG("parse json failed");
116             clonePhoneName_ = GetPhoneName();
117             return;
118         }
119         for (auto &obj : jsonObj) {
120             if (obj.contains(PHONE_TYPE) && obj.at(PHONE_TYPE) == PHONE_DEVICE_TYPE) {
121                 clonePhoneName_ = obj.at(PHONE_DETAIL);
122             }
123         }
124         if (clonePhoneName_.empty()) {
125             MEDIA_ERR_LOG("read json error");
126             clonePhoneName_ = GetPhoneName();
127         }
128     }
129     ffrt_disable_worker_escape();
130     MEDIA_INFO_LOG("Set ffrt_disable_worker_escape");
131 }
132 
CloneInfoPushBack(std::vector<CloneDbInfo> & pushInfos,std::vector<CloneDbInfo> & popInfos)133 void OthersCloneRestore::CloneInfoPushBack(std::vector<CloneDbInfo> &pushInfos, std::vector<CloneDbInfo> &popInfos)
134 {
135     std::lock_guard<std::mutex> guard(cloneMutex_);
136     for (auto &info : popInfos) {
137         pushInfos.push_back(info);
138     }
139 }
140 
GetDbInfo(int32_t sceneCode,std::vector<CloneDbInfo> & mediaDbInfo,const std::shared_ptr<NativeRdb::ResultSet> & resultSet)141 void OthersCloneRestore::GetDbInfo(int32_t sceneCode, std::vector<CloneDbInfo> &mediaDbInfo,
142     const std::shared_ptr<NativeRdb::ResultSet> &resultSet)
143 {
144     std::vector<CloneDbInfo> infos;
145     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
146         CloneDbInfo tmpDbInfo;
147         tmpDbInfo.data = GetStringVal(OTHER_CLONE_DATA, resultSet);
148         if (sceneCode == I_PHONE_CLONE_RESTORE) {
149             tmpDbInfo.displayName = GetStringVal(OTHER_CLONE_DISPLAYNAME, resultSet);
150             tmpDbInfo.dateModified = GetDoubleVal(OTHER_CLONE_MODIFIED, resultSet);
151             tmpDbInfo.dateTaken = GetDoubleVal(OTHER_CLONE_TAKEN, resultSet);
152             tmpDbInfo.latitude = GetDoubleVal(OTHER_CLONE_LATITUDE, resultSet);
153             tmpDbInfo.longitude = GetDoubleVal(OTHER_CLONE_LONGITUDE, resultSet);
154         } else {
155             tmpDbInfo.dateModified = static_cast<double>(GetInt64Val(OTHER_CLONE_MODIFIED, resultSet));
156             tmpDbInfo.dateTaken = static_cast<double>(GetInt64Val(OTHER_CLONE_TAKEN, resultSet));
157         }
158         infos.push_back(tmpDbInfo);
159     };
160     CloneInfoPushBack(mediaDbInfo, infos);
161 }
162 
HandleSelectBatch(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,int32_t offset,int32_t sceneCode,std::vector<CloneDbInfo> & mediaDbInfo)163 void OthersCloneRestore::HandleSelectBatch(std::shared_ptr<NativeRdb::RdbStore> mediaRdb, int32_t offset,
164     int32_t sceneCode, std::vector<CloneDbInfo> &mediaDbInfo)
165 {
166     if (mediaRdb == nullptr) {
167         MEDIA_ERR_LOG("rdb is nullptr, Maybe init failed.");
168         return;
169     }
170 
171     const int32_t BATCH_SIZE = 1000;
172     std::string queryExternalMayClonePhoto;
173 
174     if (sceneCode == I_PHONE_CLONE_RESTORE) {
175         queryExternalMayClonePhoto =
176             "SELECT _data, primaryStr, latitude, longitude, date_modified, datetaken FROM mediainfo LIMIT " +
177             std::to_string(offset) + ", " + std::to_string(BATCH_SIZE);
178     } else if (sceneCode == LITE_PHONE_CLONE_RESTORE) {
179         queryExternalMayClonePhoto = "SELECT _data, date_modified, datetaken FROM mediainfo LIMIT " +
180             std::to_string(offset) + ", " + std::to_string(BATCH_SIZE);
181     } else {
182         queryExternalMayClonePhoto = "SELECT _data, date_modified, datetaken FROM mediainfo LIMIT " +
183             std::to_string(offset) + ", " + std::to_string(BATCH_SIZE);
184     }
185 
186     auto resultSet = mediaRdb->QuerySql(queryExternalMayClonePhoto);
187     if (resultSet == nullptr) {
188         MEDIA_ERR_LOG("Query resultSql is null.");
189         return;
190     }
191 
192     std::vector<CloneDbInfo> batchResults;
193     batchResults.reserve(BATCH_SIZE);
194     GetDbInfo(sceneCode, batchResults, resultSet);
195     CloneInfoPushBack(mediaDbInfo, batchResults);
196     resultSet->Close();
197 }
198 
BuildDbPath(const std::string & dbName)199 std::string OthersCloneRestore::BuildDbPath(const std::string &dbName)
200 {
201     if (dbName == PHOTO_SD_MEDIA_INFO_DB_NAME || dbName == VIDEO_SD_MEDIA_INFO_DB_NAME) {
202         return OTHER_CLONE_FILE_ROOT_PATH + "/" + dbName;
203     }
204     return OTHER_CLONE_DB_PATH + dbName;
205 }
206 
CheckDbExists(const std::string & dbPath,const std::string & dbName)207 bool OthersCloneRestore::CheckDbExists(const std::string &dbPath, const std::string &dbName)
208 {
209     if (access(dbPath.c_str(), F_OK) != 0) {
210         MEDIA_ERR_LOG("Init rdb not exists, dbName = %{public}s", dbName.c_str());
211         return false;
212     }
213     return true;
214 }
215 
InitializeDatabase(const std::string & dbName,const std::string & dbPath)216 std::shared_ptr<NativeRdb::RdbStore> OthersCloneRestore::InitializeDatabase(
217     const std::string &dbName, const std::string &dbPath)
218 {
219     std::shared_ptr<NativeRdb::RdbStore> mediaRdb;
220     int32_t initErr = BackupDatabaseUtils::InitDb(mediaRdb, dbName, dbPath, mediaAppName_, false);
221     if (mediaRdb == nullptr) {
222         MEDIA_ERR_LOG("Init rdb fail, dbName = %{public}s, err = %{public}d", dbName.c_str(), initErr);
223         return nullptr;
224     }
225 
226     return mediaRdb;
227 }
228 
GetTotalRecordCount(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,const std::string & dbName)229 int32_t OthersCloneRestore::GetTotalRecordCount(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,
230     const std::string &dbName)
231 {
232     std::string selectTotalCloneMediaNumber = "SELECT count(1) AS count FROM mediainfo";
233     int32_t totalNumber = BackupDatabaseUtils::QueryInt(mediaRdb, selectTotalCloneMediaNumber, CUSTOM_COUNT);
234     MEDIA_INFO_LOG("dbName = %{public}s, totalNumber = %{public}d", dbName.c_str(), totalNumber);
235     return totalNumber;
236 }
237 
ProcessBatch(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,int32_t offset,std::vector<CloneDbInfo> & mediaDbInfo)238 void OthersCloneRestore::ProcessBatch(std::shared_ptr<NativeRdb::RdbStore> mediaRdb, int32_t offset,
239     std::vector<CloneDbInfo> &mediaDbInfo)
240 {
241     std::vector<CloneDbInfo> batchResults;
242     HandleSelectBatch(mediaRdb, offset, sceneCode_, batchResults);
243     CloneInfoPushBack(mediaDbInfo, batchResults);
244     batchResults.clear();
245     batchResults.shrink_to_fit();
246 }
247 
ProcessChunk(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,int32_t chunkStart,int32_t chunkEnd,std::vector<CloneDbInfo> & mediaDbInfo)248 void OthersCloneRestore::ProcessChunk(std::shared_ptr<NativeRdb::RdbStore> mediaRdb, int32_t chunkStart,
249     int32_t chunkEnd, std::vector<CloneDbInfo> &mediaDbInfo)
250 {
251     const int32_t BATCH_SIZE = 1000;
252     int32_t batchesInChunk = (chunkEnd - chunkStart + BATCH_SIZE - 1) / BATCH_SIZE;
253     for (int32_t batchIdx = 0; batchIdx < batchesInChunk; ++batchIdx) {
254         int32_t offset = chunkStart + batchIdx * BATCH_SIZE;
255         ProcessBatch(mediaRdb, offset, mediaDbInfo);
256     }
257 }
258 
QueryDatabaseRecords(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,int32_t totalNumber,std::vector<CloneDbInfo> & mediaDbInfo)259 void OthersCloneRestore::QueryDatabaseRecords(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,
260     int32_t totalNumber, std::vector<CloneDbInfo> &mediaDbInfo)
261 {
262     const int32_t CHUNK_SIZE = 10000;
263     for (int32_t chunkStart = 0; chunkStart < totalNumber; chunkStart += CHUNK_SIZE) {
264         int32_t chunkEnd = std::min(chunkStart + CHUNK_SIZE, totalNumber);
265         ProcessChunk(mediaRdb, chunkStart, chunkEnd, mediaDbInfo);
266         if (chunkStart % BATCHES_CHUNK_NUMBER == 0) {
267             MEDIA_INFO_LOG("Processed chunk %{public}d/%{public}d, current restore: %{public}zu records",
268                 chunkStart / CHUNK_SIZE + 1,
269                 (totalNumber + CHUNK_SIZE - 1) / CHUNK_SIZE,
270                 mediaDbInfo.size());
271         }
272     }
273 }
274 
IsPhotoVideoDatabase(const std::string & dbName)275 bool OthersCloneRestore::IsPhotoVideoDatabase(const std::string &dbName)
276 {
277     return (dbName == PHOTO_DB_NAME || dbName == PHOTO_SD_MEDIA_INFO_DB_NAME ||
278             dbName == VIDEO_DB_NAME || dbName == VIDEO_SD_MEDIA_INFO_DB_NAME);
279 }
280 
BuildPhotoVideoDbMap(std::vector<CloneDbInfo> & mediaDbInfo)281 void OthersCloneRestore::BuildPhotoVideoDbMap(std::vector<CloneDbInfo> &mediaDbInfo)
282 {
283     photoDbMap_.clear();
284     size_t reserveSize = std::min(mediaDbInfo.size(), static_cast<size_t>(PRE_ALLOC_PHOTOMAP_VECTOR));
285     photoDbMap_.reserve(reserveSize);
286 
287     for (auto& info : mediaDbInfo) {
288         photoDbMap_[info.data] = &info;
289         if (!info.displayName.empty()) {
290             photoDbMap_[info.displayName] = &info;
291         }
292     }
293 }
294 
BuildAudioDbMap(std::vector<CloneDbInfo> & mediaDbInfo)295 void OthersCloneRestore::BuildAudioDbMap(std::vector<CloneDbInfo> &mediaDbInfo)
296 {
297     audioDbMap_.clear();
298     size_t reserveSize = std::min(mediaDbInfo.size(), static_cast<size_t>(PRE_ALLOC_AUDIOMAP_VECTOR));
299     audioDbMap_.reserve(reserveSize);
300 
301     for (auto& info : mediaDbInfo) {
302         audioDbMap_[info.data] = &info;
303         if (!info.displayName.empty()) {
304             audioDbMap_[info.displayName] = &info;
305         }
306     }
307 }
308 
BuildDbInfoMap(const std::string & dbName,std::vector<CloneDbInfo> & mediaDbInfo)309 void OthersCloneRestore::BuildDbInfoMap(const std::string &dbName, std::vector<CloneDbInfo> &mediaDbInfo)
310 {
311     if (IsPhotoVideoDatabase(dbName)) {
312         BuildPhotoVideoDbMap(mediaDbInfo);
313     } else if (dbName == AUDIO_DB_NAME) {
314         BuildAudioDbMap(mediaDbInfo);
315     }
316 }
317 
GetCloneDbInfos(const std::string & dbName,std::vector<CloneDbInfo> & mediaDbInfo)318 void OthersCloneRestore::GetCloneDbInfos(const std::string &dbName, std::vector<CloneDbInfo> &mediaDbInfo)
319 {
320     std::string dbPath = BuildDbPath(dbName);
321     if (!CheckDbExists(dbPath, dbName)) {
322         return;
323     }
324 
325     auto mediaRdb = InitializeDatabase(dbName, dbPath);
326     if (mediaRdb == nullptr) {
327         return;
328     }
329 
330     int32_t totalNumber = GetTotalRecordCount(mediaRdb, dbName);
331 
332     QueryDatabaseRecords(mediaRdb, totalNumber, mediaDbInfo);
333 
334     BuildDbInfoMap(dbName, mediaDbInfo);
335 }
336 
ReportMissingFilesFromDB(std::vector<CloneDbInfo> & mediaDbInfo,const std::string & dbType)337 void OthersCloneRestore::ReportMissingFilesFromDB(std::vector<CloneDbInfo> &mediaDbInfo, const std::string &dbType)
338 {
339     for (auto &info : mediaDbInfo) {
340         if (!info.fileExists) {
341             (dbType == STAT_TYPE_PHOTO) ? photoFileNotFoundCount_++ : audioFileNotFoundCount_++;
342             MEDIA_ERR_LOG("Missing file from db! Db path: %{public}s", info.data.c_str());
343         }
344     }
345 }
346 
Init(const std::string & backupRetoreDir,const std::string & upgradeFilePath,bool isUpgrade)347 int32_t OthersCloneRestore::Init(const std::string &backupRetoreDir, const std::string &upgradeFilePath, bool isUpgrade)
348 {
349     if (BaseRestore::Init() != E_OK) {
350         MEDIA_ERR_LOG("GetBackupInfo init failed");
351         return E_FAIL;
352     }
353     if (mediaLibraryRdb_ == nullptr) {
354         MEDIA_ERR_LOG("GetBackupInfo Rdbstore is null");
355         return E_FAIL;
356     }
357     int64_t startGetInfo = MediaFileUtils::UTCTimeMilliSeconds();
358     GetCloneDbInfos(AUDIO_DB_NAME, audioDbInfo_);
359     GetCloneDbInfos(PHOTO_DB_NAME, photoDbInfo_);
360     GetCloneDbInfos(PHOTO_SD_MEDIA_INFO_DB_NAME, photoDbInfo_);
361     GetCloneDbInfos(VIDEO_DB_NAME, photoDbInfo_);
362     GetCloneDbInfos(VIDEO_SD_MEDIA_INFO_DB_NAME, photoDbInfo_);
363     int64_t startCurrent = MediaFileUtils::UTCTimeMilliSeconds();
364     int32_t err = GetAllfilesInCurrentDir(backupRestoreDir_);
365     if (err != E_OK) {
366         MEDIA_ERR_LOG("get all files err %{public}d", err);
367         return err;
368     }
369     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
370     ReportMissingFilesFromDB(audioDbInfo_, STAT_TYPE_AUDIO);
371     ReportMissingFilesFromDB(photoDbInfo_, STAT_TYPE_PHOTO);
372 
373     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
374         .Report("INIT_OTHERS_CLONE", "",
375             "get clone db cost: " + std::to_string(startCurrent - startGetInfo) +
376             ", recursively getting all files cost: " + std::to_string(end - startCurrent) +
377             "; photo file size: " + std::to_string(photoInfos_.size()) +
378             ", audio file size: " + std::to_string(audioInfos_.size()) +
379             "; photo db size: " + std::to_string(photoDbInfo_.size()) +
380             ", audio db size: " + std::to_string(audioDbInfo_.size()) +
381             "; db photo file not found: " + std::to_string(photoFileNotFoundCount_) +
382             ", db audio file not found: " + std::to_string(audioFileNotFoundCount_));
383     this->photoAlbumDao_.SetMediaLibraryRdb(this->mediaLibraryRdb_);
384     this->photosRestore_.OnStart(this->mediaLibraryRdb_, nullptr);
385     MEDIA_INFO_LOG("Init end");
386     return E_OK;
387 }
388 
GetInsertValue(const FileInfo & fileInfo,const std::string & newPath,int32_t sourceType)389 NativeRdb::ValuesBucket OthersCloneRestore::GetInsertValue(const FileInfo &fileInfo, const std::string &newPath,
390     int32_t sourceType)
391 {
392     NativeRdb::ValuesBucket values;
393     values.PutString(MediaColumn::MEDIA_FILE_PATH, newPath);
394     values.PutString(MediaColumn::MEDIA_TITLE, fileInfo.title);
395     values.PutString(MediaColumn::MEDIA_NAME, fileInfo.displayName);
396     values.PutString(PhotoColumn::PHOTO_MEDIA_SUFFIX, ScannerUtils::GetFileExtension(fileInfo.displayName));
397     // use owner_album_id to mark the album id which the photo is in.
398     values.PutInt(PhotoColumn::PHOTO_OWNER_ALBUM_ID, fileInfo.ownerAlbumId);
399     // only SOURCE album has package_name and owner_package.
400     values.PutString(MediaColumn::MEDIA_PACKAGE_NAME, fileInfo.packageName);
401     values.PutString(MediaColumn::MEDIA_OWNER_PACKAGE, fileInfo.bundleName);
402     values.PutInt(PhotoColumn::PHOTO_STRONG_ASSOCIATION, fileInfo.strongAssociation);
403     if (fileInfo.dateTaken != 0) {
404         values.PutLong(MediaColumn::MEDIA_DATE_TAKEN, fileInfo.dateTaken);
405         values.PutLong(MediaColumn::MEDIA_DATE_ADDED, fileInfo.dateTaken);
406     }
407     if (fileInfo.dateModified != 0) {
408         values.PutLong(MediaColumn::MEDIA_DATE_MODIFIED, fileInfo.dateModified);
409     }
410     values.PutInt(MediaColumn::MEDIA_HIDDEN, fileInfo.hidden);
411     values.PutLong(MediaColumn::MEDIA_DATE_TRASHED, fileInfo.dateTrashed);
412     values.PutInt(PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_BACKUP));
413     if (fileInfo.burstKey.size() > 0) {
414         values.PutInt(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::BURST));
415         values.PutInt(PhotoColumn::PHOTO_BURST_COVER_LEVEL, this->photosRestore_.FindBurstCoverLevel(fileInfo));
416         values.PutString(PhotoColumn::PHOTO_BURST_KEY, this->photosRestore_.FindBurstKey(fileInfo));
417     }
418     return values;
419 }
420 
ParseSourcePathToPath(const std::string & sourcePath,const std::string & prefix)421 static std::string ParseSourcePathToPath(const std::string &sourcePath, const std::string &prefix)
422 {
423     size_t startPos = sourcePath.find(prefix);
424     std::string result = sourcePath;
425     if (startPos != std::string::npos) {
426         startPos += prefix.length();
427         result = sourcePath.substr(startPos, sourcePath.size() - startPos);
428     }
429     return result;
430 }
431 
Base32Decode(const std::string & input)432 static std::string Base32Decode(const std::string &input)
433 {
434     std::string result;
435     result.reserve(input.length() * BASE32_CHAR_BITS / BASE32_BYTE_BITS + 1);
436     uint32_t val = 0;
437     uint32_t valbits = 0;
438     const char* data = input.data();
439     size_t len = input.length();
440 
441     for (size_t idx = 0; idx < len; ++idx) {
442         char c = data[idx];
443         if (c >= 'A' && c <= 'Z') {
444             val = (val << CHAR_ARRAY_LENGTH) + (c - 'A');
445             valbits += CHAR_ARRAY_LENGTH;
446         } else if (c >= '2' && c <= '7') {
447             val = (val << CHAR_ARRAY_LENGTH) + (c - '2' + 26); // 26 : A-Z
448             valbits += CHAR_ARRAY_LENGTH;
449         }
450         if (valbits >= ASCII_CHAR_LENGTH) {
451             valbits -= ASCII_CHAR_LENGTH;
452             result += static_cast<char>(val >> valbits);
453             val &= (1 << valbits) - 1;
454         }
455     }
456     return result;
457 }
458 
GetSubStrings(const std::string & originalString,char delimiter)459 static std::vector<std::string> GetSubStrings(const std::string &originalString, char delimiter)
460 {
461     std::vector<std::string> substrings;
462     if (originalString.empty()) {
463         return substrings;
464     }
465 
466     substrings.reserve(BASE32_BYTE_BITS); // Expected number of segments
467     const char* start = originalString.data();
468     const char* end = start + originalString.length();
469     const char* current = start;
470 
471     for (const char* p = start; p != end; ++p) {
472         if (*p == delimiter) {
473             substrings.emplace_back(current, p - current);
474             current = p + 1;
475         }
476     }
477 
478     if (current != end) {
479         substrings.emplace_back(current, end - current);
480     }
481 
482     return substrings;
483 }
484 
RecoverHiddenOrRecycleFile(std::string & currentPath,FileInfo & tmpInfo,std::string & decodeFileName)485 static bool RecoverHiddenOrRecycleFile(std::string &currentPath, FileInfo &tmpInfo, std::string &decodeFileName)
486 {
487     size_t hiddenAlbumPos = currentPath.find("hiddenAlbum/bins/");
488     size_t recyclePos = currentPath.find("recycle/bins/");
489     bool recycleFlag = false;
490     if (hiddenAlbumPos != std::string::npos) {
491         tmpInfo.hidden = 1;
492     } else if (recyclePos != std::string::npos) {
493         recycleFlag = true;
494     } else {
495         return false;
496     }
497 
498     size_t lastSlashPos = currentPath.find_last_of('/');
499     if (lastSlashPos == std::string::npos) {
500         MEDIA_INFO_LOG("currentPath %{public}s is abnormal", currentPath.c_str());
501         return false;
502     }
503     std::string target = currentPath.substr(lastSlashPos + 1);
504     if (target.find(".") != std::string::npos) {
505         MEDIA_INFO_LOG("currentPath %{public}s is already decoded", currentPath.c_str());
506         return false;
507     }
508     std::vector<std::string> substrings = GetSubStrings(Base32Decode(target), '|');
509     if (substrings.size() != 8) { // 8 : info num after decode
510         MEDIA_ERR_LOG("currentPath %{public}s decode fail", currentPath.c_str());
511         return false;
512     }
513     decodeFileName = substrings[DECODE_NAME_IDX] + substrings[DECODE_SURFIX_IDX];
514     if (recycleFlag) {
515         auto res = std::from_chars(substrings[DECODE_TIME_IDX].data(),
516             substrings[DECODE_TIME_IDX].data() + substrings[DECODE_TIME_IDX].size(),
517             tmpInfo.dateTrashed, 10); //10 : decimal
518         if (res.ec != std::errc()) {
519             MEDIA_ERR_LOG("get dateTrashed %{public}s fail", substrings[DECODE_TIME_IDX].c_str());
520             return false;
521         }
522     }
523     return true;
524 }
525 
AddAudioFile(FileInfo & tmpInfo)526 void OthersCloneRestore::AddAudioFile(FileInfo &tmpInfo)
527 {
528     UpDateFileModifiedTime(tmpInfo);
529     size_t relativePathPos = 0;
530     size_t startPos = tmpInfo.filePath.find(INTERNAL_PREFIX);
531     std::string startPath = tmpInfo.filePath;
532     if (startPos != std::string::npos) {
533         startPath = tmpInfo.filePath.substr(startPos);
534         BackupFileUtils::GetPathPosByPrefixLevel(sceneCode_, startPath, INTERNAL_PREFIX_LEVEL, relativePathPos);
535     }
536     tmpInfo.relativePath = startPath.substr(relativePathPos);
537     if (tmpInfo.relativePath == tmpInfo.filePath) {
538         tmpInfo.relativePath = ParseSourcePathToPath(tmpInfo.filePath, OTHER_CLONE_FILE_ROOT_PATH);
539     }
540     audioInfos_.emplace_back(tmpInfo);
541 }
542 
CheckBurstAndGetKey(const std::string & displayName,std::string & burstKey)543 int32_t CheckBurstAndGetKey(const std::string &displayName, std::string &burstKey)
544 {
545     size_t burstPos = displayName.find("_BURST");
546     if (burstPos == std::string::npos) {
547         return 0;
548     }
549     size_t burstStartPos = (burstPos >= IOS_BURST_CODE_LEN) ? burstPos - IOS_BURST_CODE_LEN : 0;
550     burstKey = displayName.substr(burstStartPos, burstPos - burstStartPos);
551     if (displayName.find("COVER") != std::string::npos) {
552         return static_cast<int32_t>(BurstCoverLevelType::COVER);
553     }
554     return static_cast<int32_t>(BurstCoverLevelType::MEMBER);
555 }
556 
CloneIosBurstPhoto(FileInfo & fileInfo)557 void CloneIosBurstPhoto(FileInfo &fileInfo)
558 {
559     std::string burstKey = fileInfo.burstKey;
560     fileInfo.isBurst = CheckBurstAndGetKey(fileInfo.displayName, burstKey);
561     fileInfo.burstKey = burstKey;
562 }
563 
SetFileInfosInCurrentDir(const std::string & file,struct stat & statInfo)564 void OthersCloneRestore::SetFileInfosInCurrentDir(const std::string &file, struct stat &statInfo)
565 {
566     FileInfo tmpInfo;
567     std::string tmpFile = file;
568     std::string decodeFileName = "";
569     if (RecoverHiddenOrRecycleFile(tmpFile, tmpInfo, decodeFileName)) {
570         tmpInfo.displayName = decodeFileName;
571     } else {
572         tmpInfo.displayName = ExtractFileName(tmpFile);
573     }
574     tmpInfo.filePath = tmpFile;
575     tmpInfo.oldPath = tmpFile; // for failed files statistics
576     tmpInfo.title = BackupFileUtils::GetFileTitle(tmpInfo.displayName);
577     tmpInfo.fileType = MediaFileUtils::GetMediaType(tmpInfo.displayName);
578     tmpInfo.fileSize = statInfo.st_size;
579     tmpInfo.dateModified = MediaFileUtils::Timespec2Millisecond(statInfo.st_mtim);
580     if (sceneCode_ == I_PHONE_CLONE_RESTORE) {
581         CloneIosBurstPhoto(tmpInfo);
582     }
583     if (tmpInfo.fileType == MediaType::MEDIA_TYPE_IMAGE) {
584         size_t enhancedPos = file.rfind("_enhanced");
585         if (enhancedPos != std::string::npos) {
586             size_t dotPos = file.find_last_of('.');
587             if (dotPos != std::string::npos && dotPos > enhancedPos) {
588                 MEDIA_INFO_LOG("%{private}s is an enhanced image!", file.c_str());
589                 tmpInfo.strongAssociation = STRONG_ASSOCIATION_ENABLE;
590             }
591         }
592     }
593     if (tmpInfo.fileType  == MediaType::MEDIA_TYPE_IMAGE || tmpInfo.fileType  == MediaType::MEDIA_TYPE_VIDEO) {
594         UpDateFileModifiedTime(tmpInfo);
595         UpdateFileGPS(tmpInfo);
596         photoInfos_.emplace_back(tmpInfo);
597     } else if (tmpInfo.fileType  == MediaType::MEDIA_TYPE_AUDIO) {
598         AddAudioFile(tmpInfo);
599     } else {
600         tmpInfo.fileType = MediaFileUtils::GetMediaTypeNotSupported(tmpInfo.displayName);
601         if (tmpInfo.fileType  == MediaType::MEDIA_TYPE_IMAGE || tmpInfo.fileType  == MediaType::MEDIA_TYPE_VIDEO) {
602             UpDateFileModifiedTime(tmpInfo);
603             photoInfos_.emplace_back(tmpInfo);
604             MEDIA_WARN_LOG("Not supported media %{public}s",
605                 BackupFileUtils::GarbleFilePath(tmpFile, sceneCode_).c_str());
606         } else if (tmpInfo.fileType  == MediaType::MEDIA_TYPE_AUDIO) {
607             AddAudioFile(tmpInfo);
608             MEDIA_WARN_LOG("Not supported audio %{public}s",
609                 BackupFileUtils::GarbleFilePath(tmpFile, sceneCode_).c_str());
610         } else {
611             MEDIA_WARN_LOG("Not supported file %{public}s",
612                 BackupFileUtils::GarbleFilePath(tmpFile, sceneCode_).c_str());
613         }
614     }
615 }
616 
ConvertPathToRealPath(const std::string & srcPath,const std::string & prefix,std::string & newPath,std::string & relativePath)617 bool OthersCloneRestore::ConvertPathToRealPath(const std::string &srcPath, const std::string &prefix,
618     std::string &newPath, std::string &relativePath)
619 {
620     size_t pos = 0;
621     CHECK_AND_RETURN_RET(BackupFileUtils::GetPathPosByPrefixLevel(sceneCode_, srcPath,
622         INTERNAL_PREFIX_LEVEL, pos), false);
623     newPath = prefix + srcPath;
624     relativePath = srcPath.substr(pos);
625     return true;
626 }
627 
ConvertPathToRealPath(const std::string & srcPath,const std::string & prefix,std::string & newPath,std::string & relativePath,FileInfo & fileInfo)628 bool OthersCloneRestore::ConvertPathToRealPath(const std::string &srcPath, const std::string &prefix,
629     std::string &newPath, std::string &relativePath, FileInfo &fileInfo)
630 {
631     CHECK_AND_RETURN_RET(srcPath != "", false);
632     if (MediaFileUtils::StartsWith(srcPath, INTERNAL_PREFIX)) {
633         return ConvertPathToRealPath(srcPath, prefix, newPath, relativePath);
634     }
635     size_t pos = 0;
636     if (!BackupFileUtils::GetPathPosByPrefixLevel(sceneCode_, srcPath, SD_PREFIX_LEVEL, pos)) {
637         return false;
638     }
639     relativePath = srcPath.substr(pos);
640     if (fileInfo.fileSize < TAR_FILE_LIMIT || fileInfo.hidden > 0 ||
641         fileInfo.dateTrashed > 0) {
642         newPath = prefix + srcPath; // packed as tar, hidden or trashed, use path in DB
643     } else {
644         newPath = prefix + relativePath; // others, remove sd prefix, use relative path
645     }
646     fileInfo.isInternal = false;
647     return true;
648 }
649 
CheckSamePathForSD(const std::string & dataPath,FileInfo & fileInfo,const std::string & filePath)650 bool OthersCloneRestore::CheckSamePathForSD(const std::string &dataPath, FileInfo &fileInfo,
651     const std::string &filePath)
652 {
653     std::string newPath = "";
654     std::string newRelativePath = "";
655     ConvertPathToRealPath(dataPath, OTHER_CLONE_FILE_ROOT_PATH, newPath, newRelativePath, fileInfo);
656     return newPath == filePath;
657 }
658 
UpdateFileGPS(FileInfo & fileInfo)659 void OthersCloneRestore::UpdateFileGPS(FileInfo &fileInfo)
660 {
661     CloneDbInfo* infoPtr = nullptr;
662 
663     if (fileInfo.fileType == MediaType::MEDIA_TYPE_AUDIO) {
664         auto it = audioDbMap_.find(fileInfo.displayName);
665         if (it != audioDbMap_.end()) {
666             infoPtr = it->second;
667         } else {
668             return;
669         }
670     } else if (fileInfo.fileType  == MediaType::MEDIA_TYPE_IMAGE || fileInfo.fileType  == MediaType::MEDIA_TYPE_VIDEO) {
671         auto it = photoDbMap_.find(fileInfo.displayName);
672         if (it != photoDbMap_.end()) {
673             infoPtr = it->second;
674         } else {
675             it = audioDbMap_.find(fileInfo.displayName);
676             if (it != audioDbMap_.end()) {
677                 MEDIA_WARN_LOG("find video in audio info map %{public}s", fileInfo.displayName.c_str());
678                 infoPtr = it->second;
679             } else {
680                 return;
681             }
682         }
683     } else {
684         MEDIA_WARN_LOG("Not supported file %{public}s", fileInfo.displayName.c_str());
685         return;
686     }
687 
688     fileInfo.latitude = infoPtr->latitude;
689     fileInfo.longitude = infoPtr->longitude;
690 }
691 
GenerateSearchKey(const FileInfo & fileInfo)692 std::string OthersCloneRestore::GenerateSearchKey(const FileInfo &fileInfo)
693 {
694     if (sceneCode_ == I_PHONE_CLONE_RESTORE) {
695         return fileInfo.displayName;
696     } else if (sceneCode_ == LITE_PHONE_CLONE_RESTORE) {
697         return ParseSourcePathToPath(fileInfo.filePath, OTHER_CLONE_FILE_ROOT_PATH);
698     } else {
699         return ParseSourcePathToPath(fileInfo.filePath, OTHER_CLONE_FILE_ROOT_PATH);
700     }
701 }
702 
FindAudioDbInfo(const std::string & key,const std::string & displayName)703 CloneDbInfo* OthersCloneRestore::FindAudioDbInfo(const std::string &key, const std::string &displayName)
704 {
705     auto it = audioDbMap_.find(key);
706     if (it != audioDbMap_.end()) {
707         it->second->fileExists = true;
708         return it->second;
709     }
710 
711     it = audioDbMap_.find(displayName);
712     if (it != audioDbMap_.end()) {
713         it->second->fileExists = true;
714         return it->second;
715     }
716 
717     return nullptr;
718 }
719 
FindPhotoDbInfo(const std::string & key,const std::string & displayName)720 CloneDbInfo* OthersCloneRestore::FindPhotoDbInfo(const std::string &key, const std::string &displayName)
721 {
722     auto it = photoDbMap_.find(key);
723     if (it != photoDbMap_.end()) {
724         it->second->fileExists = true;
725         return it->second;
726     }
727 
728     it = photoDbMap_.find(displayName);
729     if (it != photoDbMap_.end()) {
730         it->second->fileExists = true;
731         return it->second;
732     }
733 
734     it = audioDbMap_.find(key);
735     if (it == audioDbMap_.end()) {
736         it = audioDbMap_.find(displayName);
737     }
738 
739     if (it != audioDbMap_.end()) {
740         MEDIA_WARN_LOG("find video in audio info map %{public}s", displayName.c_str());
741         it->second->fileExists = true;
742         return it->second;
743     }
744 
745     return nullptr;
746 }
747 
FindDbInfoByFileType(const FileInfo & fileInfo,const std::string & key)748 CloneDbInfo* OthersCloneRestore::FindDbInfoByFileType(const FileInfo &fileInfo, const std::string &key)
749 {
750     if (fileInfo.fileType == MediaType::MEDIA_TYPE_AUDIO) {
751         return FindAudioDbInfo(key, fileInfo.displayName);
752     } else if (fileInfo.fileType == MediaType::MEDIA_TYPE_IMAGE ||
753                fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
754         return FindPhotoDbInfo(key, fileInfo.displayName);
755     } else {
756         MEDIA_WARN_LOG("Not supported file %{public}s", fileInfo.displayName.c_str());
757         return nullptr;
758     }
759 }
760 
ConvertTimeToSeconds(double timeValue)761 double OthersCloneRestore::ConvertTimeToSeconds(double timeValue)
762 {
763     if (timeValue < SECONDS_LEVEL_LIMIT) {
764         return timeValue * static_cast<double>(MSEC_TO_SEC);
765     }
766     return timeValue;
767 }
768 
UpdateFileTimeInfo(FileInfo & fileInfo,CloneDbInfo * dbInfo)769 void OthersCloneRestore::UpdateFileTimeInfo(FileInfo &fileInfo, CloneDbInfo *dbInfo)
770 {
771     double dateModified = ConvertTimeToSeconds(dbInfo->dateModified);
772     double dateTaken = ConvertTimeToSeconds(dbInfo->dateTaken);
773 
774     fileInfo.dateModified = static_cast<int64_t>(dateModified);
775     fileInfo.dateTaken = static_cast<int64_t>(dateTaken);
776 
777     BackupFileUtils::ModifyFile(fileInfo.filePath, fileInfo.dateModified / MSEC_TO_SEC);
778 }
779 
UpDateFileModifiedTime(FileInfo & fileInfo)780 void OthersCloneRestore::UpDateFileModifiedTime(FileInfo &fileInfo)
781 {
782     std::string key = GenerateSearchKey(fileInfo);
783     CloneDbInfo* infoPtr = FindDbInfoByFileType(fileInfo, key);
784 
785     if (infoPtr == nullptr) {
786         return;
787     }
788 
789     UpdateFileTimeInfo(fileInfo, infoPtr);
790 }
791 
GetAllfilesInCurrentDir(const std::string & path)792 int32_t OthersCloneRestore::GetAllfilesInCurrentDir(const std::string &path)
793 {
794     int err = E_OK;
795     DIR *dirPath = nullptr;
796     struct dirent *currentFile = nullptr;
797     size_t len = path.length();
798     struct stat statInfo;
799 
800     if (len >= FILENAME_MAX - 1) {
801         return ERR_INCORRECT_PATH;
802     }
803 
804     std::unique_ptr<char[]> fName = std::make_unique<char[]>(FILENAME_MAX);
805     if (strcpy_s(fName.get(), FILENAME_MAX, path.c_str()) != ERR_SUCCESS) {
806         return ERR_MEM_ALLOC_FAIL;
807     }
808     fName[len++] = '/';
809     if ((dirPath = opendir(path.c_str())) == nullptr) {
810         MEDIA_ERR_LOG("Failed to opendir %{private}s, errno %{private}d", path.c_str(), errno);
811         return ERR_NOT_ACCESSIBLE;
812     }
813 
814     while ((currentFile = readdir(dirPath)) != nullptr) {
815         if (!strcmp(currentFile->d_name, ".") || !strcmp(currentFile->d_name, "..")) {
816             continue;
817         }
818         if (strncpy_s(fName.get() + len, FILENAME_MAX - len, currentFile->d_name, FILENAME_MAX - len)) {
819             MEDIA_ERR_LOG("Failed to copy file name %{private}s ", fName.get());
820             continue;
821         }
822         if (lstat(fName.get(), &statInfo) == -1) {
823             MEDIA_ERR_LOG("Failed to get info of directory %{private}s ", fName.get());
824             continue;
825         }
826         std::string currentPath = fName.get();
827         if (S_ISDIR(statInfo.st_mode)) {
828             (void)GetAllfilesInCurrentDir(currentPath);
829         } else if (S_ISREG(statInfo.st_mode)) {
830             SetFileInfosInCurrentDir(fName.get(), statInfo);
831         } else {
832             MEDIA_INFO_LOG("Not directory or regular file, name is %{private}s", fName.get());
833         }
834     }
835     closedir(dirPath);
836     dirPath = nullptr;
837     return err;
838 }
839 
HandleInsertBatch(int32_t offset)840 void OthersCloneRestore::HandleInsertBatch(int32_t offset)
841 {
842     int32_t totalNumber = std::min(static_cast<int32_t>(photoInfos_.size()),
843         static_cast<int32_t>(offset + QUERY_NUMBER));
844     vector<FileInfo> insertInfos;
845     for (offset; offset < totalNumber; offset++) {
846         FileInfo info = photoInfos_[offset];
847         if (info.fileType != MediaType::MEDIA_TYPE_IMAGE && info.fileType != MediaType::MEDIA_TYPE_VIDEO) {
848             MEDIA_WARN_LOG("photo info error : %{public}s", info.displayName.c_str());
849             continue;
850         }
851         if (sceneCode_ == I_PHONE_CLONE_RESTORE && info.otherSubtype == I_PHONE_DYNAMIC_VIDEO_TYPE) {
852             continue;
853         }
854         UpdateAlbumInfo(info);
855         insertInfos.push_back(info);
856     }
857     InsertPhoto(insertInfos);
858 }
859 
ReportCloneBefore()860 void OthersCloneRestore::ReportCloneBefore()
861 {
862     MEDIA_INFO_LOG("Start ReportCloneBefore.");
863     DatabaseReport()
864         .SetSceneCode(sceneCode_)
865         .SetTaskId(taskId_)
866         .ReportMedia(mediaLibraryRdb_, DatabaseReport::PERIOD_BEFORE);
867 
868     UpgradeRestoreTaskReport()
869         .SetSceneCode(sceneCode_)
870         .SetTaskId(taskId_)
871         .Report("others Clone Restore", "",
872             "sceneCode_: " + std::to_string(sceneCode_) +
873             ", isAccountValid_: " + std::to_string(isAccountValid_) +
874             ", isSyncSwitchOpen: " + std::to_string(isSyncSwitchOn_));
875     MEDIA_INFO_LOG("End ReportCloneBefore.");
876 }
877 
RestorePhoto()878 void OthersCloneRestore::RestorePhoto()
879 {
880     if (!photoInfos_.size()) {
881         MEDIA_INFO_LOG("photo infos size zero");
882         return;
883     }
884     ReportCloneBefore();
885     std::vector<FileInfo> fileInfos;
886     totalNumber_ += photoInfos_.size();
887     RestoreAlbum(photoInfos_);
888     unsigned long pageSize = 200;
889     vector<FileInfo> insertInfos;
890     int32_t totalNumber = static_cast<int32_t>(photoInfos_.size());
891     ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_CLONE_THREAD_NUM);
892     for (int32_t offset = 0; offset < totalNumber; offset += QUERY_NUMBER) {
893         ffrt::submit([this, offset]() {
894             HandleInsertBatch(offset);
895             }, { &offset }, {}, ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
896     }
897     ffrt::wait();
898     ProcessBurstPhotos();
899 }
900 
InsertPhoto(std::vector<FileInfo> & fileInfos)901 void OthersCloneRestore::InsertPhoto(std::vector<FileInfo> &fileInfos)
902 {
903     int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
904     vector<NativeRdb::ValuesBucket> values = BaseRestore::GetInsertValues(sceneCode_, fileInfos, SourceType::PHOTOS);
905     int64_t startInsert = MediaFileUtils::UTCTimeMilliSeconds();
906     int64_t rowNum = 0;
907     int32_t errCode = BatchInsertWithRetry(PhotoColumn::PHOTOS_TABLE, values, rowNum);
908     if (errCode != E_OK) {
909         MEDIA_ERR_LOG("BatchInsert fail err %{public}d", errCode);
910         UpdateFailedFiles(fileInfos, RestoreError::INSERT_FAILED);
911         return;
912     }
913 
914     int64_t startMove = MediaFileUtils::UTCTimeMilliSeconds();
915     migrateDatabaseNumber_ += rowNum;
916     int32_t fileMoveCount = 0;
917     int32_t videoFileMoveCount = 0;
918     MoveMigrateFile(fileInfos, fileMoveCount, videoFileMoveCount, sceneCode_);
919     int64_t startUpdate = MediaFileUtils::UTCTimeMilliSeconds();
920     UpdatePhotosByFileInfoMap(mediaLibraryRdb_, fileInfos);
921     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
922     MEDIA_INFO_LOG("generate values cost %{public}ld, insert %{public}ld assets cost %{public}ld"
923         ", and move %{public}ld files (%{public}ld + %{public}ld) cost %{public}ld. update cost %{public}ld",
924         (long)(startInsert - start), (long)rowNum, (long)(startMove - startInsert),
925         (long)fileMoveCount, (long)(fileMoveCount - videoFileMoveCount),
926         (long)videoFileMoveCount, (long)(startUpdate - startMove), (long)(end - startUpdate));
927 }
928 
NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)929 bool OthersCloneRestore::NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> &fileInfos,
930     NeedQueryMap &needQueryMap)
931 {
932     return true;
933 }
934 
RestoreAudio()935 void OthersCloneRestore::RestoreAudio()
936 {
937     MEDIA_INFO_LOG("restore audio");
938     if (sceneCode_ == I_PHONE_CLONE_RESTORE) {
939         MEDIA_INFO_LOG("No need move audio");
940         return;
941     }
942     if (!audioInfos_.size()) {
943         MEDIA_INFO_LOG("audio infos size zero");
944         return;
945     }
946     audioTotalNumber_ += audioInfos_.size();
947     int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
948     InsertAudio(sceneCode_, audioInfos_);
949     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
950     MEDIA_INFO_LOG("generate values cost %{public}ld, insert audio %{public}ld",
951         (long)(end - start), (long)audioTotalNumber_);
952 }
953 
HandleRestData()954 void OthersCloneRestore::HandleRestData()
955 {
956     MEDIA_INFO_LOG("Start to handle rest data in native.");
957     RestoreThumbnail();
958 }
959 
ParseSourcePathToLPath(int32_t sceneCode,const std::string & filePath,int32_t fileType)960 std::string OthersCloneRestore::ParseSourcePathToLPath(int32_t sceneCode, const std::string &filePath,
961     int32_t fileType)
962 {
963     std::string lPath = filePath;
964     std::string source = GetFileHeadPath(sceneCode, fileType);
965     auto findPos = lPath.find(source);
966     if (findPos != std::string::npos) {
967         lPath.replace(lPath.find(source), source.length(), "");
968     } else {
969         MEDIA_WARN_LOG("find other clone path error path: %{public}s",
970             BackupFileUtils::GarbleFilePath(filePath, sceneCode).c_str());
971         source = LITE_CLONE_SD_FILE_PATH;
972         findPos = lPath.find(source);
973         if (findPos != std::string::npos) {
974             lPath.replace(lPath.find(source), source.length(), "");
975             std::size_t startPos = lPath.find_first_of(FILE_SEPARATOR);
976             if (startPos != std::string::npos) {
977                 lPath = lPath.substr(startPos);
978             }
979         } else {
980             source = OTHER_CLONE_FILE_ROOT_PATH;
981             findPos = lPath.find(source);
982             if (findPos != std::string::npos) {
983                 lPath.replace(lPath.find(source), source.length(), "");
984             }
985         }
986     }
987     std::size_t startPos = lPath.find_first_of(FILE_SEPARATOR);
988     if (startPos != std::string::npos) {
989         lPath = lPath.substr(startPos);
990     }
991     std::size_t pos = lPath.find_last_of(FILE_SEPARATOR);
992     if (pos != std::string::npos) {
993         lPath = lPath.substr(0, pos);
994     } else {
995         MEDIA_WARN_LOG("find error path is: %{public}s",
996             BackupFileUtils::GarbleFilePath(filePath, sceneCode).c_str());
997         lPath = FILE_SEPARATOR;
998     }
999     if (lPath.empty()) {
1000         MEDIA_WARN_LOG("find path is empty: %{public}s",
1001             BackupFileUtils::GarbleFilePath(filePath, sceneCode).c_str());
1002         lPath = FILE_SEPARATOR;
1003     }
1004     lPath = lPath == AlbumPlugin::LPATH_HIDDEN_ALBUM ? AlbumPlugin::LPATH_RECOVER : lPath;
1005     return lPath;
1006 }
1007 
GetFileHeadPath(int32_t sceneCode,int32_t fileType)1008 std::string OthersCloneRestore::GetFileHeadPath(int32_t sceneCode, int32_t fileType)
1009 {
1010     if (sceneCode == I_PHONE_CLONE_RESTORE) {
1011         if (fileType == MediaType::MEDIA_TYPE_IMAGE) {
1012             return I_PHONE_IMAGE_FILE_PATH;
1013         }
1014         if (fileType == MediaType::MEDIA_TYPE_VIDEO) {
1015             return I_PHONE_VIDEO_FILE_PATH;
1016         }
1017         MEDIA_WARN_LOG("GetFileHeadPath other fileType.");
1018         return I_PHONE_IMAGE_FILE_PATH;
1019     }
1020     return OTHER_CLONE_FILE_PATH;
1021 }
1022 
AddGalleryAlbum(std::vector<PhotoAlbumRestore::GalleryAlbumRowData> & galleryAlbumInfos,const std::string & lPath)1023 void OthersCloneRestore::AddGalleryAlbum(std::vector<PhotoAlbumRestore::GalleryAlbumRowData> &galleryAlbumInfos,
1024     const std::string &lPath)
1025 {
1026     auto pathMatch = [outerLPath {lPath}](const auto &galleryAlbumInfo) {
1027         return galleryAlbumInfo.lPath == outerLPath;
1028     };
1029     auto it = std::find_if(galleryAlbumInfos.begin(), galleryAlbumInfos.end(), pathMatch);
1030     if (it != galleryAlbumInfos.end()) {
1031         return;
1032     }
1033 
1034     PhotoAlbumRestore::GalleryAlbumRowData galleryAlbum;
1035     std::size_t pos = lPath.find_last_of(FILE_SEPARATOR);
1036     if (pos != std::string::npos) {
1037         galleryAlbum.albumName = lPath.substr(pos + 1);
1038     }
1039     if (galleryAlbum.albumName.empty()) {
1040         galleryAlbum.albumName = lPath;
1041     }
1042     galleryAlbum.lPath = lPath;
1043     galleryAlbum.priority = 1;
1044     galleryAlbumInfos.emplace_back(galleryAlbum);
1045 }
1046 
ParseResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info,std::string dbName)1047 bool OthersCloneRestore::ParseResultSet(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info,
1048     std::string dbName)
1049 {
1050     return true;
1051 }
1052 
ParseResultSetForAudio(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info)1053 bool OthersCloneRestore::ParseResultSetForAudio(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info)
1054 {
1055     return true;
1056 }
1057 
RestoreAlbum(std::vector<FileInfo> & fileInfos)1058 void OthersCloneRestore::RestoreAlbum(std::vector<FileInfo> &fileInfos)
1059 {
1060     std::vector<PhotoAlbumDao::PhotoAlbumRowData> albumInfos = this->photoAlbumDao_.GetPhotoAlbums();
1061     std::vector<PhotoAlbumRestore::GalleryAlbumRowData> galleryAlbumInfos;
1062     for (auto &info : fileInfos) {
1063         if (IsIosMovingPhotoVideo(info, sceneCode_)) {
1064             continue;
1065         }
1066         info.lPath = ParseSourcePathToLPath(sceneCode_, info.filePath, info.fileType);
1067         AddGalleryAlbum(galleryAlbumInfos, info.lPath);
1068     }
1069     std::vector<PhotoAlbumDao::PhotoAlbumRowData> albumInfosToRestore =
1070         photoAlbumRestore_.GetAlbumsToRestore(albumInfos, galleryAlbumInfos);
1071     auto ret =  photoAlbumDao_.RestoreAlbums(albumInfosToRestore);
1072     if (ret != NativeRdb::E_OK) {
1073         MEDIA_ERR_LOG("Failed to RestoreAlbums : %{public}d", ret);
1074     }
1075 }
1076 
HasSameFileForDualClone(FileInfo & fileInfo)1077 bool OthersCloneRestore::HasSameFileForDualClone(FileInfo &fileInfo)
1078 {
1079     PhotosDao::PhotosRowData rowData = this->photosRestore_.FindSameFile(fileInfo);
1080     int32_t fileId = rowData.fileId;
1081     std::string cloudPath = rowData.data;
1082     if (fileId <= 0 || cloudPath.empty()) {
1083         return false;
1084     }
1085     // Meed extra check to determine whether or not to drop the duplicate file.
1086     return ExtraCheckForCloneSameFile(fileInfo, rowData);
1087 }
1088 
ToLower(const std::string & str)1089 static std::string ToLower(const std::string &str)
1090 {
1091     std::string lowerStr;
1092     std::transform(
1093         str.begin(), str.end(), std::back_inserter(lowerStr), [](unsigned char c) { return std::tolower(c); });
1094     return lowerStr;
1095 }
1096 
FindAlbumInfo(FileInfo & fileInfo)1097 PhotoAlbumDao::PhotoAlbumRowData OthersCloneRestore::FindAlbumInfo(FileInfo &fileInfo)
1098 {
1099     PhotoAlbumDao::PhotoAlbumRowData albumInfo;
1100     if (fileInfo.lPath.empty()) {
1101         MEDIA_ERR_LOG("others clone lPath is empty, path: %{public}s",
1102             BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode_).c_str());
1103         return albumInfo;
1104     }
1105     if (ToLower(fileInfo.lPath) == ToLower(AlbumPlugin::LPATH_SCREEN_SHOTS) &&
1106         fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
1107         albumInfo = this->photoAlbumDao_.BuildAlbumInfoOfRecorders();
1108         albumInfo = this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
1109         MEDIA_INFO_LOG(
1110             "others clone: screenshots redirect to screenrecords, path: %{public}s",
1111             BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode_).c_str());
1112         fileInfo.lPath = AlbumPlugin::LPATH_SCREEN_RECORDS;
1113         return albumInfo;
1114     }
1115     albumInfo = this->photoAlbumDao_.GetPhotoAlbum(fileInfo.lPath);
1116     if (albumInfo.lPath.empty()) {
1117         MEDIA_ERR_LOG("others clone: albumInfo is empty, path: %{public}s",
1118             BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode_).c_str());
1119     }
1120     return albumInfo;
1121 }
1122 
UpdateAlbumInfo(FileInfo & info)1123 void OthersCloneRestore::UpdateAlbumInfo(FileInfo &info)
1124 {
1125     PhotoAlbumDao::PhotoAlbumRowData albumInfo = FindAlbumInfo(info);
1126     info.mediaAlbumId = albumInfo.albumId;
1127     info.ownerAlbumId = albumInfo.albumId;
1128 }
1129 
AnalyzeSource()1130 void OthersCloneRestore::AnalyzeSource()
1131 {
1132     MEDIA_INFO_LOG("analyze source later");
1133 }
1134 
GetIosMovingPhotoSize(const std::string iosMovingPhotoImagePath)1135 size_t GetIosMovingPhotoSize(const std::string iosMovingPhotoImagePath)
1136 {
1137     std::string iosMovingPhotoVideoPath =
1138         iosMovingPhotoImagePath.substr(0, iosMovingPhotoImagePath.find_last_of(".")) + ".MOV";
1139     size_t imageSize = 0;
1140     size_t videoSize = 0;
1141     (void)MediaFileUtils::GetFileSize(iosMovingPhotoImagePath, imageSize);
1142     (void)MediaFileUtils::GetFileSize(iosMovingPhotoVideoPath, videoSize);
1143     return (videoSize == 0) ? 0 : imageSize + videoSize + EXTRADATA_LEN;
1144 }
1145 
IsIosMovingPhotoVideo(FileInfo & fileInfo,int32_t sceneCode)1146 bool OthersCloneRestore::IsIosMovingPhotoVideo(FileInfo &fileInfo, int32_t sceneCode)
1147 {
1148     if (sceneCode != I_PHONE_CLONE_RESTORE || fileInfo.filePath.find(I_PHONE_DYNAMIC_IMAGE) == string::npos) {
1149         return false;
1150     }
1151     auto idx = fileInfo.filePath.find(I_PHONE_DYNAMIC_VIDEO);
1152     if (idx != string::npos) {
1153         fileInfo.otherSubtype = I_PHONE_DYNAMIC_VIDEO_TYPE;
1154         return true;
1155     } else {
1156         fileInfo.subtype = static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
1157         fileInfo.fileSize = static_cast<int64_t>(GetIosMovingPhotoSize(fileInfo.filePath));
1158     }
1159     return false;
1160 }
1161 
1162 } // namespace Media
1163 } // namespace OHOS
1164