• 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 "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