• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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