1 /*
2  * Copyright (C) 2024 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 "ringtone_file_utils.h"
18 
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <ftw.h>
22 #include <fstream>
23 #include <sstream>
24 #include <sys/sendfile.h>
25 #include <unistd.h>
26 #include <iostream>
27 
28 #include "directory_ex.h"
29 #include "ringtone_db_const.h"
30 #include "ringtone_errno.h"
31 #include "ringtone_log.h"
32 #include "ringtone_mimetype_utils.h"
33 #include "ringtone_type.h"
34 #include "vibrate_type.h"
35 #include "securec.h"
36 
37 namespace OHOS {
38 namespace Media {
39 using namespace std;
40 static const int32_t OPEN_FDS = 128;
41 static const mode_t MODE_RWX_USR_GRP = 02771;
42 static const mode_t MODE_RW_USR = 0644;
43 const vector<string> EXIF_SUPPORTED_EXTENSION = {
44     RINGTONE_CONTAINER_TYPE_3GA,
45     RINGTONE_CONTAINER_TYPE_AC3,
46     RINGTONE_CONTAINER_TYPE_A52,
47     RINGTONE_CONTAINER_TYPE_AMR,
48     RINGTONE_CONTAINER_TYPE_IMY,
49     RINGTONE_CONTAINER_TYPE_RTTTL,
50     RINGTONE_CONTAINER_TYPE_XMF,
51     RINGTONE_CONTAINER_TYPE_RTX,
52     RINGTONE_CONTAINER_TYPE_MXMF,
53     RINGTONE_CONTAINER_TYPE_M4A,
54     RINGTONE_CONTAINER_TYPE_M4B,
55     RINGTONE_CONTAINER_TYPE_M4P,
56     RINGTONE_CONTAINER_TYPE_F4A,
57     RINGTONE_CONTAINER_TYPE_F4B,
58     RINGTONE_CONTAINER_TYPE_F4P,
59     RINGTONE_CONTAINER_TYPE_M3U,
60     RINGTONE_CONTAINER_TYPE_SMF,
61     RINGTONE_CONTAINER_TYPE_MKA,
62     RINGTONE_CONTAINER_TYPE_RA,
63     RINGTONE_CONTAINER_TYPE_MP3,
64     RINGTONE_CONTAINER_TYPE_AAC,
65     RINGTONE_CONTAINER_TYPE_ADTS,
66     RINGTONE_CONTAINER_TYPE_ADT,
67     RINGTONE_CONTAINER_TYPE_SND,
68     RINGTONE_CONTAINER_TYPE_FLAC,
69     RINGTONE_CONTAINER_TYPE_MP2,
70     RINGTONE_CONTAINER_TYPE_MP1,
71     RINGTONE_CONTAINER_TYPE_MPA,
72     RINGTONE_CONTAINER_TYPE_M4R,
73     RINGTONE_CONTAINER_TYPE_WAV,
74     RINGTONE_CONTAINER_TYPE_OGG
75 };
76 
IsTargetExtension(const string & path)77 static bool IsTargetExtension(const string &path)
78 {
79     const string ext = RingtoneFileUtils::GetExtensionFromPath(path);
80     std::string mimeType = RingtoneMimeTypeUtils::GetMimeTypeFromExtension(ext);
81     int32_t mime = RingtoneMimeTypeUtils::GetMediaTypeFromMimeType(mimeType);
82     if (mime == RINGTONE_MEDIA_TYPE_AUDIO) {
83         return true;
84     }
85     RINGTONE_ERR_LOG("MimeType error:%{public}s,%{public}s", ext.c_str(), mimeType.c_str());
86     bool ret = find(EXIF_SUPPORTED_EXTENSION.begin(), EXIF_SUPPORTED_EXTENSION.end(), ext) !=
87         EXIF_SUPPORTED_EXTENSION.end();
88     if (!ret) {
89         RINGTONE_ERR_LOG("invalid target extension:%{public}s", ext.c_str());
90     }
91     return ret;
92 }
93 
IsVibrateFile(const string & path)94 static bool IsVibrateFile(const string &path)
95 {
96     const string ext = RingtoneFileUtils::GetExtensionFromPath(path);
97     bool ret = (ext == VIBRATE_CONTAINER_TYPE_JSON);
98     if (!ret) {
99         RINGTONE_ERR_LOG("invalid target extension:%{public}s", ext.c_str());
100     }
101     return ret;
102 }
103 
SplitByChar(const string & str,const char split)104 string RingtoneFileUtils::SplitByChar(const string &str, const char split)
105 {
106     size_t splitIndex = str.find_last_of(split);
107     return (splitIndex == string::npos) ? ("") : (str.substr(splitIndex + 1));
108 }
109 
GetExtensionFromPath(const string & path)110 string RingtoneFileUtils::GetExtensionFromPath(const string &path)
111 {
112     string extention = SplitByChar(path, '.');
113     if (!extention.empty()) {
114         transform(extention.begin(), extention.end(), extention.begin(), ::tolower);
115     }
116     return extention;
117 }
118 
GetFileNameFromPath(const string & path)119 string RingtoneFileUtils::GetFileNameFromPath(const string &path)
120 {
121     string fileName = {};
122     size_t found = path.rfind("/");
123     if (found != string::npos && (found + 1) < path.size()) {
124         fileName = path.substr(found + 1);
125     } else {
126         fileName = "";
127     }
128 
129     return fileName;
130 }
131 
ParseFromUri(const string & path,const string & key)132 static string ParseFromUri(const string& path, const string& key)
133 {
134     RINGTONE_INFO_LOG("parsing uri : %{public}s for key : %{public}s", path.c_str(), key.c_str());
135     auto keyLen = key.size();
136     auto found = path.find(key);
137     if (found == string::npos) {
138         RINGTONE_INFO_LOG("there is no such field in uri: %{public}s", path.c_str());
139         return "";
140     }
141     string sub = path.substr(found + keyLen + 1);
142     found = sub.find("&");
143     if (found != string::npos) {
144         sub = sub.substr(0, found);
145     }
146     sub = RingtoneFileUtils::UrlDecode(sub);
147     RINGTONE_INFO_LOG("parsing uri : %{public}s -> key=%{public}s, value=%{public}s",
148         path.c_str(), key.c_str(), sub.c_str());
149     return sub;
150 }
151 
GetFileNameFromPathOrUri(const string & path,bool & isTitle)152 string RingtoneFileUtils::GetFileNameFromPathOrUri(const string &path, bool &isTitle)
153 {
154     string fileName = {};
155     size_t found = path.find("content://");
156     if (found == 0) {
157         fileName = ParseFromUri(path, "title"); // Pay attention! It's actually "title".
158         isTitle = true;
159     } else {
160         fileName = GetFileNameFromPath(path);
161         isTitle = false;
162     }
163     RINGTONE_INFO_LOG("%{public}s -> %{public}s", path.c_str(), fileName.c_str());
164     return fileName;
165 }
166 
GetBaseNameFromPath(const string & path)167 string RingtoneFileUtils::GetBaseNameFromPath(const string &path)
168 {
169     size_t found = path.rfind("/");
170     size_t foundDot = path.rfind(".");
171 
172     string baseName = {};
173     found = (found == string::npos ? 0 : found);
174     if ((foundDot > found) && (foundDot != string::npos)) {
175         baseName = path.substr(found + 1, foundDot - found - 1);
176     } else {
177         baseName = "";
178     }
179 
180     return baseName;
181 }
182 
IsSameFile(const string & srcPath,const string & dstPath)183 bool RingtoneFileUtils::IsSameFile(const string &srcPath, const string &dstPath)
184 {
185     struct stat srcStatInfo {};
186     struct stat dstStatInfo {};
187 
188     if (access(srcPath.c_str(), F_OK) || access(dstPath.c_str(), F_OK)) {
189         return false;
190     }
191     if (stat(srcPath.c_str(), &srcStatInfo) != 0) {
192         RINGTONE_ERR_LOG("Failed to get file %{private}s StatInfo, err=%{public}d", srcPath.c_str(), errno);
193         return false;
194     }
195     if (stat(dstPath.c_str(), &dstStatInfo) != 0) {
196         RINGTONE_ERR_LOG("Failed to get file %{private}s StatInfo, err=%{public}d", dstPath.c_str(), errno);
197         return false;
198     }
199     if (srcStatInfo.st_size != dstStatInfo.st_size) { /* file size */
200         RINGTONE_INFO_LOG("Size differs, srcStatInfo.st_size != dstStatInfo.st_size");
201         return false;
202     }
203 
204     return true;
205 }
206 
UnlinkCb(const char * fpath,const struct stat * sb,int32_t typeflag,struct FTW * ftwbuf)207 static int32_t UnlinkCb(const char *fpath, const struct stat *sb, int32_t typeflag, struct FTW *ftwbuf)
208 {
209     CHECK_AND_RETURN_RET_LOG(fpath != nullptr, E_FAIL, "fpath == nullptr");
210     int32_t errRet = remove(fpath);
211     if (errRet) {
212         RINGTONE_ERR_LOG("Failed to remove errno: %{public}d, path: %{private}s", errno, fpath);
213     }
214 
215     return errRet;
216 }
217 
RemoveDirectory(const string & path)218 int32_t RingtoneFileUtils::RemoveDirectory(const string &path)
219 {
220     return nftw(path.c_str(), UnlinkCb, OPEN_FDS, FTW_DEPTH | FTW_PHYS);
221 }
222 
Mkdir(const string & subStr,shared_ptr<int> errCodePtr)223 bool RingtoneFileUtils::Mkdir(const string &subStr, shared_ptr<int> errCodePtr)
224 {
225     mode_t mask = umask(0);
226     if (mkdir(subStr.c_str(), MODE_RWX_USR_GRP) == -1) {
227         if (errCodePtr != nullptr) {
228             *errCodePtr = errno;
229         }
230         RINGTONE_ERR_LOG("Failed to create directory %{public}d", errno);
231         umask(mask);
232         return (errno == EEXIST) ? true : false;
233     }
234     umask(mask);
235     return true;
236 }
237 
IsDirectory(const string & dirName,shared_ptr<int> errCodePtr)238 bool RingtoneFileUtils::IsDirectory(const string &dirName, shared_ptr<int> errCodePtr)
239 {
240     struct stat statInfo {};
241 
242     if (stat(dirName.c_str(), &statInfo) == 0) {
243         if (statInfo.st_mode & S_IFDIR) {
244             return true;
245         }
246     } else if (errCodePtr != nullptr) {
247         *errCodePtr = errno;
248         return false;
249     }
250 
251     return false;
252 }
253 
CreateDirectory(const string & dirPath,shared_ptr<int> errCodePtr)254 bool RingtoneFileUtils::CreateDirectory(const string &dirPath, shared_ptr<int> errCodePtr)
255 {
256     string subStr;
257     string segment;
258 
259     stringstream folderStream(dirPath);
260     while (getline(folderStream, segment, '/')) {
261         if (segment.empty()) {
262             continue;
263         }
264 
265         subStr.append(RINGTONE_SLASH_CHAR + segment);
266         if (!IsDirectory(subStr, errCodePtr)) {
267             if (!Mkdir(subStr, errCodePtr)) {
268                 return false;
269             }
270         }
271     }
272     return true;
273 }
274 
OpenFile(const string & filePath,const string & mode)275 int32_t RingtoneFileUtils::OpenFile(const string &filePath, const string &mode)
276 {
277     int32_t errCode = E_ERR;
278 
279     if (filePath.empty() || mode.empty()) {
280         RINGTONE_ERR_LOG("Invalid open argument! mode: %{private}s, path: %{private}s", mode.c_str(), filePath.c_str());
281         return errCode;
282     }
283 
284     if (!IsTargetExtension(filePath)) {
285         return E_INVALID_PATH;
286     }
287 
288     static const unordered_map<string, int32_t> RINGTONE_OPEN_MODE_MAP = {
289         { RINGTONE_FILEMODE_READONLY, O_RDONLY },
290         { RINGTONE_FILEMODE_WRITEONLY, O_WRONLY },
291         { RINGTONE_FILEMODE_READWRITE, O_RDWR },
292         { RINGTONE_FILEMODE_WRITETRUNCATE, O_WRONLY | O_TRUNC },
293         { RINGTONE_FILEMODE_WRITEAPPEND, O_WRONLY | O_APPEND },
294         { RINGTONE_FILEMODE_READWRITETRUNCATE, O_RDWR | O_TRUNC },
295         { RINGTONE_FILEMODE_READWRITEAPPEND, O_RDWR | O_APPEND },
296     };
297     if (RINGTONE_OPEN_MODE_MAP.find(mode) == RINGTONE_OPEN_MODE_MAP.end()) {
298         return E_ERR;
299     }
300 
301     if (filePath.size() >= PATH_MAX) {
302         RINGTONE_ERR_LOG("File path too long %{public}d", (int)filePath.size());
303         return errCode;
304     }
305     string absFilePath;
306     if (!PathToRealPath(filePath, absFilePath)) {
307         RINGTONE_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
308         return errCode;
309     }
310     if (absFilePath.empty()) {
311         RINGTONE_ERR_LOG("Failed to obtain the canonical path for source path %{public}d %{private}s",
312             errno, filePath.c_str());
313         return errCode;
314     }
315     RINGTONE_INFO_LOG("File absFilePath is %{private}s", absFilePath.c_str());
316     return open(absFilePath.c_str(), RINGTONE_OPEN_MODE_MAP.at(mode));
317 }
318 
OpenVibrateFile(const std::string & filePath,const std::string & mode)319 int32_t RingtoneFileUtils::OpenVibrateFile(const std::string &filePath, const std::string &mode)
320 {
321     int32_t errCode = E_ERR;
322 
323     if (filePath.empty() || mode.empty()) {
324         RINGTONE_ERR_LOG("Invalid open argument! mode: %{private}s, path: %{private}s", mode.c_str(), filePath.c_str());
325         return errCode;
326     }
327 
328     if (!IsVibrateFile(filePath)) {
329         return E_INVALID_PATH;
330     }
331 
332     static const unordered_map<string, int32_t> RINGTONE_OPEN_MODE_MAP = {
333         { RINGTONE_FILEMODE_READONLY, O_RDONLY },
334         { RINGTONE_FILEMODE_WRITEONLY, O_WRONLY },
335         { RINGTONE_FILEMODE_READWRITE, O_RDWR },
336         { RINGTONE_FILEMODE_WRITETRUNCATE, O_WRONLY | O_TRUNC },
337         { RINGTONE_FILEMODE_WRITEAPPEND, O_WRONLY | O_APPEND },
338         { RINGTONE_FILEMODE_READWRITETRUNCATE, O_RDWR | O_TRUNC },
339         { RINGTONE_FILEMODE_READWRITEAPPEND, O_RDWR | O_APPEND },
340     };
341     if (RINGTONE_OPEN_MODE_MAP.find(mode) == RINGTONE_OPEN_MODE_MAP.end()) {
342         return E_ERR;
343     }
344 
345     if (filePath.size() >= PATH_MAX) {
346         RINGTONE_ERR_LOG("File path too long %{public}d", (int)filePath.size());
347         return errCode;
348     }
349     string absFilePath;
350     if (!PathToRealPath(filePath, absFilePath)) {
351         RINGTONE_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
352         return errCode;
353     }
354     if (absFilePath.empty()) {
355         RINGTONE_ERR_LOG("Failed to obtain the canonical path for source path %{public}d %{private}s",
356             errno, filePath.c_str());
357         return errCode;
358     }
359     RINGTONE_INFO_LOG("File absFilePath is %{private}s", absFilePath.c_str());
360     return open(absFilePath.c_str(), RINGTONE_OPEN_MODE_MAP.at(mode));
361 }
362 
IsFileExists(const string & fileName)363 bool RingtoneFileUtils::IsFileExists(const string &fileName)
364 {
365     struct stat statInfo {};
366 
367     return ((stat(fileName.c_str(), &statInfo)) == 0);
368 }
369 
CreateFile(const string & filePath)370 int32_t RingtoneFileUtils::CreateFile(const string &filePath)
371 {
372     int32_t errCode = E_ERR;
373 
374     if (filePath.empty()) {
375         RINGTONE_ERR_LOG("Filepath is empty");
376         return E_VIOLATION_PARAMETERS;
377     }
378 
379     if (!IsTargetExtension(filePath)) {
380         return E_INVALID_PATH;
381     }
382 
383     if (IsFileExists(filePath)) {
384         RINGTONE_ERR_LOG("the file exists path: %{private}s", filePath.c_str());
385         return E_FILE_EXIST;
386     }
387 
388     ofstream file(filePath);
389     if (!file) {
390         RINGTONE_ERR_LOG("Output file path could not be created errno %{public}d", errno);
391         return errCode;
392     }
393 
394     file.close();
395 
396     return E_SUCCESS;
397 }
398 
DeleteFile(const string & fileName)399 bool RingtoneFileUtils::DeleteFile(const string &fileName)
400 {
401     return (remove(fileName.c_str()) == 0);
402 }
403 
MoveFile(const string & oldPath,const string & newPath)404 bool RingtoneFileUtils::MoveFile(const string &oldPath, const string &newPath)
405 {
406     bool errRet = false;
407 
408     if (IsFileExists(oldPath) && !IsFileExists(newPath)) {
409         errRet = (rename(oldPath.c_str(), newPath.c_str()) == 0);
410     }
411 
412     return errRet;
413 }
414 
CopyFileUtil(const string & filePath,const string & newPath)415 bool RingtoneFileUtils::CopyFileUtil(const string &filePath, const string &newPath)
416 {
417     struct stat fst{};
418     bool ret = false;
419     if (filePath.size() >= PATH_MAX) {
420         RINGTONE_ERR_LOG("File path too long %{public}d", static_cast<int>(filePath.size()));
421         return ret;
422     }
423     RINGTONE_INFO_LOG("File path is %{private}s", filePath.c_str());
424     string absFilePath;
425     if (!PathToRealPath(filePath, absFilePath)) {
426         RINGTONE_ERR_LOG("file is not real path, file path: %{private}s", filePath.c_str());
427         return ret;
428     }
429     if (absFilePath.empty()) {
430         RINGTONE_ERR_LOG("Failed to obtain the canonical path for source path%{private}s %{public}d",
431             filePath.c_str(), errno);
432         return ret;
433     }
434 
435     int32_t source = open(absFilePath.c_str(), O_RDONLY);
436     if (source == -1) {
437         RINGTONE_ERR_LOG("Open failed for source file");
438         return ret;
439     }
440 
441     int32_t dest = open(newPath.c_str(), O_WRONLY | O_CREAT, MODE_RW_USR);
442     if (dest == -1) {
443         RINGTONE_ERR_LOG("Open failed for destination file %{public}d", errno);
444         close(source);
445         return ret;
446     }
447 
448     if (fstat(source, &fst) == 0) {
449         // Copy file content
450         if (sendfile(dest, source, nullptr, fst.st_size) != E_ERR) {
451             // Copy ownership and mode of source file
452             if (fchown(dest, fst.st_uid, fst.st_gid) == 0 &&
453                 fchmod(dest, fst.st_mode) == 0) {
454                 ret= true;
455             }
456         }
457     }
458 
459     close(source);
460     close(dest);
461 
462     return ret;
463 }
464 
Timespec2Millisecond(const struct timespec & time)465 int64_t RingtoneFileUtils::Timespec2Millisecond(const struct timespec &time)
466 {
467     return time.tv_sec * MSEC_TO_SEC + time.tv_nsec / MSEC_TO_NSEC;
468 }
469 
StartsWith(const string & str,const string & prefix)470 bool RingtoneFileUtils::StartsWith(const string &str, const string &prefix)
471 {
472     return str.compare(0, prefix.size(), prefix) == 0;
473 }
474 
UTCTimeMilliSeconds()475 int64_t RingtoneFileUtils::UTCTimeMilliSeconds()
476 {
477     struct timespec t;
478     clock_gettime(CLOCK_REALTIME, &t);
479     return t.tv_sec * MSEC_TO_SEC + t.tv_nsec / MSEC_TO_NSEC;
480 }
481 
UTCTimeSeconds()482 int64_t RingtoneFileUtils::UTCTimeSeconds()
483 {
484     struct timespec t{};
485     t.tv_sec = 0;
486     t.tv_nsec = 0;
487     clock_gettime(CLOCK_REALTIME, &t);
488     return (int64_t)(t.tv_sec);
489 }
490 
StrCreateTimeByMilliseconds(const string & format,int64_t time)491 string RingtoneFileUtils::StrCreateTimeByMilliseconds(const string &format, int64_t time)
492 {
493     char strTime[DEFAULT_TIME_SIZE] = "";
494     int64_t times = time / MSEC_TO_SEC;
495     auto tm = localtime(&times);
496     if (tm == nullptr) {
497         return "";
498     }
499     (void)strftime(strTime, sizeof(strTime), format.c_str(), tm);
500     return strTime;
501 }
502 
503 static const int URL_DECODE_DOUBLE = 2;
UrlDecode(const string & src)504 string RingtoneFileUtils::UrlDecode(const string &src)
505 {
506     string ret;
507     char ch;
508     int tmpNum;
509     for (size_t i = 0; i < src.length(); i++) {
510         if (src[i]=='%') {
511             if (sscanf_s(src.substr(i + 1, URL_DECODE_DOUBLE).c_str(), "%x", &tmpNum) == -1) {
512                 RINGTONE_ERR_LOG("Not a valid url: %{private}s", src.c_str());
513                 return src;
514             }
515             ch = static_cast<char>(tmpNum);
516             ret += ch;
517             i = i + URL_DECODE_DOUBLE;
518         } else {
519             ret += src[i];
520         }
521     }
522     return ret;
523 }
524 
MkdirRecursive(const string & path,size_t start)525 static int32_t MkdirRecursive(const string &path, size_t start)
526 {
527     RINGTONE_DEBUG_LOG("start pos %{public}zu", start);
528     size_t end = path.find("/", start + 1);
529 
530     string subDir = "";
531     if (end == std::string::npos) {
532         if (start + 1 == path.size()) {
533             RINGTONE_DEBUG_LOG("path size=%zu", path.size());
534         } else {
535             subDir = path.substr(start + 1, path.size() - start - 1);
536         }
537     } else {
538         subDir = path.substr(start + 1, end - start - 1);
539     }
540 
541     if (subDir.size() == 0) {
542         return E_SUCCESS;
543     } else {
544         string real = path.substr(0, start + subDir.size() + 1);
545         mode_t mask = umask(0);
546         int result = mkdir(real.c_str(), MODE_RWX_USR_GRP);
547         if (result == 0) {
548             RINGTONE_INFO_LOG("mkdir %{public}s successfully", real.c_str());
549         } else {
550             RINGTONE_INFO_LOG("mkdir %{public}s failed, errno is %{public}d", real.c_str(), errno);
551         }
552         umask(mask);
553     }
554     if (end == std::string::npos) {
555         return E_SUCCESS;
556     }
557 
558     return MkdirRecursive(path, end);
559 }
560 
CreatePreloadFolder(const string & path)561 int32_t RingtoneFileUtils::CreatePreloadFolder(const string &path)
562 {
563     RINGTONE_DEBUG_LOG("start");
564     if (access(path.c_str(), F_OK) == 0) {
565         RINGTONE_DEBUG_LOG("dir is existing");
566         return E_SUCCESS;
567     }
568 
569     auto start = path.find(RINGTONE_CUSTOMIZED_BASE_PATH);
570     if (start == string::npos) {
571         RINGTONE_ERR_LOG("base dir is wrong");
572         return E_ERR;
573     }
574 
575     return MkdirRecursive(path, start + RINGTONE_CUSTOMIZED_BASE_PATH.size());
576 }
577 
CreateRingtoneDir()578 void RingtoneFileUtils::CreateRingtoneDir()
579 {
580     static const vector<string> userPreloadDirs = {
581         { RINGTONE_CUSTOMIZED_ALARM_PATH }, { RINGTONE_CUSTOMIZED_RINGTONE_PATH },
582         { RINGTONE_CUSTOMIZED_NOTIFICATIONS_PATH }
583     };
584 
585     for (const auto &dir: userPreloadDirs) {
586         if (CreatePreloadFolder(dir) != E_SUCCESS) {
587             RINGTONE_INFO_LOG("scan failed on dir %{public}s", dir.c_str());
588             continue;
589         }
590     }
591 }
592 
MoveDirectory(const std::string & srcDir,const std::string & dstDir)593 int32_t RingtoneFileUtils::MoveDirectory(const std::string &srcDir, const std::string &dstDir)
594 {
595     if (access(srcDir.c_str(), F_OK) != 0) {
596         RINGTONE_ERR_LOG("access srcDir failed, errno is %{public}d", errno);
597         return E_FAIL;
598     }
599     if (access(dstDir.c_str(), F_OK) != 0) {
600         RINGTONE_ERR_LOG("access dstDir failed, errno is %{public}d", errno);
601         return E_FAIL;
602     }
603     int ret = E_SUCCESS;
604     for (const auto &dirEntry : std::filesystem::directory_iterator{ srcDir }) {
605         std::string srcFilePath = dirEntry.path();
606         std::string tmpFilePath = srcFilePath;
607         std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
608         if (!MoveFile(srcFilePath, dstFilePath)) {
609             RINGTONE_ERR_LOG("Move file failed, errno is %{public}d", errno);
610             ret = E_FAIL;
611         }
612     }
613     return ret;
614 }
615 
AccessRingtoneDir()616 void RingtoneFileUtils::AccessRingtoneDir()
617 {
618     if (access(RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str(), F_OK) != 0) {
619         CreateRingtoneDir();
620         return;
621     }
622     struct stat fileStat;
623     if (stat(RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str(), &fileStat) != 0) {
624         RINGTONE_ERR_LOG("stat dir failed, errno is %{public}d", errno);
625         return;
626     }
627     // 检查组的写权限
628     if ((fileStat.st_mode & S_IWGRP) != 0) {
629         return;
630     }
631     if (IsEmptyFolder(RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str())) {
632         RINGTONE_ERR_LOG("The directory is empty and lacks group write permission.");
633         if (DeleteFile(RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str())) {
634             RINGTONE_ERR_LOG("DeleteFile denied, errCode: %{public}d", errno);
635         }
636         CreateRingtoneDir();
637     } else { //rename and move file
638         RINGTONE_ERR_LOG("The directory is not empty and lacks group write permission.");
639         if (MoveFile(RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str(),
640             RINGTONE_CUSTOMIZED_BASE_RINGTONETMP_PATH.c_str())) {
641             if (CreatePreloadFolder(RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str()) != E_SUCCESS) {
642                 RINGTONE_ERR_LOG("Create Ringtone dir failed, errno is %{public}d", errno);
643                 //restore dir
644                 MoveFile(RINGTONE_CUSTOMIZED_BASE_RINGTONETMP_PATH.c_str(),
645                     RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str());
646                 return;
647             }
648             if (MoveDirectory(RINGTONE_CUSTOMIZED_BASE_RINGTONETMP_PATH.c_str(),
649                 RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str()) != E_SUCCESS) {
650                 RINGTONE_ERR_LOG("Move dir failed, errno is %{public}d", errno);
651                 CreateRingtoneDir();
652                 return;
653             }
654             if (DeleteFile(RINGTONE_CUSTOMIZED_BASE_RINGTONETMP_PATH.c_str())) {
655                 RINGTONE_ERR_LOG("DeleteFile denied, errCode: %{public}d", errno);
656             }
657         } else {
658             RINGTONE_ERR_LOG("Move Ringtone dir failed, errno is %{public}d", errno);
659         }
660     }
661     return;
662 }
663 
GetFileExtension(const string & path)664 string RingtoneFileUtils::GetFileExtension(const string &path)
665 {
666     if (!path.empty()) {
667         size_t dotIndex = path.rfind(".");
668         if (dotIndex != string::npos) {
669             return path.substr(dotIndex + 1);
670         }
671     }
672 
673     RINGTONE_ERR_LOG("Failed to obtain file extension because given pathname is empty");
674     return "";
675 }
676 } // namespace Media
677 } // namespace OHOS
678