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