historical/m0-applesillicon.git/xnu-qemu-arm64-5.1.0/roms/openbios/fs/grubfs/fsys_affs.c
2024-01-16 11:20:27 -06:00

712 lines
17 KiB
C

#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