Mon 14 Oct 23:06:38 CEST 2024
This commit is contained in:
parent
de03924cf6
commit
a61e0eae57
662
kernel/diskfs.c
Normal file
662
kernel/diskfs.c
Normal file
|
@ -0,0 +1,662 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2015-2019 The University of Notre Dame
|
||||||
|
This software is distributed under the GNU General Public License.
|
||||||
|
See the file LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
|
#include "kernel/error.h"
|
||||||
|
#include "kmalloc.h"
|
||||||
|
#include "diskfs.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "fs_internal.h"
|
||||||
|
#include "bcache.h"
|
||||||
|
#include "page.h"
|
||||||
|
|
||||||
|
/* Read or write a block from the raw device, starting from zero. */
|
||||||
|
|
||||||
|
static int diskfs_block_read(struct device *d, struct diskfs_block *b, uint32_t blockno )
|
||||||
|
{
|
||||||
|
return bcache_read(d, b->data, 1, blockno) ? DISKFS_BLOCK_SIZE : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int diskfs_block_write(struct device *d, struct diskfs_block *b, uint32_t blockno )
|
||||||
|
{
|
||||||
|
return bcache_write(d, b->data, 1, blockno) ? DISKFS_BLOCK_SIZE : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read or write a bitmap block, starting from the bitmap offset. */
|
||||||
|
|
||||||
|
static int diskfs_bitmap_block_read(struct fs_volume *v, struct diskfs_block *b, uint32_t blockno )
|
||||||
|
{
|
||||||
|
if(blockno>=v->disk.bitmap_blocks) return KERROR_OUT_OF_SPACE;
|
||||||
|
return diskfs_block_read(v->device,b,v->disk.bitmap_start+blockno);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int diskfs_bitmap_block_write(struct fs_volume *v, struct diskfs_block *b, uint32_t blockno )
|
||||||
|
{
|
||||||
|
if(blockno>=v->disk.bitmap_blocks) return KERROR_OUT_OF_SPACE;
|
||||||
|
return diskfs_block_write(v->device,b,v->disk.bitmap_start+blockno);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read or write an inode block, starting from the inode block offset. */
|
||||||
|
|
||||||
|
static int diskfs_inode_block_read(struct fs_volume *v, struct diskfs_block *b, uint32_t blockno )
|
||||||
|
{
|
||||||
|
if(blockno>=v->disk.inode_blocks) return KERROR_OUT_OF_SPACE;
|
||||||
|
return diskfs_block_read(v->device,b,v->disk.inode_start+blockno);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int diskfs_inode_block_write(struct fs_volume *v, struct diskfs_block *b, uint32_t blockno )
|
||||||
|
{
|
||||||
|
if(blockno>=v->disk.inode_blocks) return KERROR_OUT_OF_SPACE;
|
||||||
|
return diskfs_block_write(v->device,b,v->disk.inode_start+blockno);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read or write a data block, starting from the data block offset. */
|
||||||
|
|
||||||
|
static int diskfs_data_block_read(struct fs_volume *v, struct diskfs_block *b, uint32_t blockno )
|
||||||
|
{
|
||||||
|
if(blockno>=v->disk.data_blocks) return KERROR_OUT_OF_SPACE;
|
||||||
|
return diskfs_block_read(v->device,b,v->disk.data_start+blockno);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int diskfs_data_block_write(struct fs_volume *v, struct diskfs_block *b, uint32_t blockno )
|
||||||
|
{
|
||||||
|
if(blockno>=v->disk.data_blocks) return KERROR_OUT_OF_SPACE;
|
||||||
|
return diskfs_block_write(v->device,b,v->disk.data_start+blockno);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Allocate a new data block by scanning the bitmap.
|
||||||
|
If available, return the block number.
|
||||||
|
If nothing available, return zero.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint32_t diskfs_data_block_alloc( struct fs_volume *v )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
struct diskfs_superblock *s= &v->disk;
|
||||||
|
int i, j, k;
|
||||||
|
|
||||||
|
for(i=0;i<s->bitmap_blocks;i++) {
|
||||||
|
diskfs_bitmap_block_read(v,b,i);
|
||||||
|
for(j=0;j<DISKFS_BLOCK_SIZE;j++) {
|
||||||
|
if(b->data[j]!=0xff) {
|
||||||
|
for(k=0;k<8;k++) {
|
||||||
|
if(!((1<<k) & b->data[j])) {
|
||||||
|
int blockno = i*DISKFS_BLOCK_SIZE+j*8+k;
|
||||||
|
|
||||||
|
// Never allocate block zero;
|
||||||
|
if(blockno==0) continue;
|
||||||
|
|
||||||
|
// Do not exceet the actual number of blocks
|
||||||
|
if(blockno>=v->disk.data_blocks) break;
|
||||||
|
|
||||||
|
b->data[j] |= 1<<k;
|
||||||
|
diskfs_bitmap_block_write(v,b,i);
|
||||||
|
page_free(b);
|
||||||
|
return blockno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("diskfs: warning: out of space!\n");
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void diskfs_data_block_free( struct fs_volume *v, int blockno )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
|
||||||
|
int bitmap_block = blockno/DISKFS_BLOCK_SIZE;
|
||||||
|
int bitmap_byte = blockno%DISKFS_BLOCK_SIZE/8;
|
||||||
|
int bitmap_bit = blockno%DISKFS_BLOCK_SIZE%8;
|
||||||
|
|
||||||
|
diskfs_bitmap_block_read(v,b,bitmap_block);
|
||||||
|
b->data[bitmap_byte] &= ~(1<<bitmap_bit);
|
||||||
|
diskfs_bitmap_block_write(v,b,bitmap_block);
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int diskfs_inumber_alloc( struct fs_volume *v )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for(i=0;i<v->disk.inode_blocks;i++) {
|
||||||
|
diskfs_inode_block_read(v,b,i);
|
||||||
|
for(j=0;j<DISKFS_INODES_PER_BLOCK;j++) {
|
||||||
|
if(!b->inodes[j].inuse) {
|
||||||
|
int inumber = i * DISKFS_INODES_PER_BLOCK + j;
|
||||||
|
b->inodes[j].inuse = 1;
|
||||||
|
diskfs_inode_block_write(v,b,i);
|
||||||
|
page_free(b);
|
||||||
|
return inumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("diskfs: warning: out of inodes!\n");
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void diskfs_inumber_free( struct fs_volume *v, int inumber )
|
||||||
|
{
|
||||||
|
int inode_block = inumber / DISKFS_INODES_PER_BLOCK;
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
diskfs_inode_block_read(v,b,inode_block);
|
||||||
|
b->inodes[inumber%DISKFS_INODES_PER_BLOCK].inuse = 0;
|
||||||
|
diskfs_inode_block_write(v,b,inode_block);
|
||||||
|
page_free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_inode_load( struct fs_volume *v, int inumber, struct diskfs_inode *inode )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
|
||||||
|
int inode_block = inumber / DISKFS_INODES_PER_BLOCK;
|
||||||
|
int inode_position = inumber % DISKFS_INODES_PER_BLOCK;
|
||||||
|
|
||||||
|
diskfs_inode_block_read(v,b,inode_block);
|
||||||
|
memcpy(inode,&b->inodes[inode_position],sizeof(*inode));
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_inode_save( struct fs_volume *v, int inumber, struct diskfs_inode *inode )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
|
||||||
|
int inode_block = inumber / DISKFS_INODES_PER_BLOCK;
|
||||||
|
int inode_position = inumber % DISKFS_INODES_PER_BLOCK;
|
||||||
|
|
||||||
|
diskfs_inode_block_read(v,b,inode_block);
|
||||||
|
memcpy(&b->inodes[inode_position],inode,sizeof(*inode));
|
||||||
|
diskfs_inode_block_write(v,b,inode_block);
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_inode_read( struct fs_dirent *d, struct diskfs_block *b, uint32_t block )
|
||||||
|
{
|
||||||
|
int actual;
|
||||||
|
|
||||||
|
if(block<DISKFS_DIRECT_POINTERS) {
|
||||||
|
actual = d->disk.direct[block];
|
||||||
|
} else {
|
||||||
|
diskfs_data_block_read(d->volume,b,d->disk.indirect);
|
||||||
|
actual = b->pointers[block-DISKFS_DIRECT_POINTERS];
|
||||||
|
}
|
||||||
|
|
||||||
|
return diskfs_data_block_read(d->volume,b,actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_inode_write( struct fs_dirent *d, struct diskfs_block *b, uint32_t block )
|
||||||
|
{
|
||||||
|
int actual;
|
||||||
|
|
||||||
|
struct diskfs_inode *i = &d->disk;
|
||||||
|
|
||||||
|
if(block<DISKFS_DIRECT_POINTERS) {
|
||||||
|
actual = i->direct[block];
|
||||||
|
if(actual==0) {
|
||||||
|
actual = diskfs_data_block_alloc(d->volume);
|
||||||
|
if(actual==0) return KERROR_OUT_OF_SPACE;
|
||||||
|
i->direct[block] = actual;
|
||||||
|
diskfs_inode_save(d->volume,d->inumber,i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct diskfs_block *iblock = page_alloc(0);
|
||||||
|
|
||||||
|
if(i->indirect==0) {
|
||||||
|
actual = diskfs_data_block_alloc(d->volume);
|
||||||
|
if(actual==0) {
|
||||||
|
page_free(iblock);
|
||||||
|
return KERROR_OUT_OF_SPACE;
|
||||||
|
}
|
||||||
|
i->indirect = actual;
|
||||||
|
diskfs_inode_save(d->volume,d->inumber,i);
|
||||||
|
memset(iblock,0,DISKFS_BLOCK_SIZE);
|
||||||
|
diskfs_data_block_write(d->volume,iblock,i->indirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
diskfs_data_block_read(d->volume,iblock,i->indirect);
|
||||||
|
actual = iblock->pointers[block-DISKFS_DIRECT_POINTERS];
|
||||||
|
if(actual==0) {
|
||||||
|
actual = diskfs_data_block_alloc(d->volume);
|
||||||
|
if(actual==0) {
|
||||||
|
page_free(iblock);
|
||||||
|
return KERROR_OUT_OF_SPACE;
|
||||||
|
}
|
||||||
|
iblock->pointers[block-DISKFS_DIRECT_POINTERS] = actual;
|
||||||
|
diskfs_data_block_write(d->volume,iblock,i->indirect);
|
||||||
|
}
|
||||||
|
page_free(iblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return diskfs_data_block_write(d->volume,b,actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_dirent * diskfs_dirent_create( struct fs_volume *volume, int inumber, int type )
|
||||||
|
{
|
||||||
|
struct fs_dirent *d = kmalloc(sizeof(*d));
|
||||||
|
memset(d,0,sizeof(*d));
|
||||||
|
|
||||||
|
diskfs_inode_load(volume,inumber,&d->disk);
|
||||||
|
|
||||||
|
d->volume = volume;
|
||||||
|
d->size = d->disk.size;
|
||||||
|
d->inumber = inumber;
|
||||||
|
d->refcount = 1;
|
||||||
|
d->isdir = type==DISKFS_ITEM_DIR;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int diskfs_dirent_close( struct fs_dirent *d )
|
||||||
|
{
|
||||||
|
// XXX check if inode dirty first
|
||||||
|
diskfs_inode_save(d->volume,d->inumber,&d->disk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if two strings a and b (with lengths) have the same contents. Note that diskfs_item.name is not null-terminated but has diskfs_item.name_length characters. When comparing to a null-terminated string, we must check the length first and then the bytes of the string. */
|
||||||
|
|
||||||
|
static int diskfs_name_equals( const char *a, int alength, const char *b, int blength )
|
||||||
|
{
|
||||||
|
return alength==blength && !strncmp(a,b,alength);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_dirent * diskfs_dirent_lookup( struct fs_dirent *d, const char *name )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
int nblocks = d->size / DISKFS_BLOCK_SIZE;
|
||||||
|
if(d->size%DISKFS_BLOCK_SIZE) nblocks++;
|
||||||
|
|
||||||
|
int name_length = strlen(name);
|
||||||
|
|
||||||
|
for(i=0;i<nblocks;i++) {
|
||||||
|
diskfs_inode_read(d,b,i);
|
||||||
|
for(j=0;j<DISKFS_ITEMS_PER_BLOCK;j++) {
|
||||||
|
struct diskfs_item *r = &b->items[j];
|
||||||
|
if(r->type!=DISKFS_ITEM_BLANK && diskfs_name_equals(name,name_length,r->name,r->name_length)) {
|
||||||
|
int inumber = r->inumber;
|
||||||
|
page_free(b);
|
||||||
|
return diskfs_dirent_create(d->volume,inumber,r->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_dirent_list( struct fs_dirent *d, char *buffer, int length )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
|
||||||
|
int nblocks = d->size / DISKFS_BLOCK_SIZE;
|
||||||
|
if(d->size%DISKFS_BLOCK_SIZE) nblocks++;
|
||||||
|
|
||||||
|
int i,j;
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
for(i=0;i<nblocks;i++) {
|
||||||
|
diskfs_inode_read(d,b,i);
|
||||||
|
|
||||||
|
for(j=0;j<DISKFS_ITEMS_PER_BLOCK;j++) {
|
||||||
|
struct diskfs_item *r = &b->items[j];
|
||||||
|
|
||||||
|
switch(r->type) {
|
||||||
|
case DISKFS_ITEM_FILE:
|
||||||
|
case DISKFS_ITEM_DIR:
|
||||||
|
memcpy(buffer,r->name,r->name_length);
|
||||||
|
buffer[r->name_length] = 0;
|
||||||
|
buffer += r->name_length + 1;
|
||||||
|
length -= r->name_length + 1;
|
||||||
|
total += r->name_length + 1;
|
||||||
|
break;
|
||||||
|
case DISKFS_ITEM_BLANK:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_dirent_resize( struct fs_dirent *d, uint32_t size )
|
||||||
|
{
|
||||||
|
d->size = d->disk.size = size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int diskfs_dirent_add( struct fs_dirent *d, const char *name, int type, int inumber )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
int nblocks = d->size / DISKFS_BLOCK_SIZE;
|
||||||
|
if(d->size%DISKFS_BLOCK_SIZE) nblocks++;
|
||||||
|
|
||||||
|
for(i=0;i<nblocks;i++) {
|
||||||
|
diskfs_inode_read(d,b,i);
|
||||||
|
for(j=0;j<DISKFS_ITEMS_PER_BLOCK;j++) {
|
||||||
|
struct diskfs_item *r = &b->items[j];
|
||||||
|
if(r->type==DISKFS_ITEM_BLANK) {
|
||||||
|
|
||||||
|
r->type = type;
|
||||||
|
r->inumber = inumber;
|
||||||
|
r->name_length = strlen(name);
|
||||||
|
memcpy(r->name,name,r->name_length);
|
||||||
|
|
||||||
|
/* Save the modified data block. */
|
||||||
|
diskfs_inode_write(d,b,i);
|
||||||
|
|
||||||
|
/* If this increased the logical size, update that too. */
|
||||||
|
uint32_t newsize = (i*DISKFS_BLOCK_SIZE) + (j+1)*sizeof(struct diskfs_item);
|
||||||
|
if(newsize>d->size) {
|
||||||
|
diskfs_dirent_resize(d,newsize);
|
||||||
|
diskfs_inode_save(d->volume,d->inumber,&d->disk);
|
||||||
|
}
|
||||||
|
page_free(b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(b->data,0,DISKFS_BLOCK_SIZE);
|
||||||
|
struct diskfs_item *r = &b->items[0];
|
||||||
|
|
||||||
|
r->inumber = inumber;
|
||||||
|
r->type = type;
|
||||||
|
r->name_length = strlen(name);
|
||||||
|
memcpy(r->name,name,r->name_length);
|
||||||
|
|
||||||
|
diskfs_dirent_resize(d,d->size+sizeof(*r));
|
||||||
|
diskfs_inode_write(d,b,i);
|
||||||
|
diskfs_inode_save(d->volume,d->inumber,&d->disk);
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_dirent * diskfs_dirent_create_file_or_dir( struct fs_dirent *d, const char *name, int type )
|
||||||
|
{
|
||||||
|
if(strlen(name)>DISKFS_NAME_MAX) return 0; // KERROR_NAME_TOO_LONG
|
||||||
|
|
||||||
|
struct fs_dirent *t = diskfs_dirent_lookup(d,name);
|
||||||
|
if(t) {
|
||||||
|
diskfs_dirent_close(t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inumber = diskfs_inumber_alloc(d->volume);
|
||||||
|
if(inumber==0) {
|
||||||
|
return 0; // KERROR_OUT_OF_SPACE
|
||||||
|
}
|
||||||
|
|
||||||
|
struct diskfs_inode inode;
|
||||||
|
memset(&inode,0,sizeof(inode));
|
||||||
|
inode.inuse = 1;
|
||||||
|
inode.size = 0;
|
||||||
|
diskfs_inode_save(d->volume,inumber,&inode);
|
||||||
|
diskfs_dirent_add(d,name,type,inumber);
|
||||||
|
return diskfs_dirent_create(d->volume,inumber,type);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_dirent * diskfs_dirent_create_file( struct fs_dirent *d, const char *name )
|
||||||
|
{
|
||||||
|
return diskfs_dirent_create_file_or_dir(d,name,DISKFS_ITEM_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_dirent * diskfs_dirent_create_dir( struct fs_dirent *d, const char *name )
|
||||||
|
{
|
||||||
|
return diskfs_dirent_create_file_or_dir(d,name,DISKFS_ITEM_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diskfs_inode_delete( struct fs_volume *v, struct diskfs_inode *node, int inumber )
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
// XXX check for errors in here
|
||||||
|
for(i=0;i<DISKFS_DIRECT_POINTERS;i++) {
|
||||||
|
diskfs_data_block_free(v,node->direct[i]);
|
||||||
|
size += v->block_size;
|
||||||
|
if(size>=node->size) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(size<node->size) {
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
diskfs_data_block_read(v,b,node->indirect);
|
||||||
|
for(i=0;i<DISKFS_POINTERS_PER_BLOCK;i++) {
|
||||||
|
diskfs_data_block_free(v,b->pointers[i]);
|
||||||
|
size += v->block_size;
|
||||||
|
if(size>=node->size) break;
|
||||||
|
}
|
||||||
|
page_free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(node,sizeof(*node),0);
|
||||||
|
diskfs_inode_save(v,inumber,node);
|
||||||
|
diskfs_inumber_free(v,inumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_dirent_remove( struct fs_dirent *d, const char *name )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
|
||||||
|
int name_length = strlen(name);
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
int nblocks = d->size / DISKFS_BLOCK_SIZE;
|
||||||
|
if(d->size%DISKFS_BLOCK_SIZE) nblocks++;
|
||||||
|
|
||||||
|
for(i=0;i<nblocks;i++) {
|
||||||
|
diskfs_inode_read(d,b,i);
|
||||||
|
for(j=0;j<DISKFS_ITEMS_PER_BLOCK;j++) {
|
||||||
|
struct diskfs_item *r = &b->items[j];
|
||||||
|
|
||||||
|
if(r->type!=DISKFS_ITEM_BLANK && r->name_length==name_length && diskfs_name_equals(name,name_length,r->name,r->name_length)) {
|
||||||
|
|
||||||
|
if(r->type==DISKFS_ITEM_DIR) {
|
||||||
|
struct diskfs_inode inode;
|
||||||
|
diskfs_inode_load(d->volume,r->inumber,&inode);
|
||||||
|
if(inode.size>0) {
|
||||||
|
page_free(b);
|
||||||
|
return KERROR_NOT_EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int inumber = r->inumber;
|
||||||
|
r->type = DISKFS_ITEM_BLANK;
|
||||||
|
diskfs_inode_write(d,b,i);
|
||||||
|
diskfs_inode_delete(d->volume,&d->disk,inumber);
|
||||||
|
page_free(b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_dirent_write_block( struct fs_dirent *d, const char *data, uint32_t blockno )
|
||||||
|
{
|
||||||
|
return diskfs_inode_write(d,(void*)data,blockno);
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_dirent_read_block( struct fs_dirent *d, char *data, uint32_t blockno )
|
||||||
|
{
|
||||||
|
return diskfs_inode_read(d,(void*)data,blockno);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern struct fs disk_fs;
|
||||||
|
|
||||||
|
struct fs_volume * diskfs_volume_open( struct device *device )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(0);
|
||||||
|
|
||||||
|
printf("diskfs: opening device %s unit %d\n",device_name(device),device_unit(device));
|
||||||
|
|
||||||
|
diskfs_block_read(device,b,0);
|
||||||
|
|
||||||
|
struct diskfs_superblock *sb = &b->superblock;
|
||||||
|
|
||||||
|
if(sb->magic!=DISKFS_MAGIC) {
|
||||||
|
printf("diskfs: no filesystem found!\n");
|
||||||
|
page_free(b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_volume *v = kmalloc(sizeof(*v));
|
||||||
|
v->fs = &disk_fs;
|
||||||
|
v->device = device;
|
||||||
|
v->block_size = device_block_size(device);
|
||||||
|
v->refcount = 1;
|
||||||
|
v->disk = *sb;
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
|
||||||
|
printf("diskfs: %d bitmap blocks, %d inode blocks, %d data blocks\n",
|
||||||
|
v->disk.bitmap_blocks,
|
||||||
|
v->disk.inode_blocks,
|
||||||
|
v->disk.data_blocks);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_dirent * diskfs_volume_root( struct fs_volume *v )
|
||||||
|
{
|
||||||
|
return diskfs_dirent_create(v,0,DISKFS_ITEM_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_volume_close( struct fs_volume *v )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int diskfs_volume_format( struct device *device )
|
||||||
|
{
|
||||||
|
struct diskfs_block *b = page_alloc(1);
|
||||||
|
struct diskfs_superblock sb;
|
||||||
|
|
||||||
|
int nblocks = device_nblocks(device);
|
||||||
|
|
||||||
|
printf("diskfs: formatting device %s unit %d\n",device_name(device),device_unit(device));
|
||||||
|
|
||||||
|
sb.magic = DISKFS_MAGIC;
|
||||||
|
sb.block_size = DISKFS_BLOCK_SIZE;
|
||||||
|
sb.inode_blocks = 1024 / sizeof(struct diskfs_inode);
|
||||||
|
|
||||||
|
int remaining_blocks = nblocks - sb.inode_blocks;
|
||||||
|
sb.bitmap_blocks = 1 + remaining_blocks / (DISKFS_BLOCK_SIZE*8);
|
||||||
|
sb.data_blocks = remaining_blocks - sb.bitmap_blocks;
|
||||||
|
|
||||||
|
sb.inode_start = 1;
|
||||||
|
sb.bitmap_start = sb.inode_start + sb.inode_blocks;
|
||||||
|
sb.data_start = sb.bitmap_start + sb.bitmap_blocks;
|
||||||
|
|
||||||
|
printf("diskfs: %d inode blocks, %d bitmap blocks, %d data blocks\n",
|
||||||
|
sb.inode_blocks, sb.bitmap_blocks, sb.data_blocks );
|
||||||
|
|
||||||
|
memset(b,0,DISKFS_BLOCK_SIZE);
|
||||||
|
b->superblock = sb;
|
||||||
|
|
||||||
|
printf("diskfs: writing superblock\n");
|
||||||
|
diskfs_block_write(device,b,0);
|
||||||
|
|
||||||
|
memset(b,0,DISKFS_BLOCK_SIZE);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
printf("diskfs: writing %d inode blocks\n",sb.inode_blocks);
|
||||||
|
|
||||||
|
for(i=sb.inode_blocks-1;i>=0;i--) {
|
||||||
|
diskfs_block_write(device,b,sb.inode_start+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("diskfs: writing %d bitmap blocks\n",sb.bitmap_blocks);
|
||||||
|
|
||||||
|
for(i=sb.bitmap_blocks-1;i>=0;i--) {
|
||||||
|
diskfs_block_write(device,b,sb.bitmap_start+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("diskfs: creating root directory\n");
|
||||||
|
|
||||||
|
// Mark the zeroth and first blocks as used.
|
||||||
|
b->data[0] = 0x03;
|
||||||
|
diskfs_block_write(device,b,sb.bitmap_start);
|
||||||
|
|
||||||
|
// Set up the zeroth inode as the root directory with a single direct block.
|
||||||
|
memset(b,0,DISKFS_BLOCK_SIZE);
|
||||||
|
b->inodes[0].inuse = 1;
|
||||||
|
b->inodes[0].size = sizeof(struct diskfs_item);
|
||||||
|
b->inodes[0].direct[0] = 1;
|
||||||
|
diskfs_block_write(device,b,sb.inode_start);
|
||||||
|
|
||||||
|
// Create the first directory entry as dot and write it to the first block.
|
||||||
|
memset(b,0,DISKFS_BLOCK_SIZE);
|
||||||
|
b->items[0].inumber = 0;
|
||||||
|
b->items[0].type = DISKFS_ITEM_DIR;
|
||||||
|
b->items[0].name_length = 1;
|
||||||
|
b->items[0].name[0] = '.';
|
||||||
|
diskfs_block_write(device,b,sb.data_start+1);
|
||||||
|
|
||||||
|
page_free(b);
|
||||||
|
|
||||||
|
printf("diskfs: flushing buffer cache\n");
|
||||||
|
bcache_flush_device(device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_ops diskfs_ops = {
|
||||||
|
.volume_open = diskfs_volume_open,
|
||||||
|
.volume_close = diskfs_volume_close,
|
||||||
|
.volume_format = diskfs_volume_format,
|
||||||
|
.volume_root = diskfs_volume_root,
|
||||||
|
|
||||||
|
.lookup = diskfs_dirent_lookup,
|
||||||
|
.mkdir = diskfs_dirent_create_dir,
|
||||||
|
.mkfile = diskfs_dirent_create_file,
|
||||||
|
.read_block = diskfs_dirent_read_block,
|
||||||
|
.write_block = diskfs_dirent_write_block,
|
||||||
|
.list = diskfs_dirent_list,
|
||||||
|
.remove = diskfs_dirent_remove,
|
||||||
|
.resize = diskfs_dirent_resize,
|
||||||
|
.close = diskfs_dirent_close
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct fs disk_fs = {
|
||||||
|
"diskfs",
|
||||||
|
&diskfs_ops,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
int diskfs_init(void)
|
||||||
|
{
|
||||||
|
fs_register(&disk_fs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user