view src/fs.c @ 69:19000e354e36

Start working on redoing the error codes
author Jonathan Pevarnek <pevarnj@gmail.com>
date Sun, 24 Apr 2011 18:28:12 -0400
parents 406b6e8ec54f
children 3b73044b740f
line wrap: on
line source

#include <fs.h>
#include <std.h>
#include <tod.h>
#include <error.h>

static u32 setTod(Inode *inPtr);
static u32 getCacheLoc(u32 blkno);
static u32 cacheAdd(u32 blkno);
static int setFileSize(u32 fid, size_t size);
static int setBlockAt(u32 block, short isBlock);
static void* readFSBlock(u32 blkno);
static u32 getBlockData(u32 blkno, void* ptr);
static int writeFSBlock(u32 blkno, void *ptr);
static int sync(u32 blkno);

static u32 DevID;
static u32 CacheCap; //how many blocks the cache can hold
static u32 CacheSize; //the current number of elts in the cache
static FSBlk *FS_Cache = NULL; //A pointer to the actual cache
static u32 *CacheLocs; //what location each block points to
static u32 CacheNext; //the next location to toss a cached block into
static u32 rootLoc;

ErrCode init_fs(u32 devnum, u64 __memsize)
{
	//Create the cache
	CacheCap = ((__memsize/100)/FSBLKSIZE)*CACHESPACE;
	//number of blocks to store in the cache
	FS_Cache = malloc(CacheCap*FSBLKSIZE);
	if(!FS_Cache) return mkError(MODFS, ALLOCFAIL, ERROR);
	CacheLocs = malloc(CacheCap);
	if(!CacheLocs) return mkError(MODFS, ALLOCFAIL, ERROR);
	CacheSize = 0;
	CacheNext = 0;

	DevID = find_dev(0x100);
	Superblock *sb;
	sb = readFSBlock(1);
	if(!sb) return -1;
	if(sb->magic != 0x42420374) return mkError(MODFS, NOMAGIC, ERROR);
	rootLoc = sb->root_inode;

	return notError(MODFS);
}

ErrCode getFInfo(u32 n, void* de)
{
	Inode *root = readFSBlock(rootLoc);
	if(!root) return mkError(MODFS, BLKREADFAIL, ERROR);
	if(n >= root->size/DEPBLK) return mkError(MODFS, OUTOFRANGE, WARN);
	Direntry *dp = readFSBlock(root->blocks[n/DEPBLK]);
	if(!dp) return mkError(MODFS, BLKREADFAIL, ERROR);
	memcpy(de, dp + n%DEPBLK, sizeof(Direntry));
	return notError(MODFS);
}

//This sets *fid to be equal to the fileid of the file with name fname
ErrCode lookupFile(char *fname, u32 *fid)
{
	size_t i;
	for(i = 0; 1; i++) {
		Direntry de;
		ErrCode err = getFInfo(i, &de);
		if(err == mkError(MODFS, OUTOFRANGE, WARN)) break; //have iterated through all files
		else if(isError(err)) return err; //blah
		if(!fnameCmp(fname, de.fname)) {
			*fid = de.inode;
			return notError(MODFS);
		}
	}
	return mkError(MODFS, NOTFILE, ERROR);
}

//PRECON:  fid is a valid file id
//This sets *size equal to the size of the file
ErrCode getFileSize(u32 fid, u32 *size)
{
	Inode *ptr = readFSBlock(fid);
	if(!ptr) return mkError(MODFS, BLKREADFAIL, ERROR);
	*size = ptr->size;
	return notError(MODFS);
}

//PRECON:  ptr points to a large enough location to hold all the data in file
//         fid
int getFileData(u32 fid, void *ptr)
{
	int ret = 0;
	int i;
	Inode in;
	if(getBlockData(fid, &in)) {
		ret = -1;
		goto end;
	}

	u32 size = in.size;
	for(i = 0; i < in.nblocks; i++) {
		Inode *filePtr = readFSBlock(in.blocks[i]);
		if(!filePtr) {
			ret = -1;
			goto end;
		}
		memcpy(ptr, filePtr, Min_u32(size, FSBLKSIZE));
		ptr += FSBLKSIZE;
		size -= FSBLKSIZE;
	}

end:
	return ret;
}

int setFileData(u32 fid, const void *ptr, size_t size)
{
	int ret = 0;
	unsigned int i;
	if(setFileSize(fid, size)) { //TODO efficiency (talk to Jeff)
		ret = -1;
		goto end; 
	}
	Inode in;
	if(getBlockData(fid, &in)) {
		ret = -1;
		goto end;
	}

	for(i = 0; i < in.nblocks; i++) {
		Inode *filePtr = readFSBlock(in.blocks[i]);
		if(!filePtr) {
			ret = -1;
			goto end;
		}
		memcpy(filePtr, ptr, Min_u32(size, FSBLKSIZE));
		sync(in.blocks[i]);
		ptr += FSBLKSIZE;
		size -= FSBLKSIZE;
	}

	if(setTod(&in)) { //sadly, this needs to be updated...
		ret = -1;
		goto end;
	}
	if(writeFSBlock(fid, &in)) {
		ret = -1;
		goto end;
	}

end:
	return ret;
}

//sets the file to have a size equal to size.  The data will be preserved if
//the file is currently larger than that or will be jibberish if the file is
//currently smaller
static int setFileSize(u32 fid, size_t size)
{
	int ret = 0;
	unsigned int i, j;
	u16 neededBlocks = (size + FSBLKSIZE - 1)/FSBLKSIZE;
	if(neededBlocks > MAXBLOCKS) {
		ret = -1;
		goto end;
	}
	Inode in;
	if(getBlockData(fid, &in)) {
		ret = -1;
		goto end;
	}

	if(in.nblocks >= neededBlocks) { //get rid of some blocks
		for(i = neededBlocks; i < in.nblocks; i++) { //if it is equal, will skip this loop
			if(setBlockAt(in.blocks[i], 0)) {
				ret = -1;
				goto end;
			}
		}
	} else { //there are fewer blocks
		for(i = in.nblocks; i < neededBlocks; i++) {
			in.blocks[i] = 0;
			for(j = in.blocks[i - 1]; in.blocks[i] == 0; j++)
				if(!isBlockAt(j)) in.blocks[i] = j;
			if(setBlockAt(in.blocks[i], 1)) {
				ret = -1;
				goto end;
			}
		}
	}
	in.nblocks = neededBlocks;
	in.size = size;
	if(setTod(&in)) {
		ret = -1;
		goto end;
	}
	if(writeFSBlock(fid, &in)) {
		ret = -1;
		goto end;
	}

end:
	return ret;
}

short isBlockAt(u32 block)
{ //TODO reconsider return value
	u32 inBlock = block/(8*FSBLKSIZE) + 2; //which block the bit is in
	u32 blockSpot = (block%(8*FSBLKSIZE))/8; //which u8 the bit is in
	u32 spotSpot = 7 - block%8; //which bit the bit is
	u8 *ptr = readFSBlock(inBlock);
//	if(!ptr) return -1; //TODO return value
	return (ptr[blockSpot] >> spotSpot) & 1;
}

//sets the block table to indicate whether there is a block at block
int setBlockAt(u32 block, short isBlock)
{
	u32 inBlock = block/(8*FSBLKSIZE) + 2; //which block the bit is in
	u32 blockSpot = (block%(8*FSBLKSIZE))/8; //which u8 the bit is in
	u32 spotSpot = 7 - block%8; //which bit the bit is
	u8 *ptr = readFSBlock(inBlock);
	if(!ptr) return -1;
	if(isBlock) ptr[blockSpot] |= 1 << spotSpot;
	else ptr[blockSpot] &= ~(1 << spotSpot);
	sync(inBlock);
	return 0;
}

void printFname(char *name)
{
	putline(name, 28);
}

//PRECON:  fname points to a location 28 characters long
//Sets fname to contain a filename entered by the user
void getFname(char *fname)
{
	int chars = getline(fname, FNAMELEN);
	for(;chars < FNAMELEN; chars++) {
		fname[chars] = ' ';
	}
}

//Checks whether two file names are equal
int fnameCmp(const char *a, const char *b)
{
	int i;
	for(i = 0; i < FNAMELEN; i++, a++, b++) {
		if(*a - *b) return *a - *b;
	}
	return 0;
}

static u32 setTod(Inode *inPtr)
{
	u64 tod;
	if(get_tod(&tod)) return -1;
	inPtr->mtime = tod >> 12;
	return 0;
}

static u32 getCacheLoc(u32 blkno)
{
	int i;
	for(i = 0; i < CacheSize; i++) {
		if(CacheLocs[i] == blkno) return i;
	}
	return CacheCap;
}

//PRECON:   block blkno is not already in the cache
//sets aside space in the cache for some item.  NOTE: this does not read the
//current contents of the disk to the cache
static u32 cacheAdd(u32 blkno)
{
	u32 ret = CacheNext;
	CacheLocs[CacheNext] = blkno;
	if(CacheSize != CacheCap) CacheSize += 1;
	if(CacheNext != CacheCap - 1) CacheNext += 1;
	else CacheNext = 0;
	return ret;
}

//returns a pointer pointing to a location where the data from blkno will be
//stored
static void* readFSBlock(u32 blkno)
{
	u32 cacheLoc = getCacheLoc(blkno); //Do not reload if in cache
	if(cacheLoc == CacheCap) { //It was not found in the cache
		cacheLoc = cacheAdd(blkno);
		FSBlk *nextFSB = FS_Cache + cacheLoc;
		DskBlk *nextDSKB = (DskBlk *) nextFSB; //block to put data in
		if(fba_read_blk(DevID, blkno*2, nextDSKB)) return NULL;
		if(fba_read_blk(DevID, blkno*2 + 1, nextDSKB + 1)) return NULL;
	}
	return (void *)(FS_Cache + cacheLoc);
}

static u32 getBlockData(u32 blkno, void* ptr)
{
	Inode *temp = readFSBlock(blkno);
	if(!temp) return -1;
	memcpy(ptr, temp, FSBLKSIZE);
	return 0;
}

//Writes 1024 bytes from *ptr to data block blkno
static int writeFSBlock(u32 blkno, void *ptr)
{
	u32 cacheLoc = getCacheLoc(blkno);
	if(cacheLoc == CacheCap)
		cacheLoc = cacheAdd(blkno); //need room in cache for data
	FSBlk *nextFSB = FS_Cache + cacheLoc;
	memcpy(nextFSB, ptr, FSBLKSIZE); //copy the data to the cache
	DskBlk *nextDSKB = (DskBlk *) nextFSB; //where to get the data from
	if(fba_write_blk(DevID, blkno*2, nextDSKB)) return -1; //load from the cache to the disk
	
	if(fba_write_blk(DevID, blkno*2 + 1, nextDSKB + 1)) return -1;
	if(!isBlockAt(blkno))
		if(setBlockAt(blkno, 1)) return -1;
	return 0;
}

//updates the data in block blkno based upon the data in the cache.  If block
//blkno is not in the cache, returns non-zero
static int sync(u32 blkno)
{
	u32 cacheLoc = getCacheLoc(blkno);
	if(cacheLoc == CacheCap) return -1;
	FSBlk *nextFSB = FS_Cache + cacheLoc;
	DskBlk *nextDSKB = (DskBlk *) nextFSB; //where to get the data from
	if(fba_write_blk(DevID, blkno*2, nextDSKB)) return -1;
	if(fba_write_blk(DevID, blkno*2 + 1, nextDSKB + 1)) return -1;
	return 0;
}