libdragon
|
DragonFS filesystem implementation and newlib hooks. More...
Data Structures | |
struct | directory_entry |
Representation of a directory entry. More... | |
struct | file_entry |
Representation of a file sector. More... | |
struct | open_file |
Open file handle structure. More... | |
Files | |
file | dragonfs.c |
DragonFS. | |
file | dfsinternal.h |
Internal DFS Definitions. | |
file | dragonfs.h |
DragonFS. | |
Defines | |
#define | FLAGS_ID 0xFFFFFFFF |
The special ID value in directory_entry::flags defining the master sector. | |
#define | NEXTENTRY_ID 0xDEADBEEF |
The special ID value in directory_entry::next_entry defining the master sector. | |
#define | SECTOR_SIZE 256 |
The size of a sector. | |
#define | SECTOR_PAYLOAD 252 |
The size of a sector payload. | |
#define | DFS_DEFAULT_LOCATION 0xB0101000 |
Default filesystem location. | |
#define | MAX_OPEN_FILES 4 |
Maximum open files in DragonFS. | |
#define | MAX_FILENAME_LEN 243 |
Maximum filename length. | |
#define | MAX_DIRECTORY_DEPTH 100 |
Maximum depth of directories supported. | |
#define | FILETYPE(x) ((x) & 3) |
Macro to extract the file type from a DragonFS file flag. | |
Typedefs | |
typedef struct directory_entry | directory_entry_t |
Type definition. | |
typedef struct file_entry | file_entry_t |
Type definition. | |
typedef struct open_file | open_file_t |
Open file handle structure. | |
Enumerations | |
enum | { WALK_CHDIR, WALK_OPEN } |
Directory walking flags. More... | |
enum | { TYPE_ANY, TYPE_FILE, TYPE_DIR } |
Directory walking return flags. More... | |
Functions | |
static void | grab_sector (void *cart_loc, void *ram_loc) |
Read a sector from cartspace. | |
static open_file_t * | find_free_file () |
Find a free open file structure. | |
static open_file_t * | find_open_file (uint32_t x) |
Find an open file structure based on a handle. | |
static int | sector_from_loc (uint32_t loc) |
Look up a sector number based on offset. | |
static int | offset_into_sector (uint32_t loc) |
Look up a byte offset into a sector. | |
static int | data_left_in_sector (uint32_t loc) |
Look up the remaining data size in a sector. | |
static uint32_t | get_flags (directory_entry_t *dirent) |
Return the file flags given a directory entry. | |
static uint32_t | get_size (directory_entry_t *dirent) |
Return the file size given a directory entry. | |
static directory_entry_t * | get_first_entry (directory_entry_t *dirent) |
Get the directory pointer from a directory entry. | |
static directory_entry_t * | get_next_entry (directory_entry_t *dirent) |
Get the next directory entry. | |
static file_entry_t * | get_first_sector (directory_entry_t *dirent) |
Get the file pointer from a directory entry. | |
static file_entry_t * | get_next_sector (file_entry_t *fileent) |
Get the next file sector given a current file sector. | |
static void | walk_sectors (open_file_t *file, uint32_t num_sectors) |
Walk forward in a file a specified number of sectors. | |
static void | clear_directory () |
Reset the directory stack to the root. | |
static void | push_directory (directory_entry_t *dirent) |
Push a directory onto the stack. | |
static directory_entry_t * | pop_directory () |
Pop a directory from the stack. | |
static directory_entry_t * | peek_directory () |
Peek at the top directory on the stack. | |
static char * | get_next_token (char *path, char *token) |
Parse out the next token in a path delimited by '\'. | |
static directory_entry_t * | find_dirent (char *name, directory_entry_t *cur_node) |
Find a directory node in the current path given a name. | |
static int | recurse_path (const char *const path, int mode, directory_entry_t **dirent, int type) |
Walk a path string, either changing directories or finding the right path. | |
static int | __dfs_init (uint32_t base_fs_loc) |
Helper functioner to initialize the filesystem. | |
int | dfs_chdir (const char *const path) |
Change directories to the specified path. | |
int | dfs_dir_findfirst (const char *const path, char *buf) |
Find the first file or directory in a directory listing. | |
int | dfs_dir_findnext (char *buf) |
Find the next file or directory in a directory listing. | |
int | dfs_open (const char *const path) |
Open a file given a path. | |
int | dfs_close (uint32_t handle) |
Close an already open file handle. | |
int | dfs_seek (uint32_t handle, int offset, int origin) |
Seek to an offset in the file. | |
int | dfs_tell (uint32_t handle) |
Return the current offset into a file. | |
int | dfs_read (void *const buf, int size, int count, uint32_t handle) |
Read data from a file. | |
int | dfs_size (uint32_t handle) |
Return the file size of an open file. | |
int | dfs_eof (uint32_t handle) |
Return whether the end of file has been reached. | |
static void * | __open (char *name, int flags) |
Newlib-compatible open. | |
static int | __fstat (void *file, struct stat *st) |
Newlib-compatible fstat. | |
static int | __lseek (void *file, int ptr, int dir) |
Newlib-compatible lseek. | |
static int | __read (void *file, uint8_t *ptr, int len) |
Newlib-compatible read. | |
static int | __close (void *file) |
Newlib-compatible close. | |
static int | __findfirst (char *path, dir_t *dir) |
Newlib-compatible findfirst. | |
static int | __findnext (dir_t *dir) |
Newlib-compatible findnext. | |
int | dfs_init (uint32_t base_fs_loc) |
Initialize the filesystem. | |
Variables | |
static uint32_t | base_ptr = 0 |
Base filesystem pointer. | |
static open_file_t | open_files [MAX_OPEN_FILES] |
Open file tracking. | |
static uint32_t | directories [MAX_DIRECTORY_DEPTH] |
Directory pointer stack. | |
static uint32_t | directory_top = 0 |
Depth into directory pointer stack. | |
static directory_entry_t * | next_entry = 0 |
Pointer to next directory entry set when doing a directory walk. | |
static filesystem_t | dragon_fs |
Structure used for hooking DragonFS into newlib. | |
DragonFS Return values | |
#define | DFS_ESUCCESS 0 |
Success. | |
#define | DFS_EBADINPUT -1 |
Input parameters invalid. | |
#define | DFS_ENOFILE -2 |
File does not exist. | |
#define | DFS_EBADFS -3 |
Bad filesystem. | |
#define | DFS_ENOMEM -4 |
No memory for operation. | |
#define | DFS_EBADHANDLE -5 |
Invalid file handle. | |
DragonFS file type flags | |
#define | FLAGS_FILE 0x0 |
This is a file entry. | |
#define | FLAGS_DIR 0x1 |
This is a directory entry. | |
#define | FLAGS_EOF 0x2 |
This is the end of a directory list. |
DragonFS filesystem implementation and newlib hooks.
DragonFS is a read only ROM filesystem for the N64. It provides an interface that homebrew developers can use to load resources from cartridge space that were not available at compile time. This can mean sprites or other game assets, or the filesystem can be appended at a later time if the homebrew developer wishes end users to be able to insert custom levels, music or other assets. It is loosely based off of FAT with consideration into application and limitations of the N64.
The filesystem can be generated using 'mkdfs' which is included in the 'tools' directory of libdragon. Due to the read-only nature, DFS does not support empty files or empty directories. Attempting to create a filesystem with either of these using 'mkdfs' will result in an error. If a filesystem contains either empty files or empty directories, the result of manipulating the filesystem is undefined.
DragonFS does not support writing, renaming or symlinking of files. It supports only file and directory types.
DFS files have a maximum size of 16,777,216 bytes. Directories can have an unlimited number of files in them. Each token (separated by a / in the path) can be 243 characters maximum. Directories can be 100 levels deep at maximum. There can be 4 files open simultaneously.
When DFS is initialized, it will register itself with newlib using 'rom:/' as a prefix. Files can be accessed either with standard POSIX functions and the 'rom:/' prefix or with DFS API calls and no prefix. Files can be opened using both sets of API calls simultaneously as long as no more than four files are open at any one time.
#define DFS_DEFAULT_LOCATION 0xB0101000 |
Default filesystem location.
The default is 1MB into the ROM space, plus the header offset
#define FILETYPE | ( | x | ) | ((x) & 3) |
Macro to extract the file type from a DragonFS file flag.
[in] | x | File flags from DFS entry |
#define MAX_FILENAME_LEN 243 |
Maximum filename length.
This value is due to the direcory structure
anonymous enum |
anonymous enum |
static int __close | ( | void * | file | ) | [static] |
Newlib-compatible close.
[in] | file | File pointer as returned by __open |
static int __dfs_init | ( | uint32_t | base_fs_loc | ) | [static] |
Helper functioner to initialize the filesystem.
[in] | base_fs_loc | Location of the filesystem |
static int __findfirst | ( | char * | path, |
dir_t * | dir | ||
) | [static] |
Newlib-compatible findfirst.
[in] | path | Absolute path of the directory to walk |
[out] | dir | Directory structure to populate with information on the first entry found |
static int __findnext | ( | dir_t * | dir | ) | [static] |
Newlib-compatible findnext.
[out] | dir | Directory structure to populate with information on the next entry found |
Newlib-compatible fstat.
[in] | file | File pointer as returned by __open |
[out] | st | Stat structure to populate |
static int __lseek | ( | void * | file, |
int | ptr, | ||
int | dir | ||
) | [static] |
Newlib-compatible lseek.
[in] | file | File pointer as returned by __open |
[in] | ptr | Offset based on dir |
[in] | dir | A direction to seek from. Either #SEEK_SET, #SEEK_CUR or #SEEK_END |
static void* __open | ( | char * | name, |
int | flags | ||
) | [static] |
Newlib-compatible open.
[in] | name | Absolute path of the file to open |
[in] | flags | POSIX file flags |
static int __read | ( | void * | file, |
uint8_t * | ptr, | ||
int | len | ||
) | [static] |
Newlib-compatible read.
[in] | file | File pointer as returned by __open |
[out] | ptr | Pointer to buffer to read to |
[in] | len | Length in bytes to read |
static int data_left_in_sector | ( | uint32_t | loc | ) | [inline, static] |
Look up the remaining data size in a sector.
Given a byte offset from the start of a filesystem, this function will return the number of bytes from the current location to the end of the sector.
[in] | loc | Offset in bytes |
int dfs_chdir | ( | const char *const | path | ) |
Change directories to the specified path.
Supports absolute and relative
[in] | path | Relative or absolute path to change directories to |
int dfs_close | ( | uint32_t | handle | ) |
Close an already open file handle.
[in] | handle | A valid file handle as returned from dfs_open. |
int dfs_dir_findfirst | ( | const char *const | path, |
char * | buf | ||
) |
Find the first file or directory in a directory listing.
Supports absolute and relative. If the path is invalid, returns a negative DFS_errno. If a file or directory is found, returns the flags of the entry and copies the name into buf.
[in] | path | The path to look for files in |
[out] | buf | Buffer to place the name of the file or directory found |
int dfs_dir_findnext | ( | char * | buf | ) |
Find the next file or directory in a directory listing.
[out] | buf | Buffer to place the name of the next file or directory found |
int dfs_eof | ( | uint32_t | handle | ) |
Return whether the end of file has been reached.
[in] | handle | A valid file handle as returned from dfs_open. |
int dfs_init | ( | uint32_t | base_fs_loc | ) |
Initialize the filesystem.
Given a base offset where the filesystem should be found, this function will initialize the filesystem to read from cartridge space. This function will also register DragonFS with newlib so that standard POSIX file operations work with DragonFS.
[in] | base_fs_loc | Memory mapped location at which to find the filesystem. This is normally 0xB0000000 + the offset used when building your ROM + the size of the header file used. |
int dfs_open | ( | const char *const | path | ) |
Open a file given a path.
Check if we have any free file handles, and if we do, try to open the file specified. Supports absolute and relative paths
[in] | path | Path of the file to open |
int dfs_read | ( | void *const | buf, |
int | size, | ||
int | count, | ||
uint32_t | handle | ||
) |
Read data from a file.
[out] | buf | Buffer to read into |
[in] | size | Size of each element to read |
[in] | count | Number of elements to read |
[in] | handle | A valid file handle as returned from dfs_open. |
int dfs_seek | ( | uint32_t | handle, |
int | offset, | ||
int | origin | ||
) |
Seek to an offset in the file.
[in] | handle | A valid file handle as returned from dfs_open. |
[in] | offset | A byte offset from the origin to seek from. |
[in] | origin | An offset to seek from. Either #SEEK_SET, #SEEK_CUR or #SEEK_END. |
int dfs_size | ( | uint32_t | handle | ) |
Return the file size of an open file.
[in] | handle | A valid file handle as returned from dfs_open. |
int dfs_tell | ( | uint32_t | handle | ) |
Return the current offset into a file.
[in] | handle | A valid file handle as returned from dfs_open. |
static directory_entry_t* find_dirent | ( | char * | name, |
directory_entry_t * | cur_node | ||
) | [static] |
Find a directory node in the current path given a name.
[in] | name | Name of the file or directory in question |
[in] | cur_node | Directory entry to start search from |
static open_file_t* find_free_file | ( | ) | [static] |
Find a free open file structure.
static open_file_t* find_open_file | ( | uint32_t | x | ) | [static] |
Find an open file structure based on a handle.
[in] | x | The file handle given to the open file |
static directory_entry_t* get_first_entry | ( | directory_entry_t * | dirent | ) | [inline, static] |
Get the directory pointer from a directory entry.
This function is used to grab the first directory entry of a subdirectory given the current directory pointer.
[in] | dirent | Directory entry to retrieve directory pointer from |
static file_entry_t* get_first_sector | ( | directory_entry_t * | dirent | ) | [inline, static] |
Get the file pointer from a directory entry.
This function is used to grab the first sector of a file given the current directory pointer.
[in] | dirent | Directory entry to retrieve file pointer from |
static uint32_t get_flags | ( | directory_entry_t * | dirent | ) | [inline, static] |
Return the file flags given a directory entry.
[in] | dirent | Directory entry to retrieve flags from |
static directory_entry_t* get_next_entry | ( | directory_entry_t * | dirent | ) | [inline, static] |
Get the next directory entry.
[in] | dirent | Directory entry to retrieve next entry from |
static file_entry_t* get_next_sector | ( | file_entry_t * | fileent | ) | [inline, static] |
Get the next file sector given a current file sector.
[in] | fileent | File entry structure to retrieve next sector from |
static char* get_next_token | ( | char * | path, |
char * | token | ||
) | [static] |
Parse out the next token in a path delimited by '\'.
[in] | path | Current path to extract next token from |
[out] | token | String buffer to place the extracted token |
static uint32_t get_size | ( | directory_entry_t * | dirent | ) | [inline, static] |
Return the file size given a directory entry.
[in] | dirent | Directory entry to retrieve size from |
static void grab_sector | ( | void * | cart_loc, |
void * | ram_loc | ||
) | [inline, static] |
Read a sector from cartspace.
This function handles fetching a sector from cartspace into RDRAM using DMA.
[in] | cart_loc | Pointer to cartridge location |
[out] | ram_loc | Pointer to RAM buffer to place the read sector |
static int offset_into_sector | ( | uint32_t | loc | ) | [inline, static] |
Look up a byte offset into a sector.
Given a byte offset from the start of a filesystem, this function will return the offset into the current sector. This essentially clamps the ouput from 0 to SECTOR_PAYLOAD.
[in] | loc | Offset in bytes |
static directory_entry_t* peek_directory | ( | ) | [inline, static] |
Peek at the top directory on the stack.
static directory_entry_t* pop_directory | ( | ) | [inline, static] |
Pop a directory from the stack.
static void push_directory | ( | directory_entry_t * | dirent | ) | [inline, static] |
Push a directory onto the stack.
[in] | dirent | Directory entry to push onto the stack |
static int recurse_path | ( | const char *const | path, |
int | mode, | ||
directory_entry_t ** | dirent, | ||
int | type | ||
) | [static] |
Walk a path string, either changing directories or finding the right path.
If mode is WALK_CHDIR, the result of this function is entering into the new directory on success, or the old directory being returned on failure.
If mode is WALK_OPEN, the result of this function is the directory remains unchanged and a pointer to the directory entry for the requested file or directory is returned. If it is a file, the directory entry for the file itself is returned. If it is a directory, the directory entry of the first file or directory inside that directory is returned.
The type specifier allows a person to specify that only a directory or file should be returned. This works for WALK_OPEN only.
[in] | path | The path to walk through |
[in] | mode | Either WALK_CHDIR or WALK_OPEN. |
[in,out] | dirent | Directory entry to start at, directory entry finished at |
[in] | type | Either TYPE_ANY, TYPE_FILE, or TYPE_DIR. |
static int sector_from_loc | ( | uint32_t | loc | ) | [inline, static] |
Look up a sector number based on offset.
Given a byte offset from the start of a filesystem, this function will return the sector that this byte offset falls into.
[in] | loc | Offset in bytes |
static void walk_sectors | ( | open_file_t * | file, |
uint32_t | num_sectors | ||
) | [static] |
Walk forward in a file a specified number of sectors.
[in] | file | Open file structure |
[in] | num_sectors | Number of sectors to advance the file |
filesystem_t dragon_fs [static] |
{ __open, __fstat, __lseek, __read, 0, __close, 0, __findfirst, __findnext }
Structure used for hooking DragonFS into newlib.
The following section of code is for bridging into newlib's filesystem hooks to allow posix access to DragonFS filesystem.