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