1 /** 2 * Copyright (c) 2021-2022 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 #ifndef PLATFORMS_UNIX_LIBPANDABASE_FILE_H 17 #define PLATFORMS_UNIX_LIBPANDABASE_FILE_H 18 19 #include <array> 20 #include <cerrno> 21 #include <climits> 22 #include <cstddef> 23 #include <cstdint> 24 #include <cstdlib> 25 #include <iosfwd> 26 #if PANDA_TARGET_MACOS || PANDA_TARGET_IOS 27 #include <mach-o/dyld.h> 28 // Undefine the conflict Mac marco 29 #undef BYTE_SIZE 30 #endif 31 #include <ostream> 32 #include <string> 33 #include <string_view> 34 #include <sys/stat.h> 35 #include <unistd.h> 36 37 #include "macros.h" 38 #include "os/error.h" 39 #include "utils/expected.h" 40 #include "utils/logger.h" 41 42 namespace panda::os::unix::file { 43 44 class File { 45 public: File(int fd)46 explicit File(int fd) : fd_(fd) {} 47 ~File() = default; 48 DEFAULT_COPY_SEMANTIC(File); 49 DEFAULT_MOVE_SEMANTIC(File); 50 Read(void * buf,size_t n)51 Expected<size_t, Error> Read(void *buf, size_t n) const 52 { 53 ssize_t res = read(fd_, buf, n); 54 if (res < 0) { 55 return Unexpected(Error(errno)); 56 } 57 return {static_cast<size_t>(res)}; 58 } 59 ReadAll(void * buf,size_t n)60 bool ReadAll(void *buf, size_t n) const 61 { 62 auto res = Read(buf, n); 63 if (res) { 64 return res.Value() == n; 65 } 66 67 return false; 68 } 69 Write(const void * buf,size_t n)70 Expected<size_t, Error> Write(const void *buf, size_t n) const 71 { 72 ssize_t res = write(fd_, buf, n); 73 if (res < 0) { 74 return Unexpected(Error(errno)); 75 } 76 return {static_cast<size_t>(res)}; 77 } 78 WriteAll(const void * buf,size_t n)79 bool WriteAll(const void *buf, size_t n) const 80 { 81 auto res = Write(buf, n); 82 if (res) { 83 return res.Value() == n; 84 } 85 86 return false; 87 } 88 Close()89 int Close() const 90 { 91 return close(fd_); 92 } 93 GetFileSize()94 Expected<size_t, Error> GetFileSize() const 95 { 96 #if PANDA_TARGET_MACOS || PANDA_TARGET_IOS 97 struct stat st { 98 }; 99 int r = fstat(fd_, &st); 100 #else 101 struct stat64 st { 102 }; 103 int r = fstat64(fd_, &st); 104 #endif 105 if (r == 0) { 106 return {static_cast<size_t>(st.st_size)}; 107 } 108 return Unexpected(Error(errno)); 109 } 110 IsValid()111 bool IsValid() const 112 { 113 return fd_ != -1; 114 } 115 GetFd()116 int GetFd() const 117 { 118 return fd_; 119 } 120 GetPathDelim()121 constexpr static std::string_view GetPathDelim() 122 { 123 return "/"; 124 } 125 GetExtendedFilePath(const std::string & path)126 static const std::string GetExtendedFilePath(const std::string &path) 127 { 128 return path; 129 } 130 GetTmpPath()131 static Expected<std::string, Error> GetTmpPath() 132 { 133 #if defined(PANDA_TARGET_MOBILE) 134 return std::string("/data/local/tmp"); 135 #else 136 const char *temp = getenv("XDG_RUNTIME_DIR"); 137 temp = temp != nullptr ? temp : getenv("TMPDIR"); 138 temp = temp != nullptr ? temp : getenv("TMP"); 139 temp = temp != nullptr ? temp : getenv("TEMP"); 140 temp = temp != nullptr ? temp : "/tmp"; 141 return std::string(temp); 142 #endif 143 } 144 GetExecutablePath()145 static Expected<std::string, Error> GetExecutablePath() 146 { 147 constexpr size_t BUFFER_SIZE = 1024; 148 std::array<char, BUFFER_SIZE> buffer = {0}; 149 #if PANDA_TARGET_MACOS || PANDA_TARGET_IOS 150 uint32_t size = BUFFER_SIZE; 151 if (_NSGetExecutablePath(buffer.data(), &size) != 0) { 152 return Unexpected(Error(errno)); 153 } 154 #else 155 ssize_t len = readlink("/proc/self/exe", buffer.data(), buffer.size() - 1); 156 if (len == -1) { 157 return Unexpected(Error(errno)); 158 } 159 #endif 160 161 std::string::size_type pos = std::string(buffer.data()).find_last_of(File::GetPathDelim()); 162 163 return (pos != std::string::npos) ? std::string(buffer.data()).substr(0, pos) : std::string(""); 164 } 165 GetAbsolutePath(std::string_view relative_path)166 static Expected<std::string, Error> GetAbsolutePath(std::string_view relative_path) 167 { 168 std::array<char, PATH_MAX> buffer = {0}; 169 auto fp = realpath(relative_path.data(), buffer.data()); 170 if (fp == nullptr) { 171 return Unexpected(Error(errno)); 172 } 173 174 return std::string(fp); 175 } 176 IsDirectory(const std::string & path)177 static bool IsDirectory(const std::string &path) 178 { 179 return HasStatMode(path, S_IFDIR); 180 } 181 IsRegularFile(const std::string & path)182 static bool IsRegularFile(const std::string &path) 183 { 184 return HasStatMode(path, S_IFREG); 185 } 186 ClearData()187 bool ClearData() 188 { 189 // SetLength 190 { 191 int rc = ftruncate(fd_, 0); 192 if (rc < 0) { 193 PLOG(ERROR, RUNTIME) << "Failed to reset the length"; 194 return false; 195 } 196 } 197 198 // Move offset 199 { 200 off_t rc = lseek(fd_, 0, SEEK_SET); 201 if (rc == static_cast<off_t>(-1)) { 202 PLOG(ERROR, RUNTIME) << "Failed to reset the offset"; 203 return false; 204 } 205 return true; 206 } 207 } 208 Reset()209 bool Reset() 210 { 211 return lseek(fd_, 0, SEEK_SET) == 0; 212 } 213 SetSeek(off_t offset)214 bool SetSeek(off_t offset) 215 { 216 return lseek(fd_, offset, SEEK_SET) >= 0; 217 } 218 SetSeekEnd()219 bool SetSeekEnd() 220 { 221 return lseek(fd_, 0, SEEK_END) == 0; 222 } 223 224 private: 225 int fd_; 226 HasStatMode(const std::string & path,uint16_t mode)227 static bool HasStatMode(const std::string &path, uint16_t mode) 228 { 229 struct stat s = {}; 230 231 if (stat(path.c_str(), &s) != 0) { 232 return false; 233 } 234 235 return static_cast<bool>(s.st_mode & mode); 236 } 237 }; 238 239 } // namespace panda::os::unix::file 240 241 #endif // PLATFORMS_UNIX_LIBPANDABASE_FILE_H 242