• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &regexStr)
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(&times);
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