DragonFS filesystem implementation and newlib hooks.
More...
|
#define | ROOT_FLAGS 0xFFFFFFFF |
| The special ID value in directory_entry::flags defining the root sector.
|
|
#define | ROOT_NEXT_ENTRY 0xDEADBEEF |
| The special ID value in directory_entry::next_entry defining the root sector.
|
|
#define | ROOT_PATH "DragonFS 2.0" |
| Special path value in directory_entry::path defining the root sector.
|
|
#define | SECTOR_SIZE 256 |
| The size of a sector.
|
|
#define | SECTOR_PAYLOAD 252 |
| The size of a sector payload.
|
|
#define | DFS_DEFAULT_LOCATION 0 |
| Default filesystem location. More...
|
|
#define | MAX_OPEN_FILES 4 |
| Maximum open files in DragonFS.
|
|
#define | MAX_FILENAME_LEN 243 |
| Maximum filename length. More...
|
|
#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. More...
|
|
|
int | dfs_chdir (const char *const path) |
| Change directories to the specified path.
More...
|
|
int | dfs_dir_findfirst (const char *const path, char *buf) |
| Find the first file or directory in a directory listing. More...
|
|
int | dfs_dir_findnext (char *buf) |
| Find the next file or directory in a directory listing. More...
|
|
int | dfs_open (const char *const path) |
| Open a file given a path. More...
|
|
int | dfs_close (uint32_t handle) |
| Close an already open file handle. More...
|
|
int | dfs_seek (uint32_t handle, int offset, int origin) |
| Seek to an offset in the file. More...
|
|
int | dfs_tell (uint32_t handle) |
| Return the current offset into a file. More...
|
|
int | dfs_read (void *const buf, int size, int count, uint32_t handle) |
| Read data from a file. More...
|
|
int | dfs_size (uint32_t handle) |
| Return the file size of an open file. More...
|
|
uint32_t | dfs_rom_addr (const char *path) |
| Return the physical address of a file (in ROM space) More...
|
|
int | dfs_eof (uint32_t handle) |
| Return whether the end of file has been reached. More...
|
|
int | dfs_init (uint32_t base_fs_loc) |
| Initialize the filesystem. More...
|
|
const char * | dfs_strerror (int error) |
| Convert DFS error code into an error string.
|
|
|
#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_ENFILE -4 |
| Too many open files.
|
|
#define | DFS_EBADHANDLE -5 |
| Invalid file handle.
|
|
|
#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 256 MiB. 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 (open, fopen) using the 'rom:/' prefix or the lower-level DFS API calls without prefix. In most cases, it is not necessary to use the DFS API directly, given that the standard C functions are more comprehensive. 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.
DragonFS does not support file compression; if you want to compress your assets, use the asset API (asset_load / asset_fopen).
◆ directory_entry
Representation of a directory entry.
Type definition.
Data Fields |
uint32_t |
next_entry |
Offset to next directory entry. |
uint32_t |
flags |
File size and flags. See FLAGS_FILE, FLAGS_DIR and FLAGS_EOF. |
char |
path[MAX_FILENAME_LEN+1] |
The file or directory name. |
uint32_t |
file_pointer |
Offset to start sector of the file. |
◆ open_file_t
Open file handle structure.
Data Fields |
uint8_t |
cached_data[512] |
Cached data to speed up small reads. We want this buffer to be 8-byte aligned for DMA, but also 16-byte aligned so that it doesn't share cachelines with other members of the structure, so it's easier to handle coherency.
|
uint32_t |
cached_loc |
location of the cached data |
uint32_t |
handle |
The unique file handle to refer to this file by. |
uint32_t |
size |
The size in bytes of this file. |
uint32_t |
loc |
The offset of the current location in the file. |
uint32_t |
cart_start_loc |
The offset within the filesystem where the file is stored. |
◆ DFS_DEFAULT_LOCATION
#define DFS_DEFAULT_LOCATION 0 |
Default filesystem location.
The default value 0 instruct dfs_init to search for the DFS image within the rompak.
◆ MAX_FILENAME_LEN
#define MAX_FILENAME_LEN 243 |
Maximum filename length.
This value is due to the direcory structure
◆ FILETYPE
#define FILETYPE |
( |
|
x | ) |
((x) & 3) |
Macro to extract the file type from a DragonFS file flag.
- Parameters
-
[in] | x | File flags from DFS entry |
- Returns
- The file type flag
◆ anonymous enum
Directory walking flags.
Enumerator |
---|
WALK_CHDIR | Walk the directory structure for the purpose of changing directories.
|
WALK_OPEN | Walk the directory structure for the purpose of opening a file or directory.
|
◆ anonymous enum
Directory walking return flags.
Enumerator |
---|
TYPE_ANY | Return any file or directory found.
|
TYPE_FILE | Return a file from directory walk.
|
TYPE_DIR | Return a directory from a directory walk.
|
◆ dfs_chdir()
int dfs_chdir |
( |
const char *const |
path | ) |
|
Change directories to the specified path.
Supports absolute and relative
- Parameters
-
[in] | path | Relative or absolute path to change directories to |
- Returns
- DFS_ESUCCESS on success or a negative value on error.
◆ dfs_dir_findfirst()
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.
- Parameters
-
[in] | path | The path to look for files in |
[out] | buf | Buffer to place the name of the file or directory found |
- Returns
- The flags (FLAGS_FILE, FLAGS_DIR, FLAGS_EOF) or a negative value on error.
◆ dfs_dir_findnext()
int dfs_dir_findnext |
( |
char * |
buf | ) |
|
Find the next file or directory in a directory listing.
- Note
- Should be called after doing a dfs_dir_findfirst.
- Parameters
-
[out] | buf | Buffer to place the name of the next file or directory found |
- Returns
- The flags (FLAGS_FILE, FLAGS_DIR, FLAGS_EOF) or a negative value on error.
◆ dfs_open()
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
- Parameters
-
[in] | path | Path of the file to open |
- Returns
- A valid file handle to reference the file by or a negative error on failure.
◆ dfs_close()
int dfs_close |
( |
uint32_t |
handle | ) |
|
Close an already open file handle.
- Parameters
-
[in] | handle | A valid file handle as returned from dfs_open. |
- Returns
- DFS_ESUCCESS on success or a negative value on error.
◆ dfs_seek()
int dfs_seek |
( |
uint32_t |
handle, |
|
|
int |
offset, |
|
|
int |
origin |
|
) |
| |
Seek to an offset in the file.
- Parameters
-
[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 . |
- Returns
- DFS_ESUCCESS on success or a negative value on error.
◆ dfs_tell()
int dfs_tell |
( |
uint32_t |
handle | ) |
|
Return the current offset into a file.
- Parameters
-
[in] | handle | A valid file handle as returned from dfs_open. |
- Returns
- The current byte offset into a file or a negative error on failure.
◆ dfs_read()
int dfs_read |
( |
void *const |
buf, |
|
|
int |
size, |
|
|
int |
count, |
|
|
uint32_t |
handle |
|
) |
| |
Read data from a file.
- Parameters
-
[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. |
- Returns
- The actual number of bytes read or a negative value on failure.
◆ dfs_size()
int dfs_size |
( |
uint32_t |
handle | ) |
|
Return the file size of an open file.
- Parameters
-
[in] | handle | A valid file handle as returned from dfs_open. |
- Returns
- The file size in bytes or a negative value on failure.
◆ dfs_rom_addr()
uint32_t dfs_rom_addr |
( |
const char * |
path | ) |
|
Return the physical address of a file (in ROM space)
This function should be used for highly-specialized, high-performance use cases. Using dfs_open / dfs_read is generally acceptable performance-wise, and is easier to use rather than managing direct access to PI space.
Direct access to ROM data must go through io_read or dma_read. Do not dereference directly as the console might hang if the PI is busy.
- Parameters
-
- Returns
- A pointer to the physical address of the file body, or 0 if the file was not found.
◆ dfs_eof()
int dfs_eof |
( |
uint32_t |
handle | ) |
|
Return whether the end of file has been reached.
- Parameters
-
[in] | handle | A valid file handle as returned from dfs_open. |
- Returns
- 1 if the end of file is reached, 0 if not, and a negative value on error.
◆ dfs_init()
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/C file operations work with DragonFS, using the "rom:/" prefix".
The function needs to know where the DFS image is located within the cartridge space. To simplify this, you can pass DFS_DEFAULT_LOCATION which tells dfs_init to search for the DFS image by itself, using the rompak TOC (see rompak_internal.h). Most users should use this option.
Otherwise, if the ROM cannot be built with a rompak TOC for some reason, a virtual address should be passed. This is normally 0xB0000000 + the offset used when building your ROM + the size of the header file used (typically 0x1000).
- Parameters
-
[in] | base_fs_loc | Virtual address in cartridge space at which to find the filesystem, or DFS_DEFAULT_LOCATION to automatically search for the filesystem in the cartridge (using the rompak). |
- Returns
- DFS_ESUCCESS on success or a negative error otherwise.