diff options
Diffstat (limited to 'qemu/roms/openbios/fs/grubfs/fsys_affs.c')
-rw-r--r-- | qemu/roms/openbios/fs/grubfs/fsys_affs.c | 712 |
1 files changed, 712 insertions, 0 deletions
diff --git a/qemu/roms/openbios/fs/grubfs/fsys_affs.c b/qemu/roms/openbios/fs/grubfs/fsys_affs.c new file mode 100644 index 000000000..c4a76322b --- /dev/null +++ b/qemu/roms/openbios/fs/grubfs/fsys_affs.c @@ -0,0 +1,712 @@ +#ifdef FSYS_AFFS +#include "shared.h" +#include "filesys.h" + +/******************************** RDB definitions */ +#define RDB_LOCATION_LIMIT 16 +#define IDNAME_RIGIDDISK 0x5244534B /* 'RDSK' */ + +struct RigidDiskBlock +{ + unsigned long rdb_ID; + unsigned long rdb_SummedLongs; + long rdb_ChkSum; + unsigned long rdb_HostID; + unsigned long rdb_BlockBytes; + unsigned long rdb_Flags; + unsigned long rdb_BadBlockList; + unsigned long rdb_PartitionList; + unsigned long rdb_FileSysHeaderList; + unsigned long rdb_DriveInit; + unsigned long rdb_Reserved1[6]; + unsigned long rdb_Cylinders; + unsigned long rdb_Sectors; + unsigned long rdb_Heads; + unsigned long rdb_Interleave; + unsigned long rdb_Park; + unsigned long rdb_Reserved2[3]; + unsigned long rdb_WritePreComp; + unsigned long rdb_ReducedWrite; + unsigned long rdb_StepRate; + unsigned long rdb_Reserved3[5]; + unsigned long rdb_RDBBlocksLo; + unsigned long rdb_RDBBlocksHi; + unsigned long rdb_LoCylinder; + unsigned long rdb_HiCylinder; + unsigned long rdb_CylBlocks; + unsigned long rdb_AutoParkSeconds; + unsigned long rdb_HighRDSKBlock; + unsigned long rdb_Reserved4; + char rdb_DiskVendor[8]; + char rdb_DiskProduct[16]; + char rdb_DiskRevision[4]; + char rdb_ControllerVendor[8]; + char rdb_ControllerProduct[16]; + char rdb_ControllerRevision[4]; + char rdb_DriveInitName[40]; +}; + +struct PartitionBlock +{ + unsigned long pb_ID; + unsigned long pb_SummedLongs; + long pb_ChkSum; + unsigned long pb_HostID; + unsigned long pb_Next; + unsigned long pb_Flags; + unsigned long pb_Reserved1[2]; + unsigned long pb_DevFlags; + char pb_DriveName[32]; + unsigned long pb_Reserved2[15]; + unsigned long pb_Environment[20]; + unsigned long pb_EReserved[12]; +}; + +#define DE_TABLESIZE 0 +#define DE_SIZEBLOCK 1 +#define DE_BLOCKSIZE 2 +#define DE_NUMHEADS 3 +#define DE_SECSPERBLOCK 4 +#define DE_BLKSPERTRACK 5 +#define DE_RESERVEDBLKS 6 +#define DE_PREFAC 7 +#define DE_INTERLEAVE 8 +#define DE_LOWCYL 9 +#define DE_HIGHCYL 10 +#define DE_UPPERCYL DE_HIGHCYL +#define DE_NUMBUFFERS 11 +#define DE_BUFMEMTYPE 12 +#define DE_MEMBUFTYPE DE_BUFMEMTYPE +#define DE_MAXTRANSFER 13 +#define DE_MASK 14 +#define DE_BOOTPRI 15 +#define DE_DOSTYPE 16 +#define DE_BAUD 17 +#define DE_CONTROL 18 +#define DE_BOOTBLOCKS 19 + + +/******************************** AFFS definitions */ +#define T_SHORT 2 +#define T_LIST 16 + +#define ST_FILE -3 +#define ST_ROOT 1 +#define ST_USERDIR 2 + +struct BootBlock{ + int id; + int chksum; + int rootblock; + int data[127]; +}; + +struct RootBlock{ + int p_type; //0 + int n1[2]; //1-2 + int hashtable_size; //3 + int n2; //4 + int checksum; //5 + int hashtable[72]; //6-77 + int bitmap_valid_flag; //78 + int bitmap_ptrs[25]; //79-103 + int bitmap_extension; //104 + int root_days; //105 + int root_mins; //106 + int root_ticks; //107; + char diskname[32]; //108-115 + int n3[2]; //116-117 + int volume_days; //118 + int volume_mins; //119 + int volume_ticks; //120 + int creation_days; //121 + int creation_mins; //122 + int creation_ticks; //123 + int n4[3]; //124-126 + int s_type; //127 +}; + +struct DirHeader { + int p_type; //0 + int own_key; //1 + int n1[3]; //2-4 + int checksum; //5 + int hashtable[72]; //6-77 + int n2; //78 + int owner; //79 + int protection; //80 + int n3; //81 + char comment[92]; //82-104 + int days; //105 + int mins; //106 + int ticks; //107 + char name[32]; //108-115 + int n4[2]; //116-117 + int linkchain; //118 + int n5[5]; //119-123 + int hashchain; //124 + int parent; //125 + int n6; //126 + int s_type; //127 +}; + +struct FileHeader { + int p_type; //0 + int own_key; //1 + int n1[3]; //2-4 + int checksum; //5 + int filekey_table[72]; //6-77 + int n2; //78 + int owner; //79 + int protection; //80 + int bytesize; //81 + char comment[92]; //82-104 + int days; //105 + int mins; //106 + int ticks; //107 + char name[32]; //108-115 + int n3[2]; //116-117 + int linkchain; //118 + int n4[5]; //119-123 + int hashchain; //124 + int parent; //125 + int extension; //126 + int s_type; //127 +}; + +struct FileKeyExtension{ + int p_type; //0 + int own_key; //1 + int table_size; //2 + int n1[2]; //3-4 + int checksum; //5 + int filekey_table[72]; //6-77 + int info[46]; //78-123 + int n2; //124 + int parent; //125 + int extension; //126 + int s_type; //127 +}; + +struct Position { + unsigned int block; + short filekey; + unsigned short byte; + unsigned int offset; +}; + +struct ReadData { + unsigned int header_block; + struct Position current; + unsigned int filesize; +}; + +//#warning "Big vs. little endian for configure needed" +#define AROS_BE2LONG(l) \ + ( \ + ((((unsigned long)(l)) >> 24) & 0x000000FFUL) | \ + ((((unsigned long)(l)) >> 8) & 0x0000FF00UL) | \ + ((((unsigned long)(l)) << 8) & 0x00FF0000UL) | \ + ((((unsigned long)(l)) << 24) & 0xFF000000UL) \ + ) + +struct CacheBlock { + int blocknum; + unsigned short flags; + unsigned short access_count; + unsigned int blockbuffer[128]; +}; +#define LockBuffer(x) (((struct CacheBlock *)(x))->flags |= 0x0001) +#define UnLockBuffer(x) (((struct CacheBlock *)(x))->flags &= ~0x0001) + +#define MAX_CACHE_BLOCKS 10 + +struct FSysBuffer { + struct ReadData file; + struct CacheBlock blocks[MAX_CACHE_BLOCKS]; +}; + +#define bootBlock(x) ((struct BootBlock *)(x)->blockbuffer) +#define rootBlock(x) ((struct RootBlock *)(x)->blockbuffer) +#define dirHeader(x) ((struct DirHeader *)(x)->blockbuffer) +#define fileHeader(x) ((struct FileHeader *)(x)->blockbuffer) +#define extensionBlock(x) ((struct FileKeyExtension *)(x)->blockbuffer) + +#define rdsk(x) ((struct RigidDiskBlock *)(x)->blockbuffer) +#define part(x) ((struct PartitionBlock *)(x)->blockbuffer) + +static struct FSysBuffer *fsysb; +static int blockoffset; /* offset if there is an embedded RDB partition */ +static int rootb; /* block number of root block */ +static int rdbb; /* block number of rdb block */ + +static void initCache(void) +{ +int i; + + for (i=0;i<MAX_CACHE_BLOCKS;i++) + { + fsysb->blocks[i].blocknum = -1; + fsysb->blocks[i].flags = 0; + fsysb->blocks[i].access_count = 0; + } +} + +static struct CacheBlock *getBlock(unsigned int block) +{ +struct CacheBlock *freeblock; +int i; + + /* get first unlocked block */ + i = 0; + do + { + freeblock = &fsysb->blocks[i++]; + } while (freeblock->flags & 0x0001); + /* search through list if block is already loaded in */ + for (i=0;i<MAX_CACHE_BLOCKS;i++) + { + if (fsysb->blocks[i].blocknum == block) + { + fsysb->blocks[i].access_count++; + return &fsysb->blocks[i]; + } + if (!(fsysb->blocks[i].flags & 0x0001)) + if (freeblock->access_count>fsysb->blocks[i].access_count) + freeblock = &fsysb->blocks[i]; + } + freeblock->blocknum = block; + devread(block+blockoffset, 0, 512, (char *)freeblock->blockbuffer); + return freeblock; +} + +static unsigned int calcChkSum(unsigned short SizeBlock, unsigned int *buffer) +{ +unsigned int sum=0,count=0; + + for (count=0;count<SizeBlock;count++) + sum += AROS_BE2LONG(buffer[count]); + return sum; +} + +int affs_mount(void) { +struct CacheBlock *cblock; +int i; + + if ( + (current_drive & 0x80) && + (current_partition != 0xFFFFFF) && + (current_slice != 0x30) + ) + return 0; + fsysb = (struct FSysBuffer *)FSYS_BUF; + blockoffset = 0; + initCache(); + /* check for rdb partitiontable */ + for (i=0;i<RDB_LOCATION_LIMIT;i++) + { + cblock = getBlock(i); + if ( + ( + ((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFFFFFF00)==0x444F5300) && + ((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFF)>0) + ) || + (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK) + ) + break; + } + if (i == RDB_LOCATION_LIMIT) + return 0; + if (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK) + { + /* we have an RDB partition table within a MBR-Partition */ + rdbb = i; + } + else if (i<2) + { + /* partition type is 0x30 = AROS and AFFS formatted */ + rdbb = RDB_LOCATION_LIMIT; + rootb = (part_length-1+2)/2; + cblock = getBlock(rootb); + if ( + (AROS_BE2LONG(rootBlock(cblock)->p_type) != T_SHORT) || + (AROS_BE2LONG(rootBlock(cblock)->s_type) != ST_ROOT) || + calcChkSum(128, cblock->blockbuffer) + ) + return 0; + } + else + return 0; + return 1; +} + +static int seek(unsigned long offset) +{ +struct CacheBlock *cblock; +unsigned long block; +unsigned long togo; + + block = fsysb->file.header_block; + + togo = offset / 512; + fsysb->file.current.filekey = 71-(togo % 72); + togo /= 72; + fsysb->file.current.byte = offset % 512; + fsysb->file.current.offset = offset; + while ((togo) && (block)) + { + disk_read_func = disk_read_hook; + cblock = getBlock(block); + disk_read_func = NULL; + block = AROS_BE2LONG(extensionBlock(cblock)->extension); + togo--; + } + if (togo) + return 1; + fsysb->file.current.block = block; + return 0; +} + +int affs_read(char *buf, int len) { +struct CacheBlock *cblock; +unsigned short size; +unsigned int readbytes = 0; + + if (fsysb->file.current.offset != filepos) + { + if (seek(filepos)) + return ERR_FILELENGTH; + } + if (fsysb->file.current.block == 0) + return 0; + if (len>(fsysb->file.filesize-fsysb->file.current.offset)) + len=fsysb->file.filesize-fsysb->file.current.offset; + disk_read_func = disk_read_hook; + cblock = getBlock(fsysb->file.current.block); + disk_read_func = NULL; + while (len) + { + disk_read_func = disk_read_hook; + if (fsysb->file.current.filekey<0) + { + fsysb->file.current.filekey = 71; + fsysb->file.current.block = AROS_BE2LONG(extensionBlock(cblock)->extension); + if (fsysb->file.current.block) + { + cblock = getBlock(fsysb->file.current.block); + } + //#warning "else shouldn't occour" + } + size = 512; + size -= fsysb->file.current.byte; + if (size>len) + { + size = len; + devread + ( + AROS_BE2LONG + ( + extensionBlock(cblock)->filekey_table + [fsysb->file.current.filekey] + )+blockoffset, + fsysb->file.current.byte, size, (char *)((long)buf+readbytes) + ); + fsysb->file.current.byte += size; + } + else + { + devread + ( + AROS_BE2LONG + ( + extensionBlock(cblock)->filekey_table + [fsysb->file.current.filekey] + )+blockoffset, + fsysb->file.current.byte, size, (char *)((long)buf+readbytes) + ); + fsysb->file.current.byte = 0; + fsysb->file.current.filekey--; + } + disk_read_func = NULL; + len -= size; + readbytes += size; + } + fsysb->file.current.offset += readbytes; + filepos = fsysb->file.current.offset; + return readbytes; +} + +static unsigned char capitalch(unsigned char ch, unsigned char flags) +{ + + if ((flags==0) || (flags==1)) + return (unsigned char)((ch>='a') && (ch<='z') ? ch-('a'-'A') : ch); + else // DOS\(>=2) + return (unsigned char)(((ch>=224) && (ch<=254) && (ch!=247)) || + ((ch>='a') && (ch<='z')) ? ch-('a'-'A') : ch); +} + +// str2 is a BCPL string +static int noCaseStrCmp(char *str1, char *str2, unsigned char flags) +{ +unsigned char length; + + length=str2++[0]; + do { + if ((*str1==0) && (length==0)) + return 0; + length--; +// if ((*str1==0) && (*str2==0)) return 1; + } while (capitalch(*str1++,flags)==capitalch(*str2++,flags)); + str1--; + return (*str1) ? 1 : -1; +} + +static unsigned int getHashKey(char *name,unsigned int tablesize, unsigned char flags) +{ +unsigned int length; + + length=0; + while (name[length] != 0) + length++; + while (*name!=0) + length=(length * 13 +capitalch(*name++,flags)) & 0x7FF; + return length%tablesize; +} + +static grub_error_t getHeaderBlock(char *name, struct CacheBlock **dirh) +{ +int key; + + key = getHashKey(name, 72, 1); + if (!dirHeader(*dirh)->hashtable[key]) + return ERR_FILE_NOT_FOUND; + *dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashtable[key])); + if (calcChkSum(128, (*dirh)->blockbuffer)) + { +#ifdef DEBUG_AFFS +printf("ghb: %d\n", (*dirh)->blocknum); +#endif + return ERR_FSYS_CORRUPT; + } + if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT) + return ERR_BAD_FILETYPE; + while (noCaseStrCmp(name,dirHeader(*dirh)->name,1) != 0) + { + if (!dirHeader(*dirh)->hashchain) + return ERR_FILE_NOT_FOUND; + *dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashchain)); + if (calcChkSum(128, (*dirh)->blockbuffer)) + { +#ifdef DEBUG_AFFS +printf("ghb2: %d\n", (*dirh)->blocknum); +#endif + return ERR_FSYS_CORRUPT; + } + if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT) + return ERR_BAD_FILETYPE; + } + return 0; +} + +static char *copyPart(char *src, char *dst) +{ + while ((*src != '/') && (*src)) + *dst++ = *src++; + if (*src == '/') + src++; + *dst-- = 0; + /* cut off spaces at the end */ + while (*dst == ' ') + *dst-- = 0; + return src; +} + +static grub_error_t findBlock(char *name, struct CacheBlock **dirh) +{ +char dname[32]; +int block; + + name++; /* skip "/" */ + /* partition table part */ + if (rdbb < RDB_LOCATION_LIMIT) + { + int bpc; + + blockoffset = 0; + *dirh = getBlock(rdbb); + if (*name==0) + return 0; + name = copyPart(name, dname); + bpc = AROS_BE2LONG(rdsk(*dirh)->rdb_Sectors)*AROS_BE2LONG(rdsk(*dirh)->rdb_Heads); + block = AROS_BE2LONG(rdsk(*dirh)->rdb_PartitionList); + while (block != -1) + { + *dirh = getBlock(block); + if (noCaseStrCmp(dname, part(*dirh)->pb_DriveName, 1) == 0) + break; + block = AROS_BE2LONG(part(*dirh)->pb_Next); + } + if (block == -1) + return ERR_FILE_NOT_FOUND; + if ( + ((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFFFFFF00)!=0x444F5300) || + ((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFF)==0) + ) + return ERR_BAD_FILETYPE; + blockoffset = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_LOWCYL]); + rootb = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_HIGHCYL]); + rootb = rootb-blockoffset+1; /* highcyl-lowcyl+1 */ + rootb *= bpc; + rootb = rootb-1+AROS_BE2LONG(part(*dirh)->pb_Environment[DE_RESERVEDBLKS]); + rootb /= 2; + blockoffset *= bpc; + } + + /* filesystem part */ + *dirh = getBlock(rootb); + while (*name) + { + if ( + (AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_ROOT) && + (AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_USERDIR) + ) + return ERR_BAD_FILETYPE; + name = copyPart(name, dname); + errnum = getHeaderBlock(dname, dirh); + if (errnum) + return errnum; + } + return 0; +} + +#ifndef STAGE1_5 +static void checkPossibility(char *filename, char *bstr) +{ + char cstr[32]; + + if (noCaseStrCmp(filename, bstr, 1)<=0) + { + if (print_possibilities>0) + print_possibilities = -print_possibilities; + memcpy(cstr, bstr+1, bstr[0]); + cstr[bstr[0]]=0; + print_a_completion(cstr); + } +} +#else +#define checkPossibility(a, b) do { } while(0) +#endif + +int affs_dir(char *dirname) +{ + struct CacheBlock *buffer1; + struct CacheBlock *buffer2; + char *current = dirname; + char filename[128]; + char *fname = filename; + int i,block; + + if (print_possibilities) + { + while (*current) + current++; + while (*current != '/') + current--; + current++; + while (*current) + { + *fname++ = *current; + *current++ = 0; + } + *fname=0; + errnum = findBlock(dirname, &buffer1); + if (errnum) + return 0; + if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == IDNAME_RIGIDDISK) + { + block = AROS_BE2LONG(rdsk(buffer1)->rdb_PartitionList); + while (block != -1) + { + buffer1 = getBlock(block); + checkPossibility(filename, part(buffer1)->pb_DriveName); + block = AROS_BE2LONG(part(buffer1)->pb_Next); + } +#ifndef STAGE1_5 + if (*filename == 0) + if (print_possibilities>0) + print_possibilities = -print_possibilities; +#endif + } + else if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == T_SHORT) + { + LockBuffer(buffer1); + for (i=0;i<72;i++) + { + block = dirHeader(buffer1)->hashtable[i]; + while (block) + { + buffer2 = getBlock(AROS_BE2LONG(block)); + if (calcChkSum(128, buffer2->blockbuffer)) + { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + if (AROS_BE2LONG(dirHeader(buffer2)->p_type) != T_SHORT) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + checkPossibility(filename, dirHeader(buffer2)->name); + block = dirHeader(buffer2)->hashchain; + } + } + UnLockBuffer(buffer1); +#ifndef STAGE1_5 + if (*filename == 0) + if (print_possibilities>0) + print_possibilities = -print_possibilities; +#endif + } + else + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + while (*current != '/') + current--; + current++; + fname = filename; + while (*fname) + *current++ = *fname++; + //#warning "TODO: add some more chars until possibilities differ" + if (print_possibilities>0) + errnum = ERR_FILE_NOT_FOUND; + return (print_possibilities<0); + } + else + { + while (*current && !isspace(*current)) + *fname++ = *current++; + *fname = 0; + + errnum = findBlock(filename, &buffer2); + if (errnum) + return 0; + if (AROS_BE2LONG(fileHeader(buffer2)->s_type)!=ST_FILE) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + fsysb->file.header_block = AROS_BE2LONG(fileHeader(buffer2)->own_key); + fsysb->file.current.block = AROS_BE2LONG(fileHeader(buffer2)->own_key); + fsysb->file.current.filekey = 71; + fsysb->file.current.byte = 0; + fsysb->file.current.offset = 0; + fsysb->file.filesize = AROS_BE2LONG(fileHeader(buffer2)->bytesize); + filepos = 0; + filemax = fsysb->file.filesize; + return 1; + } +} +#endif |