#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;iblocks[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;iblocks[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;countid) & 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