1 /*
2  * Copyright (C) 2023 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 "MediaLibraryBackupUtils"
17 
18 #include "backup_file_utils.h"
19 
20 #include <utime.h>
21 #include <sys/types.h>
22 
23 #include "backup_const_column.h"
24 #include "scanner_utils.h"
25 #include "media_file_uri.h"
26 #include "metadata_extractor.h"
27 #include "mimetype_utils.h"
28 #include "medialibrary_errno.h"
29 #include "media_log.h"
30 #include "media_file_utils.h"
31 #include "medialibrary_asset_operations.h"
32 #include "medialibrary_data_manager_utils.h"
33 #include "moving_photo_file_utils.h"
34 
35 namespace OHOS {
36 namespace Media {
37 const string DEFAULT_IMAGE_NAME = "IMG_";
38 const string DEFAULT_VIDEO_NAME = "VID_";
39 const string DEFAULT_AUDIO_NAME = "AUD_";
40 const string LOW_QUALITY_PATH = "Documents/cameradata/";
41 const size_t INVALID_RET = -1;
42 const int32_t APP_TWIN_DATA_START = 128;
43 const int32_t APP_TWIN_DATA_END = 147;
44 
45 constexpr int ASSET_MAX_COMPLEMENT_ID = 999;
46 std::shared_ptr<DataShare::DataShareHelper> BackupFileUtils::sDataShareHelper_ = nullptr;
47 std::shared_ptr<FileAccessHelper> BackupFileUtils::fileAccessHelper_ = std::make_shared<FileAccessHelper>();
48 
GetValidPath(string & filePath)49 bool FileAccessHelper::GetValidPath(string &filePath)
50 {
51     if (access(filePath.c_str(), F_OK) == 0) {
52         return true;
53     }
54 
55     string resultPath = filePath;
56     size_t pos = 0;
57     while ((pos = resultPath.find("/", pos + 1)) != string::npos) {
58         string curPath = resultPath.substr(0, pos);
59         if (!ConvertCurrentPath(curPath, resultPath)) {
60             MEDIA_ERR_LOG("convert fail, path: %{public}s", MediaFileUtils::DesensitizePath(filePath).c_str());
61             return false;
62         }
63     }
64 
65     string curPath = resultPath;
66     if (!ConvertCurrentPath(curPath, resultPath)) {
67         MEDIA_ERR_LOG("convert fail, path: %{public}s", MediaFileUtils::DesensitizePath(filePath).c_str());
68         return false;
69     }
70 
71     filePath = resultPath;
72     return true;
73 }
74 
ConvertCurrentPath(string & curPath,string & resultPath)75 bool FileAccessHelper::ConvertCurrentPath(string &curPath, string &resultPath)
76 {
77     if (access(curPath.c_str(), F_OK) == 0) {
78         return true;
79     }
80 
81     string parentDir = filesystem::path(curPath).parent_path().string();
82     transform(curPath.begin(), curPath.end(), curPath.begin(), ::tolower);
83     {
84         std::lock_guard<std::mutex> guard(mapMutex);
85         if (pathMap.find(curPath) != pathMap.end()) {
86             resultPath.replace(0, curPath.length(), pathMap[curPath]);
87             return true;
88         }
89     }
90     if (!MediaFileUtils::IsFileExists(parentDir)) {
91         MEDIA_WARN_LOG("%{public}s doesn't exist, skip.", parentDir.c_str());
92         return false;
93     }
94     for (const auto &entry : filesystem::directory_iterator(parentDir,
95         std::filesystem::directory_options::skip_permission_denied)) {
96         string entryPath = entry.path();
97         transform(entryPath.begin(), entryPath.end(), entryPath.begin(), ::tolower);
98         if (entryPath == curPath) {
99             resultPath.replace(0, curPath.length(), entry.path());
100             {
101                 std::lock_guard<std::mutex> guard(mapMutex);
102                 pathMap[curPath] = entry.path();
103             }
104             return true;
105         }
106     }
107 
108     return false;
109 }
110 
FillMetadata(std::unique_ptr<Metadata> & data)111 int32_t BackupFileUtils::FillMetadata(std::unique_ptr<Metadata> &data)
112 {
113     int32_t err = GetFileMetadata(data);
114     if (err != E_OK) {
115         MEDIA_ERR_LOG("failed to get file metadata");
116         return err;
117     }
118     if (data->GetFileMediaType() == MEDIA_TYPE_IMAGE) {
119         err = MetadataExtractor::ExtractImageMetadata(data);
120     } else {
121         err = MetadataExtractor::ExtractAVMetadata(data, Scene::AV_META_SCENE_CLONE);
122         MEDIA_INFO_LOG("Extract av metadata end");
123     }
124     if (err != E_OK) {
125         MEDIA_ERR_LOG("failed to extension data");
126         return err;
127     }
128     return E_OK;
129 }
130 
ConvertLowQualityPath(int32_t sceneCode,const std::string & filePath,const string & relativePath)131 string BackupFileUtils::ConvertLowQualityPath(int32_t sceneCode, const std::string &filePath,
132     const string &relativePath)
133 {
134     string result = filePath;
135     size_t displayNameIndex = result.rfind("/");
136     if (displayNameIndex == string::npos) {
137         return result;
138     }
139     std::string displayName = result.substr(displayNameIndex + 1);
140     size_t dotPos = displayName.find_last_of(".");
141     if (dotPos != string::npos) {
142         displayName.replace(dotPos, displayName.length() - dotPos, ".camera");
143     }
144     size_t pos = result.find(relativePath);
145     if (pos == string::npos) {
146         return result;
147     }
148     string publicPath = result.substr(0, pos + 1);
149     result = publicPath + LOW_QUALITY_PATH + displayName;
150     return result;
151 }
152 
GetFileMetadata(std::unique_ptr<Metadata> & data)153 int32_t BackupFileUtils::GetFileMetadata(std::unique_ptr<Metadata> &data)
154 {
155     std::string path = data->GetFilePath();
156     struct stat statInfo {};
157     if (stat(path.c_str(), &statInfo) != 0) {
158         MEDIA_ERR_LOG("stat syscall err %{public}d", errno);
159         return E_FAIL;
160     }
161     data->SetFileSize(statInfo.st_size);
162     auto dateModified = static_cast<int64_t>(MediaFileUtils::Timespec2Millisecond(statInfo.st_mtim));
163     if (dateModified == 0) {
164         dateModified = MediaFileUtils::UTCTimeMilliSeconds();
165         MEDIA_WARN_LOG("Invalid dateModified from st_mtim, use current time instead: %{public}lld",
166             static_cast<long long>(dateModified));
167     }
168     if (dateModified != 0 && data->GetFileDateModified() == 0) {
169         data->SetFileDateModified(dateModified);
170     }
171     string extension = ScannerUtils::GetFileExtension(data->GetFileName()); // in case when trashed or hidden
172     string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension);
173     data->SetFileExtension(extension);
174     data->SetFileMimeType(mimeType);
175     return E_OK;
176 }
177 
GarbleFilePath(const std::string & filePath,int32_t sceneCode,std::string cloneFilePath)178 string BackupFileUtils::GarbleFilePath(const std::string &filePath, int32_t sceneCode, std::string cloneFilePath)
179 {
180     if (filePath.empty()) {
181         return filePath;
182     }
183     size_t displayNameIndex = filePath.rfind("/");
184     if (displayNameIndex == string::npos || displayNameIndex + 1 >= filePath.size()) {
185         return filePath;
186     }
187     std::string garbleDisplayName = GarbleFileName(filePath.substr(displayNameIndex + 1));
188     std::string path;
189     if (sceneCode == UPGRADE_RESTORE_ID) {
190         path = filePath.substr(0, displayNameIndex).replace(0, UPGRADE_FILE_DIR.length(), GARBLE);
191     } else if (sceneCode == DUAL_FRAME_CLONE_RESTORE_ID) {
192         path = filePath.substr(0, displayNameIndex).replace(0, GARBLE_DUAL_FRAME_CLONE_DIR.length(), GARBLE);
193     } else if (sceneCode == CLONE_RESTORE_ID) {
194         path = filePath.substr(0, displayNameIndex).replace(0, cloneFilePath.length(), GARBLE);
195     } else if (sceneCode == I_PHONE_CLONE_RESTORE) {
196         path = filePath.substr(0, displayNameIndex).replace(0, OTHER_CLONE_PATH.length(), GARBLE);
197     } else if (sceneCode == OTHERS_PHONE_CLONE_RESTORE) {
198         path = filePath.substr(0, displayNameIndex).replace(0, OTHER_CLONE_PATH.length(), GARBLE);
199     } else {
200         path = filePath.substr(0, displayNameIndex);
201     }
202     path += "/" + garbleDisplayName;
203     return path;
204 }
205 
GarbleFileName(const std::string & fileName)206 string BackupFileUtils::GarbleFileName(const std::string &fileName)
207 {
208     if (fileName.empty()) {
209         return fileName;
210     }
211     if (fileName.find("Screenshot_") == 0 || fileName.find("IMG_") == 0 || fileName.find("VID_") == 0 ||
212         fileName.find("SVID_") == 0) {
213         return fileName;
214     }
215     size_t titleIndex = fileName.rfind(".");
216     if (titleIndex == string::npos) {
217         titleIndex = fileName.size();
218     }
219     if (titleIndex <= GARBLE.size() * GARBLE_UNIT) {
220         return fileName;
221     }
222     return GARBLE + fileName.substr(GARBLE.size());
223 }
224 
CreateAssetPathById(int32_t fileId,int32_t mediaType,const string & extension,string & filePath)225 int32_t BackupFileUtils::CreateAssetPathById(int32_t fileId, int32_t mediaType, const string &extension,
226     string &filePath)
227 {
228     int32_t bucketNum = 0;
229     int32_t errCode = MediaFileUri::CreateAssetBucket(fileId, bucketNum);
230     if (errCode != E_OK) {
231         return errCode;
232     }
233 
234     string realName;
235     errCode = CreateAssetRealName(fileId, mediaType, extension, realName);
236     if (errCode != E_OK) {
237         return errCode;
238     }
239 
240     string dirPath = (mediaType == MediaType::MEDIA_TYPE_AUDIO ? RESTORE_AUDIO_CLOUD_DIR : RESTORE_CLOUD_DIR) + "/" +
241         to_string(bucketNum);
242     string localDirPath = GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::LOCAL, dirPath);
243     if (!MediaFileUtils::IsFileExists(localDirPath)) {
244         bool ret = MediaFileUtils::CreateDirectory(localDirPath);
245         errCode = ret? E_OK: E_CHECK_DIR_FAIL;
246     }
247     if (errCode != E_OK) {
248         MEDIA_ERR_LOG("Create Dir Failed! localDirPath=%{private}s", localDirPath.c_str());
249         return errCode;
250     }
251 
252     filePath = dirPath + "/" + realName;
253     return E_OK;
254 }
255 
CreateAssetRealName(int32_t fileId,int32_t mediaType,const string & extension,string & name)256 int32_t BackupFileUtils::CreateAssetRealName(int32_t fileId, int32_t mediaType,
257     const string &extension, string &name)
258 {
259     string fileNumStr = to_string(fileId);
260     if (fileId <= ASSET_MAX_COMPLEMENT_ID) {
261         size_t fileIdLen = fileNumStr.length();
262         fileNumStr = ("00" + fileNumStr).substr(fileIdLen - 1);
263     }
264 
265     string mediaTypeStr;
266     switch (mediaType) {
267         case MediaType::MEDIA_TYPE_IMAGE:
268             mediaTypeStr = DEFAULT_IMAGE_NAME;
269             break;
270         case MediaType::MEDIA_TYPE_VIDEO:
271             mediaTypeStr = DEFAULT_VIDEO_NAME;
272             break;
273         case MediaType::MEDIA_TYPE_AUDIO:
274             mediaTypeStr = DEFAULT_AUDIO_NAME;
275             break;
276         default:
277             MEDIA_ERR_LOG("This mediatype %{public}d can not get real name", mediaType);
278             return E_INVALID_VALUES;
279     }
280     name = mediaTypeStr + to_string(MediaFileUtils::UTCTimeSeconds()) + "_" + fileNumStr + "." + extension;
281     return E_OK;
282 }
283 
GetFullPathByPrefixType(PrefixType prefixType,const std::string & relativePath)284 std::string BackupFileUtils::GetFullPathByPrefixType(PrefixType prefixType, const std::string &relativePath)
285 {
286     std::string fullPath;
287     auto it = PREFIX_MAP.find(prefixType);
288     if (it == PREFIX_MAP.end()) {
289         MEDIA_ERR_LOG("Get path prefix failed: %{public}d", prefixType);
290         return fullPath;
291     }
292     fullPath = it->second + relativePath;
293     return fullPath;
294 }
295 
CreatePath(int32_t mediaType,const std::string & displayName,std::string & path)296 int32_t BackupFileUtils::CreatePath(int32_t mediaType, const std::string &displayName, std::string &path)
297 {
298     int32_t uniqueId = MediaLibraryAssetOperations::CreateAssetUniqueId(mediaType);
299     int32_t errCode = BackupFileUtils::CreateAssetPathById(uniqueId, mediaType,
300         MediaFileUtils::GetExtensionFromPath(displayName), path);
301     if (errCode != E_OK) {
302         MEDIA_ERR_LOG("Create path failed, errCode: %{public}d", errCode);
303         path.clear();
304         return errCode;
305     }
306     return E_OK;
307 }
308 
PreparePath(const std::string & path)309 int32_t BackupFileUtils::PreparePath(const std::string &path)
310 {
311     size_t index = path.rfind("/");
312     if (index == std::string::npos || index == path.length() - 1) {
313         MEDIA_ERR_LOG("Parse directory path failed: %{private}s", path.c_str());
314         return E_CHECK_DIR_FAIL;
315     }
316     std::string dirPath = path.substr(0, index);
317     if (!MediaFileUtils::IsFileExists(dirPath) && !MediaFileUtils::CreateDirectory(dirPath)) {
318         MEDIA_ERR_LOG("Directory path doesn't exist and was created failed: %{public}s", dirPath.c_str());
319         return E_CHECK_DIR_FAIL;
320     }
321     return E_OK;
322 }
323 
GetReplacedPathByPrefixType(PrefixType srcPrefixType,PrefixType dstPrefixType,const std::string & path)324 std::string BackupFileUtils::GetReplacedPathByPrefixType(PrefixType srcPrefixType, PrefixType dstPrefixType,
325     const std::string &path)
326 {
327     std::string replacedPath;
328     if (PREFIX_MAP.count(srcPrefixType) == 0 || PREFIX_MAP.count(dstPrefixType) == 0) {
329         MEDIA_ERR_LOG("Get source or destination prefix failed: %{public}d, %{public}d", srcPrefixType, dstPrefixType);
330         return replacedPath;
331     }
332     std::string srcPrefix = PREFIX_MAP.at(srcPrefixType);
333     std::string dstPrefix = PREFIX_MAP.at(dstPrefixType);
334     replacedPath = path;
335     replacedPath.replace(0, srcPrefix.length(), dstPrefix);
336     return replacedPath;
337 }
338 
MoveFile(const string & oldPath,const string & newPath,int32_t sceneCode)339 int32_t BackupFileUtils::MoveFile(const string &oldPath, const string &newPath, int32_t sceneCode)
340 {
341     bool errRet = false;
342     if (!MediaFileUtils::IsFileExists(oldPath)) {
343         MEDIA_ERR_LOG("old path: %{public}s is not exists.", GarbleFilePath(oldPath, sceneCode).c_str());
344         return E_NO_SUCH_FILE;
345     } else if (MediaFileUtils::IsFileExists(newPath)) {
346         MEDIA_ERR_LOG("new path: %{public}s is exists.", GarbleFilePath(newPath, sceneCode).c_str());
347         return E_FILE_EXIST;
348     }
349     return rename(oldPath.c_str(), newPath.c_str());
350 }
351 
ModifyFile(const std::string path,int64_t modifiedTime)352 void BackupFileUtils::ModifyFile(const std::string path, int64_t modifiedTime)
353 {
354     if (modifiedTime <= 0) {
355         MEDIA_ERR_LOG("ModifyTime error!");
356         return;
357     }
358     struct utimbuf buf;
359     buf.actime = modifiedTime; // second
360     buf.modtime = modifiedTime; // second
361     int ret = utime(path.c_str(), &buf);
362     if (ret != 0) {
363         MEDIA_ERR_LOG("Modify file failed: %{public}d", ret);
364     }
365 }
366 
IsLowQualityImage(std::string & filePath,int32_t sceneCode,string relativePath,bool hasLowQualityImage)367 int32_t BackupFileUtils::IsLowQualityImage(std::string &filePath, int32_t sceneCode,
368     string relativePath, bool hasLowQualityImage)
369 {
370     struct stat statInfo {};
371     std::string garbledFilePath = BackupFileUtils::GarbleFilePath(filePath, sceneCode);
372     if (!hasLowQualityImage) {
373         MEDIA_ERR_LOG("Invalid file (%{public}s), no low quality image, err: %{public}d", garbledFilePath.c_str(),
374             errno);
375         return E_FAIL;
376     }
377     string realPath = ConvertLowQualityPath(sceneCode, filePath, relativePath);
378     if (stat(realPath.c_str(), &statInfo) != E_SUCCESS) {
379         MEDIA_ERR_LOG("Invalid Low quality image! file:%{public}s, err:%{public}d", garbledFilePath.c_str(), errno);
380         return E_NO_SUCH_FILE;
381     }
382     MEDIA_INFO_LOG("Low quality image! file: %{public}s", garbledFilePath.c_str());
383     filePath = realPath;
384     if (statInfo.st_mode & S_IFDIR) {
385         MEDIA_ERR_LOG("Invalid file (%{public}s), is a directory", garbledFilePath.c_str());
386         return E_FAIL;
387     }
388     if (statInfo.st_size <= 0) {
389         MEDIA_ERR_LOG("Invalid file (%{public}s), get size (%{public}lld) <= 0", garbledFilePath.c_str(),
390             (long long)statInfo.st_size);
391         return E_FAIL;
392     }
393     return E_OK;
394 }
395 
IsFileValid(std::string & filePath,int32_t sceneCode,string relativePath,bool hasLowQualityImage)396 int32_t BackupFileUtils::IsFileValid(std::string &filePath, int32_t sceneCode,
397     string relativePath, bool hasLowQualityImage)
398 {
399     std::string garbledFilePath = BackupFileUtils::GarbleFilePath(filePath, sceneCode);
400     struct stat statInfo {};
401     if (stat(filePath.c_str(), &statInfo) != E_SUCCESS) {
402         bool res = false;
403         if (fileAccessHelper_ != nullptr) {
404             res = fileAccessHelper_->GetValidPath(filePath);
405         }
406         if (stat(filePath.c_str(), &statInfo) != E_SUCCESS) {
407             return hasLowQualityImage ? IsLowQualityImage(filePath, sceneCode, relativePath, hasLowQualityImage) :
408                 E_NO_SUCH_FILE;
409         }
410     }
411     if (statInfo.st_mode & S_IFDIR) {
412         MEDIA_ERR_LOG("Invalid file (%{public}s), is a directory", garbledFilePath.c_str());
413         return E_FAIL;
414     }
415     if (statInfo.st_size <= 0) {
416         MEDIA_ERR_LOG("Invalid file (%{public}s), get size (%{public}lld) <= 0", garbledFilePath.c_str(),
417             (long long)statInfo.st_size);
418         return E_FAIL;
419     }
420     return E_OK;
421 }
422 
GetFileNameFromPath(const string & path)423 string BackupFileUtils::GetFileNameFromPath(const string &path)
424 {
425     size_t pos = GetLastSlashPosFromPath(path);
426     if (pos == INVALID_RET || pos + 1 >= path.size()) {
427         MEDIA_ERR_LOG("Failed to obtain file name because pos is invalid or out of range, path: %{public}s, "
428             "size: %{public}zu, pos: %{public}zu", GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str(), path.size(), pos);
429         return "";
430     }
431     return path.substr(pos + 1);
432 }
433 
GetFileTitle(const string & displayName)434 string BackupFileUtils::GetFileTitle(const string &displayName)
435 {
436     string::size_type pos = displayName.find_last_of('.');
437     return (pos == string::npos) ? displayName : displayName.substr(0, pos);
438 }
439 
GetDetailsPath(int32_t sceneCode,const std::string & type,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)440 std::string BackupFileUtils::GetDetailsPath(int32_t sceneCode, const std::string &type,
441     const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
442 {
443     std::string detailsPath = RESTORE_FAILED_FILES_PATH + "_" + type + ".txt";
444     if (MediaFileUtils::IsFileExists(detailsPath) && !MediaFileUtils::DeleteFile(detailsPath)) {
445         MEDIA_ERR_LOG("%{public}s exists and delete failed", detailsPath.c_str());
446         return "";
447     }
448     if (failedFiles.empty() || limit == 0) {
449         return "";
450     }
451     if (MediaFileUtils::CreateAsset(detailsPath) != E_SUCCESS) {
452         MEDIA_ERR_LOG("Create %{public}s failed", detailsPath.c_str());
453         return "";
454     }
455     std::string failedFilesStr = GetFailedFilesStr(sceneCode, failedFiles, limit);
456     if (!MediaFileUtils::WriteStrToFile(detailsPath, failedFilesStr)) {
457         MEDIA_ERR_LOG("Write to %{public}s failed", detailsPath.c_str());
458         return "";
459     }
460     return detailsPath;
461 }
462 
GetFailedFilesStr(int32_t sceneCode,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)463 std::string BackupFileUtils::GetFailedFilesStr(int32_t sceneCode,
464     const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
465 {
466     std::stringstream failedFilesStream;
467     failedFilesStream << "[";
468     for (const auto &iter : failedFiles) {
469         if (limit == 0) {
470             break;
471         }
472         failedFilesStream << "\n\"";
473         failedFilesStream << GetFailedFile(sceneCode, iter.first, iter.second);
474         limit > 1 ? failedFilesStream << "\"," : failedFilesStream << "\"";
475         limit--;
476     }
477     failedFilesStream << "\n]";
478     return failedFilesStream.str();
479 }
480 
CreateDataShareHelper(const sptr<IRemoteObject> & token)481 void BackupFileUtils::CreateDataShareHelper(const sptr<IRemoteObject> &token)
482 {
483     if (token != nullptr) {
484         sDataShareHelper_ = DataShare::DataShareHelper::Creator(token, MEDIALIBRARY_DATA_URI);
485         if (sDataShareHelper_ == nullptr) {
486             MEDIA_ERR_LOG("generate thumbnails after restore failed, the sDataShareHelper_ is nullptr.");
487         }
488     }
489 }
490 
GenerateThumbnailsAfterRestore()491 void BackupFileUtils::GenerateThumbnailsAfterRestore()
492 {
493     if (sDataShareHelper_ == nullptr) {
494         return;
495     }
496     std::string updateUri = PAH_GENERATE_THUMBNAILS_RESTORE;
497     MediaFileUtils::UriAppendKeyValue(updateUri, URI_PARAM_API_VERSION, to_string(MEDIA_API_VERSION_V10));
498     Uri uri(updateUri);
499     DataShare::DataSharePredicates emptyPredicates;
500     DataShare::DataShareValuesBucket valuesBucket;
501     valuesBucket.Put(MEDIA_DATA_DB_THUMBNAIL_READY, 0);
502     int result = sDataShareHelper_->Update(uri, emptyPredicates, valuesBucket);
503     if (result < 0) {
504         MEDIA_ERR_LOG("generate thumbnails after restore failed, the sDataShareHelper_ update error");
505     }
506 }
507 
GetFailedFilesList(int32_t sceneCode,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)508 std::vector<std::string> BackupFileUtils::GetFailedFilesList(int32_t sceneCode,
509     const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
510 {
511     std::vector<std::string> failedFilesList;
512     for (const auto &iter : failedFiles) {
513         if (limit == 0) {
514             break;
515         }
516         failedFilesList.push_back(GetFailedFile(sceneCode, iter.first, iter.second));
517         limit--;
518     }
519     return failedFilesList;
520 }
521 
GetFailedFile(int32_t sceneCode,const std::string & failedFilePath,const FailedFileInfo & failedFileInfo)522 std::string BackupFileUtils::GetFailedFile(int32_t sceneCode, const std::string &failedFilePath,
523     const FailedFileInfo &failedFileInfo)
524 {
525     MEDIA_ERR_LOG("Failed file: %{public}s, %{public}s, %{public}s, %{public}s",
526         GarbleFilePath(failedFilePath, sceneCode).c_str(), failedFileInfo.albumName.c_str(),
527         GarbleFileName(failedFileInfo.displayName).c_str(), failedFileInfo.errorCode.c_str());
528     // format: albumName/displayName
529     return failedFileInfo.albumName + "/" + failedFileInfo.displayName;
530 }
531 
GetPathPosByPrefixLevel(int32_t sceneCode,const std::string & path,int32_t prefixLevel,size_t & pos)532 bool BackupFileUtils::GetPathPosByPrefixLevel(int32_t sceneCode, const std::string &path, int32_t prefixLevel,
533     size_t &pos)
534 {
535     int32_t count = 0;
536     for (size_t index = 0; index < path.length(); index++) {
537         if (path[index] != '/') {
538             continue;
539         }
540         count++;
541         if (count == prefixLevel) {
542             pos = index;
543             break;
544         }
545     }
546     if (count < prefixLevel) {
547         MEDIA_ERR_LOG("Get position failed for %{public}s, %{public}d < %{public}d",
548             GarbleFilePath(path, sceneCode).c_str(), count, prefixLevel);
549         return false;
550     }
551     return true;
552 }
553 
ShouldIncludeSd(const std::string & prefix)554 bool BackupFileUtils::ShouldIncludeSd(const std::string &prefix)
555 {
556     return MediaFileUtils::IsFileExists(prefix + "/" + PHOTO_SD_DB_NAME) ||
557         MediaFileUtils::IsFileExists(prefix + "/" + VIDEO_SD_DB_NAME);
558 }
559 
DeleteSdDatabase(const std::string & prefix)560 void BackupFileUtils::DeleteSdDatabase(const std::string &prefix)
561 {
562     std::vector<std::string> sdDbs = { PHOTO_SD_DB_NAME, VIDEO_SD_DB_NAME };
563     for (const auto &sdDb : sdDbs) {
564         std::string sdDbPath = prefix + "/" + sdDb;
565         if (!MediaFileUtils::IsFileExists(sdDbPath)) {
566             continue;
567         }
568         if (!MediaFileUtils::DeleteFile(sdDbPath)) {
569             MEDIA_ERR_LOG("Delete Sd database %{public}s failed, errno: %{public}d", sdDb.c_str(), errno);
570         }
571     }
572 }
573 
IsLivePhoto(const FileInfo & fileInfo)574 bool BackupFileUtils::IsLivePhoto(const FileInfo &fileInfo)
575 {
576     return fileInfo.specialFileType == LIVE_PHOTO_TYPE || fileInfo.specialFileType == LIVE_PHOTO_HDR_TYPE;
577 }
578 
addPathSuffix(const string & oldPath,const string & suffix,string & newPath)579 static void addPathSuffix(const string &oldPath, const string &suffix, string &newPath)
580 {
581     if (oldPath.empty() || suffix.empty()) {
582         MEDIA_WARN_LOG("oldPath or suffix is empty");
583         return;
584     }
585 
586     newPath = oldPath + suffix;
587     while (MediaFileUtils::IsFileExists(newPath)) {
588         newPath += ".dup" + suffix;
589     }
590 }
591 
ConvertToMovingPhoto(FileInfo & fileInfo)592 bool BackupFileUtils::ConvertToMovingPhoto(FileInfo &fileInfo)
593 {
594     if (!MediaFileUtils::IsFileExists(fileInfo.filePath)) {
595         MEDIA_ERR_LOG("Live photo does not exist, path: %{private}s, errno: %{public}d",
596             fileInfo.filePath.c_str(), errno);
597         return false;
598     }
599 
600     string movingPhotoImagePath;
601     addPathSuffix(fileInfo.filePath, ".jpg", movingPhotoImagePath);
602     addPathSuffix(fileInfo.filePath, ".mp4", fileInfo.movingPhotoVideoPath);
603     addPathSuffix(fileInfo.filePath, ".extra", fileInfo.extraDataPath);
604     int32_t ret = MovingPhotoFileUtils::ConvertToMovingPhoto(
605         fileInfo.filePath, movingPhotoImagePath, fileInfo.movingPhotoVideoPath, fileInfo.extraDataPath);
606     if (ret != E_OK) {
607         return false;
608     }
609 
610     if (!MediaFileUtils::DeleteFile(fileInfo.filePath)) {
611         MEDIA_WARN_LOG("Failed to delete original live photo: %{private}s, errno: %{public}d",
612             fileInfo.filePath.c_str(), errno);
613     }
614     fileInfo.filePath = movingPhotoImagePath;
615     return true;
616 }
617 
GetLastSlashPosFromPath(const std::string & path)618 size_t BackupFileUtils::GetLastSlashPosFromPath(const std::string &path)
619 {
620     if (path.empty()) {
621         MEDIA_ERR_LOG("Failed to obtain last slash pos because given path is empty");
622         return INVALID_RET;
623     }
624     size_t pos = path.rfind("/");
625     if (pos == std::string::npos) {
626         MEDIA_ERR_LOG("Failed to obtain last slash pos because / not found");
627         return INVALID_RET;
628     }
629     return pos;
630 }
631 
GetFileFolderFromPath(const std::string & path,bool shouldStartWithSlash)632 std::string BackupFileUtils::GetFileFolderFromPath(const std::string &path, bool shouldStartWithSlash)
633 {
634     size_t endPos = GetLastSlashPosFromPath(path);
635     if (endPos == INVALID_RET) {
636         MEDIA_ERR_LOG("Failed to obtain file folder, path: %{public}s",
637             GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str());
638         return "";
639     }
640     size_t startPos = MediaFileUtils::StartsWith(path, "/") && !shouldStartWithSlash ? 1 : 0;
641     if (startPos >= endPos) {
642         MEDIA_ERR_LOG("Failed to obtain file folder because start %{public}zu >= end %{public}zu, path: %{public}s",
643             startPos, endPos, GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str());
644         return "";
645     }
646     return path.substr(startPos, endPos - startPos);
647 }
648 
GetExtraPrefixForRealPath(int32_t sceneCode,const std::string & path)649 std::string BackupFileUtils::GetExtraPrefixForRealPath(int32_t sceneCode, const std::string &path)
650 {
651     return sceneCode == UPGRADE_RESTORE_ID && IsAppTwinData(path) ? APP_TWIN_DATA_PREFIX : "";
652 }
653 
IsAppTwinData(const std::string & path)654 bool BackupFileUtils::IsAppTwinData(const std::string &path)
655 {
656     int32_t userId = GetUserId(path);
657     return userId >= APP_TWIN_DATA_START && userId <= APP_TWIN_DATA_END;
658 }
659 
GetUserId(const std::string & path)660 int32_t BackupFileUtils::GetUserId(const std::string &path)
661 {
662     int32_t userId = -1;
663      if (!MediaFileUtils::StartsWith(path, INTERNAL_PREFIX)) {
664         return userId;
665     }
666     std::string tmpPath = path.substr(INTERNAL_PREFIX.size());
667     if (tmpPath.empty()) {
668         MEDIA_ERR_LOG("Get substr failed, path: %{public}s", path.c_str());
669         return userId;
670     }
671     size_t posStart = tmpPath.find_first_of("/");
672     if (posStart == std::string::npos) {
673         MEDIA_ERR_LOG("Get first / failed, path: %{public}s", path.c_str());
674         return userId;
675     }
676     size_t posEnd = tmpPath.find_first_of("/", posStart + 1);
677     if (posEnd == std::string::npos) {
678         MEDIA_ERR_LOG("Get second / failed, path: %{public}s", path.c_str());
679         return userId;
680     }
681     std::string userIdStr = tmpPath.substr(posStart + 1, posEnd - posStart -1);
682     if (userIdStr.empty() || !MediaLibraryDataManagerUtils::IsNumber(userIdStr)) {
683         MEDIA_ERR_LOG("Get userId failed, empty or not number, path: %{public}s", path.c_str());
684         return userId;
685     }
686     return std::atoi(userIdStr.c_str());
687 }
688 } // namespace Media
689 } // namespace OHOS