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 #include "post_proc.h"
35 #include "thumbnail_utils.h"
36
37 namespace OHOS {
38 namespace Media {
39 const string DEFAULT_IMAGE_NAME = "IMG_";
40 const string DEFAULT_VIDEO_NAME = "VID_";
41 const string DEFAULT_AUDIO_NAME = "AUD_";
42 const string LOW_QUALITY_PATH = "Documents/cameradata/";
43 const size_t INVALID_RET = -1;
44 const int32_t APP_TWIN_DATA_START = 128;
45 const int32_t APP_TWIN_DATA_END = 147;
46 const int32_t CROSS_POLICY_ERR = 18;
47
48 constexpr int ASSET_MAX_COMPLEMENT_ID = 999;
49 std::shared_ptr<DataShare::DataShareHelper> BackupFileUtils::sDataShareHelper_ = nullptr;
50 std::shared_ptr<FileAccessHelper> BackupFileUtils::fileAccessHelper_ = std::make_shared<FileAccessHelper>();
51
52 const std::string BackupFileUtils::IMAGE_FORMAT = "image/jpeg";
53 const std::string BackupFileUtils::LCD_FILE_NAME = "LCD.jpg";
54 const std::string BackupFileUtils::THM_FILE_NAME = "THM.jpg";
55 const uint8_t BackupFileUtils::IMAGE_QUALITY = 90;
56 const uint32_t BackupFileUtils::IMAGE_NUMBER_HINT = 1;
57 const int32_t BackupFileUtils::IMAGE_MIN_BUF_SIZE = 8192;
58
GetValidPath(string & filePath)59 bool FileAccessHelper::GetValidPath(string &filePath)
60 {
61 if (access(filePath.c_str(), F_OK) == 0) {
62 return true;
63 }
64
65 string resultPath = filePath;
66 size_t pos = 0;
67 while ((pos = resultPath.find("/", pos + 1)) != string::npos) {
68 string curPath = resultPath.substr(0, pos);
69 if (!ConvertCurrentPath(curPath, resultPath)) {
70 MEDIA_ERR_LOG("convert fail, path: %{public}s", MediaFileUtils::DesensitizePath(filePath).c_str());
71 return false;
72 }
73 }
74
75 string curPath = resultPath;
76 if (!ConvertCurrentPath(curPath, resultPath)) {
77 MEDIA_ERR_LOG("convert fail, path: %{public}s", MediaFileUtils::DesensitizePath(filePath).c_str());
78 return false;
79 }
80
81 filePath = resultPath;
82 return true;
83 }
84
ConvertCurrentPath(string & curPath,string & resultPath)85 bool FileAccessHelper::ConvertCurrentPath(string &curPath, string &resultPath)
86 {
87 if (access(curPath.c_str(), F_OK) == 0) {
88 return true;
89 }
90
91 string parentDir = filesystem::path(curPath).parent_path().string();
92 transform(curPath.begin(), curPath.end(), curPath.begin(), ::tolower);
93 {
94 std::lock_guard<std::mutex> guard(mapMutex);
95 if (pathMap.find(curPath) != pathMap.end()) {
96 resultPath.replace(0, curPath.length(), pathMap[curPath]);
97 return true;
98 }
99 }
100 if (!MediaFileUtils::IsFileExists(parentDir)) {
101 MEDIA_WARN_LOG("%{public}s doesn't exist, skip.", parentDir.c_str());
102 return false;
103 }
104 for (const auto &entry : filesystem::directory_iterator(parentDir,
105 std::filesystem::directory_options::skip_permission_denied)) {
106 string entryPath = entry.path();
107 transform(entryPath.begin(), entryPath.end(), entryPath.begin(), ::tolower);
108 if (entryPath == curPath) {
109 resultPath.replace(0, curPath.length(), entry.path());
110 {
111 std::lock_guard<std::mutex> guard(mapMutex);
112 pathMap[curPath] = entry.path();
113 }
114 return true;
115 }
116 }
117
118 return false;
119 }
120
FillMetadata(std::unique_ptr<Metadata> & data)121 int32_t BackupFileUtils::FillMetadata(std::unique_ptr<Metadata> &data)
122 {
123 int32_t err = GetFileMetadata(data);
124 if (err != E_OK) {
125 MEDIA_ERR_LOG("failed to get file metadata");
126 return err;
127 }
128 if (data->GetFileMediaType() == MEDIA_TYPE_IMAGE) {
129 err = MetadataExtractor::ExtractImageMetadata(data);
130 } else {
131 err = MetadataExtractor::ExtractAVMetadata(data, Scene::AV_META_SCENE_CLONE);
132 MEDIA_INFO_LOG("Extract av metadata end");
133 }
134 if (err != E_OK) {
135 MEDIA_ERR_LOG("failed to extension data");
136 return err;
137 }
138 return E_OK;
139 }
140
ConvertLowQualityPath(int32_t sceneCode,const std::string & filePath,const string & relativePath)141 string BackupFileUtils::ConvertLowQualityPath(int32_t sceneCode, const std::string &filePath,
142 const string &relativePath)
143 {
144 string result = filePath;
145 size_t displayNameIndex = result.rfind("/");
146 if (displayNameIndex == string::npos) {
147 return result;
148 }
149 std::string displayName = result.substr(displayNameIndex + 1);
150 size_t dotPos = displayName.find_last_of(".");
151 if (dotPos != string::npos) {
152 displayName.replace(dotPos, displayName.length() - dotPos, ".camera");
153 }
154 size_t pos = result.find(relativePath);
155 if (pos == string::npos) {
156 return result;
157 }
158 string publicPath = result.substr(0, pos + 1);
159 result = publicPath + LOW_QUALITY_PATH + displayName;
160 return result;
161 }
162
ParseResolution(const std::string & resolution,int32_t & width,int32_t & height)163 void BackupFileUtils::ParseResolution(const std::string &resolution, int32_t &width,
164 int32_t &height)
165 {
166 //default 0
167 width = 0, height = 0;
168 if (resolution.empty()) {
169 return;
170 }
171 size_t delimiter_pos = resolution.find('x');
172 if (delimiter_pos == std::string::npos) {
173 return;
174 }
175 std::string width_str = resolution.substr(0, delimiter_pos);
176 std::string height_str = resolution.substr(delimiter_pos + 1);
177 width = std::atoi(width_str.c_str());
178 height = std::atoi(height_str.c_str());
179 if (width == 0 || height == 0) {
180 width = 0;
181 height = 0;
182 }
183 }
184
GetFileMetadata(std::unique_ptr<Metadata> & data)185 int32_t BackupFileUtils::GetFileMetadata(std::unique_ptr<Metadata> &data)
186 {
187 string extension = ScannerUtils::GetFileExtension(data->GetFileName()); // in case when trashed or hidden
188 string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension);
189 data->SetFileExtension(extension);
190 data->SetFileMimeType(mimeType);
191 std::string path = data->GetFilePath();
192 struct stat statInfo {};
193 if (stat(path.c_str(), &statInfo) != 0) {
194 MEDIA_ERR_LOG("stat syscall err %{public}d", errno);
195 return E_FAIL;
196 }
197 data->SetFileSize(statInfo.st_size);
198 auto dateModified = static_cast<int64_t>(MediaFileUtils::Timespec2Millisecond(statInfo.st_mtim));
199 if (dateModified == 0) {
200 dateModified = MediaFileUtils::UTCTimeMilliSeconds();
201 MEDIA_WARN_LOG("Invalid dateModified from st_mtim, use current time instead: %{public}lld",
202 static_cast<long long>(dateModified));
203 }
204 if (dateModified != 0 && data->GetFileDateModified() == 0) {
205 data->SetFileDateModified(dateModified);
206 }
207 return E_OK;
208 }
209
GarbleFilePath(const std::string & filePath,int32_t sceneCode,std::string cloneFilePath)210 string BackupFileUtils::GarbleFilePath(const std::string &filePath, int32_t sceneCode, std::string cloneFilePath)
211 {
212 if (filePath.empty()) {
213 return filePath;
214 }
215 size_t displayNameIndex = filePath.rfind("/");
216 if (displayNameIndex == string::npos || displayNameIndex + 1 >= filePath.size()) {
217 return filePath;
218 }
219 std::string garbleDisplayName = GarbleFileName(filePath.substr(displayNameIndex + 1));
220 std::string path;
221 if (sceneCode == UPGRADE_RESTORE_ID) {
222 path = filePath.substr(0, displayNameIndex).replace(0, UPGRADE_FILE_DIR.length(), GARBLE);
223 } else if (sceneCode == DUAL_FRAME_CLONE_RESTORE_ID) {
224 path = filePath.substr(0, displayNameIndex).replace(0, GARBLE_DUAL_FRAME_CLONE_DIR.length(), GARBLE);
225 } else if (sceneCode == CLONE_RESTORE_ID) {
226 path = filePath.substr(0, displayNameIndex).replace(0, cloneFilePath.length(), GARBLE);
227 } else if (sceneCode == I_PHONE_CLONE_RESTORE) {
228 path = filePath.substr(0, displayNameIndex).replace(0, OTHER_CLONE_PATH.length(), GARBLE);
229 } else if (sceneCode == OTHERS_PHONE_CLONE_RESTORE) {
230 path = filePath.substr(0, displayNameIndex).replace(0, OTHER_CLONE_PATH.length(), GARBLE);
231 } else if (sceneCode == LITE_PHONE_CLONE_RESTORE) {
232 path = filePath.substr(0, displayNameIndex).replace(0, OTHER_CLONE_PATH.length(), GARBLE);
233 } else {
234 path = filePath.substr(0, displayNameIndex);
235 }
236 path += "/" + garbleDisplayName;
237 return path;
238 }
239
GarbleFileName(const std::string & fileName)240 string BackupFileUtils::GarbleFileName(const std::string &fileName)
241 {
242 if (fileName.empty()) {
243 return fileName;
244 }
245 if (fileName.find("Screenshot_") == 0 || fileName.find("IMG_") == 0 || fileName.find("VID_") == 0 ||
246 fileName.find("SVID_") == 0) {
247 return fileName;
248 }
249 size_t titleIndex = fileName.rfind(".");
250 if (titleIndex == string::npos) {
251 titleIndex = fileName.size();
252 }
253 if (titleIndex <= GARBLE.size() * GARBLE_UNIT) {
254 return fileName;
255 }
256 return GARBLE + fileName.substr(GARBLE.size());
257 }
258
CreateAssetPathById(int32_t fileId,int32_t mediaType,const string & extension,string & filePath)259 int32_t BackupFileUtils::CreateAssetPathById(int32_t fileId, int32_t mediaType, const string &extension,
260 string &filePath)
261 {
262 int32_t bucketNum = 0;
263 int32_t errCode = MediaFileUri::CreateAssetBucket(fileId, bucketNum);
264 if (errCode != E_OK) {
265 return errCode;
266 }
267
268 string realName;
269 errCode = CreateAssetRealName(fileId, mediaType, extension, realName);
270 if (errCode != E_OK) {
271 return errCode;
272 }
273
274 string dirPath = (mediaType == MediaType::MEDIA_TYPE_AUDIO ? RESTORE_AUDIO_CLOUD_DIR : RESTORE_CLOUD_DIR) + "/" +
275 to_string(bucketNum);
276 string localDirPath = GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::LOCAL, dirPath);
277 if (!MediaFileUtils::IsFileExists(localDirPath)) {
278 bool ret = MediaFileUtils::CreateDirectory(localDirPath);
279 errCode = ret? E_OK: E_CHECK_DIR_FAIL;
280 }
281 if (errCode != E_OK) {
282 MEDIA_ERR_LOG("Create Dir Failed! localDirPath=%{private}s", localDirPath.c_str());
283 return errCode;
284 }
285
286 filePath = dirPath + "/" + realName;
287 return E_OK;
288 }
289
CreateAssetRealName(int32_t fileId,int32_t mediaType,const string & extension,string & name)290 int32_t BackupFileUtils::CreateAssetRealName(int32_t fileId, int32_t mediaType,
291 const string &extension, string &name)
292 {
293 string fileNumStr = to_string(fileId);
294 if (fileId <= ASSET_MAX_COMPLEMENT_ID) {
295 size_t fileIdLen = fileNumStr.length();
296 fileNumStr = ("00" + fileNumStr).substr(fileIdLen - 1);
297 }
298
299 string mediaTypeStr;
300 switch (mediaType) {
301 case MediaType::MEDIA_TYPE_IMAGE:
302 mediaTypeStr = DEFAULT_IMAGE_NAME;
303 break;
304 case MediaType::MEDIA_TYPE_VIDEO:
305 mediaTypeStr = DEFAULT_VIDEO_NAME;
306 break;
307 case MediaType::MEDIA_TYPE_AUDIO:
308 mediaTypeStr = DEFAULT_AUDIO_NAME;
309 break;
310 default:
311 MEDIA_ERR_LOG("This mediatype %{public}d can not get real name", mediaType);
312 return E_INVALID_VALUES;
313 }
314 name = mediaTypeStr + to_string(MediaFileUtils::UTCTimeSeconds()) + "_" + fileNumStr + "." + extension;
315 return E_OK;
316 }
317
GetFullPathByPrefixType(PrefixType prefixType,const std::string & relativePath)318 std::string BackupFileUtils::GetFullPathByPrefixType(PrefixType prefixType, const std::string &relativePath)
319 {
320 std::string fullPath;
321 auto it = PREFIX_MAP.find(prefixType);
322 if (it == PREFIX_MAP.end()) {
323 MEDIA_ERR_LOG("Get path prefix failed: %{public}d", prefixType);
324 return fullPath;
325 }
326 fullPath = it->second + relativePath;
327 return fullPath;
328 }
329
CreatePath(int32_t mediaType,const std::string & displayName,std::string & path)330 int32_t BackupFileUtils::CreatePath(int32_t mediaType, const std::string &displayName, std::string &path)
331 {
332 int32_t uniqueId = MediaLibraryAssetOperations::CreateAssetUniqueId(mediaType);
333 int32_t errCode = BackupFileUtils::CreateAssetPathById(uniqueId, mediaType,
334 MediaFileUtils::GetExtensionFromPath(displayName), path);
335 if (errCode != E_OK) {
336 MEDIA_ERR_LOG("Create path failed, errCode: %{public}d", errCode);
337 path.clear();
338 return errCode;
339 }
340 return E_OK;
341 }
342
PreparePath(const std::string & path)343 int32_t BackupFileUtils::PreparePath(const std::string &path)
344 {
345 size_t index = path.rfind("/");
346 if (index == std::string::npos || index == path.length() - 1) {
347 MEDIA_ERR_LOG("Parse directory path failed: %{private}s", path.c_str());
348 return E_CHECK_DIR_FAIL;
349 }
350 std::string dirPath = path.substr(0, index);
351 if (!MediaFileUtils::IsFileExists(dirPath) && !MediaFileUtils::CreateDirectory(dirPath)) {
352 MEDIA_ERR_LOG("Directory path doesn't exist and was created failed: %{public}s", dirPath.c_str());
353 return E_CHECK_DIR_FAIL;
354 }
355 return E_OK;
356 }
357
MoveFile(const string & oldPath,const string & newPath,int32_t sceneCode)358 int32_t BackupFileUtils::MoveFile(const string &oldPath, const string &newPath, int32_t sceneCode)
359 {
360 bool errRet = false;
361 if (!MediaFileUtils::IsFileExists(oldPath)) {
362 MEDIA_ERR_LOG("old path: %{public}s is not exists.", GarbleFilePath(oldPath, sceneCode).c_str());
363 return E_NO_SUCH_FILE;
364 } else if (MediaFileUtils::IsFileExists(newPath)) {
365 MEDIA_ERR_LOG("new path: %{public}s is exists.", GarbleFilePath(newPath, sceneCode).c_str());
366 return E_FILE_EXIST;
367 }
368 int ret = rename(oldPath.c_str(), newPath.c_str());
369 if (ret < 0 && errno == CROSS_POLICY_ERR) {
370 ret = MediaFileUtils::CopyFileAndDelSrc(oldPath, newPath) ? 0 : -1;
371 MEDIA_INFO_LOG("sendfile result: %{public}d, old path:%{public}s, new path: %{public}s",
372 ret, GarbleFilePath(oldPath, sceneCode).c_str(), GarbleFilePath(newPath, sceneCode).c_str());
373 }
374 return ret;
375 }
376
GetReplacedPathByPrefixType(PrefixType srcPrefixType,PrefixType dstPrefixType,const std::string & path)377 std::string BackupFileUtils::GetReplacedPathByPrefixType(PrefixType srcPrefixType, PrefixType dstPrefixType,
378 const std::string &path)
379 {
380 std::string replacedPath;
381 if (PREFIX_MAP.count(srcPrefixType) == 0 || PREFIX_MAP.count(dstPrefixType) == 0) {
382 MEDIA_ERR_LOG("Get source or destination prefix failed: %{public}d, %{public}d", srcPrefixType, dstPrefixType);
383 return replacedPath;
384 }
385 std::string srcPrefix = PREFIX_MAP.at(srcPrefixType);
386 std::string dstPrefix = PREFIX_MAP.at(dstPrefixType);
387 replacedPath = path;
388 replacedPath.replace(0, srcPrefix.length(), dstPrefix);
389 return replacedPath;
390 }
391
ModifyFile(const std::string path,int64_t modifiedTime)392 void BackupFileUtils::ModifyFile(const std::string path, int64_t modifiedTime)
393 {
394 if (modifiedTime <= 0) {
395 MEDIA_ERR_LOG("ModifyTime error!");
396 return;
397 }
398 struct utimbuf buf;
399 buf.actime = modifiedTime; // second
400 buf.modtime = modifiedTime; // second
401 int ret = utime(path.c_str(), &buf);
402 if (ret != 0) {
403 MEDIA_ERR_LOG("Modify file failed: %{public}d", ret);
404 }
405 }
406
GetFileNameFromPath(const string & path)407 string BackupFileUtils::GetFileNameFromPath(const string &path)
408 {
409 size_t pos = GetLastSlashPosFromPath(path);
410 if (pos == INVALID_RET || pos + 1 >= path.size()) {
411 MEDIA_ERR_LOG("Failed to obtain file name because pos is invalid or out of range, path: %{public}s, "
412 "size: %{public}zu, pos: %{public}zu", GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str(), path.size(), pos);
413 return "";
414 }
415 return path.substr(pos + 1);
416 }
417
GetFileTitle(const string & displayName)418 string BackupFileUtils::GetFileTitle(const string &displayName)
419 {
420 string::size_type pos = displayName.find_last_of('.');
421 return (pos == string::npos) ? displayName : displayName.substr(0, pos);
422 }
423
IsLowQualityImage(std::string & filePath,int32_t sceneCode,string relativePath,bool hasLowQualityImage)424 int32_t BackupFileUtils::IsLowQualityImage(std::string &filePath, int32_t sceneCode,
425 string relativePath, bool hasLowQualityImage)
426 {
427 struct stat statInfo {};
428 std::string garbledFilePath = BackupFileUtils::GarbleFilePath(filePath, sceneCode);
429 if (!hasLowQualityImage) {
430 MEDIA_ERR_LOG("Invalid file (%{public}s), no low quality image, err: %{public}d", garbledFilePath.c_str(),
431 errno);
432 return E_FAIL;
433 }
434 string realPath = ConvertLowQualityPath(sceneCode, filePath, relativePath);
435 if (stat(realPath.c_str(), &statInfo) != E_SUCCESS) {
436 MEDIA_ERR_LOG("Invalid Low quality image! file:%{public}s, err:%{public}d", garbledFilePath.c_str(), errno);
437 return E_NO_SUCH_FILE;
438 }
439 MEDIA_INFO_LOG("Low quality image! file: %{public}s", garbledFilePath.c_str());
440 filePath = realPath;
441 if (statInfo.st_mode & S_IFDIR) {
442 MEDIA_ERR_LOG("Invalid file (%{public}s), is a directory", garbledFilePath.c_str());
443 return E_FAIL;
444 }
445 if (statInfo.st_size <= 0) {
446 MEDIA_ERR_LOG("Invalid file (%{public}s), get size (%{public}lld) <= 0", garbledFilePath.c_str(),
447 (long long)statInfo.st_size);
448 return E_FAIL;
449 }
450 return E_OK;
451 }
452
IsFileValid(std::string & filePath,int32_t sceneCode,string relativePath,bool hasLowQualityImage)453 int32_t BackupFileUtils::IsFileValid(std::string &filePath, int32_t sceneCode,
454 string relativePath, bool hasLowQualityImage)
455 {
456 std::string garbledFilePath = BackupFileUtils::GarbleFilePath(filePath, sceneCode);
457 struct stat statInfo {};
458 if (stat(filePath.c_str(), &statInfo) != E_SUCCESS) {
459 bool res = false;
460 if (fileAccessHelper_ != nullptr) {
461 res = fileAccessHelper_->GetValidPath(filePath);
462 }
463 if (stat(filePath.c_str(), &statInfo) != E_SUCCESS) {
464 return hasLowQualityImage ? IsLowQualityImage(filePath, sceneCode, relativePath, hasLowQualityImage) :
465 E_NO_SUCH_FILE;
466 }
467 }
468 if (statInfo.st_mode & S_IFDIR) {
469 MEDIA_ERR_LOG("Invalid file (%{public}s), is a directory", garbledFilePath.c_str());
470 return E_FAIL;
471 }
472 if (statInfo.st_size <= 0) {
473 MEDIA_ERR_LOG("Invalid file (%{public}s), get size (%{public}lld) <= 0", garbledFilePath.c_str(),
474 (long long)statInfo.st_size);
475 return E_FAIL;
476 }
477 return E_OK;
478 }
479
GetDetailsPath(int32_t sceneCode,const std::string & type,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)480 std::string BackupFileUtils::GetDetailsPath(int32_t sceneCode, const std::string &type,
481 const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
482 {
483 std::string detailsPath = RESTORE_FAILED_FILES_PATH + "_" + type + ".txt";
484 if (MediaFileUtils::IsFileExists(detailsPath) && !MediaFileUtils::DeleteFile(detailsPath)) {
485 MEDIA_ERR_LOG("%{public}s exists and delete failed", detailsPath.c_str());
486 return "";
487 }
488 if (failedFiles.empty() || limit == 0) {
489 return "";
490 }
491 if (MediaFileUtils::CreateAsset(detailsPath) != E_SUCCESS) {
492 MEDIA_ERR_LOG("Create %{public}s failed", detailsPath.c_str());
493 return "";
494 }
495 std::string failedFilesStr = GetFailedFilesStr(sceneCode, failedFiles, limit);
496 if (!MediaFileUtils::WriteStrToFile(detailsPath, failedFilesStr)) {
497 MEDIA_ERR_LOG("Write to %{public}s failed", detailsPath.c_str());
498 return "";
499 }
500 return detailsPath;
501 }
502
GetFailedFilesStr(int32_t sceneCode,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)503 std::string BackupFileUtils::GetFailedFilesStr(int32_t sceneCode,
504 const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
505 {
506 std::stringstream failedFilesStream;
507 failedFilesStream << "[";
508 for (const auto &iter : failedFiles) {
509 if (limit == 0) {
510 break;
511 }
512 failedFilesStream << "\n\"";
513 failedFilesStream << GetFailedFile(sceneCode, iter.first, iter.second);
514 limit > 1 ? failedFilesStream << "\"," : failedFilesStream << "\"";
515 limit--;
516 }
517 failedFilesStream << "\n]";
518 return failedFilesStream.str();
519 }
520
CreateDataShareHelper(const sptr<IRemoteObject> & token)521 void BackupFileUtils::CreateDataShareHelper(const sptr<IRemoteObject> &token)
522 {
523 if (token != nullptr) {
524 sDataShareHelper_ = DataShare::DataShareHelper::Creator(token, MEDIALIBRARY_DATA_URI);
525 if (sDataShareHelper_ == nullptr) {
526 MEDIA_ERR_LOG("generate thumbnails after restore failed, the sDataShareHelper_ is nullptr.");
527 }
528 }
529 }
530
GenerateThumbnailsAfterRestore(int32_t restoreAstcCount)531 void BackupFileUtils::GenerateThumbnailsAfterRestore(int32_t restoreAstcCount)
532 {
533 if (sDataShareHelper_ == nullptr) {
534 return;
535 }
536 std::string updateUri = PAH_GENERATE_THUMBNAILS_RESTORE;
537 MediaFileUtils::UriAppendKeyValue(updateUri, URI_PARAM_API_VERSION, to_string(MEDIA_API_VERSION_V10));
538 Uri uri(updateUri);
539 DataShare::DataSharePredicates emptyPredicates;
540 DataShare::DataShareValuesBucket valuesBucket;
541 valuesBucket.Put(RESTORE_REQUEST_ASTC_GENERATE_COUNT, restoreAstcCount);
542 int result = sDataShareHelper_->Update(uri, emptyPredicates, valuesBucket);
543 if (result < 0) {
544 MEDIA_ERR_LOG("generate thumbnails after restore failed, the sDataShareHelper_ update error");
545 }
546 }
547
GetFailedFilesList(int32_t sceneCode,const std::unordered_map<std::string,FailedFileInfo> & failedFiles,size_t limit)548 std::vector<std::string> BackupFileUtils::GetFailedFilesList(int32_t sceneCode,
549 const std::unordered_map<std::string, FailedFileInfo> &failedFiles, size_t limit)
550 {
551 std::vector<std::string> failedFilesList;
552 for (const auto &iter : failedFiles) {
553 if (limit == 0) {
554 break;
555 }
556 failedFilesList.push_back(GetFailedFile(sceneCode, iter.first, iter.second));
557 limit--;
558 }
559 return failedFilesList;
560 }
561
GetFailedFile(int32_t sceneCode,const std::string & failedFilePath,const FailedFileInfo & failedFileInfo)562 std::string BackupFileUtils::GetFailedFile(int32_t sceneCode, const std::string &failedFilePath,
563 const FailedFileInfo &failedFileInfo)
564 {
565 MEDIA_ERR_LOG("Failed file: %{public}s, %{public}s, %{public}s, %{public}s",
566 GarbleFilePath(failedFilePath, sceneCode).c_str(), failedFileInfo.albumName.c_str(),
567 GarbleFileName(failedFileInfo.displayName).c_str(), failedFileInfo.errorCode.c_str());
568 // format: albumName/displayName
569 return failedFileInfo.albumName + "/" + failedFileInfo.displayName;
570 }
571
GetPathPosByPrefixLevel(int32_t sceneCode,const std::string & path,int32_t prefixLevel,size_t & pos)572 bool BackupFileUtils::GetPathPosByPrefixLevel(int32_t sceneCode, const std::string &path, int32_t prefixLevel,
573 size_t &pos)
574 {
575 int32_t count = 0;
576 for (size_t index = 0; index < path.length(); index++) {
577 if (path[index] != '/') {
578 continue;
579 }
580 count++;
581 if (count == prefixLevel) {
582 pos = index;
583 break;
584 }
585 }
586 if (count < prefixLevel) {
587 MEDIA_ERR_LOG("Get position failed for %{public}s, %{public}d < %{public}d",
588 GarbleFilePath(path, sceneCode).c_str(), count, prefixLevel);
589 return false;
590 }
591 return true;
592 }
593
ShouldIncludeSd(const std::string & prefix)594 bool BackupFileUtils::ShouldIncludeSd(const std::string &prefix)
595 {
596 return MediaFileUtils::IsFileExists(prefix + "/" + PHOTO_SD_DB_NAME) ||
597 MediaFileUtils::IsFileExists(prefix + "/" + VIDEO_SD_DB_NAME);
598 }
599
DeleteSdDatabase(const std::string & prefix)600 void BackupFileUtils::DeleteSdDatabase(const std::string &prefix)
601 {
602 std::vector<std::string> sdDbs = { PHOTO_SD_DB_NAME, VIDEO_SD_DB_NAME };
603 for (const auto &sdDb : sdDbs) {
604 std::string sdDbPath = prefix + "/" + sdDb;
605 if (!MediaFileUtils::IsFileExists(sdDbPath)) {
606 continue;
607 }
608 if (!MediaFileUtils::DeleteFile(sdDbPath)) {
609 MEDIA_ERR_LOG("Delete Sd database %{public}s failed, errno: %{public}d", sdDb.c_str(), errno);
610 }
611 }
612 }
613
IsLivePhoto(const FileInfo & fileInfo)614 bool BackupFileUtils::IsLivePhoto(const FileInfo &fileInfo)
615 {
616 return fileInfo.specialFileType == LIVE_PHOTO_TYPE || fileInfo.specialFileType == LIVE_PHOTO_HDR_TYPE;
617 }
618
addPathSuffix(const string & oldPath,const string & suffix,string & newPath)619 static void addPathSuffix(const string &oldPath, const string &suffix, string &newPath)
620 {
621 if (oldPath.empty() || suffix.empty()) {
622 MEDIA_WARN_LOG("oldPath or suffix is empty");
623 return;
624 }
625
626 newPath = oldPath + suffix;
627 while (MediaFileUtils::IsFileExists(newPath)) {
628 newPath += ".dup" + suffix;
629 }
630 }
631
ConvertToMovingPhoto(FileInfo & fileInfo)632 bool BackupFileUtils::ConvertToMovingPhoto(FileInfo &fileInfo)
633 {
634 if (!MediaFileUtils::IsFileExists(fileInfo.filePath)) {
635 MEDIA_ERR_LOG("Live photo does not exist, path: %{private}s, errno: %{public}d",
636 fileInfo.filePath.c_str(), errno);
637 return false;
638 }
639
640 string movingPhotoImagePath;
641 addPathSuffix(fileInfo.filePath, ".jpg", movingPhotoImagePath);
642 addPathSuffix(fileInfo.filePath, ".mp4", fileInfo.movingPhotoVideoPath);
643 addPathSuffix(fileInfo.filePath, ".extra", fileInfo.extraDataPath);
644 int32_t ret = MovingPhotoFileUtils::ConvertToMovingPhoto(
645 fileInfo.filePath, movingPhotoImagePath, fileInfo.movingPhotoVideoPath, fileInfo.extraDataPath);
646 if (ret != E_OK) {
647 return false;
648 }
649
650 if (!MediaFileUtils::DeleteFile(fileInfo.filePath)) {
651 MEDIA_WARN_LOG("Failed to delete original live photo: %{private}s, errno: %{public}d",
652 fileInfo.filePath.c_str(), errno);
653 }
654 fileInfo.filePath = movingPhotoImagePath;
655 return true;
656 }
657
GetLastSlashPosFromPath(const std::string & path)658 size_t BackupFileUtils::GetLastSlashPosFromPath(const std::string &path)
659 {
660 if (path.empty()) {
661 MEDIA_ERR_LOG("Failed to obtain last slash pos because given path is empty");
662 return INVALID_RET;
663 }
664 size_t pos = path.rfind("/");
665 if (pos == std::string::npos) {
666 MEDIA_ERR_LOG("Failed to obtain last slash pos because / not found");
667 return INVALID_RET;
668 }
669 return pos;
670 }
671
GetFileFolderFromPath(const std::string & path,bool shouldStartWithSlash)672 std::string BackupFileUtils::GetFileFolderFromPath(const std::string &path, bool shouldStartWithSlash)
673 {
674 size_t endPos = GetLastSlashPosFromPath(path);
675 if (endPos == INVALID_RET) {
676 MEDIA_ERR_LOG("Failed to obtain file folder, path: %{public}s",
677 GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str());
678 return "";
679 }
680 size_t startPos = MediaFileUtils::StartsWith(path, "/") && !shouldStartWithSlash ? 1 : 0;
681 if (startPos >= endPos) {
682 MEDIA_ERR_LOG("Failed to obtain file folder because start %{public}zu >= end %{public}zu, path: %{public}s",
683 startPos, endPos, GarbleFilePath(path, DEFAULT_RESTORE_ID).c_str());
684 return "";
685 }
686 return path.substr(startPos, endPos - startPos);
687 }
688
GetExtraPrefixForRealPath(int32_t sceneCode,const std::string & path)689 std::string BackupFileUtils::GetExtraPrefixForRealPath(int32_t sceneCode, const std::string &path)
690 {
691 return sceneCode == UPGRADE_RESTORE_ID && IsAppTwinData(path) ? APP_TWIN_DATA_PREFIX : "";
692 }
693
IsAppTwinData(const std::string & path)694 bool BackupFileUtils::IsAppTwinData(const std::string &path)
695 {
696 int32_t userId = GetUserId(path);
697 return userId >= APP_TWIN_DATA_START && userId <= APP_TWIN_DATA_END;
698 }
699
GetUserId(const std::string & path)700 int32_t BackupFileUtils::GetUserId(const std::string &path)
701 {
702 int32_t userId = -1;
703 if (!MediaFileUtils::StartsWith(path, INTERNAL_PREFIX)) {
704 return userId;
705 }
706 std::string tmpPath = path.substr(INTERNAL_PREFIX.size());
707 if (tmpPath.empty()) {
708 MEDIA_ERR_LOG("Get substr failed, path: %{public}s", path.c_str());
709 return userId;
710 }
711 size_t posStart = tmpPath.find_first_of("/");
712 if (posStart == std::string::npos) {
713 MEDIA_ERR_LOG("Get first / failed, path: %{public}s", path.c_str());
714 return userId;
715 }
716 size_t posEnd = tmpPath.find_first_of("/", posStart + 1);
717 if (posEnd == std::string::npos) {
718 MEDIA_ERR_LOG("Get second / failed, path: %{public}s", path.c_str());
719 return userId;
720 }
721 std::string userIdStr = tmpPath.substr(posStart + 1, posEnd - posStart -1);
722 if (userIdStr.empty() || !MediaLibraryDataManagerUtils::IsNumber(userIdStr)) {
723 MEDIA_ERR_LOG("Get userId failed, empty or not number, path: %{public}s", path.c_str());
724 return userId;
725 }
726 return std::atoi(userIdStr.c_str());
727 }
728
HandleRotateImage(const std::string & sourceFile,const std::string & targetPath,int32_t degrees,bool isLcd)729 bool BackupFileUtils::HandleRotateImage(const std::string &sourceFile,
730 const std::string &targetPath, int32_t degrees, bool isLcd)
731 {
732 uint32_t err = E_OK;
733 std::unique_ptr<ImageSource> imageSource = LoadImageSource(sourceFile, err);
734 if (err != E_OK || imageSource == nullptr) {
735 MEDIA_ERR_LOG("LoadImageSource error: %{public}d, errno: %{public}d", err, errno);
736 return false;
737 }
738 if (imageSource->IsHdrImage()) {
739 return BackupFileUtils::HandleHdrImage(std::move(imageSource), targetPath, degrees, isLcd);
740 } else {
741 return BackupFileUtils::HandleSdrImage(std::move(imageSource), targetPath, degrees, isLcd);
742 }
743 }
744
LoadImageSource(const std::string & file,uint32_t & err)745 unique_ptr<ImageSource> BackupFileUtils::LoadImageSource(const std::string &file, uint32_t &err)
746 {
747 SourceOptions opts;
748 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(file, opts, err);
749 if (err != E_OK || !imageSource) {
750 MEDIA_ERR_LOG("Failed to LoadImageSource, file exists: %{public}d", MediaFileUtils::IsFileExists(file));
751 return imageSource;
752 }
753 return imageSource;
754 }
755
HandleHdrImage(std::unique_ptr<ImageSource> imageSource,const std::string & targetPath,int32_t degrees,bool isLcd)756 bool BackupFileUtils::HandleHdrImage(std::unique_ptr<ImageSource> imageSource,
757 const std::string &targetPath, int32_t degrees, bool isLcd)
758 {
759 CHECK_AND_RETURN_RET_LOG(imageSource != nullptr, false, "Hdr imagesource null.");
760 DecodingOptionsForPicture pictOpts;
761 pictOpts.desireAuxiliaryPictures = {AuxiliaryPictureType::GAINMAP};
762 uint32_t err = E_OK;
763 auto picturePtr = imageSource->CreatePicture(pictOpts, err);
764 if (err != E_OK || picturePtr == nullptr) {
765 MEDIA_ERR_LOG("Failed to CreatePicture failed, err: %{public}d", err);
766 return false;
767 }
768 std::shared_ptr<Picture> picture = std::move(picturePtr);
769 auto pixelMap = picture->GetMainPixel();
770 auto gainMap = picture->GetGainmapPixelMap();
771 CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, false, "Failed to CreatePicture, main pixelMap is nullptr.");
772 CHECK_AND_RETURN_RET_LOG(gainMap != nullptr, false, "Failed to CreatePicture, gainmap is nullptr.");
773 if (pixelMap->GetWidth() * pixelMap->GetHeight() == 0) {
774 MEDIA_ERR_LOG("Failed to CreatePicture, pixelMap size invalid, width: %{public}d, height: %{public}d",
775 pixelMap->GetWidth(), pixelMap->GetHeight());
776 return false;
777 }
778 pixelMap->rotate(static_cast<float>(degrees));
779 gainMap->rotate(static_cast<float>(degrees));
780
781 if (isLcd) {
782 if (!EncodePicture(*picture, targetPath + LCD_FILE_NAME)) {
783 return false;
784 }
785 return ScalePixelMap(*pixelMap, *imageSource, targetPath + THM_FILE_NAME);
786 }
787 return EncodePicture(*picture, targetPath + THM_FILE_NAME);
788 }
789
EncodePicture(Picture & picture,const std::string & outFile)790 bool BackupFileUtils::EncodePicture(Picture &picture, const std::string &outFile)
791 {
792 Media::ImagePacker imagePacker;
793 PackOption option = {
794 .format = IMAGE_FORMAT,
795 .quality = IMAGE_QUALITY,
796 .numberHint = IMAGE_NUMBER_HINT,
797 .desiredDynamicRange = EncodeDynamicRange::AUTO,
798 .needsPackProperties = false
799 };
800 uint32_t err = imagePacker.StartPacking(outFile, option);
801 CHECK_AND_RETURN_RET_LOG(err == 0, false, "Failed to StartPacking %{public}d", err);
802 err = imagePacker.AddPicture(picture);
803 CHECK_AND_RETURN_RET_LOG(err == 0, false, "Failed to AddPicture %{public}d", err);
804 err = imagePacker.FinalizePacking();
805 CHECK_AND_RETURN_RET_LOG(err == 0, false, "Failed to FinalizePacking %{public}d", err);
806 return true;
807 }
808
HandleSdrImage(std::unique_ptr<ImageSource> imageSource,const std::string & targetPath,int32_t degrees,bool isLcd)809 bool BackupFileUtils::HandleSdrImage(std::unique_ptr<ImageSource> imageSource,
810 const std::string &targetPath, int32_t degrees, bool isLcd)
811 {
812 CHECK_AND_RETURN_RET_LOG(imageSource != nullptr, false, "Sdr imagesource null.");
813 DecodeOptions decodeOpts;
814 uint32_t err = ERR_OK;
815 unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
816 CHECK_AND_RETURN_RET_LOG(pixelMap != nullptr, false, "CreatePixelMap err: %{public}d", err);
817 pixelMap->rotate(static_cast<float>(degrees));
818 if (isLcd) {
819 if (!EncodePixelMap(*pixelMap, targetPath + LCD_FILE_NAME)) {
820 return false;
821 }
822 return ScalePixelMap(*pixelMap, *imageSource, targetPath + THM_FILE_NAME);
823 }
824 return EncodePixelMap(*pixelMap, targetPath + THM_FILE_NAME);
825 }
826
ScalePixelMap(PixelMap & pixelMap,ImageSource & imageSource,const std::string & outFile)827 bool BackupFileUtils::ScalePixelMap(PixelMap &pixelMap, ImageSource &imageSource, const std::string &outFile)
828 {
829 ImageInfo imageInfo;
830 uint32_t err = imageSource.GetImageInfo(0, imageInfo);
831 if (err != E_OK) {
832 MEDIA_ERR_LOG("Failed to Get ImageInfo");
833 return false;
834 }
835 int targetWidth = imageInfo.size.height;
836 int targetHeight = imageInfo.size.width;
837 if (!ThumbnailUtils::ResizeThumb(targetWidth, targetHeight)) {
838 return false;
839 }
840 Size targetSize{targetWidth, targetHeight};
841 PostProc postProc;
842 if (!postProc.ScalePixelMapEx(targetSize, pixelMap, Media::AntiAliasingOption::HIGH)) {
843 MEDIA_ERR_LOG("ScalePixelMapEx failed, targetSize: %{public}d * %{public}d",
844 targetSize.width, targetSize.height);
845 return false;
846 }
847 return EncodePixelMap(pixelMap, outFile);
848 }
849
EncodePixelMap(PixelMap & pixelMap,const std::string & outFile)850 bool BackupFileUtils::EncodePixelMap(PixelMap &pixelMap, const std::string &outFile)
851 {
852 PackOption option = {
853 .format = IMAGE_FORMAT,
854 .quality = IMAGE_QUALITY,
855 .numberHint = IMAGE_NUMBER_HINT,
856 .desiredDynamicRange = EncodeDynamicRange::SDR,
857 };
858 ImagePacker imagePacker;
859 uint32_t err = imagePacker.StartPacking(outFile, option);
860 CHECK_AND_RETURN_RET_LOG(err == 0, false, "Failed to StartPacking %{public}d", err);
861 err = imagePacker.AddImage(pixelMap);
862 CHECK_AND_RETURN_RET_LOG(err == 0, false, "Failed to AddPicture %{public}d", err);
863 err = imagePacker.FinalizePacking();
864 CHECK_AND_RETURN_RET_LOG(err == 0, false, "Failed to FinalizePacking %{public}d", err);
865 return true;
866 }
867 } // namespace Media
868 } // namespace OHOS