summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/fs/grubfs/fsys_affs.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/fs/grubfs/fsys_affs.c')
-rw-r--r--qemu/roms/openbios/fs/grubfs/fsys_affs.c712
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