Mercurial > sos > sos
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; +}