331 lines
6.9 KiB
C
331 lines
6.9 KiB
C
#include "fat.h"
|
|
#include "string.h"
|
|
#include "stdlib.h"
|
|
#include "lvalloc.h"
|
|
#include "defines.h"
|
|
|
|
fat_t g_fat;
|
|
|
|
void fat_read_cluster(fat_t* fat,u32 clus)
|
|
{
|
|
if(!IS_VALID_FAT(fat)) return;
|
|
|
|
disk_read(fat->disk,fat->datasec+((clus-2)*fat->spc),fat->spc,
|
|
fat->clusbuf);
|
|
}
|
|
|
|
static u32 fat_dir_clus(fat_dir_t* dir)
|
|
{
|
|
return (dir->dir_fstclushi<<16)|dir->dir_fstcluslo;
|
|
}
|
|
|
|
static u32 fat_dir_or_root_clus(fat_t* fat,fat_dir_t* dir)
|
|
{
|
|
if(dir != NULL)
|
|
return fat_dir_clus(dir);
|
|
return fat->rootclus;
|
|
}
|
|
|
|
u32 fat_table_read_entry(fat_t* fat,u32 idx)
|
|
{
|
|
//Do some caching
|
|
u32 clus = idx / fat->fatentperclus;
|
|
u32 offset = idx % fat->fatentperclus;
|
|
|
|
//if(!IS_VALID_FAT(fat)) return 0;
|
|
|
|
//kprintf("entry clus %u offset %u\n",
|
|
// fat->fatsec+(clus*fat->spc),offset);
|
|
if(clus == fat->curfatclus)
|
|
{
|
|
disk_read(fat->disk,fat->fatsec+(clus*fat->spc),fat->spc,fat->fatbuf);
|
|
fat->curfatclus = clus;
|
|
}
|
|
|
|
idx = FAT_CLUSTER(fat->fatbuf[offset]);
|
|
//kprintf("fat->fatbuf[offset] %u\n",idx);
|
|
//kprintf("%p\n",fat->fatbuf);
|
|
return FAT_CLUSTER(fat->fatbuf[offset]);
|
|
//kprintf("fat->fatbuf[offset] %u\n",(u64)FAT_CLUSTER(fat->fatbuf[offset]));
|
|
//return FAT_CLUSTER(fat->fatbuf[offset]);
|
|
}
|
|
|
|
void fat_read_file(fat_t* fat,fat_dir_t* file,u8* __virt buf)
|
|
{
|
|
if(!IS_VALID_FAT(fat)) return;
|
|
|
|
u32 clus = fat_dir_clus(file);
|
|
u32 size = file->dir_filesize;
|
|
u32 csize = fat->bps*fat->spc;
|
|
do {
|
|
u32 _size = MIN(size,csize);
|
|
|
|
fat_read_cluster(fat,clus);
|
|
kmemcpy(buf,fat->clusbuf,_size);
|
|
buf += _size;
|
|
size -= _size;
|
|
|
|
clus = fat_table_read_entry(fat,clus);
|
|
} while(!IS_FAT_CLUS_EOF(clus));
|
|
}
|
|
|
|
void fat_nametofmt38(const char* name,char* out)
|
|
{
|
|
char* d = out;
|
|
const char* s = name;
|
|
size_t slen = kstrlen(name);
|
|
|
|
for(u64 i = 0; i < 11; i++)
|
|
out[i] = ' ';
|
|
while(*s != '.' && (size_t)(d-out) < slen)
|
|
*d++ = ktoupper(*s++);
|
|
if((d-out) == 11) return;
|
|
d = &out[8];
|
|
s++;
|
|
for(u64 i = 0; i < 3 && *s; i++)
|
|
*d++ = ktoupper(*s++);
|
|
}
|
|
|
|
void fat_fmt38toname(const char* name,char* out)
|
|
{
|
|
char* d = out;
|
|
const char* s = name;
|
|
|
|
for(u64 i = 0; *s != ' ' && i < 11; i++)
|
|
*d++ = *s++;
|
|
if(name[8] != ' ' || name[9] != ' ' || name[10] != ' ')
|
|
{
|
|
*d++ = '.';
|
|
s = &name[8];
|
|
for(u64 i = 0; i < 3 && *s != ' '; i++)
|
|
*d++ = *s++;
|
|
}
|
|
*d++ = '\0';
|
|
}
|
|
|
|
int fat_is_valid_file(fat_dir_t* file)
|
|
{
|
|
if(file->dir_name[0] != 0 && file->dir_name[0] != (char)0xE5
|
|
&& file->dir_attr != FAT_ATTR_LONG_NAME
|
|
&& file->dir_attr != FAT_ATTR_VOLUME_ID)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
u64 fat_first_file(fat_t* fat,fat_dir_t* parent,fat_dir_t* file,
|
|
char* longname)
|
|
{
|
|
char* d;
|
|
int load_long = 1;
|
|
|
|
u32 dir_clus = fat_dir_or_root_clus(fat,parent);
|
|
do {
|
|
fat_read_cluster(fat,dir_clus);
|
|
for(u32 i = 0; i < fat->dirsperclus; i++)
|
|
{
|
|
union {
|
|
fat_dir_t* file;
|
|
fat_ldir_t* ldir;
|
|
} tmp;
|
|
tmp.file = &((fat_dir_t*)fat->clusbuf)[i];
|
|
if(tmp.ldir->ldir_attr == FAT_ATTR_LONG_NAME && load_long)
|
|
{
|
|
if(IS_FAT_LDIR_LAST(tmp.ldir->ldir_ord))
|
|
{
|
|
tmp.ldir->ldir_ord &= ~(1<<6);
|
|
load_long = 0;
|
|
}
|
|
d = longname+(13*(tmp.ldir->ldir_ord-1));
|
|
for(u32 j = 0; j < 5; j++)
|
|
{
|
|
if(tmp.ldir->ldir_name1[j] == 0xFFFF)
|
|
{
|
|
load_long = 0;
|
|
continue;
|
|
}
|
|
*d++ = DBCS2SBCS(tmp.ldir->ldir_name1[j]);
|
|
}
|
|
for(u32 j = 0; j < 6; j++)
|
|
{
|
|
if(tmp.ldir->ldir_name2[j] == 0xFFFF)
|
|
{
|
|
load_long = 0;
|
|
continue;
|
|
}
|
|
*d++ = DBCS2SBCS(tmp.ldir->ldir_name2[j]);
|
|
}
|
|
for(u32 j = 0; j < 2; j++)
|
|
{
|
|
if(tmp.ldir->ldir_name3[j] == 0xFFFF)
|
|
{
|
|
load_long = 0;
|
|
continue;
|
|
}
|
|
*d++ = DBCS2SBCS(tmp.ldir->ldir_name3[j]);
|
|
}
|
|
}
|
|
else if(fat_is_valid_file(tmp.file))
|
|
{
|
|
kmemcpy(file,tmp.file,sizeof(fat_dir_t));
|
|
return ((u64)dir_clus<<32)|(i+1);
|
|
}
|
|
}
|
|
|
|
dir_clus = fat_table_read_entry(fat,dir_clus);
|
|
} while(!IS_FAT_CLUS_EOF(dir_clus));
|
|
return 0;
|
|
}
|
|
|
|
u64 fat_next_file(fat_t* fat,u64 val,fat_dir_t* file,char* longname)
|
|
{
|
|
char* d;
|
|
int load_long = 1;
|
|
|
|
u32 dir_clus = val>>32;
|
|
u32 offset = val&0xFFFFFFFF;
|
|
if(offset == fat->dirsperclus)
|
|
{
|
|
offset = 0;
|
|
dir_clus = fat_table_read_entry(fat,dir_clus);
|
|
}
|
|
|
|
while(!IS_FAT_CLUS_EOF(dir_clus))
|
|
{
|
|
u32 i = 0;
|
|
if(offset)
|
|
{
|
|
i = offset;
|
|
offset = 0;
|
|
}
|
|
|
|
fat_read_cluster(fat,dir_clus);
|
|
for(;i < fat->dirsperclus; i++)
|
|
{
|
|
union {
|
|
fat_dir_t* file;
|
|
fat_ldir_t* ldir;
|
|
} tmp;
|
|
tmp.file = &((fat_dir_t*)fat->clusbuf)[i];
|
|
if(tmp.ldir->ldir_attr == FAT_ATTR_LONG_NAME && load_long)
|
|
{
|
|
if(IS_FAT_LDIR_LAST(tmp.ldir->ldir_ord))
|
|
{
|
|
tmp.ldir->ldir_ord &= ~(1<<6);
|
|
load_long = 0;
|
|
}
|
|
d = longname+(13*(tmp.ldir->ldir_ord-1));
|
|
for(u32 j = 0; j < 5; j++)
|
|
{
|
|
if(tmp.ldir->ldir_name1[j] == 0xFFFF)
|
|
{
|
|
load_long = 0;
|
|
continue;
|
|
}
|
|
*d++ = DBCS2SBCS(tmp.ldir->ldir_name1[j]);
|
|
}
|
|
for(u32 j = 0; j < 6; j++)
|
|
{
|
|
if(tmp.ldir->ldir_name2[j] == 0xFFFF)
|
|
{
|
|
load_long = 0;
|
|
continue;
|
|
}
|
|
*d++ = DBCS2SBCS(tmp.ldir->ldir_name2[j]);
|
|
}
|
|
for(u32 j = 0; j < 2; j++)
|
|
{
|
|
if(tmp.ldir->ldir_name3[j] == 0xFFFF)
|
|
{
|
|
load_long = 0;
|
|
continue;
|
|
}
|
|
*d++ = DBCS2SBCS(tmp.ldir->ldir_name3[j]);
|
|
}
|
|
}
|
|
else if(fat_is_valid_file(tmp.file))
|
|
{
|
|
kmemcpy(file,tmp.file,sizeof(fat_dir_t));
|
|
return ((u64)dir_clus<<32)|(i+1);
|
|
}
|
|
}
|
|
|
|
dir_clus = fat_table_read_entry(fat,dir_clus);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int fat_find_file(fat_t* fat,fat_dir_t* parent,char* name,
|
|
fat_dir_t* out)
|
|
{
|
|
u64 handle;
|
|
fat_dir_t file;
|
|
char longname[256];
|
|
char name38[11];
|
|
if(!IS_VALID_FAT(fat)) return 0;
|
|
fat_nametofmt38(name,name38);
|
|
|
|
kmemzero(longname,sizeof(longname));
|
|
handle = fat_first_file(fat,parent,&file,longname);
|
|
if(handle)
|
|
{
|
|
do {
|
|
if(*longname != '\0')
|
|
{
|
|
if(!kstrcmp(longname,name))
|
|
{
|
|
kmemcpy(out,&file,sizeof(fat_dir_t));
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!kmemcmp(file.dir_name,name38,11))
|
|
{
|
|
kmemcpy(out,&file,sizeof(fat_dir_t));
|
|
return 1;
|
|
}
|
|
}
|
|
kmemzero(longname,sizeof(longname));
|
|
} while((handle = fat_next_file(fat,handle,&file,longname)));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void fat_init(fat_t* fat,disk_t* disk)
|
|
{
|
|
fat->disk = disk;
|
|
fat->secbuf = (u8*)lvalloc(4096);
|
|
|
|
if(disk_read(fat->disk,0,1,fat->secbuf))
|
|
{
|
|
kprintf("Failed to init fat!\n");
|
|
fat->disk = NULL;
|
|
return;
|
|
}
|
|
|
|
fat->bps = *(u16*)(&fat->secbuf[11]);
|
|
fat->spc = *(u8*)(&fat->secbuf[13]);
|
|
fat->rsvdsec = *(u16*)(&fat->secbuf[14]);
|
|
fat->fatnum = *(u8*)(&fat->secbuf[16]);
|
|
|
|
fat->rootentcnt = *(u16*)(&fat->secbuf[17]);
|
|
fat->totsec = *(u32*)(&fat->secbuf[32]);
|
|
fat->fatsz = *(u32*)(&fat->secbuf[36]);
|
|
fat->rootclus = *(u32*)(&fat->secbuf[44]);
|
|
|
|
fat->clusbuf = (u8*)lvalloc(fat->spc*fat->bps);
|
|
fat->fatbuf = (u32*)lvalloc(fat->spc*fat->bps);
|
|
|
|
fat->fatsec = fat->rsvdsec;
|
|
fat->datasec = fat->fatsec+(fat->fatsz*fat->fatnum);
|
|
|
|
fat->fatentperclus = (fat->bps>>2)*fat->spc;
|
|
fat->dirsperclus = (fat->bps>>5)*fat->spc;
|
|
|
|
fat->cursec = 0;
|
|
fat->curclus = 0;
|
|
fat->curfatclus = 0;
|
|
}
|