summaryrefslogtreecommitdiff
path: root/firmware/common/fileobj_mgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/common/fileobj_mgr.c')
-rw-r--r--firmware/common/fileobj_mgr.c114
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 */
116static bool binding_assign(const struct file_base_info *srcinfop, 129static 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
159static 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
170static 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
148void file_binding_insert_last(struct file_base_binding *bindp) 178void 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 */
203bool 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 */
224void 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 {