roo_io
API Documentation for roo_io
Loading...
Searching...
No Matches
mount.cpp
Go to the documentation of this file.
2
5
6#ifdef ARDUINO
7
8namespace roo_io {
9
10namespace {
11
12Status CheckParentage(FS& fs, const char* path) {
13 std::unique_ptr<char[]> dup_path(new char[strlen(path) + 1]);
14 strcpy(dup_path.get(), path);
15 size_t pos = 0;
16 while (true) {
17 while (dup_path[pos] == '/') ++pos;
18 while (dup_path[pos] != '/') {
19 if (dup_path[pos] == 0) {
20 // We ignore the type and existence of the last segment, since our job
21 // is only to check parentage.
22 return kOk;
23 }
24 ++pos;
25 }
26 dup_path[pos] = 0;
27 {
28 fs::File f = fs.open(dup_path.get(), "r");
29 if (!f) return kNotFound;
30 if (!f.isDirectory()) return kNotDirectory;
31 }
32 dup_path[pos] = '/';
33 ++pos;
34 }
35}
36
37} // namespace
38
39ArduinoMountImpl::ArduinoMountImpl(FS& fs, bool read_only,
40 std::function<void()> unmount_fn)
41 : MountImpl(unmount_fn), fs_(fs), active_(true), read_only_(read_only) {}
42
43bool ArduinoMountImpl::isReadOnly() const { return read_only_; }
44
45Stat ArduinoMountImpl::stat(const char* path) const {
46 if (path == nullptr || path[0] != '/') {
47 return Stat(kInvalidPath);
48 }
49 if (!active_) return Stat(kNotMounted);
50 if (!fs_.exists(path)) return Stat(kNotFound);
51 fs::File f = fs_.open(path, "r");
52 if (!f) return Stat(kNotFound);
53 return f.isDirectory() ? Stat(Stat::kDir, 0) : Stat(Stat::kFile, f.size());
54}
55
56Status ArduinoMountImpl::remove(const char* path) {
57 if (path == nullptr || path[0] != '/') {
58 return kInvalidPath;
59 }
60 if (!active_) return kNotMounted;
61 if (read_only_) return kReadOnlyFilesystem;
62 {
63 fs::File f = fs_.open(path, "r");
64 if (!f) return kNotFound;
65 if (f.isDirectory()) return kNotFile;
66 }
67 return fs_.remove(path) ? kOk : kUnknownIOError;
68}
69
70Status ArduinoMountImpl::rename(const char* pathFrom, const char* pathTo) {
71 if (read_only_) return kReadOnlyFilesystem;
72 if (fs_.rename(pathFrom, pathTo)) return kOk;
73 Stat src = stat(pathFrom);
74 if (!src.exists()) {
75 return src.status();
76 }
77 Stat dst = stat(pathTo);
78 if (dst.exists()) return dst.isDirectory() ? kDirectoryExists : kFileExists;
79 if (dst.status() != kNotFound) return dst.status();
80 if (strncmp(pathFrom, pathTo, strlen(pathFrom)) == 0) {
81 return kInvalidPath;
82 }
83 // Check if the destination directory exists.
84 std::unique_ptr<char[]> dup(new char[strlen(pathTo) + 1]);
85 strcpy(dup.get(), pathTo);
86 char* last_slash = strrchr(dup.get(), '/');
87 if (last_slash != nullptr) {
88 *last_slash = 0;
89 Stat dst_dir = stat(dup.get());
90 if (dst_dir.status() == kNotFound) return kNotFound;
91 if (!dst_dir.isDirectory()) return kNotDirectory;
92 }
93 return kUnknownIOError;
94}
95
96Status ArduinoMountImpl::mkdir(const char* path) {
97 if (path == nullptr || path[0] != '/') {
98 return kInvalidPath;
99 }
100 if (!active_) return kNotMounted;
101 if (read_only_) return kReadOnlyFilesystem;
102 if (fs_.mkdir(path)) return kOk;
103 if (fs_.exists(path)) {
104 fs::File f = fs_.open(path, "r");
105 if (f) {
106 return f.isDirectory() ? kDirectoryExists : kFileExists;
107 } else {
108 return kUnknownIOError;
109 }
110 }
111 Status status = CheckParentage(fs_, path);
112 if (status != kOk) return status;
113 return kUnknownIOError;
114}
115
116Status ArduinoMountImpl::rmdir(const char* path) {
117 if (path == nullptr || path[0] != '/') {
118 return kInvalidPath;
119 }
120 if (!active_) return kNotMounted;
121 if (read_only_) return kReadOnlyFilesystem;
122 {
123 fs::File f = fs_.open(path, "r");
124 if (!f) return kNotFound;
125 if (!f.isDirectory()) return kNotDirectory;
126 if (fs_.rmdir(path)) return kOk;
127
128 fs::File child;
129 do {
130 child = f.openNextFile();
131 } while (child && (strcmp(child.name(), ".") == 0 ||
132 strcmp(child.name(), "..") == 0));
133 if (child) return kDirectoryNotEmpty;
134 }
135 return kUnknownIOError;
136}
137
138std::unique_ptr<DirectoryImpl> ArduinoMountImpl::opendir(
139 std::shared_ptr<MountImpl> mount, const char* path) {
140 if (!active_) return DirectoryError(kNotMounted);
141 fs::File f = fs_.open(path, "r");
143 if (!f) {
144 if (!fs_.exists(path)) {
145 status = roo_io::kNotFound;
146 } else {
147 status = roo_io::kOpenError;
148 }
149 }
150 return std::unique_ptr<DirectoryImpl>(
151 new ArduinoDirectoryImpl(std::move(mount), std::move(f), status));
152}
153
154std::unique_ptr<MultipassInputStream> ArduinoMountImpl::fopen(
155 std::shared_ptr<MountImpl> mount, const char* path) {
156 if (path == nullptr || path[0] != '/') {
157 return InputError(kInvalidPath);
158 }
159 if (!active_) return InputError(kNotMounted);
160 fs::File f = fs_.open(path, "r");
161 if (!f) {
162 if (!fs_.exists(path)) {
163 return InputError(kNotFound);
164 } else {
165 return InputError(kOpenError);
166 }
167 }
168 if (f.isDirectory()) {
169 return InputError(kNotFile);
170 }
171 return std::unique_ptr<MultipassInputStream>(
172 new ArduinoFileInputStream(std::move(mount), std::move(f)));
173}
174
175std::unique_ptr<OutputStream> ArduinoMountImpl::fopenForWrite(
176 std::shared_ptr<MountImpl> mount, const char* path,
177 FileUpdatePolicy update_policy) {
178 if (path == nullptr || path[0] != '/') {
179 return OutputError(kInvalidPath);
180 }
181 if (!active_) return OutputError(kNotMounted);
182 if (read_only_) {
183 return OutputError(kReadOnlyFilesystem);
184 }
185 fs::File f;
186 if (update_policy == kFailIfExists) {
187 if (fs_.exists(path)) {
188 f = fs_.open(path, "r");
189 return OutputError(f.isDirectory() ? kDirectoryExists : kFileExists);
190 }
191 f = fs_.open(path, "w");
192 } else {
193 // Try to just open, but if it fails, check if not a directory to return a
194 // more specific error.
195 f = fs_.open(path, update_policy == kTruncateIfExists ? "w" : "a");
196 if (!f && fs_.exists(path)) {
197 f = fs_.open(path, "r");
198 if (f.isDirectory()) {
199 return OutputError(kNotFile);
200 }
201 return OutputError(kOpenError);
202 }
203 }
204 if (!f) {
205 return OutputError(kOpenError);
206 }
207 return std::unique_ptr<OutputStream>(
208 new ArduinoFileOutputStream(std::move(mount), std::move(f)));
209}
210
211void ArduinoMountImpl::deactivate() { active_ = false; }
212
213} // namespace roo_io
214
215#endif // ARDUINO
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
@ kOpenError
Definition status.h:12
@ 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)