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 if (sceneCode == LITE_PHONE_CLONE_RESTORE) {
200 path = filePath.substr(0, displayNameIndex).replace(0, OTHER_CLONE_PATH.length(), GARBLE);
201 } else {
202 path = filePath.substr(0, displayNameIndex);
203 }
204 path += "/" + garbleDisplayName;
205 return path;
206 }
207
GarbleFileName(const std::string & fileName)208 string BackupFileUtils::GarbleFileName(const std::string &fileName)
209 {
210 if (fileName.empty()) {
211 return fileName;
212 }
213 if (fileName.find("Screenshot_") == 0 || fileName.find("IMG_") == 0 || fileName.find("VID_") == 0 ||
214 fileName.find("SVID_") == 0) {
215 return fileName;
216 }
217 size_t titleIndex = fileName.rfind(".");
218 if (titleIndex == string::npos) {
219 titleIndex = fileName.size();
220 }
221 if (titleIndex <= GARBLE.size() * GARBLE_UNIT) {
222 return fileName;
223 }
224 return GARBLE + fileName.substr(GARBLE.size());
225 }
226
CreateAssetPathById(int32_t fileId,int32_t mediaType,const string & extension,string & filePath)227 int32_t BackupFileUtils::CreateAssetPathById(int32_t fileId, int32_t mediaType, const string &extension,
228 string &filePath)
229 {
230 int32_t bucketNum = 0;
231 int32_t errCode = MediaFileUri::CreateAssetBucket(fileId, bucketNum);
232 if (errCode != E_OK) {
233 return errCode;
234 }
235
236 string realName;
237 errCode = CreateAssetRealName(fileId, mediaType, extension, realName);
238 if (errCode != E_OK) {
239 return errCode;
240 }
241
242 string dirPath = (mediaType == MediaType::MEDIA_TYPE_AUDIO ? RESTORE_AUDIO_CLOUD_DIR : RESTORE_CLOUD_DIR) + "/" +
243 to_string(bucketNum);
244 string localDirPath = GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::LOCAL, dirPath);
245 if (!MediaFileUtils::IsFileExists(localDirPath)) {
246 bool ret = MediaFileUtils::CreateDirectory(localDirPath);
247 errCode = ret? E_OK: E_CHECK_DIR_FAIL;
248 }
249 if (errCode != E_OK) {
250 MEDIA_ERR_LOG("Create Dir Failed! localDirPath=%{private}s", localDirPath.c_str());
251 return errCode;
252 }
253
254 filePath = dirPath + "/" + realName;
255 return E_OK;
256 }
257
CreateAssetRealName(int32_t fileId,int32_t mediaType,const string & extension,string & name)258 int32_t BackupFileUtils::CreateAssetRealName(int32_t fileId, int32_t mediaType,
259 const string &extension, string &name)
260 {
261 string fileNumStr = to_string(fileId);
262 if (fileId <= ASSET_MAX_COMPLEMENT_ID) {
263 size_t fileIdLen = fileNumStr.length();
264 fileNumStr = ("00" + fileNumStr).substr(fileIdLen - 1);
265 }
266
267 string mediaTypeStr;
268 switch (mediaType) {
269 case MediaType::MEDIA_TYPE_IMAGE:
270 mediaTypeStr = DEFAULT_IMAGE_NAME;
271 break;
272 case MediaType::MEDIA_TYPE_VIDEO:
273 mediaTypeStr = DEFAULT_VIDEO_NAME;
274 break;
275 case MediaType::MEDIA_TYPE_AUDIO:
276 mediaTypeStr = DEFAULT_AUDIO_NAME;
277 break;
278 default:
279 MEDIA_ERR_LOG("This mediatype %{public}d can not get real name", mediaType);
280 return E_INVALID_VALUES;
281 }
282 name = mediaTypeStr + to_string(MediaFileUtils::UTCTimeSeconds()) + "_" + fileNumStr + "." + extension;
283 return E_OK;
284 }
285
GetFullPathByPrefixType(PrefixType prefixType,const std::string & relativePath)286 std::string BackupFileUtils::GetFullPathByPrefixType(PrefixType prefixType, const std::string &relativePath)
287 {
288 std::string fullPath;
289 auto it = PREFIX_MAP.find(prefixType);
290 if (it == PREFIX_MAP.end()) {
291 MEDIA_ERR_LOG("Get path prefix failed: %{public}d", prefixType);
292 return fullPath;
293 }
294 fullPath = it->second + relativePath;
295 return fullPath;
296 }
297
CreatePath(int32_t mediaType,const std::string & displayName,std::string & path)298 int32_t BackupFileUtils::CreatePath(int32_t mediaType, const std::string &displayName, std::string &path)
299 {
300 int32_t uniqueId = MediaLibraryAssetOperations::CreateAssetUniqueId(mediaType);
301 int32_t errCode = BackupFileUtils::CreateAssetPathById(uniqueId, mediaType,
302 MediaFileUtils::GetExtensionFromPath(displayName), path);
303 if (errCode != E_OK) {
304 MEDIA_ERR_LOG("Create path failed, errCode: %{public}d", errCode);
305 path.clear();
306 return errCode;
307 }
308 return E_OK;
309 }
310
PreparePath(const std::string & path)311 int32_t BackupFileUtils::PreparePath(const std::string &path)
312 {
313 size_t index = path.rfind("/");
314 if (index == std::string::npos || index == path.length() - 1) {
315 MEDIA_ERR_LOG("Parse directory path failed: %{private}s", path.c_str());
316 return E_CHECK_DIR_FAIL;
317 }
318 std::string dirPath = path.substr(0, index);
319 if (!MediaFileUtils::IsFileExists(dirPath) && !MediaFileUtils::CreateDirectory(dirPath)) {
320 MEDIA_ERR_LOG("Directory path doesn't exist and was created failed: %{public}s", dirPath.c_str());
321 return E_CHECK_DIR_FAIL;
322 }
323 return E_OK;
324 }
325
GetReplacedPathByPrefixType(PrefixType srcPrefixType,PrefixType dstPrefixType,const std::string & path)326 std::string BackupFileUtils::GetReplacedPathByPrefixType(PrefixType srcPrefixType, PrefixType dstPrefixType,
327 const std::string &path)
328 {
329 std::string replacedPath;
330 if (PREFIX_MAP.count(srcPrefixType) == 0 || PREFIX_MAP.count(dstPrefixType) == 0) {
331 MEDIA_ERR_LOG("Get source or destination prefix failed: %{public}d, %{public}d", srcPrefixType, dstPrefixType);
332 return replacedPath;
333 }
334 std::string srcPrefix = PREFIX_MAP.at(srcPrefixType);
335 std::string dstPrefix = PREFIX_MAP.at(dstPrefixType);
336 replacedPath = path;
337 replacedPath.replace(0, srcPrefix.length(), dstPrefix);
338 return replacedPath;
339 }
340
MoveFile(const string & oldPath,const string & newPath,int32_t sceneCode)341 int32_t BackupFileUtils::MoveFile(const string &oldPath, const string &newPath, int32_t sceneCode)
342 {
343 bool errRet = false;
344 if (!MediaFileUtils::IsFileExists(oldPath)) {
345 MEDIA_ERR_LOG("old path: %{public}s is not exists.", GarbleFilePath(oldPath, sceneCode).c_str());
346 return E_NO_SUCH_FILE;
347 } else if (MediaFileUtils::IsFileExists(newPath)) {
348 MEDIA_ERR_LOG("new path: %{public}s is exists.", GarbleFilePath(newPath, sceneCode).c_str());
349 return E_FILE_EXIST;
350 }
351 return rename(oldPath.c_str(), newPath.c_str());
352 }
353
ModifyFile(const std::string path,int64_t modifiedTime)354 void BackupFileUtils::ModifyFile(const std::string path, int64_t modifiedTime)
355 {
356 if (modifiedTime <= 0) {
357 MEDIA_ERR_LOG("ModifyTime error!");
358 return;
359 }
360 struct utimbuf buf;
361 buf.actime = modifiedTime; // second
362 buf.modtime = modifiedTime; // second
363 int ret = utime(path.c_str(), &buf);
364 if (ret != 0) {
365 MEDIA_ERR_LOG("Modify file failed: %{public}d", ret);
366 }
367 }
368
IsLowQualityImage(std::string & filePath,int32_t sceneCode,string relativePath,bool hasLowQualityImage)369 int32_t BackupFileUtils::IsLowQualityImage(std::string &filePath, int32_t sceneCode,
370 string relativePath, bool hasLowQualityImage)
371 {
372 struct stat statInfo {};
373 std::string garbledFilePath = BackupFileUtils::GarbleFilePath(filePath, sceneCode);
374 if (!hasLowQualityImage) {
375 MEDIA_ERR_LOG("Invalid file (%{public}s), no low quality image, err: %{public}d", garbledFilePath.c_str(),
376 errno);
377 return E_FAIL;
378 }
379 string realPath = ConvertLowQualityPath(sceneCode, filePath, relativePath);
380 if (stat(realPath.c_str(), &statInfo) != E_SUCCESS) {
381 MEDIA_ERR_LOG("Invalid Low quality image! file:%{public}s, err:%{public}d", garbledFilePath.c_str(), errno);
382 return E_NO_SUCH_FILE;
383 }
384 MEDIA_INFO_LOG("Low quality image! file: %{public}s", garbledFilePath.c_str());
385 filePath = realPath;
386 if (statInfo.st_mode & S_IFDIR) {
387 MEDIA_ERR_LOG("Invalid file (%{public}s), is a directory", garbledFilePath.c_str());
388 return E_FAIL;
389 }
390 if (statInfo.st_size <= 0) {
391 MEDIA_ERR_LOG("Invalid file (%{public}s), get size (%{public}lld) <= 0", garbledFilePath.c_str(),
392 (long long)statInfo.st_size);
393 return E_FAIL;
394 }
395 return E_OK;
396 }
397
IsFileValid(std::string & filePath,int32_t sceneCode,string relativePath,bool hasLowQualityImage)398 int32_t BackupFileUtils::IsFileValid(std::string &filePath, int32_t sceneCode,
399 string relativePath, bool hasLowQualityImage)
400 {
401 std::string garbledFilePath = BackupFileUtils::GarbleFilePath(filePath, sceneCode);
402 struct stat statInfo {};
403 if (stat(filePath.c_str(), &statInfo) != E_SUCCESS) {
404 bool res = false;
405 if (fileAccessHelper_ != nullptr) {
406 res = fileAccessHelper_->GetValidPath(filePath);
407 }
408 if (stat(filePath.c_str(), &statInfo) != E_SUCCESS) {
409 return hasLowQualityImage ? IsLowQualityImage(filePath, sceneCode, relativePath, hasLowQualityImage) :
410 E_NO_SUCH_FILE;
411 }
412 }
413 if (statInfo.st_mode & S_IFDIR) {
414 MEDIA_ERR_LOG("Invalid file (%{public}s), is a directory", garbledFilePath.c_str());
415 return E_FAIL;
416 }
417 if (statInfo.st_size <= 0) {
418 MEDIA_ERR_LOG("Invalid file (%{public}s), get size (%{public}lld) <= 0", garbledFilePath.c_str(),
419 (long long)statInfo.st_size);
420 return E_FAIL;
421 }
422 return E_OK;
423 }
424
GetFileNameFromPath(const string & path)425 string BackupFileUtils::GetFileNameFromPath(const string &path)
426 {
427 size_t pos = GetLastSlashPosFromPath(path);
428 if (pos == INVALID_RET || pos + 1 >= path.size()) {
429 MEDIA_ERR_LOG("Failed to obtain file name because pos is invalid or out of range, path: %{public}s, "
430 "size: %{public}zu, pos: %{public}zu", GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str(), path.size(), pos);
431 return "";
432 }
433 return path.substr(pos + 1);
434 }
435
GetFileTitle(const string & displayName)436 string BackupFileUtils::GetFileTitle(const string &displayName)
437 {
438 string::size_type pos = displayName.find_last_of('.');
439 return (pos == string::npos) ? displayName : displayName.substr(0, pos);
440 }
441
GetDetailsPath(int32_t sceneCode,const std::string & type,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)442 std::string BackupFileUtils::GetDetailsPath(int32_t sceneCode, const std::string &type,
443 const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
444 {
445 std::string detailsPath = RESTORE_FAILED_FILES_PATH + "_" + type + ".txt";
446 if (MediaFileUtils::IsFileExists(detailsPath) && !MediaFileUtils::DeleteFile(detailsPath)) {
447 MEDIA_ERR_LOG("%{public}s exists and delete failed", detailsPath.c_str());
448 return "";
449 }
450 if (failedFiles.empty() || limit == 0) {
451 return "";
452 }
453 if (MediaFileUtils::CreateAsset(detailsPath) != E_SUCCESS) {
454 MEDIA_ERR_LOG("Create %{public}s failed", detailsPath.c_str());
455 return "";
456 }
457 std::string failedFilesStr = GetFailedFilesStr(sceneCode, failedFiles, limit);
458 if (!MediaFileUtils::WriteStrToFile(detailsPath, failedFilesStr)) {
459 MEDIA_ERR_LOG("Write to %{public}s failed", detailsPath.c_str());
460 return "";
461 }
462 return detailsPath;
463 }
464
GetFailedFilesStr(int32_t sceneCode,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)465 std::string BackupFileUtils::GetFailedFilesStr(int32_t sceneCode,
466 const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
467 {
468 std::stringstream failedFilesStream;
469 failedFilesStream << "[";
470 for (const auto &iter : failedFiles) {
471 if (limit == 0) {
472 break;
473 }
474 failedFilesStream << "\n\"";
475 failedFilesStream << GetFailedFile(sceneCode, iter.first, iter.second);
476 limit > 1 ? failedFilesStream << "\"," : failedFilesStream << "\"";
477 limit--;
478 }
479 failedFilesStream << "\n]";
480 return failedFilesStream.str();
481 }
482
CreateDataShareHelper(const sptr<IRemoteObject> & token)483 void BackupFileUtils::CreateDataShareHelper(const sptr<IRemoteObject> &token)
484 {
485 if (token != nullptr) {
486 sDataShareHelper_ = DataShare::DataShareHelper::Creator(token, MEDIALIBRARY_DATA_URI);
487 if (sDataShareHelper_ == nullptr) {
488 MEDIA_ERR_LOG("generate thumbnails after restore failed, the sDataShareHelper_ is nullptr.");
489 }
490 }
491 }
492
GenerateThumbnailsAfterRestore()493 void BackupFileUtils::GenerateThumbnailsAfterRestore()
494 {
495 if (sDataShareHelper_ == nullptr) {
496 return;
497 }
498 std::string updateUri = PAH_GENERATE_THUMBNAILS_RESTORE;
499 MediaFileUtils::UriAppendKeyValue(updateUri, URI_PARAM_API_VERSION, to_string(MEDIA_API_VERSION_V10));
500 Uri uri(updateUri);
501 DataShare::DataSharePredicates emptyPredicates;
502 DataShare::DataShareValuesBucket valuesBucket;
503 valuesBucket.Put(MEDIA_DATA_DB_THUMBNAIL_READY, 0);
504 int result = sDataShareHelper_->Update(uri, emptyPredicates, valuesBucket);
505 if (result < 0) {
506 MEDIA_ERR_LOG("generate thumbnails after restore failed, the sDataShareHelper_ update error");
507 }
508 }
509
GetFailedFilesList(int32_t sceneCode,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)510 std::vector<std::string> BackupFileUtils::GetFailedFilesList(int32_t sceneCode,
511 const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
512 {
513 std::vector<std::string> failedFilesList;
514 for (const auto &iter : failedFiles) {
515 if (limit == 0) {
516 break;
517 }
518 failedFilesList.push_back(GetFailedFile(sceneCode, iter.first, iter.second));
519 limit--;
520 }
521 return failedFilesList;
522 }
523
GetFailedFile(int32_t sceneCode,const std::string & failedFilePath,const FailedFileInfo & failedFileInfo)524 std::string BackupFileUtils::GetFailedFile(int32_t sceneCode, const std::string &failedFilePath,
525 const FailedFileInfo &failedFileInfo)
526 {
527 MEDIA_ERR_LOG("Failed file: %{public}s, %{public}s, %{public}s, %{public}s",
528 GarbleFilePath(failedFilePath, sceneCode).c_str(), failedFileInfo.albumName.c_str(),
529 GarbleFileName(failedFileInfo.displayName).c_str(), failedFileInfo.errorCode.c_str());
530 // format: albumName/displayName
531 return failedFileInfo.albumName + "/" + failedFileInfo.displayName;
532 }
533
GetPathPosByPrefixLevel(int32_t sceneCode,const std::string & path,int32_t prefixLevel,size_t & pos)534 bool BackupFileUtils::GetPathPosByPrefixLevel(int32_t sceneCode, const std::string &path, int32_t prefixLevel,
535 size_t &pos)
536 {
537 int32_t count = 0;
538 for (size_t index = 0; index < path.length(); index++) {
539 if (path[index] != '/') {
540 continue;
541 }
542 count++;
543 if (count == prefixLevel) {
544 pos = index;
545 break;
546 }
547 }
548 if (count < prefixLevel) {
549 MEDIA_ERR_LOG("Get position failed for %{public}s, %{public}d < %{public}d",
550 GarbleFilePath(path, sceneCode).c_str(), count, prefixLevel);
551 return false;
552 }
553 return true;
554 }
555
ShouldIncludeSd(const std::string & prefix)556 bool BackupFileUtils::ShouldIncludeSd(const std::string &prefix)
557 {
558 return MediaFileUtils::IsFileExists(prefix + "/" + PHOTO_SD_DB_NAME) ||
559 MediaFileUtils::IsFileExists(prefix + "/" + VIDEO_SD_DB_NAME);
560 }
561
DeleteSdDatabase(const std::string & prefix)562 void BackupFileUtils::DeleteSdDatabase(const std::string &prefix)
563 {
564 std::vector<std::string> sdDbs = { PHOTO_SD_DB_NAME, VIDEO_SD_DB_NAME };
565 for (const auto &sdDb : sdDbs) {
566 std::string sdDbPath = prefix + "/" + sdDb;
567 if (!MediaFileUtils::IsFileExists(sdDbPath)) {
568 continue;
569 }
570 if (!MediaFileUtils::DeleteFile(sdDbPath)) {
571 MEDIA_ERR_LOG("Delete Sd database %{public}s failed, errno: %{public}d", sdDb.c_str(), errno);
572 }
573 }
574 }
575
IsLivePhoto(const FileInfo & fileInfo)576 bool BackupFileUtils::IsLivePhoto(const FileInfo &fileInfo)
577 {
578 return fileInfo.specialFileType == LIVE_PHOTO_TYPE || fileInfo.specialFileType == LIVE_PHOTO_HDR_TYPE;
579 }
580
addPathSuffix(const string & oldPath,const string & suffix,string & newPath)581 static void addPathSuffix(const string &oldPath, const string &suffix, string &newPath)
582 {
583 if (oldPath.empty() || suffix.empty()) {
584 MEDIA_WARN_LOG("oldPath or suffix is empty");
585 return;
586 }
587
588 newPath = oldPath + suffix;
589 while (MediaFileUtils::IsFileExists(newPath)) {
590 newPath += ".dup" + suffix;
591 }
592 }
593
ConvertToMovingPhoto(FileInfo & fileInfo)594 bool BackupFileUtils::ConvertToMovingPhoto(FileInfo &fileInfo)
595 {
596 if (!MediaFileUtils::IsFileExists(fileInfo.filePath)) {
597 MEDIA_ERR_LOG("Live photo does not exist, path: %{private}s, errno: %{public}d",
598 fileInfo.filePath.c_str(), errno);
599 return false;
600 }
601
602 string movingPhotoImagePath;
603 addPathSuffix(fileInfo.filePath, ".jpg", movingPhotoImagePath);
604 addPathSuffix(fileInfo.filePath, ".mp4", fileInfo.movingPhotoVideoPath);
605 addPathSuffix(fileInfo.filePath, ".extra", fileInfo.extraDataPath);
606 int32_t ret = MovingPhotoFileUtils::ConvertToMovingPhoto(
607 fileInfo.filePath, movingPhotoImagePath, fileInfo.movingPhotoVideoPath, fileInfo.extraDataPath);
608 if (ret != E_OK) {
609 return false;
610 }
611
612 if (!MediaFileUtils::DeleteFile(fileInfo.filePath)) {
613 MEDIA_WARN_LOG("Failed to delete original live photo: %{private}s, errno: %{public}d",
614 fileInfo.filePath.c_str(), errno);
615 }
616 fileInfo.filePath = movingPhotoImagePath;
617 return true;
618 }
619
GetLastSlashPosFromPath(const std::string & path)620 size_t BackupFileUtils::GetLastSlashPosFromPath(const std::string &path)
621 {
622 if (path.empty()) {
623 MEDIA_ERR_LOG("Failed to obtain last slash pos because given path is empty");
624 return INVALID_RET;
625 }
626 size_t pos = path.rfind("/");
627 if (pos == std::string::npos) {
628 MEDIA_ERR_LOG("Failed to obtain last slash pos because / not found");
629 return INVALID_RET;
630 }
631 return pos;
632 }
633
GetFileFolderFromPath(const std::string & path,bool shouldStartWithSlash)634 std::string BackupFileUtils::GetFileFolderFromPath(const std::string &path, bool shouldStartWithSlash)
635 {
636 size_t endPos = GetLastSlashPosFromPath(path);
637 if (endPos == INVALID_RET) {
638 MEDIA_ERR_LOG("Failed to obtain file folder, path: %{public}s",
639 GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str());
640 return "";
641 }
642 size_t startPos = MediaFileUtils::StartsWith(path, "/") && !shouldStartWithSlash ? 1 : 0;
643 if (startPos >= endPos) {
644 MEDIA_ERR_LOG("Failed to obtain file folder because start %{public}zu >= end %{public}zu, path: %{public}s",
645 startPos, endPos, GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str());
646 return "";
647 }
648 return path.substr(startPos, endPos - startPos);
649 }
650
GetExtraPrefixForRealPath(int32_t sceneCode,const std::string & path)651 std::string BackupFileUtils::GetExtraPrefixForRealPath(int32_t sceneCode, const std::string &path)
652 {
653 return sceneCode == UPGRADE_RESTORE_ID && IsAppTwinData(path) ? APP_TWIN_DATA_PREFIX : "";
654 }
655
IsAppTwinData(const std::string & path)656 bool BackupFileUtils::IsAppTwinData(const std::string &path)
657 {
658 int32_t userId = GetUserId(path);
659 return userId >= APP_TWIN_DATA_START && userId <= APP_TWIN_DATA_END;
660 }
661
GetUserId(const std::string & path)662 int32_t BackupFileUtils::GetUserId(const std::string &path)
663 {
664 int32_t userId = -1;
665 if (!MediaFileUtils::StartsWith(path, INTERNAL_PREFIX)) {
666 return userId;
667 }
668 std::string tmpPath = path.substr(INTERNAL_PREFIX.size());
669 if (tmpPath.empty()) {
670 MEDIA_ERR_LOG("Get substr failed, path: %{public}s", path.c_str());
671 return userId;
672 }
673 size_t posStart = tmpPath.find_first_of("/");
674 if (posStart == std::string::npos) {
675 MEDIA_ERR_LOG("Get first / failed, path: %{public}s", path.c_str());
676 return userId;
677 }
678 size_t posEnd = tmpPath.find_first_of("/", posStart + 1);
679 if (posEnd == std::string::npos) {
680 MEDIA_ERR_LOG("Get second / failed, path: %{public}s", path.c_str());
681 return userId;
682 }
683 std::string userIdStr = tmpPath.substr(posStart + 1, posEnd - posStart -1);
684 if (userIdStr.empty() || !MediaLibraryDataManagerUtils::IsNumber(userIdStr)) {
685 MEDIA_ERR_LOG("Get userId failed, empty or not number, path: %{public}s", path.c_str());
686 return userId;
687 }
688 return std::atoi(userIdStr.c_str());
689 }
690 } // namespace Media
691 } // namespace OHOS