really add nitrofs support

This commit is contained in:
Dave Murphy 2008-05-12 09:03:45 +00:00
parent a6dd89dbe4
commit 02d3e47079
2 changed files with 416 additions and 0 deletions

46
nds/include/nitrofs.h Normal file
View 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
View 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);
}