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