mirror of
https://github.com/fail0verflow/mini.git
synced 2024-11-18 09:29:26 +01:00
215 lines
4.2 KiB
C
215 lines
4.2 KiB
C
|
#include "nandfs.h"
|
||
|
#include "nand.h"
|
||
|
#include "gecko.h"
|
||
|
#include "string.h"
|
||
|
|
||
|
#define PAGE_SIZE 2048
|
||
|
|
||
|
struct _nandfs_file_node {
|
||
|
u8 name[NANDFS_NAME_LEN];
|
||
|
u8 attr;
|
||
|
u8 wtf;
|
||
|
union {
|
||
|
u16 first_child;
|
||
|
u16 first_cluster;
|
||
|
};
|
||
|
u16 sibling;
|
||
|
u32 size;
|
||
|
u32 uid;
|
||
|
u16 gid;
|
||
|
u32 dummy;
|
||
|
} __attribute__((packed));
|
||
|
|
||
|
struct _nandfs_sffs {
|
||
|
u8 magic[4];
|
||
|
u32 version;
|
||
|
u32 dummy;
|
||
|
|
||
|
s16 cluster_table[32768];
|
||
|
struct _nandfs_file_node files[6143];
|
||
|
} __attribute__((packed));
|
||
|
|
||
|
static struct _nandfs_sffs sffs __attribute__((aligned(32))) MEM2_BSS;
|
||
|
static u8 buffer[8*2048] __attribute__((aligned(32))) MEM2_BSS;
|
||
|
static s32 initialized = 0;
|
||
|
|
||
|
s32 nandfs_initialize()
|
||
|
{
|
||
|
u32 i;
|
||
|
u32 supercluster = 0;
|
||
|
u32 supercluster_version = 0;
|
||
|
|
||
|
nand_reset();
|
||
|
|
||
|
for(i = 0x7F00; i < 0x7fff; i++) {
|
||
|
nand_read_page(i*8, (void *)&sffs, NULL);
|
||
|
if(memcmp(sffs.magic, "SFFS", 4) != 0)
|
||
|
continue;
|
||
|
if(supercluster == 0 || sffs.version > supercluster_version) {
|
||
|
supercluster = i;
|
||
|
supercluster_version = sffs.version;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if(supercluster == 0) {
|
||
|
gecko_printf("no supercluster found. "
|
||
|
" your nand filesystem is seriously broken...\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
gecko_printf("using supercluster starting at page %08x\n",
|
||
|
supercluster);
|
||
|
|
||
|
for(i = 0; i < sizeof(struct _nandfs_sffs)/(PAGE_SIZE*8);
|
||
|
i++) {
|
||
|
nand_read_cluster(supercluster + i,
|
||
|
((u8 *)&sffs) + (i * PAGE_SIZE * 8));
|
||
|
}
|
||
|
|
||
|
initialized = 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
s32 nandfs_open(struct nandfs_fp *fp, const char *path)
|
||
|
{
|
||
|
char *ptr, *ptr2;
|
||
|
u32 len;
|
||
|
struct _nandfs_file_node *cur = sffs.files;
|
||
|
|
||
|
if (initialized != 1)
|
||
|
return -1;
|
||
|
|
||
|
memset(fp, 0, sizeof(*fp));
|
||
|
|
||
|
if(strcmp(cur->name, "/") != 0) {
|
||
|
gecko_printf("your nandfs is corrupted. fixit!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
cur = &sffs.files[cur->first_child];
|
||
|
|
||
|
ptr = (char *)path;
|
||
|
do {
|
||
|
ptr++;
|
||
|
ptr2 = strchr(ptr, '/');
|
||
|
if (ptr2 == NULL)
|
||
|
len = strlen(ptr);
|
||
|
else {
|
||
|
ptr2++;
|
||
|
len = ptr2 - ptr - 1;
|
||
|
}
|
||
|
if (len > 12)
|
||
|
{
|
||
|
gecko_printf("invalid length: %s %s %s [%d]\n",
|
||
|
ptr, ptr2, path, len);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
gecko_printf("length: %d\n", len);
|
||
|
|
||
|
for (;;) {
|
||
|
int res = strncmp(cur->name, ptr, len);
|
||
|
if(ptr2 != NULL && strncmp(cur->name, ptr, len) == 0
|
||
|
&& strnlen(cur->name, 12) == len
|
||
|
&& (cur->attr&3) == 2
|
||
|
&& (cur->first_child&0xffff) != (s16)0xffff) {
|
||
|
cur = &sffs.files[cur->first_child];
|
||
|
ptr = ptr2-1;
|
||
|
break;
|
||
|
} else if(ptr2 == NULL &&
|
||
|
strncmp(cur->name, ptr, len) == 0 &&
|
||
|
strnlen(cur->name, 12) == len &&
|
||
|
(cur->attr&3) == 1) {
|
||
|
break;
|
||
|
} else if((cur->sibling&0xffff) != 0xffff) {
|
||
|
cur = &sffs.files[cur->sibling];
|
||
|
} else {
|
||
|
gecko_printf("unable to find %s (%s)\n", ptr,
|
||
|
path);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while(ptr2 != NULL);
|
||
|
|
||
|
fp->first_cluster = cur->first_cluster;
|
||
|
fp->cur_cluster = fp->first_cluster;
|
||
|
fp->offset = 0;
|
||
|
fp->size = cur->size;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
s32 nandfs_read(void *ptr, u32 size, u32 nmemb, struct nandfs_fp *fp)
|
||
|
{
|
||
|
u32 total = size*nmemb;
|
||
|
u32 copy_offset, copy_len;
|
||
|
|
||
|
if (initialized != 1)
|
||
|
return -1;
|
||
|
|
||
|
if (fp->offset + total > fp->size)
|
||
|
total = fp->size - fp->offset;
|
||
|
|
||
|
if (total == 0)
|
||
|
return 0;
|
||
|
|
||
|
while(total > 0) {
|
||
|
nand_read_decrypted_cluster(fp->cur_cluster, buffer);
|
||
|
copy_offset = fp->offset % (PAGE_SIZE * 8);
|
||
|
copy_len = (PAGE_SIZE * 8) - copy_offset;
|
||
|
if(copy_len > total)
|
||
|
copy_len = total;
|
||
|
memcpy(ptr, buffer + copy_offset, copy_len);
|
||
|
total -= copy_len;
|
||
|
fp->offset += copy_len;
|
||
|
|
||
|
if ((copy_offset + copy_len) >= (PAGE_SIZE * 8))
|
||
|
fp->cur_cluster = sffs.cluster_table[fp->cur_cluster];
|
||
|
}
|
||
|
|
||
|
return size*nmemb;
|
||
|
}
|
||
|
|
||
|
s32 nandfs_seek(struct nandfs_fp *fp, s32 offset, u32 whence)
|
||
|
{
|
||
|
if (initialized != 1)
|
||
|
return -1;
|
||
|
|
||
|
switch (whence) {
|
||
|
case NANDFS_SEEK_SET:
|
||
|
if (offset > fp->size)
|
||
|
return -1;
|
||
|
if (offset > 0)
|
||
|
return -1;
|
||
|
|
||
|
fp->offset = offset;
|
||
|
break;
|
||
|
|
||
|
case NANDFS_SEEK_CUR:
|
||
|
if ((fp->offset + offset) > fp->size ||
|
||
|
(fp->offset + offset) < 0)
|
||
|
return -1;
|
||
|
fp->offset += offset;
|
||
|
break;
|
||
|
|
||
|
case NANDFS_SEEK_END:
|
||
|
default:
|
||
|
if ((fp->size + offset) > fp->size ||
|
||
|
(fp->size + offset) < 0)
|
||
|
return -1;
|
||
|
fp->offset = fp->size + offset;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
int skip = fp->offset;
|
||
|
fp->cur_cluster = fp->first_cluster;
|
||
|
while (skip > (2048*8)) {
|
||
|
fp->cur_cluster = sffs.cluster_table[fp->cur_cluster];
|
||
|
skip -= 2048*8;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|