1 /*
2 * Copyright (C) 2021-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 #define MLOG_TAG "FileUtils"
16
17 #include "media_file_utils.h"
18
19 #include <algorithm>
20 #include <stack>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <filesystem>
24 #include <fstream>
25 #include <ftw.h>
26 #include <regex>
27 #include <securec.h>
28 #include <sstream>
29 #include <sys/sendfile.h>
30 #include <sys/stat.h>
31 #include <sys/statvfs.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <unordered_map>
35 #include <utime.h>
36
37 #include "avmetadatahelper.h"
38 #include "directory_ex.h"
39 #include "hmdfs.h"
40 #include "ipc_skeleton.h"
41 #include "media_column.h"
42 #include "media_file_uri.h"
43 #include "media_log.h"
44 #include "medialibrary_db_const.h"
45 #include "medialibrary_errno.h"
46 #include "medialibrary_type_const.h"
47 #include "mimetype_utils.h"
48 #include "medialibrary_tracer.h"
49 #include "ptp_medialibrary_manager_uri.h"
50 #include "string_ex.h"
51 #include "userfilemgr_uri.h"
52 #include "data_secondary_directory_uri.h"
53 #include "image_source.h"
54 #include "image_packer.h"
55
56 using namespace std;
57
58 namespace OHOS::Media {
59 static const mode_t CHOWN_RWX_USR_GRP = 02771;
60 static const mode_t CHOWN_RW_USR_GRP = 0660;
61 static const mode_t CHOWN_RO_USR_GRP = 0644;
62 constexpr size_t DISPLAYNAME_MAX = 255;
63 const int32_t OPEN_FDS = 64;
64 const std::string PATH_PARA = "path=";
65 constexpr unsigned short MAX_RECURSION_DEPTH = 4;
66 constexpr size_t DEFAULT_TIME_SIZE = 32;
67 constexpr int32_t CROSS_POLICY_ERR = 18;
68 const int32_t HMFS_MONITOR_FL = 2;
69 const int32_t INTEGER_MAX_LENGTH = 10;
70 const std::string LISTENING_BASE_PATH = "/storage/media/local/files/";
71 const std::string PHOTO_DIR = "Photo";
72 const std::string AUDIO_DIR = "Audio";
73 const std::string THUMBS_DIR = ".thumbs";
74 const std::string EDIT_DATA_DIR = ".editData";
75 const std::string THUMBS_PHOTO_DIR = ".thumbs/Photo";
76 const std::string EDIT_DATA_PHOTO_DIR = ".editData/Photo";
77 const std::string CLOUD_FILE_PATH = "/storage/cloud/files";
78 const std::string TMP_SUFFIX = "tmp";
79 const std::vector<std::string> SET_LISTEN_DIR = {
80 PHOTO_DIR, AUDIO_DIR, THUMBS_DIR, EDIT_DATA_DIR, THUMBS_PHOTO_DIR, EDIT_DATA_PHOTO_DIR
81 };
82 const std::string KVSTORE_FILE_ID_TEMPLATE = "0000000000";
83 const std::string KVSTORE_DATE_KEY_TEMPLATE = "0000000000000";
84 const std::string MAX_INTEGER = "2147483648";
85 const std::string DEFAULT_IMAGE_NAME = "IMG_";
86 const std::string DEFAULT_VIDEO_NAME = "VID_";
87 const std::string DEFAULT_AUDIO_NAME = "AUD_";
88 const int64_t UNIT = 1000;
89 const int64_t STD_UNIT = 1024;
90 const int64_t THRESHOLD = 512;
91 const std::string DATA_PATH = "/data/storage/el2/base";
92 #define HMFS_IOCTL_HW_GET_FLAGS _IOR(0XF5, 70, unsigned int)
93 #define HMFS_IOCTL_HW_SET_FLAGS _IOR(0XF5, 71, unsigned int)
94 const std::string MEDIA_DATA_DEVICE_PATH = "local";
95
96 static const std::unordered_map<std::string, std::vector<std::string>> MEDIA_MIME_TYPE_MAP = {
97 { "application/epub+zip", { "epub" } },
98 { "application/lrc", { "lrc"} },
99 { "application/pkix-cert", { "cer" } },
100 { "application/rss+xml", { "rss" } },
101 { "application/sdp", { "sdp" } },
102 { "application/smil+xml", { "smil" } },
103 { "application/ttml+xml", { "ttml", "dfxp" } },
104 { "application/vnd.ms-pki.stl", { "stl" } },
105 { "application/vnd.ms-powerpoint", { "pot", "ppt" } },
106 { "application/vnd.ms-wpl", { "wpl" } },
107 { "application/vnd.stardivision.writer", { "vor" } },
108 { "application/vnd.youtube.yt", { "yt" } },
109 { "application/x-font", { "pcf" } },
110 { "application/x-mobipocket-ebook", { "prc", "mobi" } },
111 { "application/x-pem-file", { "pem" } },
112 { "application/x-pkcs12", { "p12", "pfx" } },
113 { "application/x-subrip", { "srt" } },
114 { "application/x-webarchive", { "webarchive" } },
115 { "application/x-webarchive-xml", { "webarchivexml" } },
116 { "application/pgp-signature", { "pgp" } },
117 { "application/x-x509-ca-cert", { "crt", "der" } },
118 { "application/json", { "json" } },
119 { "application/javascript", { "js" } },
120 { "application/zip", { "zip" } },
121 { "application/rar", { "rar" } },
122 { "application/pdf", { "pdf" } },
123 { "application/msword", { "doc" } },
124 { "application/ms-excel", { "xls" } },
125 { "application/vnd.openxmlformats-officedocument.wordprocessingml.document", { "docx" } },
126 { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", { "xlsx" } },
127 { "application/vnd.openxmlformats-officedocument.presentationml.presentation", { "pptx" } },
128 { "audio/3gpp", { "3ga" } },
129 { "audio/ac3", { "ac3", "a52"} },
130 { "audio/amr", { "amr" } },
131 { "audio/imelody", { "imy" } },
132 { "audio/midi", { "rtttl", "xmf", "rtx" } },
133 { "audio/mobile-xmf", { "mxmf"} },
134 { "audio/mp4", { "m4a", "m4b", "m4p", "f4a", "f4b", "f4p" } },
135 { "audio/mpegurl", { "m3u" } },
136 { "audio/sp-midi", { "smf" } },
137 { "audio/x-matroska", { "mka" } },
138 { "audio/x-pn-realaudio", { "ra" } },
139 { "audio/x-mpeg", { "mp3" } },
140 { "audio/aac", { "aac", "adts", "adt" } },
141 { "audio/basic", { "snd" } },
142 { "audio/flac", { "flac" } },
143 { "audio/mpeg", { "mp3", "mp2", "mp1", "mpa", "m4r" } },
144 { "audio/wav", { "wav" } },
145 { "audio/ogg", { "ogg" } },
146 { "image/gif", { "gif"} },
147 { "image/heic", { "heic" } },
148 { "image/heic-sequence", { "heics", "heifs" } },
149 { "image/bmp", { "bmp", "bm" } },
150 { "image/heif", { "heif", "hif" } },
151 { "image/avif", { "avif" } },
152 { "image/ico", { "cur" } },
153 { "image/webp", { "webp"} },
154 { "image/x-adobe-dng", { "dng" } },
155 { "image/x-fuji-raf", { "raf" } },
156 { "image/x-icon", { "ico" } },
157 { "image/x-nikon-nrw", { "nrw" } },
158 { "image/x-panasonic-rw2", { "rw2" } },
159 { "image/x-pentax-pef", { "pef" } },
160 { "image/x-samsung-srw", { "srw" } },
161 { "image/x-sony-arw", { "arw" } },
162 { "image/jpeg", { "jpg", "jpeg", "jpe" } },
163 { "image/png", { "png" } },
164 { "image/svg+xml", { "svg", "svgz" } },
165 { "image/x-dcraw", { "raw" } },
166 { "image/ief", { "ief" } },
167 { "image/jp2", { "jp2", "jpg2" } },
168 { "image/ipm", { "ipm" } },
169 { "image/jpm", { "jpm" } },
170 { "image/ipx", { "jpx", "jpf" } },
171 { "image/pcx", { "pcx" } },
172 { "image/tiff", { "tiff", "tif" } },
173 { "image/vnd.divu", { "djvu", "djv" } },
174 { "image/vnd.wap.wbmp", { "wbmp" } },
175 { "image/x-canon-cr2", { "cr2" } },
176 { "image/x-canon-crw", { "crw" } },
177 { "image/x-cmu-raster", { "ras" } },
178 { "image/x-coreldraw", { "cdr" } },
179 { "image/x-coreldrawpattern", { "pat" } },
180 { "image/x-coreldrawtemplate", { "cdt" } },
181 { "image/x-corelphotopaint", { "cpt" } },
182 { "image/x-epson-erf", { "erf" } },
183 { "image/x-jg", { "art" } },
184 { "image/x-jng", { "jng" } },
185 { "image/x-nikon-nef", { "nef" } },
186 { "image/x-olvmpus-orf", { "orf" } },
187 { "image/x-photoshop", { "psd" } },
188 { "image/x-portable-anymap", { "pnm" } },
189 { "image/x-portable-bitmap", { "pbm" } },
190 { "image/x-portable-graymap", { "pgm" } },
191 { "image/x-portable-pixmap", { "ppm" } },
192 { "image/x-rgb", { "rgb" } },
193 { "image/x-xbitmap", { "xbm" } },
194 { "image/x-xpixmap", { "xpm" } },
195 { "image/x-xwindowdump", { "xwd" } },
196 { "video/3gpp2", { "3gpp2", "3gp2", "3g2" } },
197 { "video/3gpp", { "3gpp", "3gp" } },
198 { "video/mp4", { "m4v", "f4v", "mp4v", "mpeg4", "mp4" } },
199 { "video/mp2t", { "m2ts", "mts"} },
200 { "video/mp2ts", { "ts" } },
201 { "video/vnd.youtube.yt", { "yt" } },
202 { "video/x-webex", { "wrf" } },
203 { "video/mpeg", { "mpe", "mpeg", "mpeg2", "mpv2", "mp2v", "m2v", "m2t", "mpeg1", "mpv1", "mp1v", "m1v", "mpg" } },
204 { "video/quicktime", { "mov", "qt" } },
205 { "video/x-matroska", { "mkv", "mpv" } },
206 { "video/webm", { "webm" } },
207 { "video/H264", { "h264" } },
208 { "video/x-flv", { "flv" } },
209 { "video/avi", { "avi" } },
210 { "video/x-pn-realvideo", { "rmvb" } },
211 { "video/annodex", { "axv" } },
212 { "video/dl", { "dl" } },
213 { "video/dv", { "dif", "dv" } },
214 { "video/fli", { "fli" } },
215 { "video/gl", { "gl" } },
216 { "video/ogg", { "ogv" } },
217 { "video/vnd.mpegurl", { "mxu" } },
218 { "video/x-la-asf", { "lsf", "lsx" } },
219 { "video/x-mng", { "mng" } },
220 { "video/x-ms-asf", { "asf", "asx" } },
221 { "video/x-ms-wm", { "wm" } },
222 { "video/x-ms-wmv", { "wmv" } },
223 { "video/x-ms-wmx", { "wmx" } },
224 { "video/x-ms-wvx", { "wvx" } },
225 { "video/x-sgi-movie", { "movie" } },
226 { "text/comma-separated-values", { "csv" } },
227 { "text/plain", { "diff", "po", "txt" } },
228 { "text/rtf", { "rtf" } },
229 { "text/text", { "phps", "m3u", "m3u8" } },
230 { "text/xml", { "xml" } },
231 { "text/x-vcard", { "vcf" } },
232 { "text/x-c++hdr", { "hpp", "h++", "hxx", "hh" } },
233 { "text/x-c++src", { "cpp", "c++", "cxx", "cc" } },
234 { "text/css", { "css" } },
235 { "text/html", { "html", "htm", "shtml"} },
236 { "text/markdown", { "md", "markdown" } },
237 { "text/x-java", { "java" } },
238 { "text/x-python", { "py" } }
239 };
240
241 static const std::unordered_map<std::string, std::vector<std::string>> MEDIA_EXTRA_MIME_TYPE_MAP = {
242 { "audio/3gpp", { "3gpp" } },
243 { "audio/midi", { "mid", "midi", "kar" } },
244 { "audio/basic", { "au" } },
245 { "audio/x-pn-realaudio", { "rm", "ram" } },
246 { "audio/aac-adts", { "aac" } },
247 { "audio/mpeg", { "m4a", "mpga", "mpega" } },
248 { "audio/x-mpegurl", { "m3u", "m3u8" } },
249 { "audio/ffmpeg", { "ape" } },
250 { "audio/mp4", { "isma" } },
251 { "audio/ac4", { "ac4" } },
252 { "audio/amr-wb", { "awb" } },
253 { "audio/annodex", { "axa" } },
254 { "audio/csound", { "csd", "orc", "sco" } },
255 { "audio/ogg", { "oga", "ogg", "opus", "spx" } },
256 { "audio/prs.sid", { "sid" } },
257 { "audio/x-aiff", { "aif", "aiff", "aifc" } },
258 { "audio/x-gsm", { "gsm"} },
259 { "audio/x-mpegurl", { "m3u" } },
260 { "audio/x-ms-wma", { "wma" } },
261 { "audio/x-ms-wax", { "wax" } },
262 { "audio/x-realaudio", { "ra" } },
263 { "audio/x-scpls", { "pls" } },
264 { "audio/x-sd2", { "sd2" } },
265 { "audio/x-wav", { "wav" } }
266 };
267
GetAllTypes(const int32_t extension)268 vector<string> MediaFileUtils::GetAllTypes(const int32_t extension)
269 {
270 vector<std::string> allTypesVec;
271 if (extension != MEDIA_TYPE_IMAGE && extension != MEDIA_TYPE_VIDEO) {
272 return allTypesVec;
273 }
274 for (auto &item : MEDIA_MIME_TYPE_MAP) {
275 if (extension == MimeTypeUtils::GetMediaTypeFromMimeType(item.first)) {
276 for (auto &ext : item.second) {
277 allTypesVec.push_back(ext);
278 }
279 }
280 }
281 return allTypesVec;
282 }
283
UnlinkCb(const char * fpath,const struct stat * sb,int32_t typeflag,struct FTW * ftwbuf)284 int32_t UnlinkCb(const char *fpath, const struct stat *sb, int32_t typeflag, struct FTW *ftwbuf)
285 {
286 CHECK_AND_RETURN_RET_LOG(fpath != nullptr, E_FAIL, "fpath == nullptr");
287 int32_t errRet = remove(fpath);
288 CHECK_AND_PRINT_LOG(!errRet, "Failed to remove errno: %{public}d, path: %{private}s", errno, fpath);
289 return errRet;
290 }
291
RemoveDirectory(const string & path)292 int32_t MediaFileUtils::RemoveDirectory(const string &path)
293 {
294 return nftw(path.c_str(), UnlinkCb, OPEN_FDS, FTW_DEPTH | FTW_PHYS);
295 }
296
DesensitizePath(const std::string & path)297 std::string MediaFileUtils::DesensitizePath(const std::string &path)
298 {
299 string result = path;
300 CHECK_AND_RETURN_RET(result.length() > CLOUD_FILE_PATH.length(), result);
301 return result.replace(0, CLOUD_FILE_PATH.length(), "*");
302 }
303
PrintStatInformation(const std::string & path)304 void MediaFileUtils::PrintStatInformation(const std::string& path)
305 {
306 struct stat statInfo {};
307 if ((stat(path.c_str(), &statInfo)) == E_SUCCESS) {
308 MEDIA_INFO_LOG("path:%{public}s uid:%{public}d, gid:%{public}d, mode:%{public}d",
309 DesensitizePath(path).c_str(), statInfo.st_uid, statInfo.st_gid, statInfo.st_mode);
310 } else {
311 MEDIA_INFO_LOG("path:%{public}s is not exist", DesensitizePath(path).c_str());
312 }
313 }
314
Mkdir(const string & subStr,shared_ptr<int> errCodePtr)315 bool MediaFileUtils::Mkdir(const string &subStr, shared_ptr<int> errCodePtr)
316 {
317 mode_t mask = umask(0);
318 if (mkdir(subStr.c_str(), CHOWN_RWX_USR_GRP) == -1) {
319 if (errCodePtr != nullptr) {
320 *errCodePtr = errno;
321 }
322 int err = errno;
323 MEDIA_ERR_LOG("Failed to create directory %{public}d, path:%{public}s", err, DesensitizePath(subStr).c_str());
324 if (err == EACCES) {
325 PrintStatInformation(GetParentPath(subStr));
326 }
327 umask(mask);
328 return (err == EEXIST) ? true : false;
329 }
330 umask(mask);
331 return true;
332 }
333
CreateDirectory(const string & dirPath,shared_ptr<int> errCodePtr)334 bool MediaFileUtils::CreateDirectory(const string &dirPath, shared_ptr<int> errCodePtr)
335 {
336 string subStr;
337 string segment;
338
339 /* Create directory and its sub directories if does not exist
340 * take each string after '/' create directory if does not exist.
341 * Created directory will be the base path for the next sub directory.
342 */
343
344 stringstream folderStream(dirPath);
345 while (getline(folderStream, segment, '/')) {
346 if (segment.empty()) { // skip the first "/" in case of "/storage/cloud/files"
347 continue;
348 }
349
350 subStr.append(SLASH_CHAR + segment);
351 if (!IsDirectory(subStr, errCodePtr)) {
352 CHECK_AND_RETURN_RET(Mkdir(subStr, errCodePtr), false);
353 }
354 }
355
356 return true;
357 }
358
IsFileExists(const string & fileName)359 bool MediaFileUtils::IsFileExists(const string &fileName)
360 {
361 struct stat statInfo {};
362
363 return ((stat(fileName.c_str(), &statInfo)) == E_SUCCESS);
364 }
365
IsFileValid(const string & fileName)366 bool MediaFileUtils::IsFileValid(const string &fileName)
367 {
368 struct stat statInfo {};
369 if (!fileName.empty()) {
370 if (stat(fileName.c_str(), &statInfo) == E_SUCCESS) {
371 // if the given path is a directory path, return
372 CHECK_AND_RETURN_RET_LOG(!(statInfo.st_mode & S_IFDIR), false, "file is a directory");
373
374 // if the file is empty
375 CHECK_AND_WARN_LOG(statInfo.st_size != 0, "file is empty");
376 return true;
377 }
378 }
379 return false;
380 }
381
IsDirEmpty(const string & path)382 bool MediaFileUtils::IsDirEmpty(const string &path)
383 {
384 DIR *dir = opendir(path.c_str());
385 if (dir == nullptr) {
386 MEDIA_ERR_LOG("Failed to open dir:%{private}s, errno: %{public}d. Just return dir NOT empty.",
387 path.c_str(), errno);
388 return false;
389 }
390 bool ret = true;
391 struct dirent *entry;
392 while ((entry = readdir(dir)) != nullptr) {
393 if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
394 ret = false;
395 break;
396 }
397 }
398 if (closedir(dir) < 0) {
399 MEDIA_ERR_LOG("Fail to closedir: %{private}s, errno: %{public}d.", path.c_str(), errno);
400 }
401 return ret;
402 }
403
GetFileName(const string & filePath)404 string MediaFileUtils::GetFileName(const string &filePath)
405 {
406 string fileName;
407
408 if (!(filePath.empty())) {
409 size_t lastSlash = filePath.rfind('/');
410 if (lastSlash != string::npos) {
411 if (filePath.size() > (lastSlash + 1)) {
412 fileName = filePath.substr(lastSlash + 1);
413 }
414 }
415 }
416
417 return fileName;
418 }
419
CreateAssetRealName(int32_t fileId,int32_t mediaType,const string & extension,string & name)420 int32_t MediaFileUtils::CreateAssetRealName(int32_t fileId, int32_t mediaType,
421 const string &extension, string &name)
422 {
423 const int32_t maxComplementAssetId = 999;
424 string fileNumStr = to_string(fileId);
425 if (fileId <= maxComplementAssetId) {
426 size_t fileIdLen = fileNumStr.length();
427 fileNumStr = ("00" + fileNumStr).substr(fileIdLen - 1);
428 }
429
430 string mediaTypeStr;
431 switch (mediaType) {
432 case MediaType::MEDIA_TYPE_IMAGE:
433 mediaTypeStr = DEFAULT_IMAGE_NAME;
434 break;
435 case MediaType::MEDIA_TYPE_VIDEO:
436 mediaTypeStr = DEFAULT_VIDEO_NAME;
437 break;
438 case MediaType::MEDIA_TYPE_AUDIO:
439 mediaTypeStr = DEFAULT_AUDIO_NAME;
440 break;
441 default:
442 MEDIA_ERR_LOG("This mediatype %{public}d can not get real name", mediaType);
443 return E_INVALID_VALUES;
444 }
445
446 static const int32_t CONFLICT_TIME = 100;
447 if (extension.length() == 0) {
448 name = mediaTypeStr + to_string(MediaFileUtils::UTCTimeSeconds() + CONFLICT_TIME) + "_" + fileNumStr;
449 } else {
450 name = mediaTypeStr + to_string(MediaFileUtils::UTCTimeSeconds() + CONFLICT_TIME) + "_" +
451 fileNumStr + "." + extension;
452 }
453 return E_OK;
454 }
455
IsDirectory(const string & dirName,shared_ptr<int> errCodePtr)456 bool MediaFileUtils::IsDirectory(const string &dirName, shared_ptr<int> errCodePtr)
457 {
458 struct stat statInfo {};
459
460 int32_t ret = stat(dirName.c_str(), &statInfo);
461 if (ret == E_SUCCESS) {
462 if (statInfo.st_mode & S_IFDIR) {
463 return true;
464 }
465 } else if (errCodePtr != nullptr) {
466 *errCodePtr = errno;
467 MEDIA_ERR_LOG("ret: %{public}d, errno: %{public}d", ret, errno);
468 return false;
469 }
470 MEDIA_ERR_LOG("ret: %{public}d, errno: %{public}d", ret, errno);
471 return false;
472 }
473
CreateFile(const string & filePath)474 bool MediaFileUtils::CreateFile(const string &filePath)
475 {
476 bool state = false;
477
478 if (filePath.empty()) {
479 MEDIA_ERR_LOG("Invalid file path");
480 return state;
481 }
482 if (IsFileExists(filePath)) {
483 MEDIA_ERR_LOG("file already exists");
484 return state;
485 }
486
487 ofstream file(filePath);
488 if (!file) {
489 MEDIA_ERR_LOG("Output file path could not be created");
490 return state;
491 }
492
493 if (chmod(filePath.c_str(), CHOWN_RW_USR_GRP) == E_SUCCESS) {
494 state = true;
495 } else {
496 MEDIA_ERR_LOG("Failed to change permissions, error: %{public}d", errno);
497 }
498
499 file.close();
500
501 return state;
502 }
503
DeleteFile(const string & fileName)504 bool MediaFileUtils::DeleteFile(const string &fileName)
505 {
506 return (remove(fileName.c_str()) == E_SUCCESS);
507 }
508
DeleteFileWithRetry(const string & fileName)509 bool MediaFileUtils::DeleteFileWithRetry(const string &fileName)
510 {
511 int32_t maxRetryCount = 3;
512 int32_t retryCount = 0;
513 bool isRemoved = false;
514 bool isExists = false;
515 bool isDeleted = false;
516 while (!isDeleted && retryCount < maxRetryCount) {
517 retryCount++;
518 isRemoved = DeleteFile(fileName);
519 isExists = IsFileExists(fileName);
520 isDeleted = isRemoved && !isExists;
521 CHECK_AND_PRINT_LOG(isDeleted,
522 "DeleteFileWithRetry fail, retryCount: %{public}d, "
523 "isRemoved: %{public}d, isExists: %{public}d, fileName: %{public}s",
524 retryCount,
525 isRemoved,
526 isExists,
527 fileName.c_str());
528 }
529 return isDeleted;
530 }
531
DeleteDir(const string & dirName)532 bool MediaFileUtils::DeleteDir(const string &dirName)
533 {
534 bool errRet = false;
535
536 if (IsDirectory(dirName)) {
537 errRet = (RemoveDirectory(dirName) == E_SUCCESS);
538 }
539
540 return errRet;
541 }
542
CopyFileAndDelSrc(const std::string & srcFile,const std::string & destFile)543 bool MediaFileUtils::CopyFileAndDelSrc(const std::string &srcFile, const std::string &destFile)
544 {
545 bool fileExist = IsFileExists(destFile);
546 if (fileExist) {
547 MEDIA_INFO_LOG("destFile:%{private}s already exists", destFile.c_str());
548 CHECK_AND_RETURN_RET_LOG(CopyFileUtil(destFile, destFile + TMP_SUFFIX), false,
549 "copy destfile:%{private}s failed", destFile.c_str());
550 CHECK_AND_RETURN_RET_LOG(DeleteFile(destFile), false, "delete destFile:%{private}s error", destFile.c_str());
551 }
552
553 if (CopyFileUtil(srcFile, destFile)) {
554 CHECK_AND_PRINT_LOG(DeleteFile(srcFile), "delete srcFile:%{private}s failed", srcFile.c_str());
555 CHECK_AND_PRINT_LOG(DeleteFile(destFile + TMP_SUFFIX), "delete tmpFile:%{private}s failed", srcFile.c_str());
556 return true;
557 }
558
559 if (fileExist) {
560 CHECK_AND_PRINT_LOG(CopyFileUtil(destFile + TMP_SUFFIX, destFile),
561 "recover destFile:%{private}s error", destFile.c_str());
562 CHECK_AND_PRINT_LOG(DeleteFile(destFile + TMP_SUFFIX), "delete tmpFile:%{private}s failed", srcFile.c_str());
563 } else {
564 bool delDestFileRet = DeleteFile(destFile);
565 MEDIA_ERR_LOG("copy srcFile:%{private}s failed,delDestFileRet:%{public}d", srcFile.c_str(), delDestFileRet);
566 }
567 return false;
568 }
569
570 /**
571 * @brief Copy the contents of srcPath to destPath, delete the successfully copied files and directories.
572 *
573 * @param srcPath must be a directory.
574 * @param destPath must be a directory.
575 * @param curRecursionDepth current recursion depth. The maximum value is {@code MAX_RECURSION_DEPTH}.
576 * @return true: all contents of {@code srcPath} are successfully copied to {@code destPath}.
577 * false: as long as there is one item of {@code srcPath} is not successfully copied to {@code destPath}.
578 */
CopyDirAndDelSrc(const std::string & srcPath,const std::string & destPath,unsigned short curRecursionDepth)579 bool MediaFileUtils::CopyDirAndDelSrc(const std::string &srcPath, const std::string &destPath,
580 unsigned short curRecursionDepth)
581 {
582 CHECK_AND_RETURN_RET_LOG(curRecursionDepth <= MAX_RECURSION_DEPTH, false,
583 "curRecursionDepth:%{public}d>MAX_RECURSION_DEPTH", curRecursionDepth);
584 ++curRecursionDepth;
585 bool ret = true;
586 DIR* srcDir = opendir(srcPath.c_str());
587 CHECK_AND_RETURN_RET_LOG(srcDir != nullptr, false,
588 "open srcDir:%{private}s failed,errno:%{public}d", srcPath.c_str(), errno);
589
590 if (!IsFileExists(destPath)) {
591 if (!CreateDirectory(destPath)) {
592 MEDIA_ERR_LOG("create destPath:%{private}s failed", srcPath.c_str());
593 closedir(srcDir);
594 return false;
595 }
596 }
597 struct dirent* entry;
598 while ((entry = readdir(srcDir))!= nullptr) {
599 bool cond = (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0);
600 CHECK_AND_CONTINUE(!cond);
601 string srcSubPath = srcPath + SLASH_STR + (entry->d_name);
602 string destSubPath = destPath + SLASH_STR + (entry->d_name);
603 if (entry->d_type == DT_DIR) {
604 ret = CopyDirAndDelSrc(srcSubPath, destSubPath, curRecursionDepth) && ret;
605 continue;
606 }
607 if (entry->d_type == DT_REG) {
608 ret = CopyFileAndDelSrc(srcSubPath, destSubPath) && ret;
609 } else {
610 MEDIA_ERR_LOG("unknown file type,srcSubPath:%{private}s", srcSubPath.c_str());
611 ret = false;
612 }
613 }
614
615 closedir(srcDir);
616 MEDIA_INFO_LOG("srcPath:%{private}s,destPath:%{private}s,coypPathAndDelSrcRet:%{public}d",
617 srcPath.c_str(), destPath.c_str(), ret);
618 return ret;
619 }
620
BackupPhotoDir()621 void MediaFileUtils::BackupPhotoDir()
622 {
623 string dirPath = ROOT_MEDIA_DIR + PHOTO_BUCKET;
624 // check whether dir empty
625 if (!IsDirEmpty(dirPath)) {
626 MEDIA_INFO_LOG("backup for: %{private}s", dirPath.c_str());
627 string suffixName = dirPath.substr(ROOT_MEDIA_DIR.length());
628 CreateDirectory(ROOT_MEDIA_DIR + MEDIALIBRARY_TEMP_DIR);
629 CopyDirAndDelSrc(dirPath, ROOT_MEDIA_DIR + MEDIALIBRARY_TEMP_DIR + SLASH_STR + suffixName);
630 }
631 }
632
RecoverMediaTempDir()633 void MediaFileUtils::RecoverMediaTempDir()
634 {
635 string recoverPath = ROOT_MEDIA_DIR + MEDIALIBRARY_TEMP_DIR + SLASH_STR + PHOTO_BUCKET;
636 if (!IsDirEmpty(recoverPath)) {
637 DIR *dir = opendir((recoverPath).c_str());
638 if (dir == nullptr) {
639 MEDIA_ERR_LOG("Error opening temp directory, errno: %{public}d", errno);
640 return;
641 }
642
643 struct dirent *entry;
644 while ((entry = readdir(dir)) != nullptr) {
645 // filter . && .. dir
646 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
647 continue;
648 }
649 std::string fullPath = recoverPath + SLASH_STR + entry->d_name;
650 struct stat fileStat;
651 if (stat(fullPath.c_str(), &fileStat) == -1) {
652 closedir(dir);
653 return;
654 }
655 string suffixName = fullPath.substr((recoverPath).length());
656 CopyDirAndDelSrc(fullPath, ROOT_MEDIA_DIR + PHOTO_BUCKET + suffixName);
657 }
658 DeleteDir(ROOT_MEDIA_DIR + MEDIALIBRARY_TEMP_DIR);
659 closedir(dir);
660 }
661 }
662
MoveFile(const string & oldPath,const string & newPath,bool isSupportCrossPolicy)663 bool MediaFileUtils::MoveFile(const string &oldPath, const string &newPath, bool isSupportCrossPolicy)
664 {
665 bool errRet = false;
666 if (!IsFileExists(oldPath) || IsFileExists(newPath)) {
667 return errRet;
668 }
669
670 errRet = (rename(oldPath.c_str(), newPath.c_str()) == E_SUCCESS);
671 if (!errRet && isSupportCrossPolicy && errno == CROSS_POLICY_ERR) {
672 errRet = CopyFileAndDelSrc(oldPath, newPath);
673 }
674 return errRet;
675 }
676
CopyFileUtil(const string & filePath,const string & newPath)677 bool MediaFileUtils::CopyFileUtil(const string &filePath, const string &newPath)
678 {
679 struct stat fst{};
680 bool errCode = false;
681 if (filePath.size() >= PATH_MAX) {
682 MEDIA_ERR_LOG("File path too long %{public}d", static_cast<int>(filePath.size()));
683 return errCode;
684 }
685 MEDIA_DEBUG_LOG("File path is %{private}s", filePath.c_str());
686 string absFilePath;
687 if (!PathToRealPath(filePath, absFilePath)) {
688 MEDIA_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
689 return errCode;
690 }
691 if (absFilePath.empty()) {
692 MEDIA_ERR_LOG("Failed to obtain the canonical path for source path:%{public}s %{public}d",
693 filePath.c_str(), errno);
694 return errCode;
695 }
696
697 int32_t source = open(absFilePath.c_str(), O_RDONLY);
698 if (source == -1) {
699 MEDIA_ERR_LOG("Open failed for source file, errno: %{public}d", errno);
700 return errCode;
701 }
702
703 int32_t dest = open(newPath.c_str(), O_WRONLY | O_CREAT, CHOWN_RO_USR_GRP);
704 if (dest == -1) {
705 MEDIA_ERR_LOG("Open failed for destination file %{public}d", errno);
706 close(source);
707 return errCode;
708 }
709
710 if (fstat(source, &fst) == E_SUCCESS) {
711 // Copy file content
712 if (sendfile(dest, source, nullptr, fst.st_size) != E_ERR) {
713 // Copy ownership and mode of source file
714 if (fchown(dest, fst.st_uid, fst.st_gid) == E_SUCCESS &&
715 fchmod(dest, fst.st_mode) == E_SUCCESS) {
716 errCode = true;
717 }
718 }
719 }
720
721 close(source);
722 close(dest);
723
724 return errCode;
725 }
726
DecodeAsset(int32_t fd)727 static std::unique_ptr<Picture> DecodeAsset(int32_t fd)
728 {
729 if (fd < 0) {
730 MEDIA_ERR_LOG("fd = %{public}d is invalid", fd);
731 return nullptr;
732 }
733 MediaLibraryTracer tracer;
734 tracer.Start("DecodeAsset");
735
736 SourceOptions opts;
737 uint32_t err = E_OK;
738 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(fd, opts, err);
739 CHECK_AND_RETURN_RET_LOG(imageSource != nullptr, nullptr, "CreateImageSource failed, err: %{public}u", err);
740
741 DecodingOptionsForPicture decodeOptions;
742 std::unique_ptr<Picture> picturePtr = imageSource->CreatePicture(decodeOptions, err);
743 CHECK_AND_RETURN_RET_LOG(picturePtr != nullptr, nullptr, "CreatePicture failed, err: %{public}u", err);
744 return picturePtr;
745 }
746
EncodeSaveAsset(std::unique_ptr<Picture> picturePtr,const std::string & mimeType,int32_t dstFd)747 static bool EncodeSaveAsset(std::unique_ptr<Picture> picturePtr, const std::string &mimeType, int32_t dstFd)
748 {
749 if (picturePtr == nullptr) {
750 MEDIA_ERR_LOG("picturePtr is nullptr");
751 return false;
752 }
753 MediaLibraryTracer tracer;
754 tracer.Start("EncodeSaveAsset");
755
756 Media::ImagePacker imagePacker;
757 Media::PackOption packOption;
758 packOption.format = mimeType;
759 packOption.desiredDynamicRange = EncodeDynamicRange::AUTO;
760 packOption.needsPackProperties = true;
761
762 int32_t ret = imagePacker.StartPacking(dstFd, packOption);
763 CHECK_AND_RETURN_RET_LOG(ret == E_SUCCESS, false, "StartPacking failed, ret: %{public}d", ret);
764 ret = imagePacker.AddPicture(*(picturePtr));
765 CHECK_AND_RETURN_RET_LOG(ret == E_SUCCESS, false, "AddPicture failed, ret: %{public}d", ret);
766 ret = imagePacker.FinalizePacking();
767 CHECK_AND_RETURN_RET_LOG(ret == E_SUCCESS, false, "FinalizePacking failed, ret: %{public}d", ret);
768 return true;
769 }
770
DecodeEncodeSaveAsset(int32_t srcFd,int32_t dstFd,const std::string & extension)771 static bool DecodeEncodeSaveAsset(int32_t srcFd, int32_t dstFd, const std::string &extension)
772 {
773 std::unique_ptr<Picture> picturePtr = DecodeAsset(srcFd);
774 if (picturePtr == nullptr) {
775 MEDIA_ERR_LOG("DecodeAsset failed");
776 return false;
777 }
778
779 std::string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension, MEDIA_MIME_TYPE_MAP);
780 if (!EncodeSaveAsset(std::move(picturePtr), mimeType, dstFd)) {
781 MEDIA_ERR_LOG("EncodeAsset mimeType: %{public}s failed", mimeType.c_str());
782 return false;
783 }
784
785 return true;
786 }
787
ConvertFormatCopy(const std::string & srcFile,const std::string & dstFile,const std::string & extension)788 bool MediaFileUtils::ConvertFormatCopy(const std::string &srcFile, const std::string &dstFile,
789 const std::string &extension)
790 {
791 MEDIA_DEBUG_LOG("ConvertFormatCopy srcFile: %{public}s, dstFile: %{public}s, extension: %{public}s",
792 srcFile.c_str(), dstFile.c_str(), extension.c_str());
793 if (srcFile.size() >= PATH_MAX) {
794 MEDIA_ERR_LOG("File path too long %{public}d", static_cast<int>(srcFile.size()));
795 return false;
796 }
797 string absFilePath;
798 if (!PathToRealPath(srcFile, absFilePath)) {
799 MEDIA_ERR_LOG("file is not real path, file path: %{private}s", srcFile.c_str());
800 return false;
801 }
802 if (absFilePath.empty()) {
803 MEDIA_ERR_LOG("Failed to obtain the canonical path for source path:%{public}s %{public}d",
804 srcFile.c_str(), errno);
805 return false;
806 }
807
808 auto normalizedDstPath = std::filesystem::absolute(dstFile).lexically_normal();
809 if (normalizedDstPath.empty()) {
810 MEDIA_ERR_LOG("Failed to obtain the canonical path for destination path:%{public}s", srcFile.c_str());
811 return false;
812 }
813 UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
814 if (srcFd.Get() == E_ERR) {
815 MEDIA_ERR_LOG("Open failed for source file, errno: %{public}d", errno);
816 return false;
817 }
818 UniqueFd dstFd(open(normalizedDstPath.c_str(), O_WRONLY | O_CREAT, CHOWN_RO_USR_GRP));
819 if (dstFd.Get() == E_ERR) {
820 MEDIA_ERR_LOG("Open failed for destination file %{public}d", errno);
821 return false;
822 }
823
824 if (!DecodeEncodeSaveAsset(srcFd.Get(), dstFd.Get(), extension)) {
825 MEDIA_ERR_LOG("DecodeEncodeSaveAsset failed");
826 return false;
827 }
828
829 bool errCode = false;
830 struct stat fst{};
831 if (fstat(srcFd.Get(), &fst) == E_SUCCESS) {
832 // Copy ownership and mode of source file
833 if (fchown(dstFd.Get(), fst.st_uid, fst.st_gid) == E_SUCCESS && fchmod(dstFd.Get(), fst.st_mode) == E_SUCCESS) {
834 errCode = true;
835 }
836 }
837
838 return errCode;
839 }
840
ConvertFormatExtraDataDirectory(const std::string & srcDir,const std::string & dstDir,const std::string & extension)841 bool MediaFileUtils::ConvertFormatExtraDataDirectory(const std::string &srcDir, const std::string &dstDir,
842 const std::string &extension)
843 {
844 if (srcDir.empty() || dstDir.empty()) {
845 MEDIA_ERR_LOG("srcDir or dstDir is empty");
846 return E_MODIFY_DATA_FAIL;
847 }
848 if (!IsFileExists(srcDir)) {
849 MEDIA_ERR_LOG("SrcDir: %{public}s is not exist", srcDir.c_str());
850 return E_NO_SUCH_FILE;
851 }
852 if (IsFileExists(dstDir)) {
853 MEDIA_ERR_LOG("DstDir: %{public}s exists", dstDir.c_str());
854 return E_FILE_EXIST;
855 }
856 if (!IsDirectory(srcDir) || !CreateDirectory(dstDir)) {
857 MEDIA_ERR_LOG("srcDir is not directory or Create dstDir failed");
858 return E_FAIL;
859 }
860
861 std::string sourceFilePath = srcDir + "/source." + GetExtensionFromPath(srcDir);
862 for (const auto& entry : std::filesystem::recursive_directory_iterator(srcDir)) {
863 std::string srcFilePath = entry.path();
864 std::string tmpFilePath = srcFilePath;
865 std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
866 if (entry.is_directory()) {
867 if (!CreateDirectory(dstFilePath)) {
868 MEDIA_ERR_LOG("Create dir:%{public}s failed", DesensitizePath(dstFilePath).c_str());
869 return E_FAIL;
870 }
871 } else if (entry.is_regular_file()) {
872 error_code ec;
873 bool ret = false;
874 bool isEqual = std::filesystem::equivalent(srcFilePath, sourceFilePath, ec);
875 if (isEqual) {
876 dstFilePath = dstDir + "/source." + extension;
877 ret = ConvertFormatCopy(srcFilePath, dstFilePath, extension);
878 } else {
879 ret = CopyFileUtil(srcFilePath, dstFilePath);
880 }
881 if (!ret) {
882 MEDIA_ERR_LOG("copyFile failed, isSrcFile: %{public}d", isEqual);
883 return E_FAIL;
884 }
885 } else {
886 MEDIA_ERR_LOG("Unhandled path type, path:%{public}s", DesensitizePath(srcFilePath).c_str());
887 return E_FAIL;
888 }
889 }
890 return E_OK;
891 }
892
CopyFileSafe(const string & filePath,const string & newPath)893 bool MediaFileUtils::CopyFileSafe(const string &filePath, const string &newPath)
894 {
895 if (newPath.empty()) {
896 MEDIA_ERR_LOG("newPath is empty");
897 return false;
898 }
899 string newTempPath = newPath + "_" + std::to_string(MediaFileUtils::UTCTimeMilliSeconds());
900 if (!CopyFileUtil(filePath, newTempPath)) {
901 MEDIA_ERR_LOG("copy file errno: %{public}d", errno);
902 if (!DeleteFile(newTempPath)) {
903 MEDIA_ERR_LOG("del temp file errno: %{public}d", errno);
904 }
905 return false;
906 }
907 return rename(newTempPath.c_str(), newPath.c_str()) == E_OK;
908 }
909
SetDeletionRecord(int fd,const string & fileName)910 void MediaFileUtils::SetDeletionRecord(int fd, const string &fileName)
911 {
912 unsigned int flags = 0;
913 int ret = -1;
914 ret = ioctl(fd, HMFS_IOCTL_HW_GET_FLAGS, &flags);
915 if (ret < 0) {
916 MEDIA_ERR_LOG("File %{public}s Failed to get flags, errno is %{public}d", fileName.c_str(), errno);
917 return;
918 }
919
920 if (flags & HMFS_MONITOR_FL) {
921 return;
922 }
923 flags |= HMFS_MONITOR_FL;
924 ret = ioctl(fd, HMFS_IOCTL_HW_SET_FLAGS, &flags);
925 if (ret < 0) {
926 MEDIA_ERR_LOG("File %{public}s Failed to set flags, errno is %{public}d", fileName.c_str(), errno);
927 return;
928 }
929 MEDIA_INFO_LOG("Flie %{public}s Set Delete control flags is success", fileName.c_str());
930 }
931
MediaFileDeletionRecord()932 void MediaFileUtils::MediaFileDeletionRecord()
933 {
934 int fd = -1;
935 int bucketFd = -1;
936 string path;
937 struct dirent* dirEntry;
938 DIR* fileDir;
939 MEDIA_INFO_LOG("Set DeletionRecord for directory");
940 for (auto &dir : SET_LISTEN_DIR) {
941 path = LISTENING_BASE_PATH + dir;
942 fd = open(path.c_str(), O_RDONLY);
943 if (fd < 0) {
944 MEDIA_ERR_LOG("Failed to open the Dir, errno is %{public}d, %{public}s", errno, dir.c_str());
945 continue;
946 }
947 SetDeletionRecord(fd, dir);
948 close(fd);
949 if ((strcmp(dir.c_str(), ".thumbs") == 0) || (strcmp(dir.c_str(), ".editData") == 0)) {
950 continue;
951 }
952 if ((fileDir = opendir(path.c_str())) == nullptr) {
953 MEDIA_ERR_LOG("dir not exist: %{private}s, error: %{public}d", path.c_str(), errno);
954 continue;
955 }
956 while ((dirEntry = readdir(fileDir)) != nullptr) {
957 if ((strcmp(dirEntry->d_name, ".") == 0) || (strcmp(dirEntry->d_name, "..") == 0)) {
958 continue;
959 }
960 std::string fileName = path + "/" + dirEntry->d_name;
961 bucketFd = open(fileName.c_str(), O_RDONLY);
962 if (bucketFd < 0) {
963 MEDIA_ERR_LOG("Failed to open the bucketFd Dir error: %{public}d", errno);
964 continue;
965 }
966 SetDeletionRecord(bucketFd, dirEntry->d_name);
967 close(bucketFd);
968 }
969 closedir(fileDir);
970 }
971 }
972
WriteStrToFile(const string & filePath,const string & str)973 bool MediaFileUtils::WriteStrToFile(const string &filePath, const string &str)
974 {
975 if (filePath.empty()) {
976 MEDIA_ERR_LOG("FilePath is empty");
977 return false;
978 }
979 if (str.empty()) {
980 MEDIA_ERR_LOG("Write str is empty");
981 return false;
982 }
983
984 if (!IsFileExists(filePath)) {
985 MEDIA_ERR_LOG("Can not get FilePath %{private}s", filePath.c_str());
986 return false;
987 }
988
989 ofstream file(filePath);
990 if (!file.is_open()) {
991 MEDIA_ERR_LOG("Can not open FilePath %{private}s", filePath.c_str());
992 return false;
993 }
994
995 file << str;
996 file.close();
997 if (!file.good()) {
998 MEDIA_ERR_LOG("Can not write FilePath %{private}s", filePath.c_str());
999 return false;
1000 }
1001 return true;
1002 }
1003
ReadStrFromFile(const std::string & filePath,std::string & fileContent)1004 bool MediaFileUtils::ReadStrFromFile(const std::string &filePath, std::string &fileContent)
1005 {
1006 if (filePath.empty()) {
1007 MEDIA_ERR_LOG("FilePath is empty");
1008 return false;
1009 }
1010 if (!IsFileExists(filePath)) {
1011 MEDIA_ERR_LOG("Can not get FilePath %{private}s", filePath.c_str());
1012 return false;
1013 }
1014
1015 string absFilePath;
1016 if (!PathToRealPath(filePath, absFilePath)) {
1017 MEDIA_ERR_LOG("Failed to open a nullptr path %{private}s, errno=%{public}d", filePath.c_str(), errno);
1018 return false;
1019 }
1020
1021 ifstream file(absFilePath);
1022 if (!file.is_open()) {
1023 MEDIA_ERR_LOG("Can not open FilePath %{private}s", absFilePath.c_str());
1024 return false;
1025 }
1026 char ch;
1027 while (file.get(ch)) {
1028 fileContent += ch;
1029 }
1030 file.close();
1031 return true;
1032 }
1033
CopyFile(int32_t rfd,int32_t wfd)1034 bool MediaFileUtils::CopyFile(int32_t rfd, int32_t wfd)
1035 {
1036 static const off_t sendSize1G = 1LL * 1024 * 1024 * 1024;
1037 static const off_t maxSendSize2G = 2LL * 1024 * 1024 * 1024;
1038 struct stat fst = {0};
1039 if (fstat(rfd, &fst) != 0) {
1040 MEDIA_INFO_LOG("fstat failed, errno=%{public}d", errno);
1041 return false;
1042 }
1043 off_t fileSize = fst.st_size;
1044
1045 if (fileSize >= maxSendSize2G) {
1046 off_t offset = 0;
1047 while (offset < fileSize) {
1048 off_t sendSize = fileSize - offset;
1049 if (sendSize > sendSize1G) {
1050 sendSize = sendSize1G;
1051 }
1052 if (sendfile(wfd, rfd, &offset, sendSize) != sendSize) {
1053 MEDIA_INFO_LOG("send failed, errno=%{public}d", errno);
1054 return false;
1055 }
1056 }
1057 } else {
1058 if (sendfile(wfd, rfd, nullptr, fst.st_size) != fileSize) {
1059 MEDIA_INFO_LOG("send failed, errno=%{public}d", errno);
1060 return false;
1061 }
1062 }
1063 return true;
1064 }
1065
RenameDir(const string & oldPath,const string & newPath)1066 bool MediaFileUtils::RenameDir(const string &oldPath, const string &newPath)
1067 {
1068 bool errRet = false;
1069
1070 if (IsDirectory(oldPath)) {
1071 errRet = (rename(oldPath.c_str(), newPath.c_str()) == E_SUCCESS);
1072 if (!errRet) {
1073 MEDIA_ERR_LOG("Failed RenameDir errno %{public}d", errno);
1074 }
1075 }
1076
1077 return errRet;
1078 }
1079
CheckStringSize(const string & str,const size_t max)1080 int32_t MediaFileUtils::CheckStringSize(const string &str, const size_t max)
1081 {
1082 size_t size = str.length();
1083 if (size == 0) {
1084 return -EINVAL;
1085 }
1086 if (size > max) {
1087 return -ENAMETOOLONG;
1088 }
1089 return E_OK;
1090 }
1091
RegexCheck(const string & str,const string & regexStr)1092 static inline bool RegexCheck(const string &str, const string ®exStr)
1093 {
1094 const regex express(regexStr);
1095 return regex_search(str, express);
1096 }
1097
CheckTitle(const string & title)1098 int32_t MediaFileUtils::CheckTitle(const string &title)
1099 {
1100 if (title.empty()) {
1101 MEDIA_ERR_LOG("Title is empty.");
1102 return -EINVAL;
1103 }
1104
1105 static const string titleRegexCheck = R"([\\/:*?"<>|])";
1106 if (RegexCheck(title, titleRegexCheck)) {
1107 MEDIA_ERR_LOG("Failed to check title regex: %{private}s", title.c_str());
1108 return -EINVAL;
1109 }
1110 return E_OK;
1111 }
1112
1113 int32_t MediaFileUtils::CheckTitleCompatible(const string& title)
1114 {
1115 CHECK_AND_RETURN_RET_LOG(!title.empty(), -EINVAL, "Title is empty.");
1116 static const string titleRegexCheck = R"([\.\\/:*?"'`<>|{}\[\]])";
1117 CHECK_AND_RETURN_RET_LOG(!RegexCheck(title, titleRegexCheck), -EINVAL,
1118 "Failed to check title regex: %{private}s", title.c_str());
1119 return E_OK;
1120 }
1121
GetFileAssetUri(const std::string & fileAssetData,const std::string & displayName,const int32_t & fileId)1122 std::string MediaFileUtils::GetFileAssetUri(const std::string &fileAssetData, const std::string &displayName,
1123 const int32_t &fileId)
1124 {
1125 std::string filePath = fileAssetData;
1126 std::string baseUri = "file://media";
1127 size_t lastSlashInData = filePath.rfind('/');
1128 std::string fileNameInData =
1129 (lastSlashInData != std::string::npos) ? filePath.substr(lastSlashInData + 1) : filePath;
1130 size_t dotPos = fileNameInData.rfind('.');
1131 if (dotPos != std::string::npos) {
1132 fileNameInData = fileNameInData.substr(0, dotPos);
1133 }
1134 return baseUri + "/Photo/" + std::to_string(fileId) + "/" + fileNameInData + "/" + displayName;
1135 }
1136
CheckDisplayName(const string & displayName,const bool compatibleCheckTitle)1137 int32_t MediaFileUtils::CheckDisplayName(const string &displayName, const bool compatibleCheckTitle)
1138 {
1139 int err = CheckStringSize(displayName, DISPLAYNAME_MAX);
1140 if (err < 0) {
1141 return err;
1142 }
1143 if (displayName.at(0) == '.') {
1144 return -EINVAL;
1145 }
1146 string title = GetTitleFromDisplayName(displayName);
1147 if (title.empty()) {
1148 return -EINVAL;
1149 }
1150
1151 if (compatibleCheckTitle) {
1152 // 为了向前兼容,此处进行老版本的title校验
1153 return CheckTitleCompatible(title);
1154 }
1155 return CheckTitle(title);
1156 }
1157
CheckFileDisplayName(const string & displayName)1158 int32_t MediaFileUtils::CheckFileDisplayName(const string &displayName)
1159 {
1160 int err = CheckStringSize(displayName, DISPLAYNAME_MAX);
1161 if (err < 0) {
1162 return err;
1163 }
1164 if (displayName.at(0) == '.') {
1165 return -EINVAL;
1166 }
1167 static const string TITLE_REGEX_CHECK = R"([\\/:*?"'`<>|{}\[\]])";
1168 if (RegexCheck(displayName, TITLE_REGEX_CHECK)) {
1169 MEDIA_ERR_LOG("Failed to check displayName regex: %{private}s", displayName.c_str());
1170 return -EINVAL;
1171 }
1172 return E_OK;
1173 }
1174
1175 int32_t MediaFileUtils::CheckRelativePath(const std::string &relativePath)
1176 {
1177 if (relativePath.empty()) {
1178 return -EINVAL;
1179 }
1180
1181 size_t firstPoint = (relativePath.front() == '/') ? 1 : 0;
1182 size_t lastPoint = 0;
1183 while (true) {
1184 lastPoint = relativePath.find_first_of('/', firstPoint);
1185 if (lastPoint == string::npos) {
1186 lastPoint = relativePath.length();
1187 }
1188 size_t len = lastPoint - firstPoint;
1189 if (len == 0) {
1190 MEDIA_ERR_LOG("relativePath %{private}s is invalid", relativePath.c_str());
1191 return -EINVAL;
1192 }
1193 string checkedDirName = relativePath.substr(firstPoint, len);
1194 if (CheckDentryName(checkedDirName) != E_OK) {
1195 MEDIA_ERR_LOG("Dir Name %{private}s is invalid in path %{private}s",
1196 checkedDirName.c_str(), relativePath.c_str());
1197 return -EINVAL;
1198 }
1199 if (lastPoint == relativePath.length()) {
1200 break;
1201 }
1202 firstPoint = lastPoint + 1;
1203 if (firstPoint == relativePath.length()) {
1204 break;
1205 }
1206 }
1207 return E_OK;
1208 }
1209
1210 bool MediaFileUtils::CheckDisplayLevel(const int32_t &displayLevel)
1211 {
1212 if (PORTRAIT_PAGE_MODE.find(displayLevel) == PORTRAIT_PAGE_MODE.end()) {
1213 MEDIA_ERR_LOG("display level %{private}d is invalid", displayLevel);
1214 return false;
1215 }
1216 return true;
1217 }
1218
1219 string MediaFileUtils::GetHighlightPath(const string &uri)
1220 {
1221 int prefixLen = 0;
1222 string uriPrefix = "datashare:///media";
1223 if (uri.find(uriPrefix) != string::npos) {
1224 prefixLen = static_cast<int>(uriPrefix.length());
1225 } else if (uri.find(ML_FILE_URI_PREFIX) != string::npos) {
1226 prefixLen = static_cast<int>(ML_FILE_URI_PREFIX.length());
1227 } else {
1228 return "";
1229 }
1230
1231 string path;
1232 if (IsFileExists(ROOT_MEDIA_DIR + HIGHLIGHT_INFO_OLD)) {
1233 path = "/storage/cloud/files/.thumbs" + uri.substr(prefixLen);
1234 } else {
1235 path = "/storage/cloud/files" + uri.substr(prefixLen);
1236 }
1237
1238 return path;
1239 }
1240
1241 string MediaFileUtils::GetHighlightVideoPath(const string &uri)
1242 {
1243 int prefixLen = 0;
1244 string uriPrefix = "datashare:///media";
1245 if (uri.find(uriPrefix) != string::npos) {
1246 prefixLen = static_cast<int>(uriPrefix.length());
1247 } else if (uri.find(ML_FILE_URI_PREFIX) != string::npos) {
1248 prefixLen = static_cast<int>(ML_FILE_URI_PREFIX.length());
1249 } else {
1250 return "";
1251 }
1252 string path = "/storage/cloud/files" + uri.substr(prefixLen);
1253 return path;
1254 }
1255
1256 void MediaFileUtils::FormatRelativePath(string &relativePath)
1257 {
1258 if (relativePath.empty()) {
1259 return;
1260 }
1261 string FormatRelativePath = relativePath;
1262 if (relativePath.back() != '/') {
1263 relativePath += '/';
1264 }
1265 if (relativePath.front() == '/') {
1266 relativePath = relativePath.substr(1);
1267 }
1268 }
1269
1270 void MediaFileUtils::GetRootDirFromRelativePath(const string &relativePath, string &rootDir)
1271 {
1272 rootDir = relativePath;
1273 if (relativePath.empty()) {
1274 return;
1275 }
1276 if (relativePath.back() != '/') {
1277 rootDir += '/';
1278 }
1279 if (rootDir[0] == '/') {
1280 size_t dirIndex = rootDir.find_first_of('/', 1);
1281 if (dirIndex == string::npos) {
1282 return;
1283 }
1284 rootDir = rootDir.substr(1, dirIndex);
1285 } else {
1286 size_t dirIndex = rootDir.find_first_of('/');
1287 if (dirIndex == string::npos) {
1288 return;
1289 }
1290 rootDir = rootDir.substr(0, dirIndex + 1);
1291 }
1292 }
1293
1294 int32_t MediaFileUtils::CheckAlbumName(const string &albumName)
1295 {
1296 int err = CheckStringSize(albumName, DISPLAYNAME_MAX);
1297 if (err < 0) {
1298 MEDIA_ERR_LOG("Album name string size check failed: %{public}d, size is %{public}zu", err, albumName.length());
1299 return err;
1300 }
1301
1302 static const string ALBUM_NAME_REGEX = R"([\.\\/:*?"'`<>|{}\[\]])";
1303 if (RegexCheck(albumName, ALBUM_NAME_REGEX)) {
1304 MEDIA_ERR_LOG("Failed to check album name regex: %{private}s", albumName.c_str());
1305 return -EINVAL;
1306 }
1307 return E_OK;
1308 }
1309
1310 int32_t MediaFileUtils::CheckHighlightSubtitle(const string &highlightSubtitle)
1311 {
1312 size_t size = highlightSubtitle.length();
1313 CHECK_AND_RETURN_RET_LOG(size <= DISPLAYNAME_MAX, -ENAMETOOLONG,
1314 "Highlight subtitle string size check failed: size is %{public}zu", highlightSubtitle.length());
1315
1316 static const string ALBUM_NAME_REGEX = R"([\.\\/:*?"'`<>|{}\[\]])";
1317 CHECK_AND_RETURN_RET_LOG(!RegexCheck(highlightSubtitle, ALBUM_NAME_REGEX), -EINVAL,
1318 "Failed to check album name regex: %{private}s", highlightSubtitle.c_str());
1319 return E_OK;
1320 }
1321
CheckDentryName(const string & dentryName)1322 int32_t MediaFileUtils::CheckDentryName(const string &dentryName)
1323 {
1324 int err = CheckStringSize(dentryName, DISPLAYNAME_MAX);
1325 if (err < 0) {
1326 return err;
1327 }
1328
1329 static const string DENTRY_REGEX_CHECK = R"([\\/:*?"'`<>|{}\[\]])";
1330 if (RegexCheck(dentryName, DENTRY_REGEX_CHECK)) {
1331 MEDIA_ERR_LOG("Failed to check dentry regex: %{private}s", dentryName.c_str());
1332 return -EINVAL;
1333 }
1334 return E_OK;
1335 }
1336
1337 string MediaFileUtils::GetParentPath(const string &path)
1338 {
1339 string name;
1340 size_t slashIndex = path.rfind("/");
1341 if (slashIndex != string::npos) {
1342 name = path.substr(0, slashIndex);
1343 }
1344
1345 return name;
1346 }
1347
1348 string MediaFileUtils::GetTitleFromDisplayName(const string &displayName)
1349 {
1350 string title;
1351 if (!displayName.empty()) {
1352 string::size_type pos = displayName.find_last_of('.');
1353 if (pos == string::npos) {
1354 return "";
1355 }
1356 title = displayName.substr(0, pos);
1357 }
1358 return title;
1359 }
1360
1361 int64_t MediaFileUtils::GetAlbumDateModified(const string &albumPath)
1362 {
1363 struct stat statInfo {};
1364 if (!albumPath.empty() && stat(albumPath.c_str(), &statInfo) == 0) {
1365 return (statInfo.st_mtime);
1366 }
1367 return 0;
1368 }
1369
1370 int64_t MediaFileUtils::UTCTimeSeconds()
1371 {
1372 struct timespec t{};
1373 t.tv_sec = 0;
1374 t.tv_nsec = 0;
1375 clock_gettime(CLOCK_REALTIME, &t);
1376 return (int64_t)(t.tv_sec);
1377 }
1378
1379 int64_t MediaFileUtils::UTCTimeMilliSeconds()
1380 {
1381 struct timespec t;
1382 constexpr int64_t SEC_TO_MSEC = 1e3;
1383 constexpr int64_t MSEC_TO_NSEC = 1e6;
1384 clock_gettime(CLOCK_REALTIME, &t);
1385 return t.tv_sec * SEC_TO_MSEC + t.tv_nsec / MSEC_TO_NSEC;
1386 }
1387
1388 int64_t MediaFileUtils::UTCTimeNanoSeconds()
1389 {
1390 struct timespec t {};
1391 constexpr int64_t SEC_TO_NSEC = 1e9;
1392 clock_gettime(CLOCK_REALTIME, &t);
1393 return t.tv_sec * SEC_TO_NSEC + t.tv_nsec;
1394 }
1395
1396 string MediaFileUtils::StrCreateTime(const string &format, int64_t time)
1397 {
1398 char strTime[DEFAULT_TIME_SIZE] = "";
1399 CHECK_AND_RETURN_RET_LOG(time > 0, strTime, "invalid time: %{public}" PRId64, time);
1400 struct tm localTm;
1401 CHECK_AND_RETURN_RET_LOG(localtime_noenv_r(&time, &localTm) != nullptr, strTime,
1402 "localtime_noenv_r error: %{public}d", errno);
1403 CHECK_AND_PRINT_LOG(strftime(strTime, sizeof(strTime), format.c_str(), &localTm) != 0,
1404 "strftime error: %{public}d", errno);
1405 return strTime;
1406 }
1407
1408 std::string MediaFileUtils::StrCreateTimeByMilliseconds(const string &format, int64_t time)
1409 {
1410 char strTime[DEFAULT_TIME_SIZE] = "";
1411 int64_t times = time / MSEC_TO_SEC;
1412 struct tm localTm;
1413
1414 if (localtime_noenv_r(×, &localTm) == nullptr) {
1415 MEDIA_ERR_LOG("localtime_noenv_r error: %{public}d", errno);
1416 CHECK_AND_PRINT_LOG(time >= 0, "Time value is negative: %{public}lld", static_cast<long long>(time));
1417 return strTime;
1418 }
1419
1420 if (strftime(strTime, sizeof(strTime), format.c_str(), &localTm) == 0) {
1421 MEDIA_ERR_LOG("strftime error: %{public}d", errno);
1422 }
1423
1424 if (time < 0) {
1425 MEDIA_ERR_LOG("Time value is negative: %{public}lld", static_cast<long long>(time));
1426 }
1427 return strTime;
1428 }
1429
1430 string MediaFileUtils::GetIdFromUri(const string &uri)
1431 {
1432 return MediaFileUri(uri).GetFileId();
1433 }
1434
1435 string MediaFileUtils::GetNetworkIdFromUri(const string &uri)
1436 {
1437 return MediaFileUri(uri).GetNetworkId();
1438 }
1439
1440 string MediaFileUtils::UpdatePath(const string &path, const string &uri)
1441 {
1442 MediaLibraryTracer tracer;
1443 tracer.Start("MediaFileUtils::UpdatePath");
1444
1445 string retStr = path;
1446 MEDIA_DEBUG_LOG("MediaFileUtils::UpdatePath path = %{private}s, uri = %{private}s", path.c_str(), uri.c_str());
1447 if (path.empty() || uri.empty()) {
1448 return retStr;
1449 }
1450
1451 string networkId = GetNetworkIdFromUri(uri);
1452 if (networkId.empty()) {
1453 MEDIA_DEBUG_LOG("MediaFileUtils::UpdatePath retStr = %{private}s", retStr.c_str());
1454 return retStr;
1455 }
1456
1457 size_t pos = path.find(MEDIA_DATA_DEVICE_PATH);
1458 if (pos == string::npos) {
1459 return retStr;
1460 }
1461
1462 string beginStr = path.substr(0, pos);
1463 if (beginStr.empty()) {
1464 return retStr;
1465 }
1466
1467 string endStr = path.substr(pos + MEDIA_DATA_DEVICE_PATH.length());
1468 CHECK_AND_RETURN_RET(!endStr.empty(), retStr);
1469
1470 retStr = beginStr + networkId + endStr;
1471 MEDIA_DEBUG_LOG("MediaFileUtils::UpdatePath retStr = %{private}s", retStr.c_str());
1472 return retStr;
1473 }
1474
1475 MediaType MediaFileUtils::GetMediaType(const string &filePath)
1476 {
1477 if (filePath.empty()) {
1478 return MEDIA_TYPE_ALL;
1479 }
1480
1481 string extention = GetExtensionFromPath(filePath);
1482 string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extention, MEDIA_MIME_TYPE_MAP);
1483 return MimeTypeUtils::GetMediaTypeFromMimeType(mimeType);
1484 }
1485
1486 MediaType MediaFileUtils::GetMediaTypeNotSupported(const string &filePath)
1487 {
1488 if (filePath.empty()) {
1489 return MEDIA_TYPE_ALL;
1490 }
1491
1492 string extention = GetExtensionFromPath(filePath);
1493 string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extention, MEDIA_EXTRA_MIME_TYPE_MAP);
1494 return MimeTypeUtils::GetMediaTypeFromMimeType(mimeType);
1495 }
1496
1497 string MediaFileUtils::SplitByChar(const string &str, const char split)
1498 {
1499 size_t splitIndex = str.find_last_of(split);
1500 return (splitIndex == string::npos) ? ("") : (str.substr(splitIndex + 1));
1501 }
1502
1503 string MediaFileUtils::GetExtensionFromPath(const string &path)
1504 {
1505 string extention = SplitByChar(path, '.');
1506 if (!extention.empty()) {
1507 transform(extention.begin(), extention.end(), extention.begin(), ::tolower);
1508 }
1509 return extention;
1510 }
1511
1512 static void SendHmdfsCallerInfoToIoctl(const int32_t fd, const string &clientBundleName)
1513 {
1514 uint32_t tokenId = IPCSkeleton::GetCallingTokenID();
1515 HmdfsCallerInfo callerInfo;
1516 callerInfo.tokenId = tokenId;
1517
1518 if (strcpy_s(callerInfo.bundleName, sizeof(callerInfo.bundleName), clientBundleName.c_str()) != 0) {
1519 MEDIA_ERR_LOG("Failed to copy clientBundleName: %{public}s", clientBundleName.c_str());
1520 } else {
1521 MEDIA_DEBUG_LOG("clientBundleName = %{public}s", clientBundleName.c_str());
1522 int32_t ret = ioctl(fd, HMDFS_IOC_GET_CALLER_INFO, callerInfo);
1523 if (ret < 0) {
1524 MEDIA_DEBUG_LOG("Failed to set callerInfo to fd: %{public}d, error: %{public}d", fd, errno);
1525 }
1526 }
1527 }
1528
1529 int32_t MediaFileUtils::OpenFile(const string &filePath, const string &mode, const string &clientbundleName)
1530 {
1531 int32_t errCode = E_ERR;
1532
1533 if (filePath.empty() || mode.empty()) {
1534 MEDIA_ERR_LOG("Invalid open argument! mode: %{private}s, path: %{private}s", mode.c_str(), filePath.c_str());
1535 return errCode;
1536 }
1537
1538 static const unordered_map<string, int32_t> MEDIA_OPEN_MODE_MAP = {
1539 { MEDIA_FILEMODE_READONLY, O_RDONLY },
1540 { MEDIA_FILEMODE_WRITEONLY, O_WRONLY },
1541 { MEDIA_FILEMODE_READWRITE, O_RDWR },
1542 { MEDIA_FILEMODE_WRITETRUNCATE, O_WRONLY | O_TRUNC },
1543 { MEDIA_FILEMODE_WRITEAPPEND, O_WRONLY | O_APPEND },
1544 { MEDIA_FILEMODE_READWRITETRUNCATE, O_RDWR | O_TRUNC },
1545 { MEDIA_FILEMODE_READWRITEAPPEND, O_RDWR | O_APPEND },
1546 };
1547 if (MEDIA_OPEN_MODE_MAP.find(mode) == MEDIA_OPEN_MODE_MAP.end()) {
1548 return E_ERR;
1549 }
1550
1551 if (filePath.size() >= PATH_MAX) {
1552 MEDIA_ERR_LOG("File path too long %{public}d", (int)filePath.size());
1553 return errCode;
1554 }
1555 string absFilePath;
1556 if (!PathToRealPath(filePath, absFilePath)) {
1557 MEDIA_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
1558 return errCode;
1559 }
1560 if (absFilePath.empty()) {
1561 MEDIA_ERR_LOG("Failed to obtain the canonical path for source path %{public}d %{private}s",
1562 errno, filePath.c_str());
1563 return errCode;
1564 }
1565 MEDIA_DEBUG_LOG("File absFilePath is %{private}s", absFilePath.c_str());
1566 int32_t fd = open(absFilePath.c_str(), MEDIA_OPEN_MODE_MAP.at(mode));
1567 if (clientbundleName.empty()) {
1568 MEDIA_DEBUG_LOG("ClientbundleName is empty,failed to to set caller_info to fd");
1569 } else {
1570 SendHmdfsCallerInfoToIoctl(fd, clientbundleName);
1571 }
1572 return fd;
1573 }
1574
1575 int32_t MediaFileUtils::CreateAsset(const string &filePath)
1576 {
1577 MediaLibraryTracer tracer;
1578 tracer.Start("MediaFileUtils::CreateAsset");
1579
1580 int32_t errCode = E_ERR;
1581
1582 if (filePath.empty()) {
1583 MEDIA_ERR_LOG("Filepath is empty");
1584 return E_VIOLATION_PARAMETERS;
1585 }
1586
1587 if (IsFileExists(filePath)) {
1588 MEDIA_ERR_LOG("the file exists path: %{public}s", filePath.c_str());
1589 return E_FILE_EXIST;
1590 }
1591
1592 size_t slashIndex = filePath.rfind('/');
1593 if (slashIndex != string::npos) {
1594 string fileName = filePath.substr(slashIndex + 1);
1595 if (!fileName.empty() && fileName.at(0) != '.') {
1596 size_t dotIndex = filePath.rfind('.');
1597 if ((dotIndex == string::npos) && (GetMediaType(filePath) != MEDIA_TYPE_FILE)) {
1598 return errCode;
1599 }
1600 }
1601 }
1602
1603 ofstream file(filePath);
1604 if (!file) {
1605 MEDIA_ERR_LOG("Output file path could not be created errno %{public}d", errno);
1606 return errCode;
1607 }
1608
1609 file.close();
1610
1611 return E_SUCCESS;
1612 }
1613
1614 int32_t MediaFileUtils::ModifyAsset(const string &oldPath, const string &newPath)
1615 {
1616 int32_t err = E_MODIFY_DATA_FAIL;
1617
1618 if (oldPath.empty() || newPath.empty()) {
1619 MEDIA_ERR_LOG("Failed to modify asset, oldPath: %{private}s or newPath: %{private}s is empty!",
1620 oldPath.c_str(), newPath.c_str());
1621 return err;
1622 }
1623 if (!IsFileExists(oldPath)) {
1624 MEDIA_ERR_LOG("Failed to modify asset, oldPath: %{private}s does not exist!", oldPath.c_str());
1625 return E_NO_SUCH_FILE;
1626 }
1627 if (IsFileExists(newPath)) {
1628 MEDIA_ERR_LOG("Failed to modify asset, newPath: %{private}s is already exist!", newPath.c_str());
1629 return E_FILE_EXIST;
1630 }
1631 err = rename(oldPath.c_str(), newPath.c_str());
1632 if (err < 0) {
1633 int errorno = errno;
1634 MEDIA_ERR_LOG("Failed rename, errno: %{public}d, old path: %{public}s exists: %{public}d, "
1635 "new path: %{public}s exists: %{public}d", errorno, DesensitizePath(oldPath).c_str(),
1636 IsFileExists(oldPath), DesensitizePath(newPath).c_str(), IsFileExists(newPath));
1637 if (errorno == EACCES) {
1638 PrintStatInformation(GetParentPath(oldPath));
1639 }
1640 return E_FILE_OPER_FAIL;
1641 }
1642
1643 return E_SUCCESS;
1644 }
1645
1646 int32_t MediaFileUtils::OpenAsset(const string &filePath, const string &mode)
1647 {
1648 if (filePath.empty()) {
1649 return E_INVALID_PATH;
1650 }
1651 if (mode.empty()) {
1652 return E_INVALID_MODE;
1653 }
1654
1655 int32_t flags = O_RDWR;
1656 if (mode == MEDIA_FILEMODE_READONLY) {
1657 flags = O_RDONLY;
1658 } else if (mode == MEDIA_FILEMODE_WRITEONLY) {
1659 flags = O_WRONLY;
1660 } else if (mode == MEDIA_FILEMODE_WRITETRUNCATE) {
1661 flags = O_WRONLY | O_TRUNC;
1662 } else if (mode == MEDIA_FILEMODE_WRITEAPPEND) {
1663 flags = O_WRONLY | O_APPEND;
1664 } else if (mode == MEDIA_FILEMODE_READWRITETRUNCATE) {
1665 flags = O_RDWR | O_TRUNC;
1666 }
1667
1668 if (filePath.size() >= PATH_MAX) {
1669 MEDIA_ERR_LOG("File path too long %{public}d", (int)filePath.size());
1670 return E_INVALID_PATH;
1671 }
1672 MEDIA_DEBUG_LOG("File path is %{private}s", filePath.c_str());
1673 std::string absFilePath;
1674 if (!PathToRealPath(filePath, absFilePath)) {
1675 MEDIA_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
1676 return E_INVALID_PATH;
1677 }
1678 CHECK_AND_RETURN_RET_LOG(!absFilePath.empty(), E_INVALID_PATH,
1679 "Failed to obtain the canonical path for source path %{private}s %{public}d", filePath.c_str(), errno);
1680
1681 MEDIA_DEBUG_LOG("File absFilePath is %{private}s", absFilePath.c_str());
1682 return open(absFilePath.c_str(), flags);
1683 }
1684
1685 int32_t MediaFileUtils::CloseAsset(int32_t fd)
1686 {
1687 return close(fd);
1688 }
1689
1690 std::string MediaFileUtils::GetMediaTypeUri(MediaType mediaType)
1691 {
1692 switch (mediaType) {
1693 case MEDIA_TYPE_AUDIO:
1694 return MEDIALIBRARY_AUDIO_URI;
1695 case MEDIA_TYPE_VIDEO:
1696 return MEDIALIBRARY_VIDEO_URI;
1697 case MEDIA_TYPE_IMAGE:
1698 return MEDIALIBRARY_IMAGE_URI;
1699 case MEDIA_TYPE_SMARTALBUM:
1700 return MEDIALIBRARY_SMARTALBUM_CHANGE_URI;
1701 case MEDIA_TYPE_DEVICE:
1702 return MEDIALIBRARY_DEVICE_URI;
1703 case MEDIA_TYPE_FILE:
1704 default:
1705 return MEDIALIBRARY_FILE_URI;
1706 }
1707 }
1708
1709 std::string MediaFileUtils::GetMediaTypeUriV10(MediaType mediaType)
1710 {
1711 switch (mediaType) {
1712 case MEDIA_TYPE_AUDIO:
1713 return AudioColumn::DEFAULT_AUDIO_URI;
1714 case MEDIA_TYPE_VIDEO:
1715 case MEDIA_TYPE_IMAGE:
1716 return PhotoColumn::DEFAULT_PHOTO_URI;
1717 case MEDIA_TYPE_SMARTALBUM:
1718 return MEDIALIBRARY_SMARTALBUM_CHANGE_URI;
1719 case MEDIA_TYPE_DEVICE:
1720 return MEDIALIBRARY_DEVICE_URI;
1721 case MEDIA_TYPE_FILE:
1722 default:
1723 return MEDIALIBRARY_FILE_URI;
1724 }
1725 }
1726
1727 bool MediaFileUtils::CheckMode(const string &mode)
1728 {
1729 if (mode.empty()) {
1730 return false;
1731 }
1732 if (MEDIA_OPEN_MODES.find(mode) != MEDIA_OPEN_MODES.end()) {
1733 return true;
1734 } else {
1735 MEDIA_ERR_LOG("Input Mode %{private}s is invalid", mode.c_str());
1736 return false;
1737 }
1738 }
1739
1740 size_t MediaFileUtils::FindIgnoreCase(const std::string &str, const std::string &key)
1741 {
1742 auto it = search(str.begin(), str.end(), key.begin(), key.end(), [](const char a, const char b) {
1743 return ::tolower(a) == ::tolower(b);
1744 });
1745 if (it == str.end()) {
1746 return string::npos;
1747 }
1748 size_t pos = static_cast<size_t>(it - str.begin());
1749 return (pos > 0) ? pos : 0;
1750 }
1751
1752 int64_t MediaFileUtils::GetVirtualIdByType(int32_t id, MediaType type)
1753 {
1754 switch (type) {
1755 case MediaType::MEDIA_TYPE_IMAGE:
1756 case MediaType::MEDIA_TYPE_VIDEO: {
1757 return (int64_t) id * VIRTUAL_ID_DIVIDER - PHOTO_VIRTUAL_IDENTIFIER;
1758 }
1759 case MediaType::MEDIA_TYPE_AUDIO: {
1760 return (int64_t) id * VIRTUAL_ID_DIVIDER - AUDIO_VIRTUAL_IDENTIFIER;
1761 }
1762 default: {
1763 return (int64_t)id * VIRTUAL_ID_DIVIDER - FILE_VIRTUAL_IDENTIFIER;
1764 }
1765 }
1766 }
1767
1768 double MediaFileUtils::GetRealIdByTable(int32_t virtualId, const string &tableName)
1769 {
1770 if (tableName == PhotoColumn::PHOTOS_TABLE) {
1771 return (double) (virtualId + PHOTO_VIRTUAL_IDENTIFIER) / VIRTUAL_ID_DIVIDER;
1772 } else if (tableName == AudioColumn::AUDIOS_TABLE) {
1773 return (double) (virtualId + AUDIO_VIRTUAL_IDENTIFIER) / VIRTUAL_ID_DIVIDER;
1774 } else {
1775 return (double) (virtualId + FILE_VIRTUAL_IDENTIFIER) / VIRTUAL_ID_DIVIDER;
1776 }
1777 }
1778
1779 string MediaFileUtils::GetVirtualUriFromRealUri(const string &uri, const string &extrUri)
1780 {
1781 if ((uri.find(PhotoColumn::PHOTO_TYPE_URI) != string::npos) ||
1782 (uri.find(AudioColumn::AUDIO_TYPE_URI) != string::npos) ||
1783 (uri.find(PhotoColumn::HIGHTLIGHT_COVER_URI) != string::npos) ||
1784 (uri.find(URI_MTP_OPERATION) != string::npos)) {
1785 return uri;
1786 }
1787
1788 string pureUri = uri;
1789 string suffixUri;
1790 size_t questionMaskPoint = uri.rfind('?');
1791 size_t hashKeyPoint = uri.rfind('#');
1792 if (questionMaskPoint != string::npos) {
1793 suffixUri = uri.substr(questionMaskPoint);
1794 pureUri = uri.substr(0, questionMaskPoint);
1795 } else if (hashKeyPoint != string::npos) {
1796 suffixUri = uri.substr(hashKeyPoint);
1797 pureUri = uri.substr(0, hashKeyPoint);
1798 }
1799
1800 MediaFileUri fileUri(pureUri);
1801 string fileId = fileUri.GetFileId();
1802 if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
1803 return uri;
1804 }
1805 int32_t id;
1806 if (!StrToInt(fileId, id)) {
1807 MEDIA_ERR_LOG("invalid fileuri %{private}s", uri.c_str());
1808 return uri;
1809 }
1810 int64_t virtualId;
1811 MediaType type;
1812 if ((pureUri.find(MEDIALIBRARY_TYPE_IMAGE_URI) != string::npos)) {
1813 type = MediaType::MEDIA_TYPE_IMAGE;
1814 virtualId = GetVirtualIdByType(id, MediaType::MEDIA_TYPE_IMAGE);
1815 } else if (pureUri.find(MEDIALIBRARY_TYPE_VIDEO_URI) != string::npos) {
1816 type = MediaType::MEDIA_TYPE_VIDEO;
1817 virtualId = GetVirtualIdByType(id, MediaType::MEDIA_TYPE_VIDEO);
1818 } else if ((pureUri.find(MEDIALIBRARY_TYPE_AUDIO_URI) != string::npos)) {
1819 type = MediaType::MEDIA_TYPE_AUDIO;
1820 virtualId = GetVirtualIdByType(id, MediaType::MEDIA_TYPE_AUDIO);
1821 } else {
1822 type = MediaType::MEDIA_TYPE_FILE;
1823 virtualId = GetVirtualIdByType(id, MediaType::MEDIA_TYPE_FILE);
1824 }
1825 MediaFileUri virtualUri(type, to_string(virtualId), fileUri.GetNetworkId(),
1826 (fileUri.IsApi10() ? MEDIA_API_VERSION_V10 : MEDIA_API_VERSION_V9),
1827 (fileUri.IsApi10() ? extrUri : ""));
1828
1829 return suffixUri.empty() ? virtualUri.ToString() : virtualUri.ToString() + suffixUri;
1830 }
1831
1832 void GetExtrParamFromUri(const std::string &uri, std::string &displayName)
1833 {
1834 if (uri.find(PATH_PARA) != string::npos) {
1835 size_t lastSlashPosition = uri.rfind('/');
1836 if (lastSlashPosition != string::npos) {
1837 displayName = uri.substr(lastSlashPosition + 1);
1838 }
1839 }
1840 }
1841
1842 void InitPureAndSuffixUri(string &pureUri, string &suffixUri, const string &uri)
1843 {
1844 size_t questionMaskPoint = uri.rfind('?');
1845 size_t hashKeyPoint = uri.rfind('#');
1846 if (questionMaskPoint != string::npos) {
1847 suffixUri = uri.substr(questionMaskPoint);
1848 pureUri = uri.substr(0, questionMaskPoint);
1849 } else if (hashKeyPoint != string::npos) {
1850 suffixUri = uri.substr(hashKeyPoint);
1851 pureUri = uri.substr(0, hashKeyPoint);
1852 }
1853 }
1854
1855 string MediaFileUtils::GetRealUriFromVirtualUri(const string &uri)
1856 {
1857 if ((uri.find(PhotoColumn::PHOTO_TYPE_URI) != string::npos) ||
1858 (uri.find(AudioColumn::AUDIO_TYPE_URI) != string::npos) ||
1859 (uri.find(PhotoColumn::HIGHTLIGHT_COVER_URI) != string::npos) ||
1860 (uri.find(URI_MTP_OPERATION) != string::npos)) {
1861 return uri;
1862 }
1863
1864 string pureUri = uri;
1865 string suffixUri;
1866 InitPureAndSuffixUri(pureUri, suffixUri, uri);
1867 MediaFileUri fileUri(pureUri);
1868 string fileId = fileUri.GetFileId();
1869 if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
1870 return uri;
1871 }
1872 int32_t id;
1873 if (!StrToInt(fileId, id)) {
1874 MEDIA_ERR_LOG("invalid fileuri %{private}s", uri.c_str());
1875 return uri;
1876 }
1877 int32_t realId = 0;
1878 MediaType type;
1879 if ((pureUri.find(MEDIALIBRARY_TYPE_IMAGE_URI) != string::npos)) {
1880 type = MediaType::MEDIA_TYPE_IMAGE;
1881 realId = static_cast<int32_t>(GetRealIdByTable(id, PhotoColumn::PHOTOS_TABLE));
1882 } else if (pureUri.find(MEDIALIBRARY_TYPE_VIDEO_URI) != string::npos) {
1883 type = MediaType::MEDIA_TYPE_VIDEO;
1884 realId = static_cast<int32_t>(GetRealIdByTable(id, PhotoColumn::PHOTOS_TABLE));
1885 } else if ((pureUri.find(MEDIALIBRARY_TYPE_AUDIO_URI) != string::npos)) {
1886 type = MediaType::MEDIA_TYPE_AUDIO;
1887 realId = static_cast<int32_t>(GetRealIdByTable(id, AudioColumn::AUDIOS_TABLE));
1888 } else {
1889 type = MediaType::MEDIA_TYPE_FILE;
1890 realId = static_cast<int32_t>(GetRealIdByTable(id, MEDIALIBRARY_TABLE));
1891 }
1892 string extrUri;
1893 if (fileUri.IsApi10()) {
1894 string displayName;
1895 GetExtrParamFromUri(pureUri, displayName);
1896 extrUri = GetExtraUri(displayName, fileUri.GetFilePath(), false);
1897 }
1898
1899 MediaFileUri realUri(type, to_string(realId), fileUri.GetNetworkId(),
1900 (fileUri.IsApi10() ? MEDIA_API_VERSION_V10 : MEDIA_API_VERSION_V9), (fileUri.IsApi10() ? extrUri : ""));
1901
1902 if (suffixUri.empty()) {
1903 return realUri.ToString();
1904 }
1905 return realUri.ToString() + suffixUri;
1906 }
1907
1908 #ifdef MEDIALIBRARY_COMPATIBILITY
1909 string MediaFileUtils::GetTableFromVirtualUri(const std::string &virtualUri)
1910 {
1911 MediaFileUri uri(virtualUri);
1912 if (!uri.IsValid()) {
1913 MEDIA_ERR_LOG("virtual uri:%{private}s is invalid", virtualUri.c_str());
1914 return "";
1915 }
1916 string virtualId = uri.GetFileId();
1917 if (std::all_of(virtualId.begin(), virtualId.end(), ::isdigit)) {
1918 int64_t id = stol(virtualId);
1919 int64_t remainNumber = id % VIRTUAL_ID_DIVIDER;
1920 switch (remainNumber) {
1921 case VIRTUAL_ID_DIVIDER - PHOTO_VIRTUAL_IDENTIFIER:
1922 return PhotoColumn::PHOTOS_TABLE;
1923 case VIRTUAL_ID_DIVIDER - AUDIO_VIRTUAL_IDENTIFIER:
1924 return AudioColumn::AUDIOS_TABLE;
1925 case VIRTUAL_ID_DIVIDER - FILE_VIRTUAL_IDENTIFIER:
1926 return MEDIALIBRARY_TABLE;
1927 default:
1928 MEDIA_ERR_LOG("virtualId:%{public}ld is wrong", (long) id);
1929 return "";
1930 }
1931 } else {
1932 MEDIA_ERR_LOG("virtual uri:%{private}s is invalid, can not get id", virtualUri.c_str());
1933 return "";
1934 }
1935 }
1936 #endif
1937
1938 bool MediaFileUtils::IsUriV10(const string &mediaType)
1939 {
1940 return mediaType == URI_TYPE_PHOTO ||
1941 mediaType == URI_TYPE_PHOTO_ALBUM ||
1942 mediaType == URI_TYPE_AUDIO_V10;
1943 }
1944
1945 bool MediaFileUtils::IsFileTablePath(const string &path)
1946 {
1947 if (path.empty() || path.size() <= ROOT_MEDIA_DIR.size()) {
1948 return false;
1949 }
1950
1951 if (path.find(ROOT_MEDIA_DIR) == string::npos) {
1952 return false;
1953 }
1954
1955 string relativePath = path.substr(ROOT_MEDIA_DIR.size());
1956 if ((relativePath.find(DOCS_PATH) == 0)) {
1957 return true;
1958 }
1959 return false;
1960 }
1961
1962 bool MediaFileUtils::IsPhotoTablePath(const string &path)
1963 {
1964 if (path.empty() || path.size() <= ROOT_MEDIA_DIR.size()) {
1965 return false;
1966 }
1967
1968 if (path.find(ROOT_MEDIA_DIR) == string::npos) {
1969 return false;
1970 }
1971
1972 string relativePath = path.substr(ROOT_MEDIA_DIR.size());
1973
1974 const vector<string> photoPathVector = {
1975 PHOTO_BUCKET, PIC_DIR_VALUES, VIDEO_DIR_VALUES, CAMERA_DIR_VALUES
1976 };
1977 for (auto &photoPath : photoPathVector) {
1978 if (relativePath.find(photoPath) == 0) {
1979 return true;
1980 }
1981 }
1982 return false;
1983 }
1984
1985 bool MediaFileUtils::StartsWith(const std::string &str, const std::string &prefix)
1986 {
1987 return str.compare(0, prefix.size(), prefix) == 0;
1988 }
1989
1990 bool MediaFileUtils::EndsWith(const std::string &str, const std::string &suffix)
1991 {
1992 if (str.length() < suffix.length()) {
1993 return false;
1994 }
1995 return str.rfind(suffix) == str.length() - suffix.length();
1996 }
1997
1998 void MediaFileUtils::ReplaceAll(std::string &str, const std::string &from, const std::string &to)
1999 {
2000 size_t startPos = 0;
2001 while ((startPos = str.find(from, startPos)) != std::string::npos) {
2002 str.replace(startPos, from.length(), to);
2003 startPos += to.length();
2004 }
2005 }
2006
2007 void MediaFileUtils::UriAppendKeyValue(string &uri, const string &key, std::string value)
2008 {
2009 string uriKey = key + '=';
2010 if (uri.find(uriKey) != string::npos) {
2011 return;
2012 }
2013
2014 char queryMark = (uri.find('?') == string::npos) ? '?' : '&';
2015 string append = queryMark + key + '=' + value;
2016
2017 size_t pos = uri.find('#');
2018 if (pos == string::npos) {
2019 uri += append;
2020 } else {
2021 uri.insert(pos, append);
2022 }
2023 }
2024
2025 string MediaFileUtils::GetExtraUri(const string &displayName, const string &path, const bool isNeedEncode)
2026 {
2027 string extraUri = "/" + GetTitleFromDisplayName(GetFileName(path)) + "/" + displayName;
2028 if (!isNeedEncode) {
2029 return extraUri;
2030 }
2031 return MediaFileUtils::Encode(extraUri);
2032 }
2033
2034 string MediaFileUtils::GetUriByExtrConditions(const string &prefix, const string &fileId, const string &suffix)
2035 {
2036 return prefix + fileId + suffix;
2037 }
2038
2039 std::string MediaFileUtils::GetUriWithoutDisplayname(const string &uri)
2040 {
2041 if (uri.empty()) {
2042 return uri;
2043 }
2044
2045 auto index = uri.rfind("/");
2046 if (index == string::npos) {
2047 return uri;
2048 }
2049
2050 return uri.substr(0, index + 1);
2051 }
2052
2053 string MediaFileUtils::Encode(const string &uri)
2054 {
2055 const unordered_set<char> uriCompentsSet = {
2056 ';', ',', '/', '?', ':', '@', '&',
2057 '=', '+', '$', '-', '_', '.', '!',
2058 '~', '*', '(', ')'
2059 };
2060 const int32_t encodeLen = 2;
2061 ostringstream outPutStream;
2062 outPutStream.fill('0');
2063 outPutStream << std::hex;
2064
2065 for (unsigned char tmpChar : uri) {
2066 if (std::isalnum(tmpChar) || uriCompentsSet.find(tmpChar) != uriCompentsSet.end()) {
2067 outPutStream << tmpChar;
2068 } else {
2069 outPutStream << std::uppercase;
2070 outPutStream << '%' << std::setw(encodeLen) << static_cast<unsigned int>(tmpChar);
2071 outPutStream << std::nouppercase;
2072 }
2073 }
2074
2075 return outPutStream.str();
2076 }
2077
2078 string MediaFileUtils::AddDocsToRelativePath(const string &relativePath)
2079 {
2080 if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
2081 MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
2082 return DOCS_PATH + relativePath;
2083 }
2084 return relativePath;
2085 }
2086
2087 string MediaFileUtils::RemoveDocsFromRelativePath(const string &relativePath)
2088 {
2089 if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH)) {
2090 return relativePath.substr(DOCS_PATH.size());
2091 }
2092 return relativePath;
2093 }
2094
2095 int64_t MediaFileUtils::Timespec2Millisecond(const struct timespec &time)
2096 {
2097 return time.tv_sec * MSEC_TO_SEC + time.tv_nsec / MSEC_TO_NSEC;
2098 }
2099
2100 string MediaFileUtils::GetTempMovingPhotoVideoPath(const string &imagePath)
2101 {
2102 size_t splitIndex = imagePath.find_last_of('.');
2103 size_t lastSlashIndex = imagePath.find_last_of('/');
2104 if (splitIndex == string::npos || (lastSlashIndex != string::npos && lastSlashIndex > splitIndex)) {
2105 return "";
2106 }
2107 return imagePath.substr(0, lastSlashIndex + 1) + "_temp" +
2108 imagePath.substr(lastSlashIndex + 1, splitIndex - lastSlashIndex - 1) + ".mp4";
2109 }
2110
2111 string MediaFileUtils::GetMovingPhotoVideoPath(const string &imagePath)
2112 {
2113 size_t splitIndex = imagePath.find_last_of('.');
2114 size_t lastSlashIndex = imagePath.find_last_of('/');
2115 if (splitIndex == string::npos || (lastSlashIndex != string::npos && lastSlashIndex > splitIndex)) {
2116 return "";
2117 }
2118 return imagePath.substr(0, splitIndex) + ".mp4";
2119 }
2120
2121 bool MediaFileUtils::CheckMovingPhotoExtension(const string &extension)
2122 {
2123 return IsMovingPhotoMimeType(MimeTypeUtils::GetMimeTypeFromExtension(extension, MEDIA_MIME_TYPE_MAP));
2124 }
2125
2126 bool MediaFileUtils::IsMovingPhotoMimeType(const string &mimeType)
2127 {
2128 // image of moving photo must be image/jpeg, image/heif or image/heic
2129 return mimeType == "image/jpeg" || mimeType == "image/heif" || mimeType == "image/heic";
2130 }
2131
2132 bool MediaFileUtils::CheckMovingPhotoVideoExtension(const string &extension)
2133 {
2134 // video of moving photo must be video/mp4
2135 return MimeTypeUtils::GetMimeTypeFromExtension(extension, MEDIA_MIME_TYPE_MAP) == "video/mp4";
2136 }
2137
2138 bool MediaFileUtils::CheckMovingPhotoImage(const string &path)
2139 {
2140 return CheckMovingPhotoExtension(GetExtensionFromPath(path));
2141 }
2142
2143 bool MediaFileUtils::CheckMovingPhotoVideo(const string &path)
2144 {
2145 string absFilePath;
2146 if (!PathToRealPath(path, absFilePath)) {
2147 MEDIA_ERR_LOG("Failed to get real path, path: %{private}s", path.c_str());
2148 return false;
2149 }
2150 if (absFilePath.empty()) {
2151 MEDIA_ERR_LOG("Failed to check path for %{private}s, errno: %{public}d", path.c_str(), errno);
2152 return false;
2153 }
2154
2155 string extension = GetExtensionFromPath(absFilePath);
2156 if (!CheckMovingPhotoVideoExtension(extension)) {
2157 MEDIA_ERR_LOG("Failed to check extension (%{public}s) of moving photo video", extension.c_str());
2158 return false;
2159 }
2160
2161 UniqueFd uniqueFd(open(absFilePath.c_str(), O_RDONLY));
2162 return CheckMovingPhotoVideo(uniqueFd);
2163 }
2164
2165 bool MediaFileUtils::CheckMovingPhotoVideo(const UniqueFd &uniqueFd)
2166 {
2167 MediaLibraryTracer tracer;
2168 tracer.Start("MediaFileUtils::CheckMovingPhotoVideo");
2169
2170 if (uniqueFd.Get() <= 0) {
2171 MEDIA_ERR_LOG("Failed to open video of moving photo, errno = %{public}d", errno);
2172 return false;
2173 }
2174 struct stat64 st;
2175 if (fstat64(uniqueFd.Get(), &st) != 0) {
2176 MEDIA_ERR_LOG("Failed to get file state, errno = %{public}d", errno);
2177 return false;
2178 }
2179
2180 shared_ptr<AVMetadataHelper> avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
2181 if (avMetadataHelper == nullptr) {
2182 MEDIA_WARN_LOG("Failed to create AVMetadataHelper, ignore checking duration");
2183 return true;
2184 }
2185
2186 int32_t err = avMetadataHelper->SetSource(uniqueFd.Get(), 0,
2187 static_cast<int64_t>(st.st_size), AV_META_USAGE_META_ONLY);
2188 if (err != 0) {
2189 MEDIA_ERR_LOG("SetSource failed for the given file descriptor, err = %{public}d", err);
2190 return false;
2191 }
2192
2193 unordered_map<int32_t, string> resultMap = avMetadataHelper->ResolveMetadata();
2194 if (resultMap.find(AV_KEY_DURATION) == resultMap.end()) {
2195 MEDIA_ERR_LOG("AV_KEY_DURATION does not exist");
2196 return false;
2197 }
2198 string durationStr = resultMap.at(AV_KEY_DURATION);
2199 int32_t duration = std::atoi(durationStr.c_str());
2200 if (!CheckMovingPhotoVideoDuration(duration)) {
2201 MEDIA_ERR_LOG("Failed to check duration of moving photo video: %{public}d ms", duration);
2202 return false;
2203 }
2204 return true;
2205 }
2206
2207 std::string MediaFileUtils::GetTableNameByDisplayName(const std::string &displayName)
2208 {
2209 std::string extension;
2210 string::size_type currentPos = displayName.rfind('.');
2211 if (currentPos != std::string::npos) {
2212 extension = displayName.substr(currentPos + 1);
2213 }
2214
2215 auto myTypeName = MimeTypeUtils::GetMimeTypeFromExtension(extension, MEDIA_MIME_TYPE_MAP);
2216 MediaType type = MimeTypeUtils::GetMediaTypeFromMimeType(myTypeName);
2217 if (type == MEDIA_TYPE_AUDIO) {
2218 return AudioColumn::AUDIOS_TABLE;
2219 } else if (type == MEDIA_TYPE_IMAGE || type == MEDIA_TYPE_VIDEO) {
2220 return PhotoColumn::PHOTOS_TABLE;
2221 }
2222 return "";
2223 }
2224
2225 bool MediaFileUtils::GetDateModified(const string &path, int64_t &dateModified)
2226 {
2227 struct stat statInfo {};
2228 if (stat(path.c_str(), &statInfo) != E_OK) {
2229 MEDIA_ERR_LOG("stat error of %{private}s, errno: %{public}d", path.c_str(), errno);
2230 return false;
2231 }
2232 dateModified = Timespec2Millisecond(statInfo.st_mtim);
2233 return true;
2234 }
2235
2236 bool MediaFileUtils::CheckMovingPhotoVideoDuration(int32_t duration)
2237 {
2238 // duration of moving photo video must be 0~10 s
2239 constexpr int32_t MIN_DURATION_MS = 0;
2240 constexpr int32_t MAX_DURATION_MS = 10000;
2241 return duration > MIN_DURATION_MS && duration <= MAX_DURATION_MS;
2242 }
2243
2244 bool MediaFileUtils::CheckMovingPhotoEffectMode(int32_t effectMode)
2245 {
2246 return (effectMode >= static_cast<int32_t>(MovingPhotoEffectMode::EFFECT_MODE_START) &&
2247 effectMode <= static_cast<int32_t>(MovingPhotoEffectMode::EFFECT_MODE_END)) ||
2248 effectMode == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY);
2249 }
2250
2251 bool MediaFileUtils::GetFileSize(const std::string& filePath, size_t& size)
2252 {
2253 struct stat statbuf;
2254 if (lstat(filePath.c_str(), &statbuf) == -1) {
2255 MEDIA_WARN_LOG("Failed to get file size, errno: %{public}d, path: %{private}s", errno, filePath.c_str());
2256 size = 0;
2257 return false;
2258 }
2259 if (statbuf.st_size < 0) {
2260 MEDIA_WARN_LOG("File size is negative, path: %{public}s", filePath.c_str());
2261 size = 0;
2262 return false;
2263 }
2264 size = static_cast<size_t>(statbuf.st_size);
2265 return true;
2266 }
2267
2268 bool MediaFileUtils::SplitMovingPhotoUri(const std::string& uri, std::vector<std::string>& ret)
2269 {
2270 const std::string split(MOVING_PHOTO_URI_SPLIT);
2271 if (uri.empty() || IsMediaLibraryUri(uri)) {
2272 MEDIA_ERR_LOG("Failed to split moving photo uri, uri=%{public}s", uri.c_str());
2273 return false;
2274 }
2275 std::string temp = uri;
2276 size_t pos = temp.find(split);
2277 uint32_t step = split.size();
2278 ret.push_back(temp.substr(0, pos));
2279 ret.push_back(temp.substr(pos + step));
2280 return true;
2281 }
2282
2283 bool MediaFileUtils::IsMediaLibraryUri(const std::string& uri)
2284 {
2285 return !uri.empty() && uri.find(MOVING_PHOTO_URI_SPLIT) == uri.npos;
2286 }
2287
2288 void MediaFileUtils::CheckDirStatus(const std::unordered_set<std::string> &dirCheckSet, const std::string &dir)
2289 {
2290 if (dirCheckSet.count(dir) == 0) {
2291 return;
2292 }
2293 PrintStatInformation(dir);
2294 }
2295
2296 int32_t MediaFileUtils::CreateDirectoryAndCopyFiles(const std::string &srcDir, const std::string &dstDir)
2297 {
2298 if (!MediaFileUtils::IsFileExists(srcDir)) {
2299 MEDIA_WARN_LOG("%{public}s doesn't exist, skip.", srcDir.c_str());
2300 return E_OK;
2301 }
2302 if (!MediaFileUtils::IsDirectory(srcDir)) {
2303 MEDIA_WARN_LOG("%{public}s is not an directory, skip.", srcDir.c_str());
2304 return E_OK;
2305 }
2306 if (!MediaFileUtils::CreateDirectory(dstDir)) {
2307 MEDIA_ERR_LOG("Create dstDir %{public}s failed", dstDir.c_str());
2308 return E_FAIL;
2309 }
2310 for (const auto &dirEntry : std::filesystem::directory_iterator{srcDir}) {
2311 std::string srcFilePath = dirEntry.path();
2312 std::string tmpFilePath = srcFilePath;
2313 std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
2314 if (!MediaFileUtils::CopyFileUtil(srcFilePath, dstFilePath)) {
2315 MEDIA_ERR_LOG("Copy file from %{public}s to %{public}s failed.",
2316 srcFilePath.c_str(),
2317 dstFilePath.c_str());
2318 return E_FAIL;
2319 }
2320 }
2321 return E_OK;
2322 }
2323
2324 void MediaFileUtils::ModifyFile(const std::string path, int64_t modifiedTime)
2325 {
2326 if (modifiedTime <= 0) {
2327 MEDIA_ERR_LOG("ModifyTime error!");
2328 return;
2329 }
2330 struct utimbuf buf;
2331 buf.actime = modifiedTime; // second
2332 buf.modtime = modifiedTime; // second
2333 int ret = utime(path.c_str(), &buf);
2334 if (ret != 0) {
2335 MEDIA_ERR_LOG("Modify file failed: %{public}d", ret);
2336 }
2337 }
2338
2339 bool MediaFileUtils::CheckSupportedWatermarkType(int32_t watermarkType)
2340 {
2341 return watermarkType >= static_cast<int32_t>(WatermarkType::BRAND_COMMON) &&
2342 watermarkType <= static_cast<int32_t>(WatermarkType::BRAND);
2343 }
2344
2345 int32_t MediaFileUtils::CopyDirectory(const std::string &srcDir, const std::string &dstDir)
2346 {
2347 if (srcDir.empty() || dstDir.empty()) {
2348 MEDIA_ERR_LOG("Failed to copy directory, srcDir:%{public}s or newPath:%{public}s is empty!",
2349 DesensitizePath(srcDir).c_str(), DesensitizePath(dstDir).c_str());
2350 return E_MODIFY_DATA_FAIL;
2351 }
2352 if (!IsFileExists(srcDir)) {
2353 MEDIA_ERR_LOG("SrcDir:%{public}s is not exist", DesensitizePath(srcDir).c_str());
2354 return E_NO_SUCH_FILE;
2355 }
2356 if (!IsDirectory(srcDir)) {
2357 MEDIA_ERR_LOG("SrcDir:%{public}s is not directory", DesensitizePath(srcDir).c_str());
2358 return E_FAIL;
2359 }
2360 if (IsFileExists(dstDir)) {
2361 MEDIA_ERR_LOG("DstDir:%{public}s exists", DesensitizePath(dstDir).c_str());
2362 return E_FILE_EXIST;
2363 }
2364 if (!CreateDirectory(dstDir)) {
2365 MEDIA_ERR_LOG("Create dstDir:%{public}s failed", DesensitizePath(dstDir).c_str());
2366 return E_FAIL;
2367 }
2368
2369 for (const auto& entry : std::filesystem::recursive_directory_iterator(srcDir)) {
2370 std::string srcFilePath = entry.path();
2371 std::string tmpFilePath = srcFilePath;
2372 std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
2373 if (entry.is_directory()) {
2374 if (!CreateDirectory(dstFilePath)) {
2375 MEDIA_ERR_LOG("Create dir:%{public}s failed", DesensitizePath(dstFilePath).c_str());
2376 return E_FAIL;
2377 }
2378 } else if (entry.is_regular_file()) {
2379 if (!CopyFileUtil(srcFilePath, dstFilePath)) {
2380 MEDIA_ERR_LOG("Copy file from %{public}s to %{public}s failed.",
2381 DesensitizePath(srcFilePath).c_str(), DesensitizePath(dstFilePath).c_str());
2382 return E_FAIL;
2383 }
2384 } else {
2385 MEDIA_ERR_LOG("Unhandled path type, path:%{public}s", DesensitizePath(srcFilePath).c_str());
2386 return E_FAIL;
2387 }
2388 }
2389 return E_OK;
2390 }
2391
2392 bool MediaFileUtils::IsCalledBySelf()
2393 {
2394 if (IPCSkeleton::GetCallingFullTokenID() == IPCSkeleton::GetSelfTokenID()) {
2395 return E_OK;
2396 }
2397 return E_FAIL;
2398 }
2399
2400 bool MediaFileUtils::GenerateKvStoreKey(const std::string &fileId, const std::string &dateKey, std::string &key)
2401 {
2402 if (fileId.empty() || dateKey.empty()) {
2403 MEDIA_ERR_LOG("FileId:%{public}s or dateKey:%{public}s is empty", fileId.c_str(), dateKey.c_str());
2404 return false;
2405 }
2406
2407 if (fileId.length() > KVSTORE_FILE_ID_TEMPLATE.length() ||
2408 dateKey.length() > KVSTORE_DATE_KEY_TEMPLATE.length()) {
2409 MEDIA_ERR_LOG("FileId:%{public}s or dateKey:%{public}s is too long", fileId.c_str(), dateKey.c_str());
2410 return false;
2411 }
2412 key = KVSTORE_DATE_KEY_TEMPLATE.substr(dateKey.length()) + dateKey +
2413 KVSTORE_FILE_ID_TEMPLATE.substr(fileId.length()) + fileId;
2414 return true;
2415 }
2416
2417 bool MediaFileUtils::IsValidInteger(const std::string &value)
2418 {
2419 MEDIA_DEBUG_LOG("KeyWord is:%{public}s", value.c_str());
2420 std::string unsignedStr = value;
2421 while (unsignedStr.size() > 0 && unsignedStr[0] == '-') {
2422 unsignedStr = unsignedStr.substr(1);
2423 }
2424 for (size_t i = 0; i < unsignedStr.size(); i++) {
2425 if (!std::isdigit(unsignedStr[i])) {
2426 MEDIA_INFO_LOG("KeyWord invalid char of:%{public}c", unsignedStr[i]);
2427 unsignedStr = unsignedStr.substr(0, i);
2428 break;
2429 }
2430 }
2431 if (unsignedStr.size() == 0) {
2432 MEDIA_ERR_LOG("KeyWord Invalid argument");
2433 return false;
2434 } else if (unsignedStr.size() < INTEGER_MAX_LENGTH) {
2435 return true;
2436 } else if (unsignedStr.size() == INTEGER_MAX_LENGTH) {
2437 return unsignedStr < MAX_INTEGER;
2438 } else {
2439 MEDIA_ERR_LOG("KeyWord is out length!");
2440 return false;
2441 }
2442 }
2443
2444 static int64_t GetRoundSize(int64_t size)
2445 {
2446 uint64_t val = 1;
2447 int64_t multple = UNIT;
2448 int64_t stdMultiple = STD_UNIT;
2449 while (static_cast<int64_t>(val) * stdMultiple < size) {
2450 val <<= 1;
2451 if (val > THRESHOLD) {
2452 val = 1;
2453 multple *= UNIT;
2454 stdMultiple *= STD_UNIT;
2455 }
2456 }
2457 return static_cast<int64_t>(val) * multple;
2458 }
2459
2460 int64_t MediaFileUtils::GetTotalSize()
2461 {
2462 struct statvfs diskInfo;
2463 int ret = statvfs(DATA_PATH.c_str(), &diskInfo);
2464 CHECK_AND_RETURN_RET_LOG(ret == 0, E_ERR, "Get total size failed, errno:%{public}d", errno);
2465 int64_t totalSize = static_cast<long long>(diskInfo.f_bsize) * static_cast<long long>(diskInfo.f_blocks);
2466 CHECK_AND_RETURN_RET_LOG(totalSize > 0, E_ERR, "Get total size failed, totalSize:%{public}" PRId64, totalSize);
2467 totalSize = GetRoundSize(totalSize);
2468 return totalSize;
2469 }
2470
2471 int64_t MediaFileUtils::GetFreeSize()
2472 {
2473 struct statvfs diskInfo;
2474 int ret = statvfs(DATA_PATH.c_str(), &diskInfo);
2475 CHECK_AND_RETURN_RET_LOG(ret == 0, E_ERR, "Get free size failed, errno:%{public}d", errno);
2476 int64_t freeSize = static_cast<int64_t>(diskInfo.f_bsize) * static_cast<int64_t>(diskInfo.f_bfree);
2477 return freeSize;
2478 }
2479
2480 void MediaFileUtils::StatDirSize(const std::string& rootPath, size_t& totalSize)
2481 {
2482 std::stack<std::string> dirStack;
2483 dirStack.push(rootPath);
2484
2485 while (!dirStack.empty()) {
2486 std::string currentPath = dirStack.top();
2487 dirStack.pop();
2488
2489 DIR* dir = opendir(currentPath.c_str());
2490 if (dir == nullptr) {
2491 MEDIA_ERR_LOG("Failed to open directory.");
2492 continue;
2493 }
2494
2495 struct dirent* entry;
2496 while ((entry = readdir(dir)) != nullptr) {
2497 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
2498 continue;
2499 }
2500
2501 std::string fullPath = currentPath + "/" + entry->d_name;
2502 struct stat statBuf;
2503 if (stat(fullPath.c_str(), &statBuf) == -1) {
2504 MEDIA_ERR_LOG("Failed to get file status.");
2505 continue;
2506 }
2507
2508 if (S_ISDIR(statBuf.st_mode)) {
2509 dirStack.push(fullPath);
2510 } else if (S_ISREG(statBuf.st_mode)) {
2511 size_t fileSize = 0;
2512 MediaFileUtils::GetFileSize(fullPath, fileSize);
2513 totalSize += fileSize;
2514 }
2515 }
2516
2517 closedir(dir);
2518 }
2519
2520 MEDIA_INFO_LOG("Directory size: %{public}lld bytes", static_cast<long long>(totalSize));
2521 }
2522
2523 std::string MediaFileUtils::GetMimeTypeFromDisplayName(const std::string &displayName)
2524 {
2525 std::string mimeType = "";
2526 CHECK_AND_RETURN_RET_LOG(!displayName.empty(), mimeType, "displayName is empty.");
2527 std::string extension;
2528 string::size_type currentPos = displayName.rfind('.');
2529 if (currentPos != std::string::npos) {
2530 extension = displayName.substr(currentPos + 1);
2531 }
2532 CHECK_AND_RETURN_RET_LOG(!extension.empty(), mimeType, "extension is empty.");
2533 mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension, MEDIA_MIME_TYPE_MAP);
2534 return mimeType;
2535 }
2536
2537 std::string MediaFileUtils::DesensitizeUri(const std::string &fileUri)
2538 {
2539 string result = fileUri;
2540 size_t slashIndex = result.rfind('/');
2541 CHECK_AND_RETURN_RET(slashIndex != std::string::npos, result);
2542 return result.replace(slashIndex + 1, result.length() - slashIndex - 1, "*");
2543 }
2544
2545 bool MediaFileUtils::DeleteFileOrFolder(const std::string &path, bool isFile)
2546 {
2547 CHECK_AND_RETURN_RET(MediaFileUtils::IsFileExists(path), true);
2548 return isFile ? MediaFileUtils::DeleteFile(path) : MediaFileUtils::DeleteDir(path);
2549 }
2550
2551 std::string MediaFileUtils::GetReplacedPathByPrefix(const std::string srcPrefix, const std::string dstPrefix,
2552 const std::string &path)
2553 {
2554 std::string replacedPath = path;
2555 replacedPath.replace(0, srcPrefix.length(), dstPrefix);
2556 return replacedPath;
2557 }
2558
2559 int64_t MediaFileUtils::GetFileModificationTime(const std::string &path)
2560 {
2561 struct stat fileStat;
2562
2563 if (stat(path.c_str(), &fileStat) == -1) {
2564 MEDIA_ERR_LOG("stat failed. File path: %{public}s, err: %{public}s", path.c_str(), strerror(errno));
2565 return 0;
2566 }
2567 struct tm* timeInfo = localtime(&fileStat.st_mtime);
2568 if (timeInfo == nullptr) {
2569 return 0;
2570 }
2571 return static_cast<int64_t>(fileStat.st_mtime);
2572 }
2573
2574 bool MediaFileUtils::IsDirExists(const std::string &path)
2575 {
2576 struct stat st;
2577 if (stat(path.c_str(), &st) == 0) {
2578 return S_ISDIR(st.st_mode);
2579 }
2580 return false;
2581 }
2582
2583 int64_t MediaFileUtils::StrToInt64(const std::string &value)
2584 {
2585 char* pEnd = nullptr;
2586 errno = 0;
2587 // check whether convert success
2588 int64_t res = std::strtoll(value.c_str(), &pEnd, 10);
2589 if (errno == ERANGE || pEnd == value.c_str() || *pEnd != '\0') {
2590 MEDIA_ERR_LOG("%{public}s:convert err.", __func__);
2591 return 0;
2592 }
2593 return res;
2594 }
2595 } // namespace OHOS::Media