diff options
Diffstat (limited to 'firmware/common/fileobj_mgr.c')
-rw-r--r-- | firmware/common/fileobj_mgr.c | 114 |
1 files changed, 87 insertions, 27 deletions
diff --git a/firmware/common/fileobj_mgr.c b/firmware/common/fileobj_mgr.c index e34a460e10..37452fbbe1 100644 --- a/firmware/common/fileobj_mgr.c +++ b/firmware/common/fileobj_mgr.c | |||
@@ -20,12 +20,13 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "config.h" | 21 | #include "config.h" |
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include <errno.h> | ||
23 | #include "debug.h" | 24 | #include "debug.h" |
24 | #include "file.h" | 25 | #include "file.h" |
25 | #include "dir.h" | 26 | #include "dir.h" |
26 | #include "disk_cache.h" | 27 | #include "disk_cache.h" |
27 | #include "fileobj_mgr.h" | 28 | #include "fileobj_mgr.h" |
28 | #include "dircache_redirect.h" | 29 | #include "rb_namespace.h" |
29 | 30 | ||
30 | /** | 31 | /** |
31 | * Manages file and directory streams on all volumes | 32 | * Manages file and directory streams on all volumes |
@@ -34,8 +35,8 @@ | |||
34 | */ | 35 | */ |
35 | 36 | ||
36 | 37 | ||
37 | /* there will always be enough of these for all user handles, thus these | 38 | /* there will always be enough of these for all user handles, thus most of |
38 | functions don't return failure codes */ | 39 | these functions don't return failure codes */ |
39 | #define MAX_FILEOBJS (MAX_OPEN_HANDLES + AUX_FILEOBJS) | 40 | #define MAX_FILEOBJS (MAX_OPEN_HANDLES + AUX_FILEOBJS) |
40 | 41 | ||
41 | /* describes the file as an image on the storage medium */ | 42 | /* describes the file as an image on the storage medium */ |
@@ -84,6 +85,15 @@ static struct ll_head busy_bindings[NUM_VOLUMES]; | |||
84 | for (struct filestr_base *s = STREAM_##what(start); \ | 85 | for (struct filestr_base *s = STREAM_##what(start); \ |
85 | s; s = STREAM_NEXT(s)) | 86 | s; s = STREAM_NEXT(s)) |
86 | 87 | ||
88 | /* once a file/directory, always a file/directory; such a change | ||
89 | is a bug */ | ||
90 | #define CHECK_FO_DIRECTORY(callflags, fobp) \ | ||
91 | if (((callflags) ^ (fobp)->flags) & FO_DIRECTORY) \ | ||
92 | { \ | ||
93 | DEBUGF("%s - FO_DIRECTORY flag does not match: %p %u\n", \ | ||
94 | __func__, (fobp), (callflags)); \ | ||
95 | } | ||
96 | |||
87 | 97 | ||
88 | /* syncs information for the stream's old and new parent directory if any are | 98 | /* syncs information for the stream's old and new parent directory if any are |
89 | currently opened */ | 99 | currently opened */ |
@@ -96,6 +106,10 @@ static void fileobj_sync_parent(const struct file_base_info *infop[], | |||
96 | continue; /* not directory or removed can't be parent of anything */ | 106 | continue; /* not directory or removed can't be parent of anything */ |
97 | 107 | ||
98 | struct filestr_base *parentstrp = STREAM_FIRST(fobp); | 108 | struct filestr_base *parentstrp = STREAM_FIRST(fobp); |
109 | |||
110 | if (!parentstrp) | ||
111 | continue; | ||
112 | |||
99 | struct fat_file *parentfilep = &parentstrp->infop->fatfile; | 113 | struct fat_file *parentfilep = &parentstrp->infop->fatfile; |
100 | 114 | ||
101 | for (int i = 0; i < count; i++) | 115 | for (int i = 0; i < count; i++) |
@@ -111,8 +125,7 @@ static void fileobj_sync_parent(const struct file_base_info *infop[], | |||
111 | } | 125 | } |
112 | 126 | ||
113 | /* see if this file has open streams and return that fileobj_binding if so, | 127 | /* see if this file has open streams and return that fileobj_binding if so, |
114 | else grab a new one from the free list; returns true if this stream is | 128 | else grab a new one from the free list; returns true if this is new */ |
115 | the only open one */ | ||
116 | static bool binding_assign(const struct file_base_info *srcinfop, | 129 | static bool binding_assign(const struct file_base_info *srcinfop, |
117 | struct fileobj_binding **fobpp) | 130 | struct fileobj_binding **fobpp) |
118 | { | 131 | { |
@@ -123,7 +136,7 @@ static bool binding_assign(const struct file_base_info *srcinfop, | |||
123 | 136 | ||
124 | if (fat_file_is_same(&srcinfop->fatfile, &fobp->bind.info.fatfile)) | 137 | if (fat_file_is_same(&srcinfop->fatfile, &fobp->bind.info.fatfile)) |
125 | { | 138 | { |
126 | /* already has open streams */ | 139 | /* already has open streams/mounts */ |
127 | *fobpp = fobp; | 140 | *fobpp = fobp; |
128 | return false; | 141 | return false; |
129 | } | 142 | } |
@@ -143,6 +156,23 @@ static void binding_add_to_free_list(struct fileobj_binding *fobp) | |||
143 | ll_insert_last(FREE_BINDINGS(), &fobp->bind.node); | 156 | ll_insert_last(FREE_BINDINGS(), &fobp->bind.node); |
144 | } | 157 | } |
145 | 158 | ||
159 | static void bind_source_info(const struct file_base_info *srcinfop, | ||
160 | struct fileobj_binding **fobpp) | ||
161 | { | ||
162 | if (!binding_assign(srcinfop, fobpp)) | ||
163 | return; /* already in use */ | ||
164 | |||
165 | /* is new */ | ||
166 | (*fobpp)->bind.info = *srcinfop; | ||
167 | fileobj_bind_file(&(*fobpp)->bind); | ||
168 | } | ||
169 | |||
170 | static void release_binding(struct fileobj_binding *fobp) | ||
171 | { | ||
172 | fileobj_unbind_file(&fobp->bind); | ||
173 | binding_add_to_free_list(fobp); | ||
174 | } | ||
175 | |||
146 | /** File and directory internal interface **/ | 176 | /** File and directory internal interface **/ |
147 | 177 | ||
148 | void file_binding_insert_last(struct file_base_binding *bindp) | 178 | void file_binding_insert_last(struct file_base_binding *bindp) |
@@ -169,6 +199,41 @@ void file_binding_remove_next(struct file_base_binding *prevp, | |||
169 | } | 199 | } |
170 | #endif /* HAVE_DIRCACHE */ | 200 | #endif /* HAVE_DIRCACHE */ |
171 | 201 | ||
202 | /* mounts a file object as a target from elsewhere */ | ||
203 | bool fileobj_mount(const struct file_base_info *srcinfop, | ||
204 | unsigned int callflags, | ||
205 | struct file_base_binding **bindpp) | ||
206 | { | ||
207 | struct fileobj_binding *fobp; | ||
208 | bind_source_info(srcinfop, &fobp); | ||
209 | |||
210 | CHECK_FO_DIRECTORY(callflags, fobp); | ||
211 | |||
212 | if (fobp->flags & FO_MOUNTTARGET) | ||
213 | return false; /* already mounted */ | ||
214 | |||
215 | fobp->flags |= FDO_BUSY | FO_MOUNTTARGET | | ||
216 | (callflags & FO_DIRECTORY); | ||
217 | |||
218 | *bindpp = &fobp->bind; | ||
219 | |||
220 | return true; | ||
221 | } | ||
222 | |||
223 | /* unmounts the file object and frees it if now unusued */ | ||
224 | void fileobj_unmount(struct file_base_binding *bindp) | ||
225 | { | ||
226 | struct fileobj_binding *fobp = (struct fileobj_binding *)bindp; | ||
227 | |||
228 | if (!(fobp->flags & FO_MOUNTTARGET)) | ||
229 | return; /* not mounted */ | ||
230 | |||
231 | if (STREAM_FIRST(fobp) == NULL) | ||
232 | release_binding(fobp); /* no longer in use */ | ||
233 | else | ||
234 | fobp->flags &= ~FO_MOUNTTARGET; | ||
235 | } | ||
236 | |||
172 | /* opens the file object for a new stream and sets up the caches; | 237 | /* opens the file object for a new stream and sets up the caches; |
173 | * the stream must already be opened at the FS driver level and *stream | 238 | * the stream must already be opened at the FS driver level and *stream |
174 | * initialized. | 239 | * initialized. |
@@ -180,10 +245,14 @@ void fileobj_fileop_open(struct filestr_base *stream, | |||
180 | const struct file_base_info *srcinfop, | 245 | const struct file_base_info *srcinfop, |
181 | unsigned int callflags) | 246 | unsigned int callflags) |
182 | { | 247 | { |
248 | /* assign base file information */ | ||
183 | struct fileobj_binding *fobp; | 249 | struct fileobj_binding *fobp; |
184 | bool first = binding_assign(srcinfop, &fobp); | 250 | bind_source_info(srcinfop, &fobp); |
251 | |||
252 | unsigned int foflags = fobp->flags; | ||
185 | 253 | ||
186 | /* add stream to this file's list */ | 254 | /* add stream to this file's list */ |
255 | bool first = STREAM_FIRST(fobp) == NULL; | ||
187 | ll_insert_last(&fobp->list, &stream->node); | 256 | ll_insert_last(&fobp->list, &stream->node); |
188 | 257 | ||
189 | /* initiate the new stream into the enclave */ | 258 | /* initiate the new stream into the enclave */ |
@@ -197,27 +266,16 @@ void fileobj_fileop_open(struct filestr_base *stream, | |||
197 | if (first) | 266 | if (first) |
198 | { | 267 | { |
199 | /* first stream for file */ | 268 | /* first stream for file */ |
200 | fobp->bind.info = *srcinfop; | 269 | fobp->flags = foflags | FDO_BUSY | FO_SINGLE | |
201 | fobp->flags = FDO_BUSY | FO_SINGLE | | 270 | (callflags & (FO_DIRECTORY|FO_TRUNC)); |
202 | (callflags & (FO_DIRECTORY|FO_TRUNC)); | 271 | fobp->writers = 0; |
203 | fobp->writers = 0; | 272 | fobp->size = 0; |
204 | fobp->size = 0; | ||
205 | |||
206 | fileobj_bind_file(&fobp->bind); | ||
207 | } | 273 | } |
208 | else | 274 | else |
209 | { | 275 | { |
210 | /* additional stream for file */ | 276 | /* additional stream for file */ |
211 | fobp->flags &= ~FO_SINGLE; | 277 | fobp->flags = (foflags & ~FO_SINGLE) | (callflags & FO_TRUNC); |
212 | fobp->flags |= callflags & FO_TRUNC; | 278 | CHECK_FO_DIRECTORY(callflags, fobp); |
213 | |||
214 | /* once a file/directory, always a file/directory; such a change | ||
215 | is a bug */ | ||
216 | if ((callflags ^ fobp->flags) & FO_DIRECTORY) | ||
217 | { | ||
218 | DEBUGF("%s - FO_DIRECTORY flag does not match: %p %u\n", | ||
219 | __func__, stream, callflags); | ||
220 | } | ||
221 | } | 279 | } |
222 | 280 | ||
223 | if ((callflags & FD_WRITE) && ++fobp->writers == 1) | 281 | if ((callflags & FD_WRITE) && ++fobp->writers == 1) |
@@ -257,12 +315,14 @@ void fileobj_fileop_close(struct filestr_base *stream) | |||
257 | if (foflags & FO_SINGLE) | 315 | if (foflags & FO_SINGLE) |
258 | { | 316 | { |
259 | /* last stream for file; close everything */ | 317 | /* last stream for file; close everything */ |
260 | fileobj_unbind_file(&fobp->bind); | ||
261 | |||
262 | if (fobp->writers) | 318 | if (fobp->writers) |
263 | file_cache_free(&fobp->cache); | 319 | file_cache_free(&fobp->cache); |
264 | 320 | ||
265 | binding_add_to_free_list(fobp); | 321 | /* binding must stay valid if something is mounted to here */ |
322 | if (foflags & FO_MOUNTTARGET) | ||
323 | fobp->flags = foflags & (FDO_BUSY|FO_DIRECTORY|FO_MOUNTTARGET); | ||
324 | else | ||
325 | release_binding(fobp); | ||
266 | } | 326 | } |
267 | else | 327 | else |
268 | { | 328 | { |