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 16#include "util/file.h" 17 18#include <climits> 19#include <cstdlib> 20#include <cstring> 21#include <dirent.h> 22#include <functional> 23#include <string> 24#include <algorithm> 25#include <queue> 26#include <sys/stat.h> 27#include <sys/types.h> 28#include <unistd.h> 29 30#include "util/common.h" 31#include "util/logger.h" 32#include "util/string_helper.h" 33#include "util/string_builder.h" 34 35namespace OHOS { 36namespace Idl { 37File::File(const std::string &path, unsigned int mode) : mode_(mode) 38{ 39 if (path.empty()) { 40 return; 41 } 42 43 if ((mode_ & READ) != 0) { 44 OpenByRead(path); 45 return; 46 } 47 48 if ((mode_ & WRITE) != 0) { 49 fd_ = fopen(path.c_str(), "w+"); 50 } else if ((mode_ & APPEND) != 0) { 51 fd_ = fopen(path.c_str(), "a+"); 52 } 53 54 if (fd_ == nullptr) { 55 Logger::E(TAG, "can't open '%s'", path.c_str()); 56 return; 57 } 58 59 path_ = RealPath(path); 60} 61 62File::~File() 63{ 64 Close(); 65} 66 67void File::OpenByRead(const std::string &path) 68{ 69 if (!CheckValid(path)) { 70 Logger::E(TAG, "failed to check path '%s'", path.c_str()); 71 return; 72 } 73 74 std::string realPath = RealPath(path); 75 if (realPath.empty()) { 76 Logger::E(TAG, "invalid path '%s'", path.c_str()); 77 return; 78 } 79 80 fd_ = fopen(realPath.c_str(), "r"); 81 if (fd_ == nullptr) { 82 Logger::E(TAG, "can't open '%s'", realPath.c_str()); 83 return; 84 } 85 86 path_ = realPath; 87 PeekChar(); 88} 89 90char File::GetChar() 91{ 92 char c = PeekChar(); 93 94 if (position_ + 1 <= size_) { 95 position_++; 96 97 if (c != '\n') { 98 columnNo_++; 99 } else { 100 columnNo_ = 1; 101 lineNo_++; 102 } 103 } 104 return c; 105} 106 107char File::PeekChar() 108{ 109 if (position_ + 1 > size_) { 110 size_t size = Read(); 111 if (size == 0) { 112 isEof_ = true; 113 } 114 } 115 116 return buffer_[position_]; 117} 118 119bool File::IsEof() const 120{ 121 return isEof_ || buffer_[position_] == static_cast<char>(-1); 122} 123 124size_t File::Read() 125{ 126 if (isEof_ || isError_) { 127 return -1; 128 } 129 130 std::fill(buffer_, buffer_ + BUFFER_SIZE, 0); 131 size_t count = fread(buffer_, 1, BUFFER_SIZE - 1, fd_); 132 if (count < BUFFER_SIZE - 1) { 133 isError_ = ferror(fd_) != 0; 134 buffer_[count] = -1; 135 } 136 size_ = count; 137 position_ = 0; 138 if ((count == 0) || (count >= BUFFER_SIZE)) { 139 return -1; 140 } 141 return count; 142} 143 144size_t File::ReadData(void *data, size_t size) const 145{ 146 if (data == nullptr || size == 0) { 147 return 0; 148 } 149 150 if (fd_ == nullptr) { 151 return 0; 152 } 153 154 return fread(data, 1, size, fd_); 155} 156 157bool File::WriteData(const void *data, size_t size) const 158{ 159 if (data == nullptr || size == 0) { 160 return true; 161 } 162 163 if (fd_ == nullptr || !(mode_ & (WRITE | APPEND))) { 164 return false; 165 } 166 167 size_t count = fwrite(data, size, 1, fd_); 168 return count == 1; 169} 170 171void File::Flush() const 172{ 173 if ((mode_ & (WRITE | APPEND)) && fd_ != nullptr) { 174 fflush(fd_); 175 } 176} 177 178bool File::Reset() const 179{ 180 if (fd_ == nullptr) { 181 return false; 182 } 183 184 return fseek(fd_, 0, SEEK_SET) == 0; 185} 186 187bool File::Skip(long size) const 188{ 189 if (fd_ == nullptr) { 190 return false; 191 } 192 193 return fseek(fd_, size, SEEK_CUR) == 0; 194} 195 196void File::Close() 197{ 198 if (fd_ != nullptr) { 199 fclose(fd_); 200 fd_ = nullptr; 201 } 202} 203 204bool File::CreateParentDir(const std::string &path) 205{ 206 if (access(path.c_str(), F_OK | R_OK | W_OK) == 0) { 207 return true; 208 } 209 210 size_t pos = 1; 211 while ((pos = path.find(SEPARATOR, pos)) != std::string::npos) { 212 std::string partPath = StringHelper::SubStr(path, 0, pos); 213 partPath += SEPARATOR; 214 if (File::CreatePartDir(partPath) == false) { 215 return false; 216 } 217 pos += 1; 218 } 219 return true; 220} 221 222bool File::CreatePartDir(const std::string &partPath) 223{ 224 struct stat st; 225 if (stat(partPath.c_str(), &st) < 0) { 226 if (errno != ENOENT) { 227 return false; 228 } 229 230#ifndef __MINGW32__ 231 if (mkdir(partPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0) { 232#else 233 if (mkdir(partPath.c_str()) < 0) { 234#endif 235 return false; 236 } 237 } else if (!S_ISDIR(st.st_mode)) { 238 return false; 239 } 240 return true; 241} 242 243std::string File::AdapterPath(const std::string &path) 244{ 245#ifndef __MINGW32__ 246 std::string newPath = StringHelper::Replace(path, '\\', '/'); 247#else 248 std::string newPath = StringHelper::Replace(path, '/', '\\'); 249#endif 250 251 // "foo/v1_0//ifoo.h" -> "foo/v1_0/ifoo.h" 252 StringBuilder adapterPath; 253 bool hasSep = false; 254 for (size_t i = 0; i < newPath.size(); i++) { 255 char c = newPath[i]; 256 if (c == SEPARATOR) { 257 if (hasSep) { 258 continue; 259 } 260 adapterPath.Append(c); 261 hasSep = true; 262 } else { 263 adapterPath.Append(c); 264 hasSep = false; 265 } 266 } 267 return adapterPath.ToString(); 268} 269 270std::string File::AdapterRealPath(const std::string &path) 271{ 272 if (path.empty()) { 273 return ""; 274 } 275 return RealPath(File::AdapterPath(path)); 276} 277 278std::string File::RealPath(const std::string &path) 279{ 280 if (path.empty()) { 281 return ""; 282 } 283 284 char realPath[PATH_MAX + 1]; 285#ifdef __MINGW32__ 286 char *absPath = _fullpath(realPath, path.c_str(), PATH_MAX); 287#else 288 char *absPath = realpath(path.c_str(), realPath); 289#endif 290 return absPath == nullptr ? "" : absPath; 291} 292 293bool File::CheckValid(const std::string &path) 294{ 295 if (access(path.c_str(), F_OK | R_OK | W_OK) != 0) { 296 return false; 297 } 298 299 struct stat st; 300 if (stat(path.c_str(), &st) < 0) { 301 return false; 302 } 303 304 if (S_ISDIR(st.st_mode)) { 305 return false; 306 } 307 308 return true; 309} 310 311std::set<std::string> File::FindFiles(const std::string &rootDir) 312{ 313 if (rootDir.empty()) { 314 return std::set<std::string>(); 315 } 316 317 std::set<std::string> files; 318 std::queue<std::string> dirs; 319 dirs.push(rootDir); 320 while (!dirs.empty()) { 321 std::string dirPath = dirs.front().back() == SEPARATOR ? dirs.front() : dirs.front() + SEPARATOR; 322 dirs.pop(); 323 DIR *dir = opendir(dirPath.c_str()); 324 if (dir == nullptr) { 325 Logger::E(TAG, "failed to open '%s', errno:%d", dirPath.c_str(), errno); 326 continue; 327 } 328 329 struct dirent *dirInfo = readdir(dir); 330 for (; dirInfo != nullptr; dirInfo = readdir(dir)) { 331 if (strcmp(dirInfo->d_name, ".") == 0 || strcmp(dirInfo->d_name, "..") == 0) { 332 continue; 333 } 334#ifndef __MINGW32__ 335 if (dirInfo->d_type == DT_REG && StringHelper::EndWith(dirInfo->d_name, ".idl")) { 336 std::string filePath = dirPath + dirInfo->d_name; 337 files.insert(filePath); 338 continue; 339 } 340 341 if (dirInfo->d_type == DT_DIR) { 342 dirs.emplace(dirPath + dirInfo->d_name); 343 continue; 344 } 345#else 346 std::string filePath = dirPath + dirInfo->d_name; 347 struct stat fileInfo; 348 if ((stat(filePath.c_str(), &fileInfo) == 0) && S_ISREG(fileInfo.st_mode)) { 349 files.insert(filePath); 350 } 351#endif 352 } 353 closedir(dir); 354 } 355 356 return files; 357} 358 359size_t File::GetHashKey() 360{ 361 StringBuilder fileStr; 362 while (!IsEof()) { 363 fileStr.Append(GetChar()); 364 } 365 366 return std::hash<std::string>()(fileStr.ToString()); 367} 368} // namespace Idl 369} // namespace OHOS