mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-10-10 08:03:04 -04:00
Most of the churn here occurs because 'filesize' is one of the redefined filesystem functions, but some of the structs used by the native FS code also include a 'filesize' member variable which gets renamed by the macro in some but not all source files. It's easier to rename 'filesize()' to 'ffilesize()' rather than try to clean up the macro mess or renaming the struct members. There is weirdness with root_realpath() which now breaks on native builds because it was assumed to be unprefixed there. dir_get_info() was unprefixed everywhere but this just seems inconsistent; make it follow the FS_PREFIX() convention too. Change-Id: Ic3700c6234ea45f32679c1a8429d70fdb8f4088a
314 lines
9.5 KiB
C
314 lines
9.5 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
*
|
|
* Copyright (C) 2014 by Michael Sevakis
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
#ifndef _DIRCACHE_REDIRECT_H_
|
|
|
|
#include "rbpaths.h"
|
|
#include "pathfuncs.h"
|
|
#include "dir.h"
|
|
#include "dircache.h"
|
|
#include "file.h"
|
|
|
|
#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER)
|
|
#include "rb-loader.h"
|
|
#include "multiboot.h"
|
|
#include "bootdata.h"
|
|
#endif
|
|
|
|
#ifndef RB_ROOT_VOL_HIDDEN
|
|
#define RB_ROOT_VOL_HIDDEN(v) (0 == 0)
|
|
#endif
|
|
#ifndef RB_ROOT_CONTENTS_DIR
|
|
#define RB_ROOT_CONTENTS_DIR "/"
|
|
#endif
|
|
/***
|
|
** Internal redirects that depend upon whether or not dircache is made
|
|
**
|
|
** Some stuff deals with it, some doesn't right now. This is a nexus point..
|
|
**/
|
|
|
|
/** File binding **/
|
|
|
|
static inline void get_rootinfo_internal(struct file_base_info *infop)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_get_rootinfo(infop);
|
|
#else
|
|
(void)infop;
|
|
#endif
|
|
}
|
|
|
|
static inline void fileobj_bind_file(struct file_base_binding *bindp)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_bind_file(bindp);
|
|
#else
|
|
file_binding_insert_last(bindp);
|
|
#endif
|
|
}
|
|
|
|
static inline void fileobj_unbind_file(struct file_base_binding *bindp)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_unbind_file(bindp);
|
|
#else
|
|
file_binding_remove(bindp);
|
|
#endif
|
|
}
|
|
|
|
|
|
/** File event handlers **/
|
|
|
|
static inline void fileop_onopen_internal(struct filestr_base *stream,
|
|
struct file_base_info *srcinfop,
|
|
unsigned int callflags)
|
|
{
|
|
fileobj_fileop_open(stream, srcinfop, callflags);
|
|
}
|
|
|
|
static inline void fileop_onclose_internal(struct filestr_base *stream)
|
|
{
|
|
fileobj_fileop_close(stream);
|
|
}
|
|
|
|
static inline void fileop_oncreate_internal(struct filestr_base *stream,
|
|
struct file_base_info *srcinfop,
|
|
unsigned int callflags,
|
|
struct file_base_info *dirinfop,
|
|
const char *basename)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_dcfile_init(&srcinfop->dcfile);
|
|
#endif
|
|
fileobj_fileop_create(stream, srcinfop, callflags);
|
|
#ifdef HAVE_DIRCACHE
|
|
struct dirinfo_native din;
|
|
fill_dirinfo_native(&din);
|
|
dircache_fileop_create(dirinfop, stream->bindp, basename, &din);
|
|
#endif
|
|
(void)dirinfop; (void)basename;
|
|
}
|
|
|
|
static inline void fileop_onremove_internal(struct filestr_base *stream,
|
|
struct file_base_info *oldinfop)
|
|
{
|
|
fileobj_fileop_remove(stream, oldinfop);
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_fileop_remove(stream->bindp);
|
|
#endif
|
|
}
|
|
|
|
static inline void fileop_onrename_internal(struct filestr_base *stream,
|
|
struct file_base_info *oldinfop,
|
|
struct file_base_info *dirinfop,
|
|
const char *basename)
|
|
{
|
|
fileobj_fileop_rename(stream, oldinfop);
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_fileop_rename(dirinfop, stream->bindp, basename);
|
|
#endif
|
|
(void)dirinfop; (void)basename;
|
|
}
|
|
|
|
static inline void fileop_onsync_internal(struct filestr_base *stream)
|
|
{
|
|
fileobj_fileop_sync(stream);
|
|
#ifdef HAVE_DIRCACHE
|
|
struct dirinfo_native din;
|
|
fill_dirinfo_native(&din);
|
|
dircache_fileop_sync(stream->bindp, &din);
|
|
#endif
|
|
}
|
|
|
|
#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER)
|
|
static inline bool multiboot_is_boot_volume(int volume)
|
|
{
|
|
if (boot_data.version == 0)
|
|
{
|
|
/*
|
|
* Version 0 bootloaders just pass the volume number, but that's
|
|
* dynamically assigned and sometimes differs by the time we get
|
|
* into the firmware. So we can't rely on the volume passed by
|
|
* the bootloader.
|
|
*/
|
|
#if CONFIG_CPU == X1000
|
|
/* The affected X1000 players only have one drive to begin with */
|
|
return volume_drive(volume) == 0;
|
|
#else
|
|
/* FIXME: Anything else that can get here is a Sansa. */
|
|
return volume_drive(volume) == boot_data._boot_volume ||
|
|
volume == boot_data._boot_volume;
|
|
#endif
|
|
}
|
|
|
|
if (boot_data.version == 1)
|
|
{
|
|
/*
|
|
* Since version 1 the bootloader passes drive and partition
|
|
* number which unambiguously identifies the boot volume.
|
|
*/
|
|
return volume_drive(volume) == boot_data.boot_drive &&
|
|
volume_partition(volume) == boot_data.boot_partition;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
static inline void volume_onmount_internal(IF_MV_NONVOID(int volume))
|
|
{
|
|
#if defined(HAVE_MULTIBOOT) && !defined(SIMULATOR) && !defined(BOOTLOADER)
|
|
char path[VOL_MAX_LEN+2];
|
|
char rtpath[MAX_PATH / 2];
|
|
make_volume_root(volume, path);
|
|
|
|
if (boot_data_valid)
|
|
{
|
|
/* we need to mount the drive before we can access it */
|
|
root_mount_path(path, 0); /* root could be different folder don't hide */
|
|
|
|
if (multiboot_is_boot_volume(IF_MV_VOL(volume)))
|
|
{
|
|
/* get the full path to the BOOTFILE
|
|
ie. /<0>/redirectdir/.rockbox/rockbox.ext */
|
|
int rtlen = get_redirect_dir(rtpath, sizeof(rtpath),
|
|
volume, BOOTDIR, BOOTFILE);
|
|
|
|
if (rtlen <= 0 || rtlen >= (int) sizeof(rtpath))
|
|
rtlen = 0; /* path too long or sprintf error */
|
|
else if (rbfs_file_exists(rtpath))
|
|
{
|
|
rtlen = get_redirect_dir(rtpath, sizeof(rtpath), volume, "", "");
|
|
while (rtlen > 0 && rtpath[--rtlen] == PATH_SEPCH)
|
|
rtpath[rtlen] = '\0'; /* remove separators */
|
|
}
|
|
else
|
|
rtlen = 0; /* No BOOTFILE found */
|
|
|
|
#if 0 /*removed, causes issues with playback for now?*/
|
|
if (rtlen <= 0 || rtpath[rtlen] == VOL_END_TOK)
|
|
root_unmount_volume(volume); /* unmount so root can be hidden*/
|
|
#endif
|
|
if (rtlen <= 0 || root_mount_path(rtpath, NSITEM_CONTENTS) != 0)
|
|
{ /* Error occurred, card removed? Set root to default */
|
|
boot_data_valid = false;
|
|
root_unmount_volume(volume); /* unmount so root can be hidden*/
|
|
goto standard_redirect;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
standard_redirect:
|
|
root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0);
|
|
if (volume == path_strip_volume(RB_ROOT_CONTENTS_DIR, NULL, false))
|
|
root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
|
|
}
|
|
#elif defined(HAVE_MULTIVOLUME)
|
|
char path[VOL_MAX_LEN+2];
|
|
make_volume_root(volume, path);
|
|
root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0);
|
|
if (volume == path_strip_volume(RB_ROOT_CONTENTS_DIR, NULL, false))
|
|
root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
|
|
#else
|
|
const char *path = PATH_ROOTSTR;
|
|
root_mount_path(path, RB_ROOT_VOL_HIDDEN(volume) ? NSITEM_HIDDEN : 0);
|
|
root_mount_path(RB_ROOT_CONTENTS_DIR, NSITEM_CONTENTS);
|
|
#endif /* HAVE_MULTIBOOT */
|
|
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_mount();
|
|
#endif
|
|
}
|
|
|
|
static inline void volume_onunmount_internal(IF_MV_NONVOID(int volume))
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
/* First, to avoid update of something about to be destroyed anyway */
|
|
dircache_unmount(IF_MV(volume));
|
|
#endif
|
|
root_unmount_volume(IF_MV(volume));
|
|
fileobj_mgr_unmount(IF_MV(volume));
|
|
}
|
|
|
|
static inline void fileop_onunmount_internal(struct filestr_base *stream)
|
|
{
|
|
|
|
if (stream->flags & FD_WRITE)
|
|
force_close_writer_internal(stream); /* try to save stuff */
|
|
else
|
|
fileop_onclose_internal(stream); /* just readers, bye */
|
|
}
|
|
|
|
|
|
/** Directory reading **/
|
|
|
|
static inline int readdir_dirent(struct filestr_base *stream,
|
|
struct dirscan_info *scanp,
|
|
struct DIRENT *entry)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
return dircache_readdir_dirent(stream, scanp, entry);
|
|
#else
|
|
return uncached_readdir_dirent(stream, scanp, entry);
|
|
#endif
|
|
}
|
|
|
|
static inline void rewinddir_dirent(struct dirscan_info *scanp)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_rewinddir_dirent(scanp);
|
|
#else
|
|
uncached_rewinddir_dirent(scanp);
|
|
#endif
|
|
}
|
|
|
|
static inline int readdir_internal(struct filestr_base *stream,
|
|
struct file_base_info *infop,
|
|
struct fat_direntry *fatent)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
return dircache_readdir_internal(stream, infop, fatent);
|
|
#else
|
|
return uncached_readdir_internal(stream, infop, fatent);
|
|
#endif
|
|
}
|
|
|
|
static inline void rewinddir_internal(struct file_base_info *infop)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
dircache_rewinddir_internal(infop);
|
|
#else
|
|
uncached_rewinddir_internal(infop);
|
|
#endif
|
|
}
|
|
|
|
|
|
/** Misc. stuff **/
|
|
|
|
static inline struct fat_direntry *get_dir_fatent_dircache(void)
|
|
{
|
|
#ifdef HAVE_DIRCACHE
|
|
return get_dir_fatent();
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
#endif /* _DIRCACHE_REDIRECT_H_ */
|