⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 filesystem.c

📁 支持nvram盘
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 + -