📄 filesystem.c
字号:
/* temporary buffer for building sectors (created w/ xalloc() ) */
static long fs_temp_buf;
static unsigned i;
//功能:
unsigned int fs_checksum(char *buf,
unsigned short cnt,
unsigned short seed,
unsigned short old_size);
{
unsigned short crcsum,count,i;
char *pb;
pb = buf;
crcsum = seed;
count = cnt;
if (count==0)
return crcsum;
if ((old_size&0x01)!=0) //old length is odd
{
crcsum+=(*pb<<8;)
count--;
pb++;
}
for (i=0;i<count/2;i++)
{
crcsum+=*((unsigned short*)pb);
pb++; pb++;
}
if (count%2!=0)
crcsum+=*pb;
return crcsum;
}
/* checksum a block actually in the filesystem */
//block:扇区号offset:偏移量 seed 检验和起点 old_size
static unsigned short fs_checksum_far(int block,
int offset, int length, unsigned int seed, unsigned int old_size);
{
}
/* checksum a block actually in the filesystem */
nodebug root unsigned int fs_checksum_far(int block,
int offset, int length, unsigned int seed, unsigned int old_size)
{
auto int savexpc;
auto int checksum;
auto char *data_offset;
#asm
ld a,xpc
bool hl
ld l,a
ld (SP+@SP+savexpc),hl
#endasm
data_offset = fs_block_pushxpc(block);
checksum = fs_checksum(data_offset + offset, length, seed, old_size);
#asm
ld hl,(sp+@SP+savexpc)
ld a,l
ld xpc,a
#endasm
return checksum;
}
/* get a block header, and store it in fs_header */
short fs_get_header(int block, FSHeader *header)
{
fs_block_read(block, 0, (char *)header, FS_HEADER);
return 0;
}
//methods for blocklist and filelist
short fs_filelist_get(FileNumber file)
{
static int first_block;
memcpy(&first_block, fs_filelist + (sizeof(int)*file), sizeof(int));
return first_block;
}
static void fs_filelist_set(FileNumber file, int first_block)
{
memcpy(fs_filelist + (sizeof(int)*file), &first_block, sizeof(int));
}
static void fs_blocklist_get(int block, FSBlockLink *link)
{
memcpy(link, fs_blocklist + (FS_BLOCKLINK*block), FS_BLOCKLINK);
}
static void fs_blocklist_set(int block, FSBlockLink *link)
{
memcpy(fs_blocklist + (FS_BLOCKLINK*block), link, FS_BLOCKLINK);
}
static int fs_get_next_block(int block)
{
static FSBlockLink link;
fs_blocklist_get(block, &link);
return link.next_block;
}
static void fs_table_alloc(int num_blocks)
{
auto int i;
auto FSBlockLink blank_link;
fs_blocklist = xalloc(num_blocks * sizeof(FSBlockLink));
fs_filelist = xalloc(256 * sizeof(int));
blank_link.used = 0;
for(i = 0; i < num_blocks;i++)
{
fs_blocklist_set(i, &blank_link);
}
for(i = 0;i < 256;i++)
{
fs_filelist_set(i, -1);
}
}
/*** BeginHeader fs_build_tables */
void fs_build_tables();
/*** EndHeader */
nodebug void fs_build_tables()
{
auto int i, j;
auto FSBlockLink block_link;
auto FSHeader header;
auto unsigned long sequence;
auto byte filename;
auto int block, next;
fs_blocks_used = 0;
fs_nonpriv_blocks_used = 0;
//scan through the block list;
for(i = 0; i < fs_num_blocks;i++)
{
fs_get_header(i, &header);
if(header.flag == FS_USED)
{
fs_blocks_used++;
if(header.file < 128 || header.file > 143)
fs_nonpriv_blocks_used++;
fs_blocklist_get(i, &block_link);
if(block_link.used == 0)
{
//block for a new file
filename = header.file;
block = i;
sequence = header.seq;
//look for first block for file
for(j = i+1;j != i;j = (j+1)%fs_num_blocks)
{
fs_get_header(j, &header);
if(header.seq < sequence)
{
sequence = header.seq;
block = j;
}
}
//make file list entry
fs_filelist_set(filename, block);
//make block list entries for file
next = 1;
while(next)
{
next = 0;
sequence++;
for(j = 0;j < fs_num_blocks;j++)
{
fs_get_header(j, &header);
if(header.file == filename && header.seq == sequence)
{
block_link.name = filename;
block_link.used = 1;
block_link.next_block = j;
fs_blocklist_set(block, &block_link);
block = j; //new block
next = 1;
break; //start loop over
}
}
}
//last block
block_link.name = filename;
block_link.used = 1;
block_link.next_block = -1;
fs_blocklist_set(block, &block_link);
} //end of if
} //end of if
} //end of block search loop
}
/*** BeginHeader fs_find_average_wear */
unsigned long fs_find_average_wear(void);
/*** EndHeader */
nodebug unsigned long fs_find_average_wear(void)
{
auto int i;
auto unsigned long totalwear;
auto FSHeader header;
totalwear = 0;
for(i=0; i<fs_num_blocks; i++) {
/* get wear of this block */
/* this is very slow - should just go directly to the memory location */
fs_get_header(i, &header);
totalwear += header.wear;
}
return (totalwear / fs_num_blocks);
}
/*** BeginHeader fs_erase_block */
int fs_erase_block(int block, unsigned long wear);
/*** EndHeader */
/* erase a block to given wear level - if 0, use current */
nodebug int fs_erase_block(int block, unsigned long wear)
{
auto unsigned long w;
auto FSBlockLink blank;
auto FSHeader header;
w = wear;
/* get the old wear level? */
if(wear == 0) {
fs_get_header(block, &header);
w = header.wear + 1;
}
memset(&header, 0xfe, FS_HEADER);
#ifdef FS_DEBUG
printf("--> Erasing block <%d> to wearlevel <%ld>...\n", block, w);
#endif
header.flag = FS_FREE;
header.wear = w;
header.fs_version = FS_VERSION;
/* write the new header back out */
fs_block_write(block, (char *)&header, FS_HEADER);
blank.name = 0;
blank.used = 0;
blank.next_block = -1;
fs_blocklist_set(block, &blank);
}
/*** BeginHeader fs_verify_block */
int fs_verify_block(int block);
/*** EndHeader */
/* if a block isn't marked correctly, re-format it */
nodebug int fs_verify_block(int block)
{
auto FSHeader header;
/* retrive the header */
fs_get_header(block, &header); /* this is too slow? */
switch(header.flag) {
case FS_USED:
case FS_FREE:
/* add more fsck type stuff here?
(sanity check the values of the block?) */
return 0;
default:
fs_erase_block(block, fs_find_average_wear());
return 1;
}
}
/*** Beginheader fs_open_common */
int fs_open_common(File *f, FileNumber name);
/*** EndHeader */
nodebug int fs_open_common(File *f, FileNumber name)
{
auto int block, next, num_blocks;
auto FSHeader header;
block = fs_filelist_get(name);
if(block >= 0)
{
/* file exists */
f->name = name;
f->first_block = block;
fs_get_header(block, &header);
f->first_sequence = header.seq;
//find last block
next = fs_get_next_block(block);
num_blocks = 1;
while(next >= 0)
{
block = next;
next = fs_get_next_block(block);
num_blocks++;
}
f->current_block = block;
fs_get_header(block, &header);
f->current_sequence = header.seq;
f->num_blocks = num_blocks;
#ifdef FS_DEBUG
printf("--> open_common: first_block = %d, current_block = %d, num_blocks = %d\n",
f->first_block,f->current_block,num_blocks);
#endif
return 0;
}
else
{
return 1; //file not found
}
}
/*** BeginHeader fs_find_free */
int fs_find_free(void);
/*** EndHeader */
nodebug int fs_find_free(void)
{
auto int i;
auto FSSeq lowest;
auto int block;
auto FSHeader header;
lowest = 0xffffffff;
for(i=0;i<fs_num_blocks;i++) {
fs_get_header(i, &header);
#ifdef FS_DEBUG
//printf("-->\tScanning: block=%d, flag=%x, wear=%lx\n",i,fs_header.flag,fs_header.wear);
#endif
if(header.flag == FS_FREE) {
if(header.wear < lowest) {
lowest = header.wear;
block = i;
}
}
}
if(0xffffffff == lowest)
return FS_NOBLOCK;
#ifdef FS_DEBUG
//printf("--> Found free block <%d>, lowest wearlevel==%d\n",block, lowest);
#endif
return block;
}
/*** BeginHeader fs_find_block */
int fs_find_block(FileNumber name, FSSeq sequence);
/*** EndHeader */
nodebug int fs_find_block(FileNumber name, FSSeq sequence)
{
auto int i, block;
auto FSHeader header;
#ifdef FS_DEBUG
printf("--> Searching for file=%d, seq=%ld\n",name, sequence);
#endif
for(i=0; i<fs_num_blocks; i++) {
fs_get_header(i, &header);
#ifdef FS_DEBUG
//printf("-->\t Searching: block=%d, flag=%d, name=%d, seq=%ld\n",
// i, fs_header.flag, fs_header.file, fs_header.seq);
#endif
if((header.file == name)
&& (header.seq == sequence)
&& (header.flag == FS_USED) ) {
return i;
}
}
return FS_NOBLOCK;
}
/*** BeginHeader fs_verify_version */
int fs_verify_version(int block);
/*** EndHeader */
nodebug int fs_verify_version(int block)
{
static int j;
static unsigned long seq;
static byte ver;
static byte file;
auto int retval;
auto FSHeader header;
retval = 0;
/* look for duplicate blocks */
fs_get_header(block, &header);
if(header.flag != FS_USED)
return retval;
file = header.file;
seq = header.seq;
ver = header.ver;
for(j=(block+1); j<fs_num_blocks; j++) {
fs_get_header(j, &header);
if((file == header.file) && (seq == header.seq)) {
/* matching file and sequence numbers; duplicate block, kill the larger version */
retval = 1;
#ifdef FS_DEBUG
printf("--> Duplicate blocks (%d <-> %d) found (file = %d, seq = %ld)\n",
block, j, file, seq);
#endif
if(ver > header.ver) {
if((ver - header.ver) > 5) { /* arbitrary - 1 would probably do */
#ifdef FS_DEBUG
printf("-->\t\tErasing block %d\n", j);
#endif
fs_erase_block(j, 0);
} else {
#ifdef FS_DEBUG
printf("-->\t\tErasing block %d\n", block);
#endif
fs_erase_block(block, 0);
}
} else {
if((header.ver - ver) > 5) { /* arbitrary - 1 would probably do */
#ifdef FS_DEBUG
printf("-->\t\tErasing block %d\n", block);
#endif
fs_erase_block(block, 0);
} else {
#ifdef FS_DEBUG
printf("-->\t\tErasing block %d\n", j);
#endif
fs_erase_block(j, 0);
}
}
}
}
return retval;
}
/*** BeginHeader fs_block_append */
int fs_block_append(int block, char *data, int len);
/*** EndHeader */
//adds data to a block, returns new block number
nodebug int fs_block_append(int block, char *data, int len)
{
auto int new_block, old_last, start, end;
auto int first_sector, i;
auto FSHeader header, new_block_header;
auto char write_flag;
fs_get_header(block, &header);
if(len > FS_BLOCK_SIZE - header.last_byte)
return -1; //data won't fit
new_block = fs_find_free();
if(new_block == FS_NOBLOCK)
return -1;
//need to get wear level
fs_get_header(new_block, &new_block_header);
old_last = header.last_byte;
header.last_byte += len;
header.ver++;
header.wear = new_block_header.wear + 1;
header.crc = fs_checksum(data, len, header.crc,
old_last - header.first_byte);
first_sector = new_block*((int)FS_BLOCK_SIZE/FS_SECTOR_SIZE);
//write out the sectors
for(i = 0;i < (int)FS_BLOCK_SIZE/FS_SECTOR_SIZE;i++)
{
write_flag = 0;
if(i == 0)
{
//write out header
root2xmem(fs_sectorbuf, &header, FS_HEADER);
write_flag = 1;
}
if(header.first_byte < (i+1)*FS_SECTOR_SIZE &&
old_last > i*FS_SECTOR_SIZE)
{
//copy data from old block
if(header.first_byte > i*FS_SECTOR_SIZE)
start = header.first_byte;
else
start = i*FS_SECTOR_SIZE;
if(old_last < (i+1)*FS_SECTOR_SIZE)
end = old_last;
else
end = (i+1)*FS_SECTOR_SIZE;
fs_block_move(fs_sectorbuf + start - i*FS_SECTOR_SIZE,
block, start, end - start);
write_flag = 1;
}
if(header.last_byte >= i*FS_SECTOR_SIZE &&
old_last < (i+1)*FS_SECTOR_SIZE)
{
//add new data
if(old_last > i*FS_SECTOR_SIZE)
start = old_last;
else
start = i*FS_SECTOR_SIZE;
if(header.last_byte < (i+1)*FS_SECTOR_SIZE)
end = header.last_byte;
else
end = (i+1)*FS_SECTOR_SIZE;
root2xmem(fs_sectorbuf + start - i*FS_SECTOR_SIZE,
data + start - old_last, end - start );
write_flag = 1;
}
if(header.last_byte < i*FS_SECTOR_SIZE)
{
fs_erase_block(block, 0);
return new_block; //nothing more to write
}
if(write_flag)
fs_writesector(first_sector + i, fs_sectorbuf, FS_SECTOR_SIZE);
}
fs_erase_block(block, 0);
return new_block;
}
/*** BeginHeader fs_block_new */
int fs_block_new(FSHeader *header_ptr, char *buf, int len);
/*** EndHeader */
//puts data into a new block
nodebug int fs_block_new(FSHeader *header_ptr, char *buf, int len)
{
auto FSHeader old_header;
auto int first_sector, i, new_block, write_length;
new_block = fs_find_free();
if(new_block == FS_NOBLOCK)
return -1;
first_sector = new_block*((int)FS_BLOCK_SIZE/FS_SECTOR_SIZE);
fs_get_header(new_block, &old_header);
//update wear level
header_ptr->wear = old_header.wear + 1;
header_ptr->crc = fs_checksum(buf, len, 0, 0);
i = 0;
while(len > 0)
{
if(i == 0)
{
//write out header
root2xmem(fs_sectorbuf, header_ptr, FS_HEADER);
len -= FS_SECTOR_SIZE - FS_HEADER;
root2xmem(fs_sectorbuf + FS_HEADER, buf, FS_SECTOR_SIZE - FS_HEADER);
buf += FS_SECTOR_SIZE - FS_HEADER;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -