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