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_WINDOWS_LIBPANDABASE_FILE_H 17 #define PLATFORMS_WINDOWS_LIBPANDABASE_FILE_H 18 19 #include "os/error.h" 20 #include "utils/expected.h" 21 #include "utils/logger.h" 22 23 #include <array> 24 #include <cerrno> 25 #include <cstddef> 26 #include <io.h> 27 #include <string> 28 #include <sys/stat.h> 29 #include <sys/types.h> 30 31 namespace panda::os::windows::file { 32 33 // In windows API, the length of a path has a limitation of MAX_PATH, which is defined as 260 characters, 34 // the "\\?\" prefix is used to specify an extended-length path for a maximum length of 32,767 characters. 35 static const std::string PREFIX_FOR_LONG_PATH = "\\\\?\\"; 36 37 class File { 38 public: File(int fd)39 explicit File(int fd) : fd_(fd) {} 40 ~File() = default; 41 DEFAULT_MOVE_SEMANTIC(File); 42 DEFAULT_COPY_SEMANTIC(File); 43 Read(void * buf,size_t n)44 Expected<size_t, Error> Read(void *buf, size_t n) const 45 { 46 auto res = _read(fd_, buf, n); 47 if (res < 0) { 48 return Unexpected(Error(errno)); 49 } 50 return {static_cast<size_t>(res)}; 51 } 52 ReadAll(void * buf,size_t n)53 bool ReadAll(void *buf, size_t n) const 54 { 55 auto res = Read(buf, n); 56 if (res) { 57 return res.Value() == n; 58 } 59 60 return false; 61 } 62 Write(const void * buf,size_t n)63 Expected<size_t, Error> Write(const void *buf, size_t n) const 64 { 65 auto res = _write(fd_, buf, n); 66 if (res < 0) { 67 return Unexpected(Error(errno)); 68 } 69 return {static_cast<size_t>(res)}; 70 } 71 WriteAll(const void * buf,size_t n)72 bool WriteAll(const void *buf, size_t n) const 73 { 74 auto res = Write(buf, n); 75 if (res) { 76 return res.Value() == n; 77 } 78 79 return false; 80 } 81 Close()82 int Close() const 83 { 84 return _close(fd_); 85 } 86 GetFileSize()87 Expected<size_t, Error> GetFileSize() const 88 { 89 struct _stat64 st { 90 }; 91 auto r = _fstat64(fd_, &st); 92 if (r == 0) { 93 return {static_cast<size_t>(st.st_size)}; 94 } 95 return Unexpected(Error(errno)); 96 } 97 IsValid()98 bool IsValid() const 99 { 100 return fd_ != -1; 101 } 102 GetFd()103 int GetFd() const 104 { 105 return fd_; 106 } 107 GetPathDelim()108 constexpr static std::string_view GetPathDelim() 109 { 110 return "\\"; 111 } 112 GetExtendedFilePath(const std::string & path)113 static const std::string GetExtendedFilePath(const std::string &path) 114 { 115 if (LIKELY(path.length() < _MAX_PATH)) { 116 return path; 117 } else { 118 return GetExtendedLengthStylePath(path); 119 } 120 } 121 122 static Expected<std::string, Error> GetTmpPath(); 123 124 static Expected<std::string, Error> GetExecutablePath(); 125 GetAbsolutePath(std::string_view relative_path)126 static Expected<std::string, Error> GetAbsolutePath(std::string_view relative_path) 127 { 128 constexpr size_t MAX_PATH_LEN = 2048; 129 std::array<char, MAX_PATH_LEN> buffer = {0}; 130 auto fp = _fullpath(buffer.data(), relative_path.data(), buffer.size() - 1); 131 if (fp == nullptr) { 132 return Unexpected(Error(errno)); 133 } 134 135 return std::string(fp); 136 } 137 GetExtendedLengthStylePath(const std::string & path)138 static const std::string GetExtendedLengthStylePath(const std::string &path) 139 { 140 // PREFIX_FOR_LONG_PATH is added to specify it's an extended-length path, 141 // and the path needs to be composed of names seperated by backslashes 142 std::string extendedPath = PREFIX_FOR_LONG_PATH + path; 143 std::replace(extendedPath.begin(), extendedPath.end(), '/', '\\'); 144 return extendedPath; 145 } 146 IsDirectory(const std::string & path)147 static bool IsDirectory(const std::string &path) 148 { 149 return HasStatMode(path, _S_IFDIR); 150 } 151 IsRegularFile(const std::string & path)152 static bool IsRegularFile(const std::string &path) 153 { 154 return HasStatMode(path, _S_IFREG); 155 } 156 ClearData()157 bool ClearData() 158 { 159 // TODO(dkx): check we are not in RO mode 160 161 // SetLength 162 { 163 auto rc = _chsize(fd_, 0); 164 if (rc < 0) { 165 PLOG(ERROR, RUNTIME) << "Failed to reset the length"; 166 return false; 167 } 168 } 169 170 // Move offset 171 { 172 auto rc = _lseek(fd_, 0, SEEK_SET); 173 if (rc == -1) { 174 PLOG(ERROR, RUNTIME) << "Failed to reset the offset"; 175 return false; 176 } 177 return true; 178 } 179 } 180 Reset()181 bool Reset() 182 { 183 return _lseek(fd_, 0L, SEEK_SET) == 0; 184 } 185 SetSeek(long offset)186 bool SetSeek(long offset) 187 { 188 return _lseek(fd_, offset, SEEK_SET) >= 0; 189 } 190 SetSeekEnd()191 bool SetSeekEnd() 192 { 193 return _lseek(fd_, 0L, SEEK_END) == 0; 194 } 195 196 private: 197 int fd_; 198 HasStatMode(const std::string & path,uint16_t mode)199 static bool HasStatMode(const std::string &path, uint16_t mode) 200 { 201 struct _stat s = {}; 202 203 std::string tmp_path = path; 204 if (UNLIKELY(path.length() >= _MAX_PATH)) { 205 tmp_path = GetExtendedLengthStylePath(path); 206 } 207 if (_stat(tmp_path.c_str(), &s) != 0) { 208 return false; 209 } 210 211 return static_cast<bool>(s.st_mode & mode); 212 } 213 }; 214 215 } // namespace panda::os::windows::file 216 217 #endif // PLATFORMS_WINDOWS_LIBPANDABASE_FILE_H 218