9boot: added support for fragmented files and FAT32
This commit is contained in:
parent
1cd8b4c9b4
commit
ca37b188d2
1 changed files with 180 additions and 55 deletions
|
@ -1,20 +1,42 @@
|
|||
#include <u.h>
|
||||
#include "fns.h"
|
||||
|
||||
#define GETSHORT(p) (*(ushort *)(p))
|
||||
#define GETLONG(p) (*(uint *)(p))
|
||||
|
||||
enum {
|
||||
Sectsz = 0x200,
|
||||
Dirsz = 0x20,
|
||||
Maxpath = 64,
|
||||
Fat12 = 1,
|
||||
Fat16 = 2,
|
||||
Fat32 = 4,
|
||||
};
|
||||
|
||||
typedef struct Extend Extend;
|
||||
typedef struct Dir Dir;
|
||||
typedef struct Pbs Pbs;
|
||||
typedef struct Fat Fat;
|
||||
|
||||
struct Fat
|
||||
{
|
||||
ulong ver;
|
||||
int drive;
|
||||
ulong clustsize;
|
||||
ulong eofmark;
|
||||
ulong partlba;
|
||||
ulong fatlba;
|
||||
ulong dirstart; /* LBA for FAT16, cluster for FAT32 */
|
||||
ulong dirents;
|
||||
ulong datalba;
|
||||
};
|
||||
|
||||
struct Extend
|
||||
{
|
||||
int drive;
|
||||
Fat *fat;
|
||||
ulong lba;
|
||||
ulong clust;
|
||||
ulong lbaoff;
|
||||
ulong len;
|
||||
uchar *rp;
|
||||
uchar *ep;
|
||||
|
@ -53,12 +75,34 @@ struct Pbs
|
|||
uchar nheads[2];
|
||||
uchar nhidden[4];
|
||||
uchar bigvolsize[4];
|
||||
uchar driveno;
|
||||
uchar reserved0;
|
||||
uchar bootsig;
|
||||
uchar volid[4];
|
||||
uchar label[11];
|
||||
uchar type[8];
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uchar driveno;
|
||||
uchar reserved0;
|
||||
uchar bootsig;
|
||||
uchar volid[4];
|
||||
uchar label[11];
|
||||
uchar type[8];
|
||||
} fat16;
|
||||
struct
|
||||
{
|
||||
uchar fatsize[4];
|
||||
uchar flags[2];
|
||||
uchar ver[2];
|
||||
uchar rootclust[4];
|
||||
uchar fsinfo[2];
|
||||
uchar bootbak[2];
|
||||
uchar reserved0[12];
|
||||
uchar driveno;
|
||||
uchar reserved1;
|
||||
uchar bootsig;
|
||||
uchar volid[4];
|
||||
uchar label[11];
|
||||
uchar type[8];
|
||||
} fat32;
|
||||
};
|
||||
};
|
||||
|
||||
int readsect(ulong drive, ulong lba, void *buf);
|
||||
|
@ -68,14 +112,47 @@ unload(void)
|
|||
{
|
||||
}
|
||||
|
||||
static ulong
|
||||
readnext(Extend *ex, ulong clust)
|
||||
{
|
||||
Fat *fat = ex->fat;
|
||||
uint b = fat->ver;
|
||||
ulong sect, off;
|
||||
|
||||
sect = clust * b / Sectsz;
|
||||
off = clust * b % Sectsz;
|
||||
if(readsect(fat->drive, fat->fatlba + sect, ex->buf))
|
||||
memset(ex->buf, 0xff, 4);
|
||||
switch(fat->ver){
|
||||
case Fat16:
|
||||
return GETSHORT(&ex->buf[off]);
|
||||
case Fat32:
|
||||
return GETLONG(&ex->buf[off])& 0x0fffffff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
read(void *f, void *data, int len)
|
||||
{
|
||||
Extend *ex = f;
|
||||
Fat *fat = ex->fat;
|
||||
|
||||
if(ex->len > 0 && ex->rp >= ex->ep)
|
||||
if(readsect(ex->drive, ex->lba++, ex->rp = ex->buf))
|
||||
if(ex->len > 0 && ex->rp >= ex->ep){
|
||||
if(ex->clust != ~0U){
|
||||
if(ex->lbaoff % fat->clustsize == 0){
|
||||
if((ex->clust >> 4) == fat->eofmark)
|
||||
return -1;
|
||||
ex->lbaoff = (ex->clust - 2) * fat->clustsize;
|
||||
putc('.');
|
||||
ex->clust = readnext(ex, ex->clust);
|
||||
ex->lba = ex->lbaoff + fat->datalba;
|
||||
}
|
||||
ex->lbaoff++;
|
||||
}
|
||||
if(readsect(fat->drive, ex->lba++, ex->rp = ex->buf))
|
||||
return -1;
|
||||
}
|
||||
if(ex->len < len)
|
||||
len = ex->len;
|
||||
if(len > (ex->ep - ex->rp))
|
||||
|
@ -87,42 +164,21 @@ read(void *f, void *data, int len)
|
|||
}
|
||||
|
||||
void
|
||||
close(void *f)
|
||||
open(Fat *fat, void *f, ulong lba)
|
||||
{
|
||||
Extend *ex = f;
|
||||
|
||||
ex->drive = 0;
|
||||
ex->lba = 0;
|
||||
ex->fat = fat;
|
||||
ex->lba = lba;
|
||||
ex->len = 0;
|
||||
ex->lbaoff = 0;
|
||||
ex->clust = ~0U;
|
||||
ex->rp = ex->ep = ex->buf + Sectsz;
|
||||
}
|
||||
|
||||
static ulong
|
||||
rootlba(Extend *fat)
|
||||
void
|
||||
close(void *)
|
||||
{
|
||||
ulong lba;
|
||||
Pbs *p = (Pbs*)fat->buf;
|
||||
|
||||
lba = fat->lba;
|
||||
lba += *((ushort*)p->nreserv);
|
||||
lba += *((ushort*)p->fatsize) * p->nfats;
|
||||
return lba;
|
||||
}
|
||||
|
||||
static ulong
|
||||
dirlba(Extend *fat, Dir *d)
|
||||
{
|
||||
ulong clust;
|
||||
ulong dirs;
|
||||
ulong lba;
|
||||
Pbs *p = (Pbs*)fat->buf;
|
||||
|
||||
lba = rootlba(fat);
|
||||
dirs = *((ushort*)p->rootsize);
|
||||
lba += (dirs * Dirsz + Sectsz-1) / Sectsz;
|
||||
clust = *((ushort*)d->starthi)<<16 | *((ushort*)d->startlo);
|
||||
lba += (clust - 2) * p->clustsize;
|
||||
return lba;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -155,18 +211,27 @@ dirname(Dir *d, char buf[Maxpath])
|
|||
return x - buf;
|
||||
}
|
||||
|
||||
static ulong
|
||||
dirclust(Dir *d)
|
||||
{
|
||||
return *((ushort*)d->starthi)<<16 | *((ushort*)d->startlo);
|
||||
}
|
||||
|
||||
static int
|
||||
fatwalk(Extend *ex, Extend *fat, char *path)
|
||||
fatwalk(Extend *ex, Fat *fat, char *path)
|
||||
{
|
||||
char name[Maxpath], *end;
|
||||
Pbs *pbs = (Pbs*)fat->buf;
|
||||
int i, j;
|
||||
Dir d;
|
||||
|
||||
close(ex);
|
||||
ex->drive = fat->drive;
|
||||
ex->lba = rootlba(fat);
|
||||
ex->len = *((ushort*)pbs->rootsize) * Dirsz;
|
||||
if(fat->ver == Fat32){
|
||||
open(fat, ex, 0);
|
||||
ex->clust = fat->dirstart;
|
||||
ex->len = ~0U;
|
||||
}else{
|
||||
open(fat, ex, fat->dirstart);
|
||||
ex->len = fat->dirents * Dirsz;
|
||||
}
|
||||
for(;;){
|
||||
if(readn(ex, &d, Dirsz) != Dirsz)
|
||||
break;
|
||||
|
@ -178,25 +243,81 @@ fatwalk(Extend *ex, Extend *fat, char *path)
|
|||
end = path + strlen(path);
|
||||
j = end - path;
|
||||
if(i == j && memcmp(name, path, j) == 0){
|
||||
ex->rp = ex->ep;
|
||||
ex->lba = dirlba(fat, &d);
|
||||
open(fat, ex, 0);
|
||||
ex->clust = dirclust(&d);
|
||||
ex->len = *((ulong*)d.len);
|
||||
if(*end == 0)
|
||||
return 0;
|
||||
else if(d.attr & 0x10){
|
||||
ex->len = pbs->clustsize * Sectsz;
|
||||
ex->len = fat->clustsize * Sectsz;
|
||||
path = end;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(ex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
findfat(Extend *fat, int drive)
|
||||
conffat(Fat *fat, void *buf)
|
||||
{
|
||||
Pbs *p = buf;
|
||||
uint fatsize, volsize, datasize, reserved;
|
||||
uint ver, dirsize, dirents, clusters;
|
||||
|
||||
/* sanity check */
|
||||
if(GETSHORT(p->sectsize) != Sectsz){
|
||||
print("sectsize != 512\r\n");
|
||||
halt();
|
||||
}
|
||||
|
||||
/* load values from fat */
|
||||
fatsize = GETSHORT(p->fatsize);
|
||||
if(fatsize == 0)
|
||||
fatsize = GETLONG(p->fat32.fatsize);
|
||||
volsize = GETSHORT(p->volsize);
|
||||
if(volsize == 0)
|
||||
volsize = GETLONG(p->bigvolsize);
|
||||
reserved = GETSHORT(p->nreserv);
|
||||
dirents = GETSHORT(p->rootsize);
|
||||
dirsize = (dirents * Dirsz + Sectsz - 1) / Sectsz;
|
||||
datasize = volsize - (reserved + fatsize * p->nfats + dirsize);
|
||||
clusters = datasize / p->clustsize;
|
||||
|
||||
/* determine fat type */
|
||||
if(clusters < 4085)
|
||||
ver = Fat12;
|
||||
else if(clusters < 65525)
|
||||
ver = Fat16;
|
||||
else
|
||||
ver = Fat32;
|
||||
|
||||
/* another check */
|
||||
if(ver == Fat12){
|
||||
print("TODO: implement FAT12\r\n");
|
||||
halt();
|
||||
}
|
||||
|
||||
/* fill FAT descriptor */
|
||||
fat->ver = ver;
|
||||
fat->dirents = dirents;
|
||||
fat->clustsize = p->clustsize;
|
||||
fat->fatlba = fat->partlba + reserved;
|
||||
fat->dirstart = fat->fatlba + fatsize * p->nfats;
|
||||
if(ver == Fat32){
|
||||
fat->datalba = fat->dirstart;
|
||||
fat->dirstart = GETLONG(p->fat32.rootclust);
|
||||
fat->eofmark = 0xffffff;
|
||||
}else{
|
||||
fat->datalba = fat->dirstart + dirsize;
|
||||
fat->eofmark = 0xfff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
findfat(Fat *fat, int drive)
|
||||
{
|
||||
struct {
|
||||
uchar status;
|
||||
|
@ -206,20 +327,22 @@ findfat(Extend *fat, int drive)
|
|||
uchar lba[4];
|
||||
uchar len[4];
|
||||
} *p;
|
||||
uchar buf[Sectsz];
|
||||
int i;
|
||||
|
||||
if(readsect(drive, 0, fat->buf))
|
||||
if(readsect(drive, 0, buf))
|
||||
return -1;
|
||||
if(fat->buf[0x1fe] != 0x55 || fat->buf[0x1ff] != 0xAA)
|
||||
if(buf[0x1fe] != 0x55 || buf[0x1ff] != 0xAA)
|
||||
return -1;
|
||||
p = (void*)&fat->buf[0x1be];
|
||||
p = (void*)&buf[0x1be];
|
||||
for(i=0; i<4; i++){
|
||||
if(p[i].status != 0x80)
|
||||
continue;
|
||||
close(fat);
|
||||
fat->drive = drive;
|
||||
fat->lba = *((ulong*)p[i].lba);
|
||||
if(readsect(drive, fat->lba, fat->buf))
|
||||
fat->partlba = *((ulong*)p[i].lba);
|
||||
if(readsect(drive, fat->partlba, buf))
|
||||
continue;
|
||||
if(conffat(fat, buf))
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
|
@ -231,12 +354,14 @@ start(void *sp)
|
|||
{
|
||||
char path[Maxpath], *kern;
|
||||
int drive;
|
||||
Extend fat, ex;
|
||||
Extend ex;
|
||||
Fat fat;
|
||||
void *f;
|
||||
|
||||
/* drive passed in DL */
|
||||
drive = ((ushort*)sp)[5] & 0xFF;
|
||||
|
||||
print("9bootfat\r\n");
|
||||
if(findfat(&fat, drive)){
|
||||
print("no fat\r\n");
|
||||
halt();
|
||||
|
|
Loading…
Reference in a new issue