• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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