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