• 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_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