Mercurial > sos > sos
view src/fs.c @ 75:c10465be6160
Fixed language, makeFile no longer eats all errors from lookupFile
author | Jonathan Pevarnek <pevarnj@gmail.com> |
---|---|
date | Tue, 26 Apr 2011 23:17:35 -0400 |
parents | 36e6fc4a0487 |
children | 6538d7c45ad8 |
line wrap: on
line source
#include <fs.h> #include <std.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; //the block is now on the disk, time to add it to the root inode Inode *root = readFSBlock(rootLoc); if(isError(err = setFileSize(rootLoc, root->size + sizeof(Direntry)))) return err; root = readFSBlock(rootLoc); //just in case the cache get messed up u32 fileno = root->size/sizeof(Direntry) - 1; u32 blkno = root->blocks[fileno/DEPBLK]; //block where direntry is Direntry *dp = readFSBlock(blkno); if(!dp) return ERR_FSBLKREADFAIL; dp += fileno%DEPBLK; //dp is set to the current de dp->inode = *fid; //set the file location memcpy(dp->fname, fname, FNAMELEN); //set the file name if(isError(err = sync(blkno))) return err; //update the block return 0; } //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; } ErrCode setFileData(u32 fid, const void *ptr, size_t size) { ErrCode ret = 0, err; unsigned int i; if(isError(err = setFileSize(fid, size))) { ret = err; goto end; } Inode in; if(isError(err = getBlockData(fid, &in))) { ret = err; goto end; } for(i = 0; i < in.nblocks; i++) { Inode *filePtr = readFSBlock(in.blocks[i]); if(!filePtr) { ret = ERR_FSBLKREADFAIL; goto end; } memcpy(filePtr, ptr, Min_u32(size, FSBLKSIZE)); if(isError(err = sync(in.blocks[i]))) { ret = err; goto end; } ptr += FSBLKSIZE; size -= FSBLKSIZE; } if(isError(err = setTod(&in))) { //sadly, this needs to be updated... ret = makeWarn(err); //everything else should still be good } if(isError(err = writeFSBlock(fid, &in))) { ret = err; goto end; } 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) 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++) { if(isError(err = nextFreeBlock(in.blocks[i - 1], &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; }