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