changeset 104:1144f2491a39

Moved the fs code to an os folder
author Jonathan Pevarnek <pevarnj@gmail.com>
date Tue, 31 May 2011 23:58:29 -0400
parents 963bed9f5592
children fb73c5728eaf
files Makefile include/fs.h include/os/fs.h src/fs.c src/os/fs.c src/shell.c src/testFS.c
diffstat 7 files changed, 499 insertions(+), 501 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon May 30 22:55:19 2011 -0400
+++ b/Makefile	Tue May 31 23:58:29 2011 -0400
@@ -15,8 +15,8 @@
 
 sarpn_OBJS=src/sarpn.o src/std.o src/string.o src/stack.o src/operations.o src/math.o arch/arch.a
 dynamic_OBJS=src/dynamic.o src/std.o src/string.o src/stack.o arch/arch.a
-testFS_OBJS=src/testFS.o src/std.o src/string.o src/fs.o arch/arch.a
-shell_OBJS=src/shell.o src/std.o src/fs.o src/string.o src/stdio.o src/os/scall.o arch/arch.a
+testFS_OBJS=src/testFS.o src/std.o src/string.o src/os/fs.o arch/arch.a
+shell_OBJS=src/shell.o src/std.o src/os/fs.o src/string.o src/stdio.o src/os/scall.o arch/arch.a
 infLoop_OBJS=src/infLoop.o
 
 ARCH_OBJS=arch/io.o arch/cons.o arch/ebcdic.o arch/fba.o arch/ioint.o \
@@ -101,17 +101,15 @@
 # DO NOT DELETE
 
 src/dynamic.o: include/std.h include/die.h include/string.h include/stack.h
-src/fs.o: include/fs.h include/std.h include/die.h include/error.h
-src/fs.o: include/string.h include/tod.h
 src/operations.o: include/operations.h include/std.h include/die.h
 src/operations.o: include/stack.h include/string.h include/math.h
 src/sarpn.o: include/std.h include/die.h include/string.h
 src/sarpn.o: include/operations.h include/stack.h
 src/shell.o: include/std.h include/die.h include/string.h include/stdio.h
-src/shell.o: include/error.h include/fs.h include/elf.h include/psw.h
+src/shell.o: include/error.h include/os/fs.h include/elf.h include/psw.h
 src/shell.o: include/svc.h include/os/scall.h
 src/stack.o: include/stack.h include/std.h include/die.h
 src/std.o: include/std.h include/die.h include/string.h
 src/stdio.o: include/stdio.h include/std.h include/die.h include/string.h
 src/stdio.o: include/stdarg.h
-src/testFS.o: include/std.h include/die.h include/fs.h include/error.h
+src/testFS.o: include/std.h include/die.h include/os/fs.h include/error.h
--- a/include/fs.h	Mon May 30 22:55:19 2011 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-#include <std.h>
-#include <error.h>
-
-#ifndef __FS_H
-#define __FS_H
-
-#define CACHESPACE 1 //percentage of heap to use for the FS Cache
-#define FNAMELEN 28 //How long the filenames are
-#define FSBLKSIZE 1024
-#define DSKBLKSIZE 512
-#define MAXBLOCKS 248
-#define FSMAGICNUM 0x42420374
-#define DEPBLK (FSBLKSIZE / sizeof(Direntry)) //director entries per block
-
-#define ERR_FSBLKREADFAIL mkError(MODFS, BLKREADFAIL, ERROR)
-
-struct SUPERBLOCK {
-	u32 magic;              // == 0x42420374
-	u32 root_inode;         // the disk block containing the root inode
-	u32 nblocks;            // number of block on the disk
-	u32 _pad[253];          // unused (should be '\0' filled)
-};
-typedef struct SUPERBLOCK Superblock;
-
-struct INODE {
-	u32 size;               // file length in bytes
-	u32 _pad0;              // unused (should be 0)
-	u64 ctime;              // creation time stamp
-	u64 mtime;              // last modification time stamp
-	u16 nblocks;            // number of data blocks in this file
-	u16 _pad1;              // unused (should be 0)
-	u32 _pad2;              // unused (should be 0)
-	u32 blocks[MAXBLOCKS];  // file block ptrs
-};
-typedef struct INODE Inode;
-
-struct FSBLK {
-	u8 blocks[FSBLKSIZE];
-};
-typedef struct FSBLK FSBlk;
-
-struct DSKBLK {
-	u8 blocks[DSKBLKSIZE];
-};
-typedef struct DSKBLK DskBlk;
-
-struct DIRENTRY { //32 bytes
-	char fname[FNAMELEN];
-	u32 inode;
-};
-typedef struct DIRENTRY Direntry;
-
-ErrCode init_fs(u32 devnum, u64 __memsize);
-ErrCode getFInfo(u32 n, void* de);
-ErrCode lookupFile(char *fname, u32 *fid);
-ErrCode makeFile(char *fname, u32 *fid);
-ErrCode deleteFile(u32 fid);
-ErrCode fileAppend(u32 fid, void *data, u32 length);
-ErrCode fileWrite(u32 fid, void *data, u32 length, u32 offset);
-ErrCode getFileSize(u32 fid, u32 *size);
-ErrCode getFileData(u32 fid, void *ptr);
-void printFname(char *name);
-void getFname(char *fname);
-int fnameCmp(const char *a, const char *b);
-
-#endif //__FS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/os/fs.h	Tue May 31 23:58:29 2011 -0400
@@ -0,0 +1,66 @@
+#include <std.h>
+#include <error.h>
+
+#ifndef __FS_H
+#define __FS_H
+
+#define CACHESPACE 1 //percentage of heap to use for the FS Cache
+#define FNAMELEN 28 //How long the filenames are
+#define FSBLKSIZE 1024
+#define DSKBLKSIZE 512
+#define MAXBLOCKS 248
+#define FSMAGICNUM 0x42420374
+#define DEPBLK (FSBLKSIZE / sizeof(Direntry)) //director entries per block
+
+#define ERR_FSBLKREADFAIL mkError(MODFS, BLKREADFAIL, ERROR)
+
+struct SUPERBLOCK {
+	u32 magic;              // == 0x42420374
+	u32 root_inode;         // the disk block containing the root inode
+	u32 nblocks;            // number of block on the disk
+	u32 _pad[253];          // unused (should be '\0' filled)
+};
+typedef struct SUPERBLOCK Superblock;
+
+struct INODE {
+	u32 size;               // file length in bytes
+	u32 _pad0;              // unused (should be 0)
+	u64 ctime;              // creation time stamp
+	u64 mtime;              // last modification time stamp
+	u16 nblocks;            // number of data blocks in this file
+	u16 _pad1;              // unused (should be 0)
+	u32 _pad2;              // unused (should be 0)
+	u32 blocks[MAXBLOCKS];  // file block ptrs
+};
+typedef struct INODE Inode;
+
+struct FSBLK {
+	u8 blocks[FSBLKSIZE];
+};
+typedef struct FSBLK FSBlk;
+
+struct DSKBLK {
+	u8 blocks[DSKBLKSIZE];
+};
+typedef struct DSKBLK DskBlk;
+
+struct DIRENTRY { //32 bytes
+	char fname[FNAMELEN];
+	u32 inode;
+};
+typedef struct DIRENTRY Direntry;
+
+ErrCode init_fs(u32 devnum, u64 __memsize);
+ErrCode getFInfo(u32 n, void* de);
+ErrCode lookupFile(char *fname, u32 *fid);
+ErrCode makeFile(char *fname, u32 *fid);
+ErrCode deleteFile(u32 fid);
+ErrCode fileAppend(u32 fid, void *data, u32 length);
+ErrCode fileWrite(u32 fid, void *data, u32 length, u32 offset);
+ErrCode getFileSize(u32 fid, u32 *size);
+ErrCode getFileData(u32 fid, void *ptr);
+void printFname(char *name);
+void getFname(char *fname);
+int fnameCmp(const char *a, const char *b);
+
+#endif //__FS_H
--- a/src/fs.c	Mon May 30 22:55:19 2011 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,427 +0,0 @@
-#include <fs.h>
-#include <std.h>
-#include <string.h>
-#include <tod.h>
-#include <error.h>
-
-static void* readFSBlock(u32 blkno);
-static ErrCode writeFSBlock(u32 blkno, void *ptr);
-static ErrCode sync(u32 blkno);
-static ErrCode getBlockData(u32 blkno, void* ptr);
-static ErrCode setFileSize(u32 fid, size_t size);
-static ErrCode isBlockAt(u32 block, short *b);
-static ErrCode setBlockAt(u32 block, short isBlock);
-static ErrCode nextFreeBlock(u32 start, u32 *loc);
-static u32 getCacheLoc(u32 blkno);
-static u32 cacheAdd(u32 blkno);
-static ErrCode setTod(Inode *inPtr);
-
-static u32 DevID;
-static u32 CacheCap; //how many blocks the cache can hold
-static u32 CacheSize; //the current number of items 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;
-static u32 MaxBlocks;
-
-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 ERR_FSBLKREADFAIL;
-	if(sb->magic != FSMAGICNUM) return mkError(MODFS, MUGGLE, ERROR);
-	MaxBlocks = sb->nblocks;
-	rootLoc = sb->root_inode;
-
-	return 0;
-}
-
-ErrCode getFInfo(u32 n, void* de)
-{
-	Inode *root = readFSBlock(rootLoc);
-	if(!root) return ERR_FSBLKREADFAIL;
-	if(n >= root->size/DEPBLK) return mkError(MODFS, OUTOFRANGE, WARN);
-	Direntry *dp = readFSBlock(root->blocks[n/DEPBLK]);
-	if(!dp) return ERR_FSBLKREADFAIL;
-	memcpy(de, dp + n%DEPBLK, sizeof(Direntry));
-	return 0;
-}
-
-//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; //propogate error
-		if(!fnameCmp(fname, de.fname)) {
-			*fid = de.inode;
-			return 0;
-		}
-	}
-	return mkError(MODFS, NOTFILE, ERROR);
-}
-
-//makes an empty file with name fname, sets fid to the fid for the new file
-//If the file already exists, an error is returned but fid will be set to the
-//fid of that file
-ErrCode makeFile(char *fname, u32 *fid)
-{
-	ErrCode err;
-	if(!isError(err = lookupFile(fname, fid)))
-		return mkError(MODFS, EXISTS, ERROR); //the file should not exist
-	if(err != mkError(MODFS, NOTFILE, ERROR)) return err;
-	if(isError(err = nextFreeBlock(0, fid))) return err;
-
-	Inode nin;
-	nin.size = 0;
-	nin.nblocks = 0;
-	if(isError(err = setTod(&nin))) return err;
-	nin.ctime = nin.mtime;
-	nin._pad0 = nin._pad1 = nin._pad2 = 0; //I am not sure if this is needed...
-	if(isError(err = writeFSBlock(*fid, &nin))) return err;
-
-	Direntry de;
-	de.inode = *fid;
-	memcpy(de.fname, fname, FNAMELEN);
-	if(isError(err = fileAppend(rootLoc, &de, sizeof(Direntry)))) return err;
-
-	return 0;
-}
-
-ErrCode deleteFile(u32 fid)
-{
-	ErrCode err;
-	if(isError(err = setFileSize(fid, 0))) return err;
-	Direntry de;
-	u32 fileNo;
-	for(fileNo = 0; 1; fileNo++) {
-		if(isError(err = getFInfo(fileNo, &de))) return err;
-		else if(err == mkError(MODFS, OUTOFRANGE, WARN)) return mkError(MODFS, NOTFILE, ERROR);
-		if(de.inode == fid) break;
-	}
-	Inode *root = readFSBlock(rootLoc);
-	if(!root) return ERR_FSBLKREADFAIL;
-	u32 rootSize = root->size;
-	u32 numDE = rootSize/sizeof(Direntry);
-	u32 toBlkNo = root->blocks[fileNo/DEPBLK]; //block that the DE used to occupy
-	u32 endBlkNo = root->blocks[numDE/DEPBLK]; //block for the last DE
-	Direntry *td = readFSBlock(root->blocks[fileNo/DEPBLK]);
-	if(!td) return ERR_FSBLKREADFAIL;
-	td += fileNo%DEPBLK;
-	Direntry *end = readFSBlock(endBlkNo);
-		//this will fail if there is only space for one item in cache and the 2 DEs
-		//are in different blocks.  There will be no indication of failure
-	if(!end) return ERR_FSBLKREADFAIL;
-	end += numDE%DEPBLK - 1;
-	*td = *end;
-	if(isError(err = setFileSize(rootLoc, rootSize - sizeof(Direntry)))) return err;
-	if(isError(err = sync(toBlkNo))) return err; //end does not need to be synchronized
-	return 0;
-}
-
-ErrCode fileAppend(u32 fid, void *data, u32 length)
-{
-	ErrCode err;
-	u32 fileSize;
-	if(isError(err = getFileSize(fid, &fileSize))) return err;
-	if(isError(err = fileWrite(fid, data, length, fileSize))) return err;
-	return 0;
-}
-
-ErrCode fileWrite(u32 fid, void *data, u32 length, u32 offset)
-{
-	ErrCode err, ret = 0;
-	Inode *iptr = readFSBlock(fid);
-	if(!iptr) return ERR_FSBLKREADFAIL;
-	u32 oldSize = iptr->size;
-	u32 dataStop = offset + length;
-	if(dataStop > oldSize) {
-		if(isError(err = setFileSize(fid, dataStop))) return err;
-	}
-
-	Inode in;
-	if(isError(err = getBlockData(fid, &in))) return err;
-
-	u32 currPos = offset;
-	while(currPos < dataStop) {
-		u32 currBlock = in.blocks[currPos/FSBLKSIZE];
-		void *ptr = readFSBlock(currBlock);
-		if(!ptr) return ERR_FSBLKREADFAIL;
-		u32 tcOS = currPos%FSBLKSIZE; //the current offset for the block
-		u32 tcSize = Min_u32(dataStop - currPos, FSBLKSIZE); //assume 0 offset
-		tcSize = (tcSize + tcOS > FSBLKSIZE)?FSBLKSIZE - tcOS:tcSize; //take into account the offset
-		memcpy(ptr + tcOS, data, tcSize);
-		if(isError(err = sync(currBlock))) return err;
-		data += tcSize;
-		currPos += tcSize;
-	}
-
-	if(isError(err = setTod(&in))) ret = makeWarn(err);
-	if(isError(err = writeFSBlock(fid, &in))) return err;
-	return ret;
-}
-
-//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 ERR_FSBLKREADFAIL;
-	*size = ptr->size;
-	return 0;
-}
-
-//PRECON:  ptr points to a large enough location to hold all the data in file
-//         fid
-ErrCode getFileData(u32 fid, void *ptr)
-{
-	ErrCode ret = 0, err;
-	int i;
-	Inode in;
-	if(isError(err = getBlockData(fid, &in))) {
-		ret = err;
-		goto end;
-	}
-
-	u32 size = in.size;
-	for(i = 0; i < in.nblocks; i++) {
-		Inode *filePtr = readFSBlock(in.blocks[i]);
-		if(!filePtr) {
-			ret = ERR_FSBLKREADFAIL;
-			goto end;
-		}
-		memcpy(ptr, filePtr, Min_u32(size, FSBLKSIZE));
-		ptr += FSBLKSIZE;
-		size -= FSBLKSIZE;
-	}
-
-end:
-	return ret;
-}
-
-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) || (*b == ' ' && !*a)) break;
-		if(*a - *b) return *a - *b;
-	}
-	return 0;
-}
-
-//XXX HELPER FUNCTIONS XXX
-
-//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);
-}
-
-//Writes 1024 bytes from *ptr to data block blkno
-static ErrCode writeFSBlock(u32 blkno, void *ptr)
-{
-	u32 cacheLoc = getCacheLoc(blkno);
-	ErrCode err;
-	if(cacheLoc == CacheCap)
-		cacheLoc = cacheAdd(blkno); //need room in cache for data
-	FSBlk *nextFSB = FS_Cache + cacheLoc; //TODO abstraction levels?
-	memcpy(nextFSB, ptr, FSBLKSIZE); //copy the data to the cache
-	DskBlk *nextDSKB = (DskBlk *) nextFSB; //where to get the data from
-	if(isError(err = fba_write_blk(DevID, blkno*2, nextDSKB))) return err;
-	//load from the cache to the disk
-	if(isError(err = fba_write_blk(DevID, blkno*2 + 1, nextDSKB + 1))) return err;
-	short ib;
-	if(isError(err = isBlockAt(blkno, &ib))) return err;
-	if(!ib) {
-		if(isError(err = setBlockAt(blkno, 1))) return makeWarn(err);
-	}
-	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 ErrCode sync(u32 blkno)
-{
-	u32 cacheLoc = getCacheLoc(blkno);
-	if(cacheLoc == CacheCap) return mkError(MODFS, NOTINCACHE, ERROR);
-	FSBlk *nextFSB = FS_Cache + cacheLoc;
-	DskBlk *nextDSKB = (DskBlk *) nextFSB; //where to get the data from
-	if(fba_write_blk(DevID, blkno*2, nextDSKB)) return mkError(MODFS, BLKWRITEFAIL, ERROR);
-	if(fba_write_blk(DevID, blkno*2 + 1, nextDSKB + 1)) return mkError(MODFS, BLKWRITEFAIL, ERROR);
-	return 0;
-}
-
-static ErrCode getBlockData(u32 blkno, void* ptr)
-{
-	Inode *temp = readFSBlock(blkno);
-	if(!temp) return ERR_FSBLKREADFAIL;
-	memcpy(ptr, temp, FSBLKSIZE);
-	return 0;
-}
-
-//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 ErrCode setFileSize(u32 fid, size_t size) //TODO clean
-{
-	ErrCode ret = 0, err;
-	unsigned int i;
-	u16 neededBlocks = (size + FSBLKSIZE - 1)/FSBLKSIZE;
-	if(neededBlocks > MAXBLOCKS) {
-		ret = mkError(MODFS, SIZETOOLARGE, ERROR);
-		goto end;
-	}
-	Inode in;
-	if(isError(err = getBlockData(fid, &in))) {
-		ret = err;
-		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(isError(err = setBlockAt(in.blocks[i], 0))) {
-				ret = err;
-				goto end;
-			}
-		}
-	} else { //there are fewer blocks
-		for(i = in.nblocks; i < neededBlocks; i++) {
-			u32 prevLoc = (i)?in.blocks[i - 1]:fid;
-			if(isError(err = nextFreeBlock(prevLoc, &in.blocks[i]))) {
-				ret = err;
-				goto end;
-			}
-			if(isError(err = setBlockAt(in.blocks[i], 1))) {
-				ret = err;
-				goto end;
-			}
-		}
-	}
-	in.nblocks = neededBlocks;
-	in.size = size;
-	if(isError(err = setTod(&in))) {
-		ret = makeWarn(err);
-	}
-	if(isError(err = writeFSBlock(fid, &in))) {
-		ret = err;
-		goto end;
-	}
-
-end:
-	return ret;
-}
-
-static ErrCode isBlockAt(u32 block, short *b)
-{
-	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 ERR_FSBLKREADFAIL;
-	*b = (ptr[blockSpot] >> spotSpot) & 1;
-	return 0;
-}
-
-//sets the block table to indicate whether there is a block at block
-static ErrCode 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 ERR_FSBLKREADFAIL;
-	if(isBlock) ptr[blockSpot] |= 1 << spotSpot;
-	else ptr[blockSpot] &= ~(1 << spotSpot);
-	ErrCode err;
-	if(isError(err = sync(inBlock))) return err;
-	return 0;
-}
-
-static ErrCode nextFreeBlock(u32 start, u32 *loc)
-{
-	u32 i;
-	ErrCode err;
-	for(i = start; i < MaxBlocks; i++) {
-		short ib;
-		if(isError(err = isBlockAt(i, &ib))) return err;
-		if(!ib) {
-			*loc = i;
-			return 0;
-		}
-	}
-	return mkError(MODFS, DISKFULL, ERROR);
-}
-
-//TODO ErrCode?
-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
-//Returns the location in the cache where the data is
-//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;
-}
-
-//TODO consider what to do in other places if this returns a warning/error
-static ErrCode setTod(Inode *inPtr)
-{
-	u64 tod;
-	ErrCode ret;
-	ret = get_tod(&tod);
-	inPtr->mtime = tod >> 12;
-	return ret;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/fs.c	Tue May 31 23:58:29 2011 -0400
@@ -0,0 +1,427 @@
+#include <os/fs.h>
+#include <std.h>
+#include <string.h>
+#include <tod.h>
+#include <error.h>
+
+static void* readFSBlock(u32 blkno);
+static ErrCode writeFSBlock(u32 blkno, void *ptr);
+static ErrCode sync(u32 blkno);
+static ErrCode getBlockData(u32 blkno, void* ptr);
+static ErrCode setFileSize(u32 fid, size_t size);
+static ErrCode isBlockAt(u32 block, short *b);
+static ErrCode setBlockAt(u32 block, short isBlock);
+static ErrCode nextFreeBlock(u32 start, u32 *loc);
+static u32 getCacheLoc(u32 blkno);
+static u32 cacheAdd(u32 blkno);
+static ErrCode setTod(Inode *inPtr);
+
+static u32 DevID;
+static u32 CacheCap; //how many blocks the cache can hold
+static u32 CacheSize; //the current number of items 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;
+static u32 MaxBlocks;
+
+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 ERR_FSBLKREADFAIL;
+	if(sb->magic != FSMAGICNUM) return mkError(MODFS, MUGGLE, ERROR);
+	MaxBlocks = sb->nblocks;
+	rootLoc = sb->root_inode;
+
+	return 0;
+}
+
+ErrCode getFInfo(u32 n, void* de)
+{
+	Inode *root = readFSBlock(rootLoc);
+	if(!root) return ERR_FSBLKREADFAIL;
+	if(n >= root->size/DEPBLK) return mkError(MODFS, OUTOFRANGE, WARN);
+	Direntry *dp = readFSBlock(root->blocks[n/DEPBLK]);
+	if(!dp) return ERR_FSBLKREADFAIL;
+	memcpy(de, dp + n%DEPBLK, sizeof(Direntry));
+	return 0;
+}
+
+//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; //propogate error
+		if(!fnameCmp(fname, de.fname)) {
+			*fid = de.inode;
+			return 0;
+		}
+	}
+	return mkError(MODFS, NOTFILE, ERROR);
+}
+
+//makes an empty file with name fname, sets fid to the fid for the new file
+//If the file already exists, an error is returned but fid will be set to the
+//fid of that file
+ErrCode makeFile(char *fname, u32 *fid)
+{
+	ErrCode err;
+	if(!isError(err = lookupFile(fname, fid)))
+		return mkError(MODFS, EXISTS, ERROR); //the file should not exist
+	if(err != mkError(MODFS, NOTFILE, ERROR)) return err;
+	if(isError(err = nextFreeBlock(0, fid))) return err;
+
+	Inode nin;
+	nin.size = 0;
+	nin.nblocks = 0;
+	if(isError(err = setTod(&nin))) return err;
+	nin.ctime = nin.mtime;
+	nin._pad0 = nin._pad1 = nin._pad2 = 0; //I am not sure if this is needed...
+	if(isError(err = writeFSBlock(*fid, &nin))) return err;
+
+	Direntry de;
+	de.inode = *fid;
+	memcpy(de.fname, fname, FNAMELEN);
+	if(isError(err = fileAppend(rootLoc, &de, sizeof(Direntry)))) return err;
+
+	return 0;
+}
+
+ErrCode deleteFile(u32 fid)
+{
+	ErrCode err;
+	if(isError(err = setFileSize(fid, 0))) return err;
+	Direntry de;
+	u32 fileNo;
+	for(fileNo = 0; 1; fileNo++) {
+		if(isError(err = getFInfo(fileNo, &de))) return err;
+		else if(err == mkError(MODFS, OUTOFRANGE, WARN)) return mkError(MODFS, NOTFILE, ERROR);
+		if(de.inode == fid) break;
+	}
+	Inode *root = readFSBlock(rootLoc);
+	if(!root) return ERR_FSBLKREADFAIL;
+	u32 rootSize = root->size;
+	u32 numDE = rootSize/sizeof(Direntry);
+	u32 toBlkNo = root->blocks[fileNo/DEPBLK]; //block that the DE used to occupy
+	u32 endBlkNo = root->blocks[numDE/DEPBLK]; //block for the last DE
+	Direntry *td = readFSBlock(root->blocks[fileNo/DEPBLK]);
+	if(!td) return ERR_FSBLKREADFAIL;
+	td += fileNo%DEPBLK;
+	Direntry *end = readFSBlock(endBlkNo);
+		//this will fail if there is only space for one item in cache and the 2 DEs
+		//are in different blocks.  There will be no indication of failure
+	if(!end) return ERR_FSBLKREADFAIL;
+	end += numDE%DEPBLK - 1;
+	*td = *end;
+	if(isError(err = setFileSize(rootLoc, rootSize - sizeof(Direntry)))) return err;
+	if(isError(err = sync(toBlkNo))) return err; //end does not need to be synchronized
+	return 0;
+}
+
+ErrCode fileAppend(u32 fid, void *data, u32 length)
+{
+	ErrCode err;
+	u32 fileSize;
+	if(isError(err = getFileSize(fid, &fileSize))) return err;
+	if(isError(err = fileWrite(fid, data, length, fileSize))) return err;
+	return 0;
+}
+
+ErrCode fileWrite(u32 fid, void *data, u32 length, u32 offset)
+{
+	ErrCode err, ret = 0;
+	Inode *iptr = readFSBlock(fid);
+	if(!iptr) return ERR_FSBLKREADFAIL;
+	u32 oldSize = iptr->size;
+	u32 dataStop = offset + length;
+	if(dataStop > oldSize) {
+		if(isError(err = setFileSize(fid, dataStop))) return err;
+	}
+
+	Inode in;
+	if(isError(err = getBlockData(fid, &in))) return err;
+
+	u32 currPos = offset;
+	while(currPos < dataStop) {
+		u32 currBlock = in.blocks[currPos/FSBLKSIZE];
+		void *ptr = readFSBlock(currBlock);
+		if(!ptr) return ERR_FSBLKREADFAIL;
+		u32 tcOS = currPos%FSBLKSIZE; //the current offset for the block
+		u32 tcSize = Min_u32(dataStop - currPos, FSBLKSIZE); //assume 0 offset
+		tcSize = (tcSize + tcOS > FSBLKSIZE)?FSBLKSIZE - tcOS:tcSize; //take into account the offset
+		memcpy(ptr + tcOS, data, tcSize);
+		if(isError(err = sync(currBlock))) return err;
+		data += tcSize;
+		currPos += tcSize;
+	}
+
+	if(isError(err = setTod(&in))) ret = makeWarn(err);
+	if(isError(err = writeFSBlock(fid, &in))) return err;
+	return ret;
+}
+
+//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 ERR_FSBLKREADFAIL;
+	*size = ptr->size;
+	return 0;
+}
+
+//PRECON:  ptr points to a large enough location to hold all the data in file
+//         fid
+ErrCode getFileData(u32 fid, void *ptr)
+{
+	ErrCode ret = 0, err;
+	int i;
+	Inode in;
+	if(isError(err = getBlockData(fid, &in))) {
+		ret = err;
+		goto end;
+	}
+
+	u32 size = in.size;
+	for(i = 0; i < in.nblocks; i++) {
+		Inode *filePtr = readFSBlock(in.blocks[i]);
+		if(!filePtr) {
+			ret = ERR_FSBLKREADFAIL;
+			goto end;
+		}
+		memcpy(ptr, filePtr, Min_u32(size, FSBLKSIZE));
+		ptr += FSBLKSIZE;
+		size -= FSBLKSIZE;
+	}
+
+end:
+	return ret;
+}
+
+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) || (*b == ' ' && !*a)) break;
+		if(*a - *b) return *a - *b;
+	}
+	return 0;
+}
+
+//XXX HELPER FUNCTIONS XXX
+
+//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);
+}
+
+//Writes 1024 bytes from *ptr to data block blkno
+static ErrCode writeFSBlock(u32 blkno, void *ptr)
+{
+	u32 cacheLoc = getCacheLoc(blkno);
+	ErrCode err;
+	if(cacheLoc == CacheCap)
+		cacheLoc = cacheAdd(blkno); //need room in cache for data
+	FSBlk *nextFSB = FS_Cache + cacheLoc; //TODO abstraction levels?
+	memcpy(nextFSB, ptr, FSBLKSIZE); //copy the data to the cache
+	DskBlk *nextDSKB = (DskBlk *) nextFSB; //where to get the data from
+	if(isError(err = fba_write_blk(DevID, blkno*2, nextDSKB))) return err;
+	//load from the cache to the disk
+	if(isError(err = fba_write_blk(DevID, blkno*2 + 1, nextDSKB + 1))) return err;
+	short ib;
+	if(isError(err = isBlockAt(blkno, &ib))) return err;
+	if(!ib) {
+		if(isError(err = setBlockAt(blkno, 1))) return makeWarn(err);
+	}
+	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 ErrCode sync(u32 blkno)
+{
+	u32 cacheLoc = getCacheLoc(blkno);
+	if(cacheLoc == CacheCap) return mkError(MODFS, NOTINCACHE, ERROR);
+	FSBlk *nextFSB = FS_Cache + cacheLoc;
+	DskBlk *nextDSKB = (DskBlk *) nextFSB; //where to get the data from
+	if(fba_write_blk(DevID, blkno*2, nextDSKB)) return mkError(MODFS, BLKWRITEFAIL, ERROR);
+	if(fba_write_blk(DevID, blkno*2 + 1, nextDSKB + 1)) return mkError(MODFS, BLKWRITEFAIL, ERROR);
+	return 0;
+}
+
+static ErrCode getBlockData(u32 blkno, void* ptr)
+{
+	Inode *temp = readFSBlock(blkno);
+	if(!temp) return ERR_FSBLKREADFAIL;
+	memcpy(ptr, temp, FSBLKSIZE);
+	return 0;
+}
+
+//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 ErrCode setFileSize(u32 fid, size_t size) //TODO clean
+{
+	ErrCode ret = 0, err;
+	unsigned int i;
+	u16 neededBlocks = (size + FSBLKSIZE - 1)/FSBLKSIZE;
+	if(neededBlocks > MAXBLOCKS) {
+		ret = mkError(MODFS, SIZETOOLARGE, ERROR);
+		goto end;
+	}
+	Inode in;
+	if(isError(err = getBlockData(fid, &in))) {
+		ret = err;
+		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(isError(err = setBlockAt(in.blocks[i], 0))) {
+				ret = err;
+				goto end;
+			}
+		}
+	} else { //there are fewer blocks
+		for(i = in.nblocks; i < neededBlocks; i++) {
+			u32 prevLoc = (i)?in.blocks[i - 1]:fid;
+			if(isError(err = nextFreeBlock(prevLoc, &in.blocks[i]))) {
+				ret = err;
+				goto end;
+			}
+			if(isError(err = setBlockAt(in.blocks[i], 1))) {
+				ret = err;
+				goto end;
+			}
+		}
+	}
+	in.nblocks = neededBlocks;
+	in.size = size;
+	if(isError(err = setTod(&in))) {
+		ret = makeWarn(err);
+	}
+	if(isError(err = writeFSBlock(fid, &in))) {
+		ret = err;
+		goto end;
+	}
+
+end:
+	return ret;
+}
+
+static ErrCode isBlockAt(u32 block, short *b)
+{
+	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 ERR_FSBLKREADFAIL;
+	*b = (ptr[blockSpot] >> spotSpot) & 1;
+	return 0;
+}
+
+//sets the block table to indicate whether there is a block at block
+static ErrCode 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 ERR_FSBLKREADFAIL;
+	if(isBlock) ptr[blockSpot] |= 1 << spotSpot;
+	else ptr[blockSpot] &= ~(1 << spotSpot);
+	ErrCode err;
+	if(isError(err = sync(inBlock))) return err;
+	return 0;
+}
+
+static ErrCode nextFreeBlock(u32 start, u32 *loc)
+{
+	u32 i;
+	ErrCode err;
+	for(i = start; i < MaxBlocks; i++) {
+		short ib;
+		if(isError(err = isBlockAt(i, &ib))) return err;
+		if(!ib) {
+			*loc = i;
+			return 0;
+		}
+	}
+	return mkError(MODFS, DISKFULL, ERROR);
+}
+
+//TODO ErrCode?
+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
+//Returns the location in the cache where the data is
+//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;
+}
+
+//TODO consider what to do in other places if this returns a warning/error
+static ErrCode setTod(Inode *inPtr)
+{
+	u64 tod;
+	ErrCode ret;
+	ret = get_tod(&tod);
+	inPtr->mtime = tod >> 12;
+	return ret;
+}
--- a/src/shell.c	Mon May 30 22:55:19 2011 -0400
+++ b/src/shell.c	Tue May 31 23:58:29 2011 -0400
@@ -2,7 +2,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <error.h>
-#include <fs.h>
+#include <os/fs.h>
 #include <die.h>
 #include <elf.h>
 #include <psw.h>
--- a/src/testFS.c	Mon May 30 22:55:19 2011 -0400
+++ b/src/testFS.c	Tue May 31 23:58:29 2011 -0400
@@ -1,5 +1,5 @@
 #include <std.h>
-#include <fs.h>
+#include <os/fs.h>
 #include <error.h>
 
 void dumpText(char *text, int size)