mirror of
https://github.com/wiiu-env/libfat.git
synced 2024-11-22 09:59:18 +01:00
really add nitrofs support
This commit is contained in:
parent
a6dd89dbe4
commit
02d3e47079
46
nds/include/nitrofs.h
Normal file
46
nds/include/nitrofs.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
nitrofs.h
|
||||
Simple functionality for initialising nitrofs filesystem.
|
||||
|
||||
Copyright (c) 2008
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NITROFS_H
|
||||
#define _NITROFS_H
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool nitroFSInit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _NITROFS_H
|
370
nds/source/nitrofs.c
Normal file
370
nds/source/nitrofs.c
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
nitrofs.c - eris's wai ossum nitro filesystem device driver
|
||||
Based on information found at http://frangoassado.org/ds/rom_spec.txt and from the #dsdev ppls
|
||||
Kallisti (K) 2008-01-26 All rights reversed.
|
||||
*/
|
||||
#include <nds.h>
|
||||
#include <string.h>
|
||||
#include <fat.h>
|
||||
|
||||
#include <sys/dir.h>
|
||||
#include <sys/iosupport.h>
|
||||
#include <stdio.h>
|
||||
|
||||
DIR_ITER* nitroFSDirOpen(struct _reent *r, DIR_ITER *dirState, const char *path);
|
||||
int nitroDirReset(struct _reent *r, DIR_ITER *dirState);
|
||||
int nitroFSDirNext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st);
|
||||
int nitroFSDirClose(struct _reent *r, DIR_ITER *dirState);
|
||||
int nitroFSOpen(struct _reent *r, void *fileStruct, const char *path,int flags,int mode);
|
||||
int nitroFSClose(struct _reent *r,int fd);
|
||||
int nitroFSRead(struct _reent *r,int fd,char *ptr,int len);
|
||||
int nitroFSSeek(struct _reent *r,int fd,int pos,int dir);
|
||||
int nitroFSFstat(struct _reent *r,int fd,struct stat *st);
|
||||
|
||||
#define LOADERSTR "PASS" //look for this
|
||||
#define LOADERSTROFFSET 0xac
|
||||
#define FNTOFFSET 0x40
|
||||
#define FATOFFSET 0x48
|
||||
|
||||
#define NITRONAMELENMAX 0x80 //max file name is 127 +1 for zero byte :D
|
||||
#define NITROMAXPATHLEN 0x100 //256 bytes enuff?
|
||||
|
||||
#define NITROROOT 0xf000 //root entry_file_id
|
||||
#define NITRODIRMASK 0x0fff //remove leading 0xf
|
||||
|
||||
#define NITROISDIR 0x80 //mask to indicate this name entry is a dir, other 7 bits = name length
|
||||
|
||||
//Directory filename subtable entry structure
|
||||
struct ROM_FNTDir {
|
||||
u32 entry_start;
|
||||
u16 entry_file_id;
|
||||
u16 parent_id;
|
||||
};
|
||||
|
||||
//Yo, dis table is fat (describes the structures
|
||||
struct ROM_FAT {
|
||||
u32 top; //start of file in rom image
|
||||
u32 bottom; //end of file in rom image
|
||||
};
|
||||
|
||||
//used (mostly by the 'sub' functions) for the raw reading of rom image either via gba rom or dldi
|
||||
struct nitroRawStruct {
|
||||
FILE *ndsFile; //used if going thru dldi >_> (if set to null we assume GBA with loader)
|
||||
unsigned int pos; //where in the file am i?
|
||||
};
|
||||
|
||||
struct nitroFSStruct {
|
||||
struct nitroRawStruct nrs;
|
||||
unsigned int start; //where in the rom this file starts
|
||||
unsigned int end; //where in the rom this file ends
|
||||
// unsigned int pos; //where in current file are we?
|
||||
};
|
||||
|
||||
struct nitroDIRStruct {
|
||||
struct nitroRawStruct nrs;
|
||||
unsigned int namepos; //ptr to next name to lookup in list
|
||||
struct ROM_FAT romfat;
|
||||
u16 entry_id; //which entry this is (for files only) incremented with each new file in dir?
|
||||
u16 dir_id; //which directory entry this is.. used ofc for dirs only
|
||||
u16 cur_dir_id; //which directory entry we are using
|
||||
u16 parent_id; //who is the parent of the current directory (this can be used to easily ../ )
|
||||
};
|
||||
|
||||
//Globals!
|
||||
u32 fntOffset; //offset to start of filename table
|
||||
u32 fatOffset; //offset to start of file alloc table
|
||||
bool isNdsFile; //is it a nds file?
|
||||
const char *ndsfilename; //what nds file to use
|
||||
|
||||
devoptab_t nitroFSdevoptab={
|
||||
"nitro", // const char *name;
|
||||
sizeof(struct nitroFSStruct), // int structSize;
|
||||
&nitroFSOpen, // int (*open_r)(struct _reent *r, void *fileStruct, const char *path,int flags,int mode);
|
||||
&nitroFSClose, // int (*close_r)(struct _reent *r,int fd);
|
||||
NULL, // int (*write_r)(struct _reent *r,int fd,const char *ptr,int len);
|
||||
&nitroFSRead, // int (*read_r)(struct _reent *r,int fd,char *ptr,int len);
|
||||
&nitroFSSeek, // int (*seek_r)(struct _reent *r,int fd,int pos,int dir);
|
||||
&nitroFSFstat, // int (*fstat_r)(struct _reent *r,int fd,struct stat *st);
|
||||
NULL, // int (*stat_r)(struct _reent *r,const char *file,struct stat *st);
|
||||
NULL, // int (*link_r)(struct _reent *r,const char *existing, const char *newLink);
|
||||
NULL, // int (*unlink_r)(struct _reent *r,const char *name);
|
||||
NULL, // int (*chdir_r)(struct _reent *r,const char *name);
|
||||
|
||||
NULL, // int (*rename_r) (struct _reent *r, const char *oldName, const char *newName);
|
||||
NULL, // int (*mkdir_r) (struct _reent *r, const char *path, int mode);
|
||||
|
||||
sizeof(struct nitroDIRStruct), // int dirStateSize;
|
||||
&nitroFSDirOpen, // DIR_ITER* (*diropen_r)(struct _reent *r, DIR_ITER *dirState, const char *path);
|
||||
&nitroDirReset, // int (*dirreset_r)(struct _reent *r, DIR_ITER *dirState);
|
||||
&nitroFSDirNext, // int (*dirnext_r)(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
|
||||
&nitroFSDirClose // int (*dirclose_r)(struct _reent *r, DIR_ITER *dirState);
|
||||
|
||||
};
|
||||
|
||||
//inline these mebbe? these 4 'sub' functions deal with actually reading from either gba rom or .nds file :)
|
||||
//what i rly rly rly wanna know is how an actual nds cart reads from itself, but it seems no one can tell me ~_~
|
||||
//so, instead we have this weird weird haxy try gbaslot then try dldi method. If i (or you!!) ever do figure out
|
||||
//how to read the proper way can replace these 4 functions and everything should work normally :)
|
||||
int nitroSubOpen(struct nitroRawStruct *nrs) {
|
||||
if(isNdsFile) {
|
||||
if((nrs->ndsFile = fopen(ndsfilename,"rb+"))) {
|
||||
nrs->pos=0;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
nrs->ndsFile=(FILE*)NULL;
|
||||
nrs->pos=0;
|
||||
return 1;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int nitroSubClose(struct nitroRawStruct *nrs) {
|
||||
if(isNdsFile)
|
||||
return(fclose(nrs->ndsFile));
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//reads from rom image either gba rom or dldi
|
||||
int nitroSubRead(struct nitroRawStruct *nrs, void *ptr, int len) {
|
||||
if(isNdsFile) { //read from ndsfile
|
||||
len=fread(ptr,1,len,nrs->ndsFile);
|
||||
} else { //reading from gbarom
|
||||
memcpy(ptr, nrs->pos+(void*)GBAROM,len); //len isnt checked here because other checks exist in the callers (hopefully)
|
||||
}
|
||||
nrs->pos+=len;
|
||||
return(len);
|
||||
}
|
||||
|
||||
int nitroSubSeek(struct nitroRawStruct *nrs, int pos, int dir) {
|
||||
if(dir==SEEK_SET) //otherwise just set the pos :)
|
||||
nrs->pos=pos;
|
||||
else if(dir==SEEK_CUR)
|
||||
nrs->pos+=pos; //see ez!
|
||||
if(isNdsFile) { //read from ndsfile actually do a seek
|
||||
return(fseek(nrs->ndsFile,pos,dir));
|
||||
} else {
|
||||
return(nrs->pos);
|
||||
}
|
||||
}
|
||||
|
||||
//Figure out if its gba or ds, setup stuff
|
||||
bool nitroFSInit() {
|
||||
struct nitroRawStruct nrs;
|
||||
char romstr[0x10];
|
||||
|
||||
sysSetCartOwner(BUS_OWNER_ARM9 );
|
||||
|
||||
if(strncmp(((const char *)GBAROM)+LOADERSTROFFSET,LOADERSTR,strlen(LOADERSTR))==0) { // found standard nds file in gba cart
|
||||
fntOffset=((u32)*(u32*)(((const char *)GBAROM)+FNTOFFSET));
|
||||
fatOffset=((u32)*(u32*)(((const char *)GBAROM)+FATOFFSET));
|
||||
isNdsFile=false;
|
||||
AddDevice(&nitroFSdevoptab);
|
||||
return true;
|
||||
|
||||
} else { //okay then try something else ~_~
|
||||
|
||||
isNdsFile=true;
|
||||
|
||||
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 ) {
|
||||
ndsfilename=__system_argv->argv[0]; //set global for what file.nds to use
|
||||
if (!fatInitDefault()) return false;
|
||||
if(nitroSubOpen(&nrs)) {
|
||||
nitroSubSeek(&nrs,LOADERSTROFFSET,SEEK_SET);
|
||||
nitroSubRead(&nrs,romstr,strlen(LOADERSTR));
|
||||
|
||||
if(strncmp(romstr,LOADERSTR,strlen(LOADERSTR))!=0) return false;
|
||||
|
||||
nitroSubSeek(&nrs,FNTOFFSET,SEEK_SET);
|
||||
nitroSubRead(&nrs,&fntOffset,sizeof(fntOffset));
|
||||
nitroSubSeek(&nrs,FATOFFSET,SEEK_SET);
|
||||
nitroSubRead(&nrs,&fatOffset,sizeof(fatOffset));
|
||||
nitroSubClose(&nrs);
|
||||
|
||||
AddDevice(&nitroFSdevoptab);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Directory functs
|
||||
DIR_ITER* nitroFSDirOpen(struct _reent *r, DIR_ITER *dirState, const char *path) {
|
||||
struct nitroDIRStruct *dirStruct=(struct nitroDIRStruct*)dirState->dirStruct; //this makes it lots easier!
|
||||
struct stat st;
|
||||
char dirname[NITRONAMELENMAX];
|
||||
char *cptr;
|
||||
char mydirpath[NITROMAXPATHLEN]; //to hold copy of path string
|
||||
char *dirpath=mydirpath;
|
||||
//NOTE: might add prepending of chdir path? seems like lotta work for something silly that shoulda been handled in newlib anyways ~_~
|
||||
bool pathfound;
|
||||
if((cptr=strchr(path,':')))
|
||||
path=cptr+1; //move path past any device names (if it was nixy style wouldnt need this step >_>)
|
||||
strncpy(dirpath,path,sizeof(mydirpath)-1); //copy the string (as im gonna mutalate it)
|
||||
nitroSubOpen(&dirStruct->nrs); //open a file for me to use
|
||||
dirStruct->cur_dir_id=NITROROOT; //first root dir
|
||||
nitroDirReset(r,dirState); //set dir to current path
|
||||
do {
|
||||
while((cptr=strchr(dirpath,'/'))==dirpath) {
|
||||
dirpath++; //move past any leading / or // together
|
||||
}
|
||||
if(cptr)
|
||||
*cptr=0; //erase /
|
||||
//here is prolly where you should handle .. and . filenames if desired
|
||||
if(*dirpath==0) {//are we at the end of the path string?? if so there is nothing to search for we're already here !
|
||||
pathfound=true; //mostly this handles searches for root or / or no path specified cases
|
||||
break;
|
||||
}
|
||||
pathfound=false;
|
||||
while(nitroFSDirNext(r,dirState,dirname,&st)==0) {
|
||||
if((st.st_mode==S_IFDIR) && !(strcmp(dirname,dirpath))) { //if its a directory and name matches dirpath
|
||||
dirStruct->cur_dir_id=dirStruct->dir_id; //move us to the next dir in tree
|
||||
nitroDirReset(r,dirState); //set dir to current path we just found...
|
||||
pathfound=true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
if(!pathfound)
|
||||
break;
|
||||
dirpath=cptr+1; //move to right after last / we found
|
||||
} while(cptr); // go till after the last /
|
||||
if(pathfound) {
|
||||
return(dirState);
|
||||
} else {
|
||||
nitroSubClose(&dirStruct->nrs); //oops almost forgot to close the file we opened <_<
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int nitroFSDirClose(struct _reent *r, DIR_ITER *dirState) {
|
||||
return(nitroSubClose(&((struct nitroDIRStruct*)dirState->dirStruct)->nrs));
|
||||
|
||||
}
|
||||
|
||||
//reset dir to start of entry selected by dirStruct->cur_dir_id which should be set in dirOpen
|
||||
int nitroDirReset(struct _reent *r, DIR_ITER *dirState) {
|
||||
struct nitroDIRStruct *dirStruct=(struct nitroDIRStruct*)dirState->dirStruct; //this makes it lots easier!
|
||||
struct ROM_FNTDir dirsubtable;
|
||||
nitroSubSeek(&dirStruct->nrs,fntOffset+((dirStruct->cur_dir_id&NITRODIRMASK)*sizeof(struct ROM_FNTDir)),SEEK_SET);
|
||||
nitroSubRead(&dirStruct->nrs, &dirsubtable, sizeof(dirsubtable));
|
||||
dirStruct->namepos=dirsubtable.entry_start; //set namepos to first entry in this dir's table
|
||||
dirStruct->entry_id=dirsubtable.entry_file_id; //get number of first file ID in this branch
|
||||
dirStruct->parent_id=dirsubtable.parent_id; //save parent ID in case we wanna add ../ functionality
|
||||
return(0);
|
||||
}
|
||||
|
||||
int nitroFSDirNext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) {
|
||||
unsigned char next;
|
||||
struct nitroDIRStruct *dirStruct=(struct nitroDIRStruct*)dirState->dirStruct; //this makes it lots easier!
|
||||
nitroSubSeek(&dirStruct->nrs,fntOffset+dirStruct->namepos,SEEK_SET);
|
||||
nitroSubRead(&dirStruct->nrs, &next , sizeof(next));
|
||||
// next: high bit 0x80 = entry isdir.. other 7 bits r size, the 16 bits following name are dir's entryid (starts with f000)
|
||||
// 00 = endoftable //
|
||||
if(next) {
|
||||
if(next&NITROISDIR) {
|
||||
if(st) st->st_mode=S_IFDIR;
|
||||
next&=NITROISDIR^0xff; //invert bits and mask off 0x80
|
||||
nitroSubRead(&dirStruct->nrs,filename,next);
|
||||
// nitroSubRead(&dirStruct->nrs,&dirStruct->dir_id,sizeof(struct nitroDIRStruct.dir_id)); //read the dir_id
|
||||
//grr cant get the struct member size?, just wanna test it so moving on...
|
||||
nitroSubRead(&dirStruct->nrs,&dirStruct->dir_id,sizeof(u16)); //read the dir_id
|
||||
dirStruct->namepos+=next+sizeof(u16)+1; //now we points to next one plus dir_id size:D
|
||||
} else {
|
||||
if(st) st->st_mode=0;
|
||||
nitroSubRead(&dirStruct->nrs,filename,next);
|
||||
dirStruct->namepos+=next+1; //now we points to next one :D
|
||||
//read file info to get filesize (and for fileopen)
|
||||
nitroSubSeek(&dirStruct->nrs,fatOffset+(dirStruct->entry_id*sizeof(struct ROM_FAT)),SEEK_SET);
|
||||
nitroSubRead(&dirStruct->nrs, &dirStruct->romfat, sizeof(dirStruct->romfat)); //retrieve romfat entry (contains filestart and end positions)
|
||||
dirStruct->entry_id++; //advance ROM_FNTStrFile ptr
|
||||
if(st) st->st_size=dirStruct->romfat.bottom-dirStruct->romfat.top; //calculate filesize
|
||||
}
|
||||
filename[(int)next]=0; //zero last char
|
||||
return(0);
|
||||
} else {
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//fs functs
|
||||
int nitroFSOpen(struct _reent *r, void *fileStruct, const char *path,int flags,int mode) {
|
||||
struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fileStruct;
|
||||
struct nitroDIRStruct dirStruct;
|
||||
DIR_ITER dirState;
|
||||
dirState.dirStruct=&dirStruct; //create a temp dirstruct
|
||||
struct _reent dre;
|
||||
struct stat st; //all these are just used for reading the dir ~_~
|
||||
char dirfilename[NITROMAXPATHLEN]; // to hold a full path (i tried to avoid using so much stack but blah :/)
|
||||
char *filename; // to hold filename
|
||||
char *cptr; //used to string searching and manipulation
|
||||
cptr=(char*)path+strlen(path); //find the end...
|
||||
filename=NULL;
|
||||
do {
|
||||
if((*cptr=='/') || (*cptr==':')) { // split at either / or : (whichever comes first from the end!)
|
||||
cptr++;
|
||||
strncpy(dirfilename,path,cptr-path); //copy string up till and including/ or : zero rest
|
||||
dirfilename[cptr-path]=0; //it seems strncpy doesnt always zero?!
|
||||
filename=cptr; //filename = now remainder of string
|
||||
break;
|
||||
}
|
||||
} while(cptr--!=dirfilename); //search till start
|
||||
if(!filename) { //we didnt find a / or : ? shouldnt realyl happen but if it does...
|
||||
filename=(char*)path; //filename = complete path
|
||||
dirfilename[0]=0; //make directory path ""
|
||||
}
|
||||
if(nitroFSDirOpen(&dre,&dirState,dirfilename)) {
|
||||
fatStruct->start=0;
|
||||
while(nitroFSDirNext(&dre,&dirState, dirfilename, &st)==0) {
|
||||
if(!(st.st_mode & S_IFDIR) && (strcmp(dirfilename,filename)==0)) { //Found the *file* your looking for!!
|
||||
fatStruct->start=dirStruct.romfat.top;
|
||||
fatStruct->end=dirStruct.romfat.bottom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(fatStruct->start) {
|
||||
fatStruct->nrs.ndsFile=dirStruct.nrs.ndsFile; //reuse already open'd filehandle
|
||||
nitroSubSeek(&fatStruct->nrs,fatStruct->start,SEEK_SET); //seek to start of file
|
||||
return(0); //woot!
|
||||
}
|
||||
nitroFSDirClose(&dre,&dirState);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int nitroFSClose(struct _reent *r,int fd) {
|
||||
return(nitroSubClose(&((struct nitroFSStruct *)fd)->nrs));
|
||||
}
|
||||
|
||||
int nitroFSRead(struct _reent *r,int fd,char *ptr,int len) {
|
||||
struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fd;
|
||||
struct nitroRawStruct *nrs=&((struct nitroFSStruct *)fd)->nrs;
|
||||
if(nrs->pos+len > fatStruct->end)
|
||||
len=fatStruct->end-nrs->pos; //dont let us read past the end plz!
|
||||
if(nrs->pos > fatStruct->end)
|
||||
return(0); //hit eof
|
||||
return(nitroSubRead(nrs,ptr,len));
|
||||
}
|
||||
|
||||
int nitroFSSeek(struct _reent *r,int fd,int pos,int dir) {
|
||||
//need check for eof here...
|
||||
struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fd;
|
||||
struct nitroRawStruct *nrs=&((struct nitroFSStruct *)fd)->nrs;
|
||||
if(dir==SEEK_SET)
|
||||
pos+=fatStruct->start; //add start from .nds file offset
|
||||
if(pos > fatStruct->end)
|
||||
return(0); //dont let us read past the end plz!
|
||||
return(nitroSubSeek(nrs,pos,dir));
|
||||
|
||||
}
|
||||
|
||||
int nitroFSFstat(struct _reent *r,int fd,struct stat *st) {
|
||||
struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fd;
|
||||
//cant think of what else to do here besides report the size atm
|
||||
st->st_size=fatStruct->end-fatStruct->start;
|
||||
return(0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user