1 /* 2 * Copyright (C) 2013, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "dictionary/utils/file_utils.h" 18 19 #include <cstdio> 20 #include <cstring> 21 #include <dirent.h> 22 #include <fcntl.h> 23 #include <libgen.h> 24 #include <sys/types.h> 25 #include <sys/stat.h> 26 #include <unistd.h> 27 28 namespace latinime { 29 30 // Returns -1 on error. 31 /* static */ int FileUtils::getFileSize(const char *const filePath) { 32 const int fd = open(filePath, O_RDONLY); 33 if (fd == -1) { 34 return -1; 35 } 36 struct stat statBuf; 37 if (fstat(fd, &statBuf) != 0) { 38 close(fd); 39 return -1; 40 } 41 close(fd); 42 return static_cast<int>(statBuf.st_size); 43 } 44 45 /* static */ bool FileUtils::existsDir(const char *const dirPath) { 46 DIR *const dir = opendir(dirPath); 47 if (dir == NULL) { 48 return false; 49 } 50 closedir(dir); 51 return true; 52 } 53 54 // Remove a directory and all files in the directory. 55 /* static */ bool FileUtils::removeDirAndFiles(const char *const dirPath) { 56 return removeDirAndFiles(dirPath, 5 /* maxTries */); 57 } 58 59 // Remove a directory and all files in the directory, trying up to maxTimes. 60 /* static */ bool FileUtils::removeDirAndFiles(const char *const dirPath, const int maxTries) { 61 DIR *const dir = opendir(dirPath); 62 if (dir == NULL) { 63 AKLOGE("Cannot open dir %s.", dirPath); 64 return true; 65 } 66 struct dirent *dirent; 67 while ((dirent = readdir(dir)) != NULL) { 68 if (dirent->d_type == DT_DIR) { 69 continue; 70 } 71 if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) { 72 continue; 73 } 74 const int filePathBufSize = getFilePathBufSize(dirPath, dirent->d_name); 75 char filePath[filePathBufSize]; 76 getFilePath(dirPath, dirent->d_name, filePathBufSize, filePath); 77 if (remove(filePath) != 0) { 78 AKLOGE("Cannot remove file %s.", filePath); 79 closedir(dir); 80 return false; 81 } 82 } 83 closedir(dir); 84 if (remove(dirPath) != 0) { 85 if (maxTries > 0) { 86 // On NFS, deleting files sometimes creates new files. I'm not sure what the 87 // correct way of dealing with this is, but for the time being, this seems to work. 88 removeDirAndFiles(dirPath, maxTries - 1); 89 } else { 90 AKLOGE("Cannot remove directory %s.", dirPath); 91 return false; 92 } 93 } 94 return true; 95 } 96 97 /* static */ int FileUtils::getFilePathWithSuffixBufSize(const char *const filePath, 98 const char *const suffix) { 99 return strlen(filePath) + strlen(suffix) + 1 /* terminator */; 100 } 101 102 /* static */ void FileUtils::getFilePathWithSuffix(const char *const filePath, 103 const char *const suffix, const int filePathBufSize, char *const outFilePath) { 104 snprintf(outFilePath, filePathBufSize, "%s%s", filePath, suffix); 105 } 106 107 /* static */ int FileUtils::getFilePathBufSize(const char *const dirPath, 108 const char *const fileName) { 109 return strlen(dirPath) + 1 /* '/' */ + strlen(fileName) + 1 /* terminator */; 110 } 111 112 /* static */ void FileUtils::getFilePath(const char *const dirPath, const char *const fileName, 113 const int filePathBufSize, char *const outFilePath) { 114 snprintf(outFilePath, filePathBufSize, "%s/%s", dirPath, fileName); 115 } 116 117 /* static */ bool FileUtils::getFilePathWithoutSuffix(const char *const filePath, 118 const char *const suffix, const int outDirPathBufSize, char *const outDirPath) { 119 const int filePathLength = strlen(filePath); 120 const int suffixLength = strlen(suffix); 121 if (filePathLength <= suffixLength) { 122 AKLOGE("File path length (%s:%d) is shorter that suffix length (%s:%d).", 123 filePath, filePathLength, suffix, suffixLength); 124 return false; 125 } 126 const int resultFilePathLength = filePathLength - suffixLength; 127 if (outDirPathBufSize <= resultFilePathLength) { 128 AKLOGE("outDirPathBufSize is too small. filePath: %s, suffix: %s, outDirPathBufSize: %d", 129 filePath, suffix, outDirPathBufSize); 130 return false; 131 } 132 if (strncmp(filePath + resultFilePathLength, suffix, suffixLength) != 0) { 133 AKLOGE("File Path %s does not have %s as a suffix", filePath, suffix); 134 return false; 135 } 136 snprintf(outDirPath, resultFilePathLength + 1 /* terminator */, "%s", filePath); 137 return true; 138 } 139 140 /* static */ void FileUtils::getDirPath(const char *const filePath, const int outDirPathBufSize, 141 char *const outDirPath) { 142 for (int i = strlen(filePath) - 1; i >= 0; --i) { 143 if (filePath[i] == '/') { 144 if (i >= outDirPathBufSize) { 145 AKLOGE("outDirPathBufSize is too small. filePath: %s, outDirPathBufSize: %d", 146 filePath, outDirPathBufSize); 147 ASSERT(false); 148 return; 149 } 150 snprintf(outDirPath, i + 1 /* terminator */, "%s", filePath); 151 return; 152 } 153 } 154 } 155 156 /* static */ void FileUtils::getBasename(const char *const filePath, 157 const int outNameBufSize, char *const outName) { 158 const int filePathBufSize = strlen(filePath) + 1 /* terminator */; 159 char filePathBuf[filePathBufSize]; 160 snprintf(filePathBuf, filePathBufSize, "%s", filePath); 161 const char *const baseName = basename(filePathBuf); 162 const int baseNameLength = strlen(baseName); 163 if (baseNameLength >= outNameBufSize) { 164 AKLOGE("outNameBufSize is too small. filePath: %s, outNameBufSize: %d", 165 filePath, outNameBufSize); 166 return; 167 } 168 snprintf(outName, baseNameLength + 1 /* terminator */, "%s", baseName); 169 } 170 171 } // namespace latinime 172