/*
 * mkfs.c
 *
 * Copyright 2002, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * オリジナルファイルシステムを構築する。
 */


#include"types.h"
#include"lib.h"
#include"device.h"
#include"time.h"
#include"orig_fs.h"


typedef int (*IOFUNC)(void*,size_t,size_t);


/*
 * parameters : device name
 */
int mk_orig_fs(const char *device)
{
	enum{DEV_NAME_SIZE=5};	/* "/dev/"のサイズ */

	void *buf;
	int din;
	int secters;
	uint begin,last;
	uint root_blk;
	SUPER_BLOCK *sblk;
	EMPTY *empty;
	DIR *dir;
	IOFUNC read,write;
	TIME tm;
	uint i,j,k,end;


	/* Device open */
	if(cmp_path("/dev/",device)==-1)return -1;
	if((din=(int)fs_info[0]->open(device+DEV_NAME_SIZE,NULL,0))==-1)return -1;
	begin=dinode[din].begin_blk;
	last=dinode[din].last_blk;
	secters=BLOCK_SIZE/dinode[din].dev->secter_size;
	read=dinode[din].dev->read;
	write=dinode[din].dev->write;
	if((buf=kmalloc(BLOCK_SIZE))==NULL)return -1;

	/* スーパーブロックの設定 */
	sblk=(SUPER_BLOCK*)buf;
	sblk->all_blk=(last-begin+1)/secters;
	sblk->useable_blk=sblk->all_blk-1;		/* マイナススーパーブロック分 */
	sblk->begin_blk=0;
	sblk->magic_number=SBLOCK_MAGIC;
	if((sblk->empty_blk=EMPTY_BLOCK_NUM*secters+begin)>last)
		sblk->empty_blk=ROUNDDOWN(last+1,secters)-secters;
	if(write(buf,secters-SBLOCK_SECTER,SBLOCK_SECTER)!=secters-SBLOCK_SECTER)goto ERR;

	/* 空きブロックインデックスの設定 */
	empty=(EMPTY*)buf;

	for(i=sblk->empty_blk+secters;;)
	{
		k=i-secters;
		for(j=0;j<EMPTY_BLOCK_NUM;++j)
		{
			empty->block[j]=k;
			k-=secters;
		}
		empty->current=EMPTY_BLOCK_NUM-1;

		if((i+=EMPTY_BLOCK_NUM*secters)>=last)break;

		empty->next=i-secters;
		if(write(buf,secters,i-EMPTY_BLOCK_NUM*secters-secters)!=secters)goto ERR;
	}
	empty->next=ROUNDDOWN(last+1,secters)-secters;
	if(write(buf,secters,i-EMPTY_BLOCK_NUM*secters-secters)!=secters)goto ERR;
	k=empty->next;
	end=(k-empty->block[0])/secters;
	for(j=0;j<end;++j)
	{
		empty->block[j]=k;
		k-=secters;
	}
	empty->current=end-1;

	/* root directory ブロックを探す */
	if(read(buf,secters,SBLOCK_SECTER+begin)!=secters)goto ERR;
	sblk=(SUPER_BLOCK*)buf;
	i=sblk->empty_blk;
	if(read(buf,secters,i)!=secters)goto ERR;
	empty=(EMPTY*)buf;
	root_blk=empty->block[empty->current];
	--empty->current;
	if(write(buf,secters,i)!=secters)goto ERR;

	/* root directory の設定 */
	dir=(DIR*)buf;
	get_current_time(&tm);
	dir->access_time=
		((uint64)tm.year_high<<48)+((uint64)tm.year_low<<40)+((uint64)tm.month<<32)+
		((uint64)tm.day<<24)+((uint64)tm.hour<<16)+((uint64)tm.minute<<8)+tm.second;
	dir=(DIR*)buf;
	dir->file_type=DIRECTORY;
	dir->owner_id=0;			/* 未設定 */
	dir->group_id=0;			/* 未設定 */
	dir->size=BLOCK_SIZE;
	dir->create_time=dir->access_time;
	dir->modificat_time=dir->access_time;
	dir->my_block=root_blk;
	dir->next_blk=0;
	dir->empty=sizeof(DIR);
	memset(dir->hash,0,DIR_ENT_NUM);

	if(write(buf,secters,root_blk)!=secters)goto ERR;

	kfree(buf);

	return 0;

ERR:
	kfree(buf);

	return -1;
}
