int dfs_write(struct file *filp, void *data, size_t size) { struct inode *inode; size_t written; size_t count; char *p; unsigned int iblock; unsigned int start; vfs_blkno_t blk; struct buf *buf; inode = (struct inode *) filp->data; written = 0; p = (char *) data; while (size > 0) { iblock = filp->pos / inode->fs->blocksize; start = filp->pos % inode->fs->blocksize; count = inode->fs->blocksize - start; if (count > size) count = size; if (iblock < inode->desc->blocks) blk = get_inode_block(inode, iblock); else if (iblock == inode->desc->blocks) blk = expand_inode(inode); else return written; if (blk == -1) return written; if (count == inode->fs->blocksize) buf = alloc_buffer(inode->fs->cache, blk); else buf = get_buffer(inode->fs->cache, blk); if (!buf) return written; memcpy(buf->data + start, p, count); filp->flags |= F_MODIFIED; mark_buffer_updated(buf); release_buffer(inode->fs->cache, buf); filp->pos += count; p += count; written += count; size -= count; if (filp->pos > inode->desc->size) { inode->desc->size = filp->pos; mark_inode_dirty(inode); } } return written; }
/* * Add a number of blocks to an inode. */ Uint32 increase_inode_size (struct ext2_filesystem_context *context, struct ext2_inode *fp, Uint32 nbytes) { Uint32 block_size = get_block_size( context->sb ); Uint32 initial_size = fp->size; Uint32 logical_block_idx = initial_size / block_size; Uint32 blocks_allocated = 0; Uint32 total_bytes_to_alloc = nbytes; // Account for unused space in the last block. if( initial_size % block_size ) { nbytes -= block_size - (initial_size % block_size); } // Allocate at least nbytes worth of blocks. Because it needs to be // aligned, we'll always round up. Uint32 num_blocks_to_alloc = nbytes / block_size; if( nbytes % block_size ) { num_blocks_to_alloc += 1; } BlockNumber last_block_allocked = 0; for( Uint i = 0; i < num_blocks_to_alloc; ++i ) { last_block_allocked = block_alloc( context ); // Was the alloc successful? if( last_block_allocked ) { blocks_allocated++; Uint32 *inode_block = get_inode_block( fp, logical_block_idx ); *inode_block = last_block_allocked; } else { break; } } // Record the new size of the inode if( blocks_allocated == num_blocks_to_alloc ) { fp->size += total_bytes_to_alloc; } else { fp->size += total_bytes_to_alloc - ((num_blocks_to_alloc - blocks_allocated) * block_size); } return blocks_allocated; }
static int gfs_zero_inode(struct gfs_inode_info *inode) { struct gfs_super_info *sb = (struct gfs_super_info *)inode->vfs_inode.i_sb->s_fs_info; int nblocks = sb->s_chunk_size, i; for( i = 0;i<nblocks; ++i ) { struct buffer_head *bh = get_inode_block(inode, i, 1); if(!bh) return -ENOMEM; memset(bh->b_data, 0, bh->b_size); put_inode_block(inode,1); } return 0; }
int dfs_read(struct file *filp, void *data, size_t size, off64_t pos) { struct inode *inode; size_t read; size_t count; off64_t left; char *p; unsigned int iblock; unsigned int start; blkno_t blk; struct buf *buf; inode = (struct inode *) filp->data; read = 0; p = (char *) data; while (pos < inode->desc->size && size > 0) { if (filp->flags & F_CLOSED) return -EINTR; iblock = (unsigned int) (pos / inode->fs->blocksize); start = (unsigned int) (pos % inode->fs->blocksize); count = inode->fs->blocksize - start; if (count > size) count = size; left = inode->desc->size - (size_t) pos; if (count > left) count = (size_t) left; if (count <= 0) break; blk = get_inode_block(inode, iblock); if (blk == NOBLOCK) return -EIO; if (filp->flags & O_DIRECT) { if (start != 0 || count != inode->fs->blocksize) return read; if (dev_read(inode->fs->devno, p, count, blk, 0) != (int) count) return read; } else { buf = get_buffer(inode->fs->cache, blk); if (!buf) return -EIO; memcpy(p, buf->data + start, count); release_buffer(inode->fs->cache, buf); } pos += count; p += count; read += count; size -= count; } return read; }
//pass 2 pointers by ref. and inode number, returns 0 on success, updates pointers by ref. int get_inode(struct inode_block **inode_block, struct inode **inode, int inode_num) { int offset = inode_num % 8; if(inode_num < 0) return -1; *inode_block = get_inode_block(inode_num); if(!inode_block) { return -1; } *inode = &(**inode_block).inodes[offset]; return 0; }
int dfs_read(struct file *filp, void *data, size_t size) { struct inode *inode; size_t read; size_t count; size_t left; char *p; unsigned int iblock; unsigned int start; vfs_blkno_t blk; struct buf *buf; inode = (struct inode *) filp->data; read = 0; p = (char *) data; while (filp->pos < inode->desc->size && size > 0) { iblock = filp->pos / inode->fs->blocksize; start = filp->pos % inode->fs->blocksize; count = inode->fs->blocksize - start; if (count > size) count = size; left = (int) inode->desc->size - filp->pos; if (count > left) count = left; blk = get_inode_block(inode, iblock); if (blk == -1) return read; buf = get_buffer(inode->fs->cache, blk); if (!buf) return read; memcpy(p, buf->data + start, count); release_buffer(inode->fs->cache, buf); filp->pos += count; p += count; read += count; size -= count; } return read; }
int dfs_readdir(struct file *filp, struct vfs_dirent *dirp, int count) { unsigned int iblock; unsigned int start; struct inode *inode; vfs_blkno_t blk; struct buf *buf; struct dentry *de; inode = (struct inode *) filp->data; if (count != 1) return -1; if (filp->pos == inode->desc->size) return 0; if (filp->pos > inode->desc->size) return -1; iblock = filp->pos / inode->fs->blocksize; start = filp->pos % inode->fs->blocksize; blk = get_inode_block(inode, iblock); if (blk == -1) return -1; buf = get_buffer(inode->fs->cache, blk); if (!buf) return -1; de = (struct dentry *) (buf->data + start); if (de->reclen + start > inode->fs->blocksize || de->namelen <= 0 || de->namelen >= MAXPATH) { release_buffer(inode->fs->cache, buf); return -1; } dirp->ino = de->ino; dirp->reclen = de->reclen; dirp->namelen = de->namelen; memcpy(dirp->name, de->name, de->namelen); dirp->name[de->namelen] = 0; filp->pos += de->reclen; release_buffer(inode->fs->cache, buf); return 1; }
vfs_ino_t modify_dir_entry(struct inode *dir, char *name, int len, vfs_ino_t ino) { unsigned int block; vfs_blkno_t blk; struct buf *buf; char *p; struct dentry *de; vfs_ino_t oldino; if (len <= 0 || len >= MAXPATH) return -1; if (!VFS_S_ISDIR(dir->desc->mode)) return -1; for (block = 0; block < dir->desc->blocks; block++) { blk = get_inode_block(dir, block); buf = get_buffer(dir->fs->cache, blk); if (!buf) return -1; p = buf->data; while (p < buf->data + dir->fs->blocksize) { de = (struct dentry *) p; if (fnmatch(name, len, de->name, de->namelen)) { oldino = de->ino; de->ino = ino; mark_buffer_updated(buf); release_buffer(dir->fs->cache, buf); return oldino; } p += de->reclen; } release_buffer(dir->fs->cache, buf); } return -1; }
int read_dir(struct inode *dir, filldir_t filldir, void *data) { unsigned int block; vfs_blkno_t blk; struct buf *buf; char *p; struct dentry *de; int rc; if (!VFS_S_ISDIR(dir->desc->mode)) return -1; for (block = 0; block < dir->desc->blocks; block++) { blk = get_inode_block(dir, block); buf = get_buffer(dir->fs->cache, blk); if (!buf) return -1; p = buf->data; while (p < buf->data + dir->fs->blocksize) { de = (struct dentry *) p; rc = filldir(de->name, de->namelen, de->ino, data); if (rc != 0) { release_buffer(dir->fs->cache, buf); return rc; } p += de->reclen; } release_buffer(dir->fs->cache, buf); } return 0; }
int delete_dir_entry(struct inode *dir, char *name, int len) { unsigned int block; vfs_blkno_t blk; vfs_blkno_t lastblk; struct buf *buf; char *p; struct dentry *de; struct dentry *prevde; struct dentry *nextde; if (len <= 0 || len >= MAXPATH) return -1; if (!VFS_S_ISDIR(dir->desc->mode)) return -1; for (block = 0; block < dir->desc->blocks; block++) { blk = get_inode_block(dir, block); buf = get_buffer(dir->fs->cache, blk); if (!buf) return -1; p = buf->data; prevde = NULL; while (p < buf->data + dir->fs->blocksize) { de = (struct dentry *) p; if (fnmatch(name, len, de->name, de->namelen)) { if (prevde) { // Merge entry with previous entry prevde->reclen += de->reclen; memset(de, 0, sizeof(struct dentry) + NAME_ALIGN_LEN(de->namelen)); mark_buffer_updated(buf); } else if (de->reclen == dir->fs->blocksize) { // Block is empty, swap this block with last block and truncate if (block != dir->desc->blocks - 1) { lastblk = get_inode_block(dir, dir->desc->blocks - 1); set_inode_block(dir, block, lastblk); set_inode_block(dir, dir->desc->blocks - 1, buf->blkno); } truncate_inode(dir, dir->desc->blocks - 1); dir->desc->size -= dir->fs->blocksize; mark_buffer_invalid(buf); } else { // Merge with next entry nextde = (struct dentry *) (p + de->reclen); de->ino = nextde->ino; de->reclen += nextde->reclen; de->namelen = nextde->namelen; memcpy(de->name, nextde->name, nextde->namelen); // TODO: should be memmove? mark_buffer_updated(buf); } release_buffer(dir->fs->cache, buf); dir->desc->mtime = time(NULL); mark_inode_dirty(dir); return 0; } prevde = de; p += de->reclen; } release_buffer(dir->fs->cache, buf); } return -1; }
int add_dir_entry(struct inode *dir, char *name, int len, vfs_ino_t ino) { unsigned int block; vfs_blkno_t blk; struct buf *buf; char *p; struct dentry *de; struct dentry *newde; int minlen; if (len <= 0 || len >= MAXPATH) return -1; if (!VFS_S_ISDIR(dir->desc->mode)) return -1; for (block = 0; block < dir->desc->blocks; block++) { blk = get_inode_block(dir, block); buf = get_buffer(dir->fs->cache, blk); if (!buf) return -1; p = buf->data; while (p < buf->data + dir->fs->blocksize) { de = (struct dentry *) p; minlen = sizeof(struct dentry) + NAME_ALIGN_LEN(de->namelen); if (de->reclen >= minlen + sizeof(struct dentry) + NAME_ALIGN_LEN(de->namelen)) { newde = (struct dentry *) (p + minlen); newde->ino = ino; newde->reclen = de->reclen - minlen; newde->namelen = len; memcpy(newde->name, name, len); de->reclen = minlen; mark_buffer_updated(buf); release_buffer(dir->fs->cache, buf); dir->desc->mtime = time(NULL); mark_inode_dirty(dir); return 0; } p += de->reclen; } release_buffer(dir->fs->cache, buf); } blk = expand_inode(dir); if (blk == -1) return -1; buf = alloc_buffer(dir->fs->cache, blk); if (!buf) return -1; dir->desc->size += dir->fs->blocksize; dir->desc->mtime = time(NULL); mark_inode_dirty(dir); newde = (struct dentry *) (buf->data); newde->ino = ino; newde->reclen = dir->fs->blocksize; newde->namelen = len; memcpy(newde->name, name, len); mark_buffer_updated(buf); release_buffer(dir->fs->cache, buf); return 0; }
int ext2_lookup(inode *ino, const char *name, uint32_t *out) { //printf("OPEN\n"); ext2_filesystem *fs = (ino->fs); ext2_dirent *dir_entry; buffer *buff; // get number of block in total ext2_inode *in = &ino->in; uint32_t inodeSize = in->size; uint32_t blockSize = fs->blocksize; uint32_t numOfBlock = inodeSize / blockSize; //uint32_t inodenum; uint32_t currentBlock = 0; //used to report error int r, direntoffset; // for each block, get all the directory entries for (currentBlock=0; currentBlock<numOfBlock; currentBlock++) { // get the content of the block if(0 > (r = get_inode_block(ino, currentBlock, 0, &buff))) { return r; } //bufcache_release(fs->bc,buffer,0); for (direntoffset = 0; direntoffset < blockSize; direntoffset += dir_entry->rec_len) { // get the current directory entry dir_entry = (ext2_dirent*)&buff->data[direntoffset]; uint8_t nameLen = dir_entry->name_len; // compare with name if (dir_entry->inode!=0) // if valid entry { //compare the name if ( (nameLen == strlen(name)) && !strncmp(dir_entry->name,name,nameLen) ) { *out = dir_entry->inode; bufcache_release(fs->bc,buff,buff->dirty); //printf("RETURN\n"); return 0; } } } bufcache_release(fs->bc,buff,buff->dirty); } bufcache_release(fs->bc,buff,buff->dirty); //printf("RETURN\n"); return -ENOENT; }
int main(int argc, char **argv) { /* Create a test filesystem to work with. This is a "fake" filesystem with a 16-byte block size that resides entirely in memory. It only contains the subset of the data structures necessary for the test (i.e. no superblock, block group descriptors, or i-node cache are present). */ ext2_filesystem *fs = test_init(); int max_blocks = 12 + RPB + RPB*RPB + RPB*RPB*RPB; uint32_t map[max_blocks]; printf("Max # blocks per inode = %d\n",max_blocks); /* Create an i-node with the maximum file size */ inode *ino = create_test_inode(fs,max_blocks*BLOCKSIZE,map); /* Print out the block numbers of data and indirect blocks */ array *out = array_new(); print_inode_blocks(ino,out); printf("%s",out->data); array_free(out); int r; int failures = 0; printf("\n"); printf("Logical to physical block map\n"); printf("---------------------------------\n"); printf("%-10s %-10s %-10s %-10s\n","Logical","Physical","Physical","Result"); printf("%-10s %-10s %-10s %-10s\n","","(expected)","(actual)",""); /* For each logical block number, call get_inode_block to see if it returns the correct block. Since the test code stores all buffer objects in a single array, we can work out the physical block number simpy by subtracting the address of the first buffer from the address of the one returned by get_inode_block. */ int i; for (i = 0; i < max_blocks; i++) { buffer *buf; if (0 > (r = get_inode_block(ino,i,0,&buf))) { printf("%-10d %-10d %-10s FAIL\n",i,map[i],"ERROR"); failures++; } else { int blockno = ((char*)buf - buffermem)/(BLOCKSIZE+sizeof(buffer)); if (blockno == map[i]) { printf("%-10d %-10d %-10d PASS\n",i,map[i],blockno); } else { printf("%-10d %-10d %-10d FAIL\n",i,map[i],blockno); failures++; } } } if (0 < failures) { printf("One or more tests failed\n"); r = 1; } else { printf("All tests passed successfully\n"); r = 0; } /* Cleanup */ free(ino); test_cleanup(); return r; }
int dfs_write(struct file *filp, void *data, size_t size, off64_t pos) { struct inode *inode; size_t written; size_t count; char *p; unsigned int iblock; unsigned int start; blkno_t blk; struct buf *buf; int rc; inode = (struct inode *) filp->data; if (filp->flags & O_APPEND) pos = inode->desc->size; if (pos + size > DFS_MAXFILESIZE) return -EFBIG; if (S_ISDIR(inode->desc->mode)) return -EISDIR; if (pos > inode->desc->size) { rc = dfs_ftruncate(filp, pos); if (rc < 0) return rc; } written = 0; p = (char *) data; while (size > 0) { if (filp->flags & F_CLOSED) return -EINTR; iblock = (unsigned int) pos / inode->fs->blocksize; start = (unsigned int) pos % inode->fs->blocksize; count = inode->fs->blocksize - start; if (count > size) count = size; if (iblock < inode->desc->blocks) { blk = get_inode_block(inode, iblock); if (blk == NOBLOCK) return -EIO; } else if (iblock == inode->desc->blocks) { blk = expand_inode(inode); if (blk == NOBLOCK) return -ENOSPC; } else { return written; } if (filp->flags & O_DIRECT) { if (start != 0 || count != inode->fs->blocksize) return written; if (dev_write(inode->fs->devno, p, count, blk, 0) != (int) count) return written; } else { if (count == inode->fs->blocksize) { buf = alloc_buffer(inode->fs->cache, blk); } else { buf = get_buffer(inode->fs->cache, blk); } if (!buf) return -EIO; memcpy(buf->data + start, p, count); mark_buffer_updated(inode->fs->cache, buf); release_buffer(inode->fs->cache, buf); } filp->flags |= F_MODIFIED; pos += count; p += count; written += count; size -= count; if (pos > inode->desc->size) { inode->desc->size = pos; mark_inode_dirty(inode); } } return written; }