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