Mercurial > sos > sos
view src/fs.c @ 64:72d87920de94
Direntries are no longer cached separately from everything else
Main thing: direntries are no longer cached separately from everything else,
this was done to make future changes with creating/deleting a file much easier
There is currently a TON of code duplication in listFiles() and
lookupFile(fname), I am still trying to think of a better way to do this...
author | Jonathan Pevarnek <pevarnj@gmail.com> |
---|---|
date | Thu, 21 Apr 2011 21:59:51 -0400 |
parents | f0d58047305c |
children | cd108c0a9030 |
line wrap: on
line source
#include <fs.h> #include <std.h> #include <tod.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; int 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 -1; CacheLocs = malloc(CacheCap); if(!CacheLocs) return -1; CacheSize = 0; CacheNext = 0; DevID = find_dev(0x100); Superblock *sb; sb = readFSBlock(1); if(!sb) return -1; if(sb->magic != 0x42420374) return -1; rootLoc = sb->root_inode; return 0; } //this lists all the files u32 listFiles() { size_t i; Inode *rootINode = malloc(sizeof(Inode)); if(!rootINode) return -1; if(getBlockData(rootLoc, rootINode)) { free(rootINode); return -1; } u32 NFiles = rootINode->size/sizeof(Direntry); Direntry *dp = NULL; for(i = 0; i < NFiles; i++, dp++) { if(!(i%DEPBLK)) { dp = readFSBlock(rootINode->blocks[i/DEPBLK]); if(!dp) { free(rootINode); return -1; } } printFname(dp->fname), putline("\n", 1); } free(rootINode); return 0; } //This returns the "file ID" of a specific file u32 lookupFile(char *fname) { //XXX XXX XXX TODO TODO XXX XXX XXX //XXX MASSIVE CODE DUPLICATION XXX size_t i; Inode *rootINode = malloc(sizeof(Inode)); if(!rootINode) return -1; if(getBlockData(rootLoc, rootINode)) { free(rootINode); return -1; } u32 NFiles = rootINode->size/sizeof(Direntry); Direntry *dp = NULL; for(i = 0; i < NFiles; i++, dp++) { if(!(i%DEPBLK)) { dp = readFSBlock(rootINode->blocks[i/DEPBLK]); if(!dp) { free(rootINode); return -1; } } if(!fnameCmp(fname, dp->fname)) return dp->inode; //XXX THIS IS THE ONLY NON DUPLICATED LINE XXX } free(rootINode); return 0; } //PRECON: fid is a valid file id //This sets *size equal to the size of the file. Will return 0 an success int getFileSize(u32 fid, u32 *size) { Inode *ptr = readFSBlock(fid); if(!ptr) return -1; *size = ptr->size; return 0; } //PRECON: ptr points to a large enough location to hold all the data in file // fid int getFileData(u32 fid, void *ptr) { int i; Inode *inPtr = malloc(sizeof(Inode)); if(!inPtr) return -1; if(getBlockData(fid, inPtr)) { free(inPtr); return -1; } u32 size = inPtr->size; for(i = 0; i < inPtr->nblocks; i++) { Inode *filePtr = readFSBlock(inPtr->blocks[i]); if(!filePtr) { free(inPtr); return -1; } memcpy(ptr, filePtr, Min_u32(size, FSBLKSIZE)); sync(inPtr->blocks[i]); //update the content of the actual file on disk ptr += FSBLKSIZE; size -= FSBLKSIZE; } if(writeFSBlock(fid, inPtr)) { free(inPtr); return -1; } free(inPtr); return 0; } int setFileData(u32 fid, const void *ptr, size_t size) { unsigned int i; if(setFileSize(fid, size)) return -1; //TODO efficiency (talk to Jeff) Inode *inPtr = malloc(sizeof(Inode)); if(!inPtr) return -1; if(getBlockData(fid, inPtr)) { free(inPtr); return -1; } for(i = 0; i < inPtr->nblocks; i++) { Inode *filePtr = readFSBlock(inPtr->blocks[i]); if(!filePtr) { free(inPtr); return -1; } memcpy(filePtr, ptr, Min_u32(size, FSBLKSIZE)); ptr += FSBLKSIZE; size -= FSBLKSIZE; } if(setTod(inPtr)) { //sadly, this needs to be updated... free(inPtr); return -1; } if(writeFSBlock(fid, inPtr)) { free(inPtr); return -1; } free(inPtr); 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 int setFileSize(u32 fid, size_t size) { unsigned int i, j; u16 neededBlocks = (size + FSBLKSIZE - 1)/FSBLKSIZE; if(neededBlocks > MAXBLOCKS) return -1; Inode *inPtr = malloc(sizeof(Inode)); if(!inPtr) return -1; if(getBlockData(fid, inPtr)) { free(inPtr); return -1; } if(inPtr->nblocks >= neededBlocks) { //get rid of some blocks for(i = neededBlocks; i < inPtr->nblocks; i++) { //if it is equal, will skip this loop if(setBlockAt(inPtr->blocks[i], 0)) { free(inPtr); return -1; } } } else { //there are fewer blocks for(i = inPtr->nblocks; i < neededBlocks; i++) { inPtr->blocks[i] = 0; for(j = inPtr->blocks[i - 1]; inPtr->blocks[i] == 0; j++) if(!isBlockAt(j)) inPtr->blocks[i] = j; if(setBlockAt(inPtr->blocks[i], 1)) { free(inPtr); return -1; } } } inPtr->nblocks = neededBlocks; inPtr->size = size; if(setTod(inPtr)) { free(inPtr); return -1; } if(writeFSBlock(fid, inPtr)) { free(inPtr); return -1; } free(inPtr); return 0; } 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; 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; }