├── .gitignore ├── Makefile ├── filesystem.pnproj ├── include └── filesystem.h └── source └── nitrofs.c /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | lib 3 | *.bz2 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | DATESTRING := $(shell date +%Y%m%d) 10 | 11 | export FILESYSTEM_MAJOR := 0 12 | export FILESYSTEM_MINOR := 9 13 | export FILESYSTEM_PATCH := 14 14 | 15 | 16 | VERSION := $(FILESYSTEM_MAJOR).$(FILESYSTEM_MINOR).$(FILESYSTEM_PATCH) 17 | 18 | include $(DEVKITARM)/ds_rules 19 | 20 | #--------------------------------------------------------------------------------- 21 | # TARGET is the name of the output 22 | # BUILD is the directory where object files & intermediate files will be placed 23 | # SOURCES is a list of directories containing source code 24 | # DATA is a list of directories containing data files 25 | # INCLUDES is a list of directories containing header files 26 | #--------------------------------------------------------------------------------- 27 | TARGET := filesystem 28 | BUILD := build 29 | SOURCES := source 30 | DATA := data 31 | INCLUDES := include 32 | 33 | #--------------------------------------------------------------------------------- 34 | # options for code generation 35 | #--------------------------------------------------------------------------------- 36 | ARCH := -mthumb -mthumb-interwork 37 | 38 | CFLAGS := -g -Wall -O2 \ 39 | -ffunction-sections -fdata-sections \ 40 | -march=armv5te -mtune=arm946e-s \ 41 | -fomit-frame-pointer -ffast-math \ 42 | $(ARCH) 43 | 44 | CFLAGS += $(INCLUDE) -DARM9 45 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 46 | 47 | ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s 48 | LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 49 | 50 | #--------------------------------------------------------------------------------- 51 | # list of directories containing libraries, this must be the top level containing 52 | # include and lib 53 | #--------------------------------------------------------------------------------- 54 | LIBDIRS := $(LIBNDS) 55 | 56 | #--------------------------------------------------------------------------------- 57 | # no real need to edit anything past this point unless you need to add additional 58 | # rules for different file extensions 59 | #--------------------------------------------------------------------------------- 60 | ifneq ($(BUILD),$(notdir $(CURDIR))) 61 | #--------------------------------------------------------------------------------- 62 | 63 | export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a 64 | 65 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 66 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 67 | 68 | export DEPSDIR := $(CURDIR)/$(BUILD) 69 | 70 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 71 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 72 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 73 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 74 | 75 | #--------------------------------------------------------------------------------- 76 | # use CXX for linking C++ projects, CC for standard C 77 | #--------------------------------------------------------------------------------- 78 | ifeq ($(strip $(CPPFILES)),) 79 | #--------------------------------------------------------------------------------- 80 | export LD := $(CC) 81 | #--------------------------------------------------------------------------------- 82 | else 83 | #--------------------------------------------------------------------------------- 84 | export LD := $(CXX) 85 | #--------------------------------------------------------------------------------- 86 | endif 87 | #--------------------------------------------------------------------------------- 88 | 89 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 90 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 91 | 92 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 93 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 94 | -I$(CURDIR)/$(BUILD) 95 | 96 | .PHONY: $(BUILD) clean all 97 | 98 | #--------------------------------------------------------------------------------- 99 | all: $(BUILD) 100 | 101 | #--------------------------------------------------------------------------------- 102 | dist: all 103 | #--------------------------------------------------------------------------------- 104 | @tar --exclude=*CVS* --exclude=.svn -cvjf libfilesystem-src-$(VERSION).tar.bz2 include source Makefile 105 | @tar --exclude=*CVS* --exclude=.svn -cvjf libfilesystem-$(VERSION).tar.bz2 include lib 106 | 107 | install: all 108 | @mkdir -p $(DESTDIR)$(DEVKITPRO)/libnds/include 109 | @mkdir -p $(DESTDIR)$(DEVKITPRO)/libnds/lib 110 | @cp -v include/*.h $(DESTDIR)$(DEVKITPRO)/libnds/include 111 | @cp -v lib/*.a $(DESTDIR)$(DEVKITPRO)/libnds/lib 112 | 113 | lib: 114 | @[ -d $@ ] || mkdir -p $@ 115 | 116 | $(BUILD): lib 117 | @[ -d $@ ] || mkdir -p $@ 118 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 119 | 120 | #--------------------------------------------------------------------------------- 121 | clean: 122 | @echo clean ... 123 | @rm -fr $(BUILD) lib *.bz2 124 | 125 | #--------------------------------------------------------------------------------- 126 | else 127 | 128 | DEPENDS := $(OFILES:.o=.d) 129 | 130 | #--------------------------------------------------------------------------------- 131 | # main targets 132 | #--------------------------------------------------------------------------------- 133 | $(OUTPUT) : $(OFILES) 134 | 135 | 136 | -include $(DEPENDS) 137 | 138 | #--------------------------------------------------------------------------------------- 139 | endif 140 | #--------------------------------------------------------------------------------------- 141 | -------------------------------------------------------------------------------- /filesystem.pnproj: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /include/filesystem.h: -------------------------------------------------------------------------------- 1 | #ifndef _filesystem_h_ 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | bool nitroFSInit(char **basepath); 8 | 9 | #ifdef __cplusplus 10 | } 11 | #endif 12 | 13 | #endif // _filesystem_h_ 14 | -------------------------------------------------------------------------------- /source/nitrofs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static DIR_ITER* nitroFSDirOpen(struct _reent *r, DIR_ITER *dirState, const char *path); 15 | static int nitroDirReset(struct _reent *r, DIR_ITER *dirState); 16 | static int nitroFSDirNext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st); 17 | static int nitroFSDirClose(struct _reent *r, DIR_ITER *dirState); 18 | static int nitroFSOpen(struct _reent *r, void *fileStruct, const char *path,int flags,int mode); 19 | static int nitroFSClose(struct _reent *r,void *fd); 20 | static int nitroFSRead(struct _reent *r,void *fd,char *ptr,size_t len); 21 | static off_t nitroFSSeek(struct _reent *r,void *fd,off_t pos,int dir); 22 | static int nitroFSFstat(struct _reent *r,void *fd,struct stat *st); 23 | static int nitroFSstat(struct _reent *r,const char *file,struct stat *st); 24 | static int nitroFSChdir(struct _reent *r,const char *name); 25 | 26 | static tNDSHeader *__gba_cart_header = (tNDSHeader *)0x08000000; 27 | 28 | #define NITRONAMELENMAX 0x80 //max file name is 127 +1 for zero byte 29 | #define NITROMAXPATHLEN 0x100 30 | 31 | #define NITROROOT 0xf000 //root entry_file_id 32 | #define NITRODIRMASK 0x0fff //remove leading 0xf 33 | 34 | #define NITROISDIR 0x80 //mask to indicate this name entry is a dir, other 7 bits = name length 35 | 36 | //Directory filename subtable entry structure 37 | struct ROM_FNTDir { 38 | u32 entry_start; 39 | u16 entry_file_id; 40 | u16 parent_id; 41 | }; 42 | 43 | 44 | struct ROM_FAT { 45 | u32 top; //start of file in rom image 46 | u32 bottom; //end of file in rom image 47 | }; 48 | 49 | struct nitroFSStruct { 50 | unsigned int pos; //where in the file am i? 51 | unsigned int start; //where in the rom this file starts 52 | unsigned int end; //where in the rom this file ends 53 | }; 54 | 55 | struct nitroDIRStruct { 56 | unsigned int pos; //where in the file am i? 57 | unsigned int namepos; //ptr to next name to lookup in list 58 | struct ROM_FAT romfat; 59 | u16 entry_id; //which entry this is (for files only) incremented with each new file in dir? 60 | u16 dir_id; //which directory entry this is 61 | u16 cur_dir_id; //which directory entry we are using 62 | u16 parent_id; //who is the parent of the current directory 63 | u8 spc; //system path count.. used by dirnext, when 0=./ 1=../ >=2 actual dirs 64 | }; 65 | 66 | //Globals! 67 | static u32 fntOffset; //offset to start of filename table 68 | static u32 fatOffset; //offset to start of file alloc table 69 | static u16 chdirpathid; //default dir path id... 70 | static int ndsFileFD = -1; 71 | static unsigned int ndsFileLastpos; //Used to determine need to fseek or not 72 | static bool cardRead = false; 73 | 74 | devoptab_t nitroFSdevoptab={ 75 | "nitro", 76 | sizeof(struct nitroFSStruct), // int structSize; 77 | &nitroFSOpen, // int (*open_r)(struct _reent *r, void *fileStruct, const char *path,int flags,int mode); 78 | &nitroFSClose, // int (*close_r)(struct _reent *r,int fd); 79 | NULL, // int (*write_r)(struct _reent *r,int fd,const char *ptr,int len); 80 | &nitroFSRead, // int (*read_r)(struct _reent *r,int fd,char *ptr,int len); 81 | &nitroFSSeek, // int (*seek_r)(struct _reent *r,int fd,int pos,int dir); 82 | &nitroFSFstat, // int (*fstat_r)(struct _reent *r,int fd,struct stat *st); 83 | &nitroFSstat, // int (*stat_r)(struct _reent *r,const char *file,struct stat *st); 84 | NULL, // int (*link_r)(struct _reent *r,const char *existing, const char *newLink); 85 | NULL, // int (*unlink_r)(struct _reent *r,const char *name); 86 | &nitroFSChdir, // int (*chdir_r)(struct _reent *r,const char *name); 87 | NULL, // int (*rename_r) (struct _reent *r, const char *oldName, const char *newName); 88 | NULL, // int (*mkdir_r) (struct _reent *r, const char *path, int mode); 89 | sizeof(struct nitroDIRStruct), // int dirStateSize; 90 | &nitroFSDirOpen, // DIR_ITER* (*diropen_r)(struct _reent *r, DIR_ITER *dirState, const char *path); 91 | &nitroDirReset, // int (*dirreset_r)(struct _reent *r, DIR_ITER *dirState); 92 | &nitroFSDirNext, // int (*dirnext_r)(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat); 93 | &nitroFSDirClose, // int (*dirclose_r)(struct _reent *r, DIR_ITER *dirState); 94 | NULL, // int (*statvfs_r)(struct _reent *r, const char *path, struct statvfs *buf); 95 | NULL, // int (*ftruncate_r)(struct _reent *r, int fd, off_t len); 96 | NULL, // int (*fsync_r)(struct _reent *r, int fd); 97 | NULL, // void *deviceData; 98 | NULL, // int (*chmod_r)(struct _reent *r, const char *path, mode_t mode); 99 | NULL // int (*fchmod_r)(struct _reent *r, int fd, mode_t mode); 100 | }; 101 | 102 | //--------------------------------------------------------------------------------- 103 | bool nitroFSInit(char **basepath) { 104 | //--------------------------------------------------------------------------------- 105 | 106 | bool nitroInit = false; 107 | 108 | if (__NDSHeader->fatSize == 0 ) return false; 109 | 110 | sysSetCartOwner(BUS_OWNER_ARM9); 111 | sysSetCardOwner(BUS_OWNER_ARM9); 112 | 113 | char *nitropath = NULL; 114 | 115 | // test for argv & open nds file 116 | if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 ) { 117 | if ( strncmp(__system_argv->argv[0],"fat",3) == 0 || strncmp(__system_argv->argv[0],"sd",2) == 0) { 118 | if (fatInitDefault()) { 119 | ndsFileFD = open(__system_argv->argv[0], O_RDONLY); 120 | if (ndsFileFD != -1) { 121 | nitroInit = true; 122 | nitropath = malloc(PATH_MAX); 123 | if(nitropath != NULL) { 124 | nitropath=getcwd(nitropath,PATH_MAX); 125 | } 126 | } 127 | } 128 | } 129 | } 130 | 131 | // test for valid nitrofs on gba cart 132 | if (!nitroInit) { 133 | if (memcmp(&__NDSHeader->filenameOffset, &__gba_cart_header->filenameOffset, 16) == 0 ) { 134 | nitroInit = true; 135 | nitropath = strdup("nitro:/"); 136 | } 137 | } 138 | 139 | // fallback to direct card reads for desmume 140 | // TODO: validate nitrofs 141 | if (!nitroInit) { 142 | cardRead = true; nitroInit = true; 143 | nitropath = strdup("nitro:/"); 144 | } 145 | 146 | 147 | if ( nitroInit ) { 148 | fntOffset = __NDSHeader->filenameOffset; 149 | fatOffset = __NDSHeader->fatOffset; 150 | AddDevice(&nitroFSdevoptab); 151 | chdir(nitropath); 152 | } 153 | 154 | if (basepath != NULL) { 155 | *basepath = nitropath; 156 | } else { 157 | free(nitropath); 158 | } 159 | return nitroInit; 160 | } 161 | 162 | 163 | // cannot read across block boundaries (multiples of 0x200 bytes) 164 | //--------------------------------------------------------------------------------- 165 | static void nitroSubReadBlock(u32 pos, u8 *ptr, u32 len) { 166 | //--------------------------------------------------------------------------------- 167 | if ( (len & 3) == 0 && (((u32)ptr) & 3) == 0 && (pos & 3) == 0) { 168 | // if everything is word-aligned, read directly 169 | cardParamCommand(0xB7, pos, CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F) | CARD_CLK_SLOW | CARD_WR | CARD_nRESET | CARD_SEC_CMD | CARD_SEC_DAT | CARD_ACTIVATE | CARD_BLK_SIZE(1), (u32*)ptr, len >> 2); 170 | } else { 171 | // otherwise, use a temporary buffer 172 | static u32 temp[128]; 173 | cardParamCommand(0xB7, (pos & ~0x1ff), CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F) | CARD_CLK_SLOW | CARD_WR | CARD_nRESET | CARD_SEC_CMD | CARD_SEC_DAT | CARD_ACTIVATE | CARD_BLK_SIZE(1), temp, 0x200 >> 2); 174 | memcpy(ptr, ((u8*)temp) + (pos & 0x1FF), len); 175 | } 176 | } 177 | 178 | //--------------------------------------------------------------------------------- 179 | static int nitroSubReadCard(unsigned int *npos, void *ptr, int len) { 180 | //--------------------------------------------------------------------------------- 181 | u8 *ptr_u8 = (u8*)ptr; 182 | int remaining = len; 183 | 184 | if((*npos) & 0x1FF) { 185 | 186 | u32 amt = 0x200 - (*npos & 0x1FF); 187 | 188 | if(amt > remaining) amt = remaining; 189 | 190 | nitroSubReadBlock(*npos, ptr_u8, amt); 191 | remaining -= amt; 192 | ptr_u8 += amt; 193 | *npos += amt; 194 | } 195 | 196 | while(remaining >= 0x200) { 197 | nitroSubReadBlock(*npos, ptr_u8, 0x200); 198 | remaining -= 0x200; 199 | ptr_u8 += 0x200; 200 | *npos += 0x200; 201 | } 202 | 203 | if(remaining > 0) { 204 | nitroSubReadBlock(*npos, ptr_u8, remaining); 205 | *npos += remaining; 206 | } 207 | return len; 208 | } 209 | 210 | //--------------------------------------------------------------------------------- 211 | static inline int nitroSubRead(unsigned int *npos, void *ptr, int len) { 212 | //--------------------------------------------------------------------------------- 213 | if(cardRead) { 214 | unsigned int tmpPos = *npos; 215 | len = nitroSubReadCard(&tmpPos, ptr, len); 216 | 217 | } else if(ndsFileFD!=-1) { //read from ndsfile 218 | 219 | if(ndsFileLastpos!=*npos) 220 | lseek(ndsFileFD, *npos, SEEK_SET); 221 | 222 | len=read(ndsFileFD, ptr, len); 223 | 224 | } else { //reading from gbarom 225 | if (len > 0) memcpy(ptr, *npos+(void*)GBAROM,len); 226 | } 227 | 228 | if(len > 0) 229 | *npos+=len; 230 | 231 | ndsFileLastpos=*npos; //save the current file position 232 | 233 | return(len); 234 | } 235 | 236 | //--------------------------------------------------------------------------------- 237 | static inline void nitroSubSeek(unsigned int *npos, int pos, int dir) { 238 | //--------------------------------------------------------------------------------- 239 | if((dir==SEEK_SET)||(dir==SEEK_END)) //otherwise just set the pos :) 240 | *npos=pos; 241 | else if(dir==SEEK_CUR) 242 | *npos+=pos; 243 | } 244 | 245 | //--------------------------------------------------------------------------------- 246 | // Directory functions 247 | 248 | //--------------------------------------------------------------------------------- 249 | static DIR_ITER* nitroFSDirOpen(struct _reent *r, DIR_ITER *dirState, const char *path) { 250 | //--------------------------------------------------------------------------------- 251 | 252 | struct nitroDIRStruct *dirStruct=(struct nitroDIRStruct*)dirState->dirStruct; 253 | struct stat st; 254 | char dirname[NITRONAMELENMAX]; 255 | char *cptr; 256 | char mydirpath[NITROMAXPATHLEN]; //to hold copy of path string 257 | char *dirpath=mydirpath; 258 | bool pathfound; 259 | 260 | if((cptr=strchr(path,':'))) 261 | path=cptr+1; //move path past any device names 262 | 263 | strncpy(dirpath,path,sizeof(mydirpath)-1); 264 | 265 | dirStruct->pos=0; 266 | 267 | if(*dirpath=='/') //if first character is '/' use absolute root path 268 | dirStruct->cur_dir_id=NITROROOT; //first root dir 269 | else 270 | dirStruct->cur_dir_id=chdirpathid; //else use chdirpath 271 | nitroDirReset(r,dirState); //set dir to current path 272 | 273 | do { 274 | 275 | while( dirpath[0] == '/') dirpath++; // move past leading / 276 | cptr=strchr(dirpath,'/'); 277 | 278 | if(cptr) 279 | *cptr=0; // erase / 280 | 281 | 282 | if(*dirpath==0) { // are we at the end of the path string?? if so there is nothing to search for we're already here ! 283 | pathfound=true; // mostly this handles searches for root or / or no path specified cases 284 | break; 285 | } 286 | pathfound=false; 287 | 288 | while(nitroFSDirNext(r,dirState,dirname,&st)==0) { 289 | 290 | if(S_ISDIR(st.st_mode) && !(strcasecmp(dirname,dirpath))) { //if its a directory and name matches dirpath 291 | dirStruct->cur_dir_id=dirStruct->dir_id; //move us to the next dir in tree 292 | nitroDirReset(r,dirState); //set dir to current path we just found... 293 | pathfound=true; 294 | break; 295 | } 296 | }; 297 | if(!pathfound) 298 | break; 299 | dirpath=cptr+1; //move to right after last / we found 300 | } while(cptr); // go till after the last / 301 | 302 | if(pathfound) { 303 | return(dirState); 304 | } else { 305 | return(NULL); 306 | } 307 | } 308 | 309 | 310 | //--------------------------------------------------------------------------------- 311 | static int nitroFSDirClose(struct _reent *r, DIR_ITER *dirState) { 312 | //--------------------------------------------------------------------------------- 313 | return(0); 314 | } 315 | 316 | /*Consts containing relative system path strings*/ 317 | const char *syspaths[2]={ 318 | ".", 319 | ".." 320 | }; 321 | 322 | //reset dir to start of entry selected by dirStruct->cur_dir_id 323 | //--------------------------------------------------------------------------------- 324 | static int nitroDirReset(struct _reent *r, DIR_ITER *dirState) { 325 | //--------------------------------------------------------------------------------- 326 | struct nitroDIRStruct *dirStruct=(struct nitroDIRStruct*)dirState->dirStruct; 327 | struct ROM_FNTDir dirsubtable; 328 | unsigned int *pos=&dirStruct->pos; 329 | nitroSubSeek(pos,fntOffset+((dirStruct->cur_dir_id&NITRODIRMASK)*sizeof(struct ROM_FNTDir)),SEEK_SET); 330 | nitroSubRead(pos, &dirsubtable, sizeof(dirsubtable)); 331 | dirStruct->namepos=dirsubtable.entry_start; //set namepos to first entry in this dir's table 332 | dirStruct->entry_id=dirsubtable.entry_file_id; //get number of first file ID in this branch 333 | dirStruct->parent_id=dirsubtable.parent_id; //save parent ID 334 | dirStruct->spc=0; //system path counter, first two dirnext's deliver . and .. 335 | return(0); 336 | } 337 | 338 | //--------------------------------------------------------------------------------- 339 | static int nitroFSDirNext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) { 340 | //--------------------------------------------------------------------------------- 341 | unsigned char next; 342 | struct nitroDIRStruct *dirStruct=(struct nitroDIRStruct*)dirState->dirStruct; 343 | unsigned int *pos=&dirStruct->pos; 344 | if(dirStruct->spc<=1) { 345 | if(st) st->st_mode=S_IFDIR; 346 | if((dirStruct->spc==0)||(dirStruct->cur_dir_id==NITROROOT)) { // "." or its already root (no parent) 347 | dirStruct->dir_id=dirStruct->cur_dir_id; 348 | } else { // ".." 349 | dirStruct->dir_id=dirStruct->parent_id; 350 | } 351 | strcpy(filename,syspaths[dirStruct->spc++]); 352 | return(0); 353 | } 354 | nitroSubSeek(pos,fntOffset+dirStruct->namepos,SEEK_SET); 355 | nitroSubRead(pos, &next , sizeof(next)); 356 | // next: high bit 0x80 = entry isdir.. other 7 bits are size, the 16 bits following name are dir's entryid (starts with f000) 357 | // 00 = end of table // 358 | if(next) { 359 | if(next&NITROISDIR) { 360 | if(st) st->st_mode=S_IFDIR; 361 | next&=NITROISDIR^0xff; //invert bits and mask off 0x80 362 | nitroSubRead(pos,filename,next); 363 | nitroSubRead(&dirStruct->pos,&dirStruct->dir_id,sizeof(dirStruct->dir_id)); //read the dir_id 364 | dirStruct->namepos+=next+sizeof(u16)+1; // now we point to next one plus dir_id size 365 | } else { 366 | if(st) st->st_mode=0; 367 | nitroSubRead(pos,filename,next); 368 | dirStruct->namepos+=next+1; //now we point to next one 369 | //read file info to get filesize (and for fileopen) 370 | nitroSubSeek(pos,fatOffset+(dirStruct->entry_id*sizeof(struct ROM_FAT)),SEEK_SET); 371 | nitroSubRead(pos, &dirStruct->romfat, sizeof(dirStruct->romfat)); //retrieve romfat entry (contains filestart and end positions) 372 | dirStruct->entry_id++; //advance ROM_FNTStrFile ptr 373 | if(st) st->st_size=dirStruct->romfat.bottom-dirStruct->romfat.top; //calculate filesize 374 | } 375 | filename[(int)next]=0; //zero last char 376 | return(0); 377 | } else { 378 | return(-1); 379 | } 380 | } 381 | 382 | //--------------------------------------------------------------------------------- 383 | static int nitroFSOpen(struct _reent *r, void *fileStruct, const char *path,int flags,int mode) { 384 | //--------------------------------------------------------------------------------- 385 | struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fileStruct; 386 | struct nitroDIRStruct dirStruct; 387 | DIR_ITER dirState; 388 | dirState.dirStruct=&dirStruct; //create a temp dirstruct 389 | struct _reent dre; 390 | struct stat st; //all these are just used for reading the dir ~_~ 391 | char dirfilename[NITROMAXPATHLEN]; // to hold a full path (i tried to avoid using so much stack but blah :/) 392 | char *filename; // to hold filename 393 | char *cptr; //used to string searching and manipulation 394 | cptr=(char*)path+strlen(path); //find the end... 395 | filename=NULL; 396 | 397 | do { 398 | if((*cptr=='/') || (*cptr==':')) { // split at either / or : (whichever comes first form the end!) 399 | cptr++; 400 | strncpy(dirfilename,path,cptr-path); //copy string up till and including/ or : zero rest 401 | dirfilename[cptr-path]=0; 402 | filename=cptr; //filename = now remainder of string 403 | break; 404 | } 405 | } while(cptr--!=path); //search till start 406 | 407 | if(!filename) { 408 | filename=(char*)path; //filename = complete path 409 | dirfilename[0]=0; //make directory path "" 410 | } 411 | 412 | if(nitroFSDirOpen(&dre,&dirState,dirfilename)) { 413 | 414 | fatStruct->start=0; 415 | 416 | while(nitroFSDirNext(&dre,&dirState, dirfilename, &st)==0) { 417 | 418 | if(!(st.st_mode & S_IFDIR) && (strcasecmp(dirfilename,filename)==0)) { 419 | fatStruct->start=dirStruct.romfat.top; 420 | fatStruct->end=dirStruct.romfat.bottom; 421 | break; 422 | } 423 | 424 | } 425 | 426 | nitroFSDirClose(&dre,&dirState); 427 | 428 | if(fatStruct->start) { 429 | nitroSubSeek(&fatStruct->pos,fatStruct->start,SEEK_SET); //seek to start of file 430 | return(0); //woot! 431 | } 432 | 433 | } 434 | return(-1); 435 | } 436 | 437 | //--------------------------------------------------------------------------------- 438 | static int nitroFSClose(struct _reent *r,void *fd) { 439 | //--------------------------------------------------------------------------------- 440 | return(0); 441 | } 442 | 443 | //--------------------------------------------------------------------------------- 444 | static int nitroFSRead(struct _reent *r,void *fd,char *ptr,size_t len) { 445 | //--------------------------------------------------------------------------------- 446 | struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fd; 447 | unsigned int *npos=&fatStruct->pos; 448 | if(*npos+len > fatStruct->end) 449 | len=fatStruct->end-*npos; //dont read past the end 450 | if(*npos > fatStruct->end) 451 | return(0); //hit eof 452 | return(nitroSubRead(npos,ptr,len)); 453 | } 454 | 455 | //--------------------------------------------------------------------------------- 456 | static off_t nitroFSSeek(struct _reent *r,void *fd,off_t pos,int dir) { 457 | //--------------------------------------------------------------------------------- 458 | //need check for eof here... 459 | struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fd; 460 | unsigned int *npos=&fatStruct->pos; 461 | if(dir==SEEK_SET) 462 | pos+=fatStruct->start; // add start from .nds file offset 463 | else if(dir==SEEK_END) 464 | pos+=fatStruct->end; // set start to end of file 465 | if(pos > fatStruct->end) 466 | return(-1); // dont read past the end 467 | nitroSubSeek(npos,pos,dir); 468 | return(*npos-fatStruct->start); 469 | } 470 | 471 | //--------------------------------------------------------------------------------- 472 | static int nitroFSFstat(struct _reent *r,void *fd,struct stat *st) { 473 | //--------------------------------------------------------------------------------- 474 | struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fd; 475 | st->st_size=fatStruct->end-fatStruct->start; 476 | return(0); 477 | } 478 | 479 | //--------------------------------------------------------------------------------- 480 | static int nitroFSstat(struct _reent *r,const char *file,struct stat *st) { 481 | //--------------------------------------------------------------------------------- 482 | struct nitroFSStruct fatStruct; 483 | struct nitroDIRStruct dirStruct; 484 | DIR_ITER dirState; 485 | 486 | if(nitroFSOpen(NULL, &fatStruct, file, 0, 0)>=0) { 487 | st->st_mode = S_IFREG; 488 | st->st_size=fatStruct.end-fatStruct.start; 489 | return(0); 490 | } 491 | 492 | dirState.dirStruct=&dirStruct; 493 | if(nitroFSOpen(NULL, &fatStruct, file, 0, 0)>=0) { 494 | st->st_mode = S_IFREG; 495 | st->st_size=fatStruct.end-fatStruct.start; 496 | return(0); 497 | } 498 | if((nitroFSDirOpen(r, &dirState, file)!=NULL)) { 499 | 500 | st->st_mode = S_IFDIR; 501 | 502 | nitroFSDirClose(r, &dirState); 503 | return(0); 504 | } 505 | 506 | return(-1); 507 | } 508 | 509 | //--------------------------------------------------------------------------------- 510 | static int nitroFSChdir(struct _reent *r,const char *name) { 511 | //--------------------------------------------------------------------------------- 512 | struct nitroDIRStruct dirStruct; 513 | DIR_ITER dirState; 514 | dirState.dirStruct=&dirStruct; 515 | if((name!=NULL) && (nitroFSDirOpen(r, &dirState, name)!=NULL)) { 516 | chdirpathid=dirStruct.cur_dir_id; 517 | nitroFSDirClose(r, &dirState); 518 | return(0); 519 | } else { 520 | return(-1); 521 | } 522 | } 523 | 524 | --------------------------------------------------------------------------------