summaryrefslogtreecommitdiff
path: root/firmware/common/fileobj_mgr.c
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2017-02-03 17:13:58 -0500
committerWilliam Wilgus <me.theuser@yahoo.com>2020-08-20 23:08:57 +0000
commit5ef28cccf92f5eada6d502fa4b0e16a13e94be5b (patch)
tree05f9d2f8bdf3c0cc54c5893159a7dcf07c7e3e55 /firmware/common/fileobj_mgr.c
parent31fc46ded69be7438cca2ba2c2b93c1f200165a6 (diff)
downloadrockbox-5ef28cccf92f5eada6d502fa4b0e16a13e94be5b.tar.gz
rockbox-5ef28cccf92f5eada6d502fa4b0e16a13e94be5b.zip
Allow mounting of any directory as the root directory.
Provide definitions for the macros: * RB_ROOT_VOL_HIDDEN(v) to exclude certain items from the root. * RB_ROOT_CONTENTS to return a string with the name of the directory to mount in the root. Defaults are in export/rbpaths.h It's a bit much for those that don't need the full functionality. Some conditional define can cut it back a lot to cut out things only needed if alternate root mounts are required. I'm just not bothering yet. The basic concept would be applied to all targets to keep file code from forking too much. Change-Id: I90b5c0a1c949283d3102c16734b0b6ac73901a30
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 {