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