roo_io
API Documentation for roo_io
Loading...
Searching...
No Matches
posix_mount.cpp
Go to the documentation of this file.
2
3#if ROO_IO_FS_SUPPORT_POSIX
4
6
7#include <dirent.h>
8#include <stdio.h>
9#include <unistd.h>
10
11#include <cstring>
12
16#include "sys/stat.h"
17
18namespace roo_io {
19
20namespace {
21
22std::unique_ptr<char[]> cat(const char* mount_point, const char* path) {
23 std::unique_ptr<char[]> tmp(new char[strlen(path) + strlen(mount_point) + 2]);
24 if (tmp != nullptr) {
25 strcpy(tmp.get(), mount_point);
26 strcat(tmp.get(), path);
27 }
28 return tmp;
29}
30
32 struct stat st;
33 if (::stat(full_path, &st) == 0) {
34 // Found!
35 return (S_ISDIR(st.st_mode)) ? kDirectoryExists : kFileExists;
36 } else {
37 return kUnknownIOError;
38 }
39}
40
41} // namespace
42
43PosixMountImpl::PosixMountImpl(const char* mount_point, bool read_only,
44 std::function<void()> unmount_fn)
45 : MountImpl(unmount_fn),
48 read_only_(read_only) {}
49
50bool PosixMountImpl::isReadOnly() const { return read_only_; }
51
52Stat PosixMountImpl::stat(const char* path) const {
53 if (path == nullptr || path[0] != '/') {
54 return kInvalidPath;
55 }
56 if (mount_point_ == nullptr) return kNotMounted;
57 auto full_path = cat(mount_point_.get(), path);
58 if (full_path == nullptr) return kOutOfMemory;
59 struct stat st;
60 if (::stat(full_path.get(), &st) == 0) {
61 // Found!
62 Stat::Type type = S_ISDIR(st.st_mode) ? Stat::kDir : Stat::kFile;
63 uint64_t size = S_ISDIR(st.st_mode) ? 0 : st.st_size;
64 return Stat(type, size);
65 }
66 switch (errno) {
67 case ENAMETOOLONG:
68 return kInvalidPath;
69 case ENOENT:
70 return kNotFound;
71 case ENOMEM:
72 return kOutOfMemory;
73 case ENOTDIR:
74 return kNotDirectory;
75 default:
76 return kUnknownIOError;
77 }
78}
79
80Status PosixMountImpl::remove(const char* path) {
81 if (path == nullptr || path[0] != '/') {
82 return kInvalidPath;
83 }
84 if (mount_point_ == nullptr) return kNotMounted;
85 if (read_only_) return kReadOnlyFilesystem;
86 auto full_path = cat(mount_point_.get(), path);
87 if (full_path == nullptr) return kOutOfMemory;
88 if (::unlink(full_path.get()) == 0) {
89 return kOk;
90 }
91 switch (errno) {
92 case ENAMETOOLONG:
93 return kInvalidPath;
94 case ENOENT:
95 return kNotFound;
96 case ENOTDIR:
97 return kNotDirectory;
98 case EISDIR:
99 return kNotFile;
100 default:
101 return kUnknownIOError;
102 }
103}
104
105Status PosixMountImpl::rename(const char* pathFrom, const char* pathTo) {
106 if (pathFrom == nullptr || pathFrom[0] != '/') {
107 return kInvalidPath;
108 }
109 if (pathTo == nullptr || pathTo[0] != '/') {
110 return kInvalidPath;
111 }
112 if (mount_point_ == nullptr) return kNotMounted;
113 if (read_only_) return kReadOnlyFilesystem;
114
115 auto full_src_path = cat(mount_point_.get(), pathFrom);
116 if (full_src_path == nullptr) return kOutOfMemory;
117 auto full_dst_path = cat(mount_point_.get(), pathTo);
118 if (full_dst_path == nullptr) return kOutOfMemory;
119
120 if (::rename(full_src_path.get(), full_dst_path.get()) == 0) return kOk;
121 switch (errno) {
122 case ENOENT:
123 return kNotFound;
124 case EEXIST: {
125 return ResolveExistsError(full_dst_path.get());
126 }
127 case EINVAL:
128 return kInvalidPath;
129 default:
130 return kUnknownIOError;
131 }
132}
133
134Status PosixMountImpl::mkdir(const char* path) {
135 if (path == nullptr || path[0] != '/') {
136 return kInvalidPath;
137 }
138 if (mount_point_ == nullptr) return kNotMounted;
139 if (read_only_) return kReadOnlyFilesystem;
140 auto full_path = cat(mount_point_.get(), path);
141 if (full_path.get() == nullptr) return kOutOfMemory;
142 if (::mkdir(full_path.get(), 0777) == 0) return kOk;
143 switch (errno) {
144 case EEXIST: {
145 return ResolveExistsError(full_path.get());
146 }
147 case ENAMETOOLONG:
148 return kInvalidPath;
149 case ENOENT:
150 return kNotFound;
151 case ENOTDIR:
152 return kNotDirectory;
153 case EROFS:
154 return kReadOnlyFilesystem;
155 default:
156 return kUnknownIOError;
157 }
158}
159
160Status PosixMountImpl::rmdir(const char* path) {
161 if (path == nullptr || path[0] != '/') {
162 return kInvalidPath;
163 }
164 if (mount_point_ == nullptr) return kNotMounted;
165 if (read_only_) return kReadOnlyFilesystem;
166 auto full_path = cat(mount_point_.get(), path);
167 if (full_path.get() == nullptr) return kOutOfMemory;
168 if (::rmdir(full_path.get()) == 0) return kOk;
169 switch (errno) {
170 case EEXIST:
171 case ENOTEMPTY:
172 return kDirectoryNotEmpty;
173 case EINVAL:
174 return kInvalidPath;
175 case ENAMETOOLONG:
176 return kInvalidPath;
177 case ENOENT:
178 return kNotFound;
179 case ENOTDIR:
180 // TODO: differentiate between this and kAncestorNotDirectory.
181 return kNotDirectory;
182 case EROFS:
183 return kReadOnlyFilesystem;
184 default:
185 return kUnknownIOError;
186 }
187}
188
189std::unique_ptr<DirectoryImpl> PosixMountImpl::opendir(
190 std::shared_ptr<MountImpl> mount, const char* path) {
191 if (path == nullptr || path[0] != '/') {
192 return DirectoryError(kInvalidPath);
193 }
194 if (mount_point_ == nullptr) return DirectoryError(kNotMounted);
195
196 auto full_path = cat(mount_point_.get(), path);
197 if (full_path.get() == nullptr) return DirectoryError(kOutOfMemory);
198 DIR* dir = ::opendir(full_path.get());
199 if (dir != nullptr) {
200 return std::unique_ptr<DirectoryImpl>(
201 new PosixDirectoryImpl(std::move(mount), path, dir, kOk));
202 }
203 switch (errno) {
204 case ENAMETOOLONG:
205 return DirectoryError(kInvalidPath);
206 case ENOENT:
207 return DirectoryError(kNotFound);
208 case ENOTDIR:
209 return DirectoryError(kNotDirectory);
210 case ENFILE:
211 return DirectoryError(kTooManyFilesOpen);
212 default:
213 return DirectoryError(kUnknownIOError);
214 }
215}
216
217std::unique_ptr<MultipassInputStream> PosixMountImpl::fopen(
218 std::shared_ptr<MountImpl> mount, const char* path) {
219 if (path == nullptr || path[0] != '/') {
220 return InputError(kInvalidPath);
221 }
222 if (mount_point_ == nullptr) return InputError(kNotMounted);
223 auto full_path = cat(mount_point_.get(), path);
224 if (full_path.get() == nullptr) return InputError(kOutOfMemory);
225 FILE* f = ::fopen(full_path.get(), "r");
226 if (f != nullptr) {
227 return std::unique_ptr<MultipassInputStream>(
228 new PosixFileInputStream(std::move(mount), f));
229 }
230 switch (errno) {
231 case ENAMETOOLONG:
232 case EINVAL:
233 return InputError(kInvalidPath);
234 case ENOENT:
235 return InputError(kNotFound);
236 case ENOTDIR:
237 return InputError(kNotDirectory);
238 case ENFILE:
239 return InputError(kTooManyFilesOpen);
240 default:
241 return InputError(kUnknownIOError);
242 }
243}
244
245namespace {
246const char* Policy2Mode(FileUpdatePolicy policy) {
247 switch (policy) {
248 case kAppendIfExists:
249 return "a";
251 return "w";
252 default:
253 return "wx";
254 }
255}
256} // namespace
257
258std::unique_ptr<OutputStream> PosixMountImpl::fopenForWrite(
259 std::shared_ptr<MountImpl> mount, const char* path,
260 FileUpdatePolicy update_policy) {
261 if (path == nullptr || path[0] != '/') {
262 return OutputError(kInvalidPath);
263 }
264 if (mount_point_ == nullptr) return OutputError(kNotMounted);
265 if (read_only_) {
266 return OutputError(kReadOnlyFilesystem);
267 }
268 auto full_path = cat(mount_point_.get(), path);
269 if (full_path.get() == nullptr) return OutputError(kOutOfMemory);
270 FILE* f = ::fopen(full_path.get(), Policy2Mode(update_policy));
271 if (f != nullptr) {
272 return std::unique_ptr<OutputStream>(
273 new PosixFileOutputStream(std::move(mount), f));
274 }
275 switch (errno) {
276 case ENAMETOOLONG:
277 return OutputError(kInvalidPath);
278 case ENOENT:
279 return OutputError(kNotFound);
280 case ENOTDIR:
281 return OutputError(kNotDirectory);
282 case EISDIR:
283 return OutputError(kNotFile);
284 case ENFILE:
285 return OutputError(kTooManyFilesOpen);
286 case ENOMEM:
287 return OutputError(kOutOfMemory);
288 default:
289 return OutputError(kUnknownIOError);
290 }
291}
292
293void PosixMountImpl::deactivate() { mount_point_ = nullptr; }
294
295} // namespace roo_io
296
297#endif // ROO_IO_FS_SUPPORT_POSIX
Definition byte.h:6
std::unique_ptr< DirectoryImpl > DirectoryError(Status error)
roo::basic_string_view< CharT, Traits > basic_string_view
Definition string_view.h:8
Status
Definition status.h:7
@ kUnknownIOError
Definition status.h:58
@ kReadOnlyFilesystem
Definition status.h:21
@ kInvalidPath
Definition status.h:46
@ kOutOfMemory
Definition status.h:49
@ kFileExists
Definition status.h:28
@ kNotFile
Definition status.h:39
@ kOk
Definition status.h:8
@ kDirectoryExists
Definition status.h:32
@ kNotDirectory
Definition status.h:35
@ kNotMounted
Definition status.h:11
@ kNotFound
Definition status.h:24
@ kDirectoryNotEmpty
Definition status.h:43
std::unique_ptr< OutputStream > OutputError(Status error)
std::unique_ptr< MultipassInputStream > InputError(Status error)