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