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(×); 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