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
37namespace OHOS {
38namespace Media {
39using namespace std;
40static const int32_t OPEN_FDS = 128;
41static const mode_t MODE_RWX_USR_GRP = 02771;
42static const mode_t MODE_RW_USR = 0644;
43const 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
77static 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
94static 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
104string 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
110string 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
119string 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
132static 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
152string 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
167string 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
183bool 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
207static 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
218int32_t RingtoneFileUtils::RemoveDirectory(const string &path)
219{
220    return nftw(path.c_str(), UnlinkCb, OPEN_FDS, FTW_DEPTH | FTW_PHYS);
221}
222
223bool 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
238bool 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
254bool 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
275int32_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
319int32_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
363bool RingtoneFileUtils::IsFileExists(const string &fileName)
364{
365    struct stat statInfo {};
366
367    return ((stat(fileName.c_str(), &statInfo)) == 0);
368}
369
370int32_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
399bool RingtoneFileUtils::DeleteFile(const string &fileName)
400{
401    return (remove(fileName.c_str()) == 0);
402}
403
404bool 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
415bool 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
465int64_t RingtoneFileUtils::Timespec2Millisecond(const struct timespec &time)
466{
467    return time.tv_sec * MSEC_TO_SEC + time.tv_nsec / MSEC_TO_NSEC;
468}
469
470bool RingtoneFileUtils::StartsWith(const string &str, const string &prefix)
471{
472    return str.compare(0, prefix.size(), prefix) == 0;
473}
474
475int64_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
482int64_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
491string 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
503static const int URL_DECODE_DOUBLE = 2;
504string 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
525static 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
561int32_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
578void 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
593int32_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
616void 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        if (MoveFile(RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str(),
639            RINGTONE_CUSTOMIZED_BASE_RINGTONETMP_PATH.c_str())) {
640            if (CreatePreloadFolder(RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str()) != E_SUCCESS) {
641                RINGTONE_ERR_LOG("Create Ringtone dir failed, errno is %{public}d", errno);
642                //restore dir
643                MoveFile(RINGTONE_CUSTOMIZED_BASE_RINGTONETMP_PATH.c_str(),
644                    RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str());
645                return;
646            }
647            if (MoveDirectory(RINGTONE_CUSTOMIZED_BASE_RINGTONETMP_PATH.c_str(),
648                RINGTONE_CUSTOMIZED_BASE_RINGTONE_PATH.c_str()) != E_SUCCESS) {
649                RINGTONE_ERR_LOG("Move dir failed, errno is %{public}d", errno);
650                CreateRingtoneDir();
651                return;
652            }
653            if (DeleteFile(RINGTONE_CUSTOMIZED_BASE_RINGTONETMP_PATH.c_str())) {
654                RINGTONE_ERR_LOG("DeleteFile denied, errCode: %{public}d", errno);
655            }
656        } else {
657            RINGTONE_ERR_LOG("Move Ringtone dir failed, errno is %{public}d", errno);
658        }
659    }
660    return;
661}
662
663string RingtoneFileUtils::GetFileExtension(const string &path)
664{
665    if (!path.empty()) {
666        size_t dotIndex = path.rfind(".");
667        if (dotIndex != string::npos) {
668            return path.substr(dotIndex + 1);
669        }
670    }
671
672    RINGTONE_ERR_LOG("Failed to obtain file extension because given pathname is empty");
673    return "";
674}
675} // namespace Media
676} // namespace OHOS
677