summaryrefslogtreecommitdiffstats
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.tar.bz2
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 @@
****************************************************************************/
#include "config.h"
#include "system.h"
+#include <errno.h>
#include "debug.h"
#include "file.h"
#include "dir.h"
#include "disk_cache.h"
#include "fileobj_mgr.h"
-#include "dircache_redirect.h"
+#include "rb_namespace.h"
/**
* Manages file and directory streams on all volumes
@@ -34,8 +35,8 @@
*/
-/* there will always be enough of these for all user handles, thus these
- functions don't return failure codes */
+/* there will always be enough of these for all user handles, thus most of
+ these functions don't return failure codes */
#define MAX_FILEOBJS (MAX_OPEN_HANDLES + AUX_FILEOBJS)
/* describes the file as an image on the storage medium */
@@ -84,6 +85,15 @@ static struct ll_head busy_bindings[NUM_VOLUMES];
for (struct filestr_base *s = STREAM_##what(start); \
s; s = STREAM_NEXT(s))
+/* once a file/directory, always a file/directory; such a change
+ is a bug */
+#define CHECK_FO_DIRECTORY(callflags, fobp) \
+ if (((callflags) ^ (fobp)->flags) & FO_DIRECTORY) \
+ { \
+ DEBUGF("%s - FO_DIRECTORY flag does not match: %p %u\n", \
+ __func__, (fobp), (callflags)); \
+ }
+
/* syncs information for the stream's old and new parent directory if any are
currently opened */
@@ -96,6 +106,10 @@ static void fileobj_sync_parent(const struct file_base_info *infop[],
continue; /* not directory or removed can't be parent of anything */
struct filestr_base *parentstrp = STREAM_FIRST(fobp);
+
+ if (!parentstrp)
+ continue;
+
struct fat_file *parentfilep = &parentstrp->infop->fatfile;
for (int i = 0; i < count; i++)
@@ -111,8 +125,7 @@ static void fileobj_sync_parent(const struct file_base_info *infop[],
}
/* see if this file has open streams and return that fileobj_binding if so,
- else grab a new one from the free list; returns true if this stream is
- the only open one */
+ else grab a new one from the free list; returns true if this is new */
static bool binding_assign(const struct file_base_info *srcinfop,
struct fileobj_binding **fobpp)
{
@@ -123,7 +136,7 @@ static bool binding_assign(const struct file_base_info *srcinfop,
if (fat_file_is_same(&srcinfop->fatfile, &fobp->bind.info.fatfile))
{
- /* already has open streams */
+ /* already has open streams/mounts */
*fobpp = fobp;
return false;
}
@@ -143,6 +156,23 @@ static void binding_add_to_free_list(struct fileobj_binding *fobp)
ll_insert_last(FREE_BINDINGS(), &fobp->bind.node);
}
+static void bind_source_info(const struct file_base_info *srcinfop,
+ struct fileobj_binding **fobpp)
+{
+ if (!binding_assign(srcinfop, fobpp))
+ return; /* already in use */
+
+ /* is new */
+ (*fobpp)->bind.info = *srcinfop;
+ fileobj_bind_file(&(*fobpp)->bind);
+}
+
+static void release_binding(struct fileobj_binding *fobp)
+{
+ fileobj_unbind_file(&fobp->bind);
+ binding_add_to_free_list(fobp);
+}
+
/** File and directory internal interface **/
void file_binding_insert_last(struct file_base_binding *bindp)
@@ -169,6 +199,41 @@ void file_binding_remove_next(struct file_base_binding *prevp,
}
#endif /* HAVE_DIRCACHE */
+/* mounts a file object as a target from elsewhere */
+bool fileobj_mount(const struct file_base_info *srcinfop,
+ unsigned int callflags,
+ struct file_base_binding **bindpp)
+{
+ struct fileobj_binding *fobp;
+ bind_source_info(srcinfop, &fobp);
+
+ CHECK_FO_DIRECTORY(callflags, fobp);
+
+ if (fobp->flags & FO_MOUNTTARGET)
+ return false; /* already mounted */
+
+ fobp->flags |= FDO_BUSY | FO_MOUNTTARGET |
+ (callflags & FO_DIRECTORY);
+
+ *bindpp = &fobp->bind;
+
+ return true;
+}
+
+/* unmounts the file object and frees it if now unusued */
+void fileobj_unmount(struct file_base_binding *bindp)
+{
+ struct fileobj_binding *fobp = (struct fileobj_binding *)bindp;
+
+ if (!(fobp->flags & FO_MOUNTTARGET))
+ return; /* not mounted */
+
+ if (STREAM_FIRST(fobp) == NULL)
+ release_binding(fobp); /* no longer in use */
+ else
+ fobp->flags &= ~FO_MOUNTTARGET;
+}
+
/* opens the file object for a new stream and sets up the caches;
* the stream must already be opened at the FS driver level and *stream
* initialized.
@@ -180,10 +245,14 @@ void fileobj_fileop_open(struct filestr_base *stream,
const struct file_base_info *srcinfop,
unsigned int callflags)
{
+ /* assign base file information */
struct fileobj_binding *fobp;
- bool first = binding_assign(srcinfop, &fobp);
+ bind_source_info(srcinfop, &fobp);
+
+ unsigned int foflags = fobp->flags;
/* add stream to this file's list */
+ bool first = STREAM_FIRST(fobp) == NULL;
ll_insert_last(&fobp->list, &stream->node);
/* initiate the new stream into the enclave */
@@ -197,27 +266,16 @@ void fileobj_fileop_open(struct filestr_base *stream,
if (first)
{
/* first stream for file */
- fobp->bind.info = *srcinfop;
- fobp->flags = FDO_BUSY | FO_SINGLE |
- (callflags & (FO_DIRECTORY|FO_TRUNC));
- fobp->writers = 0;
- fobp->size = 0;
-
- fileobj_bind_file(&fobp->bind);
+ fobp->flags = foflags | FDO_BUSY | FO_SINGLE |
+ (callflags & (FO_DIRECTORY|FO_TRUNC));
+ fobp->writers = 0;
+ fobp->size = 0;
}
else
{
/* additional stream for file */
- fobp->flags &= ~FO_SINGLE;
- fobp->flags |= callflags & FO_TRUNC;
-
- /* once a file/directory, always a file/directory; such a change
- is a bug */
- if ((callflags ^ fobp->flags) & FO_DIRECTORY)
- {
- DEBUGF("%s - FO_DIRECTORY flag does not match: %p %u\n",
- __func__, stream, callflags);
- }
+ fobp->flags = (foflags & ~FO_SINGLE) | (callflags & FO_TRUNC);
+ CHECK_FO_DIRECTORY(callflags, fobp);
}
if ((callflags & FD_WRITE) && ++fobp->writers == 1)
@@ -257,12 +315,14 @@ void fileobj_fileop_close(struct filestr_base *stream)
if (foflags & FO_SINGLE)
{
/* last stream for file; close everything */
- fileobj_unbind_file(&fobp->bind);
-
if (fobp->writers)
file_cache_free(&fobp->cache);
- binding_add_to_free_list(fobp);
+ /* binding must stay valid if something is mounted to here */
+ if (foflags & FO_MOUNTTARGET)
+ fobp->flags = foflags & (FDO_BUSY|FO_DIRECTORY|FO_MOUNTTARGET);
+ else
+ release_binding(fobp);
}
else
{