MFS File System Implementation: Data Structures and Functions
#include "block.h"
#include "mfs.h"
char filesystem_name[] = "my_mfs.img";
Data Structures
struct super_block {
int block_size;
int num_inodes;
int num_bitmap;
int num_data_blocks;
int root_inode;
};
struct Extent {
int start;
int size;
};
struct disk_inode {
int size;
struct Extent e;
};
#define ENTRY_SIZE 14
struct entry {
char name[ENTRY_SIZE];
int is_dir;
short inode;
};
struct file {
int num;
int pos;
struct disk_inode ino;
};
struct mfs_dir {
struct disk_inode inodes;
int num_inodo;
int pos;
int pos_block;
char path[400];
};
#define NUM_FILES 4
struct file_system {
struct device *dev;
char *bitmap;
struct super_block sb;
struct disk_inode root;
struct file file[NUM_FILES];
struct mfs_dir dir;
} *fs = NULL;
Functions
static int sb_read(struct device *dev, struct super_block *sb) {
int size = block_get_block_size(dev);
char *block = malloc(size);
if (block == NULL) return -ENOMEM;
if (block_read(dev, block, 0) < size) return -EIO;
memcpy(sb, block, sizeof(struct super_block));
return 1;
}
static int sb_write(struct device *dev, struct super_block *sb) {
int size = block_get_block_size(dev);
char *block = malloc(size);
if (block == NULL) return -ENOMEM;
memset(block, '\0', size);
memcpy(block, sb, sizeof(struct super_block));
return (block_write(dev, block, 0) == size);
}
static int bitmap_read(struct file_system *fs) {
char *p;
int i;
fs->bitmap = malloc(fs->sb.block_size * fs->sb.num_bitmap);
if (fs->bitmap == NULL) return -ENOMEM;
p = fs->bitmap;
for (i = 0; i < fs->sb.num_bitmap; i++) {
block_read(fs->dev, p, 1 + i);
p += fs->sb.block_size;
}
return 1;
}
static int bitmap_write(struct file_system *fs) {
char *p;
int i;
if (fs->bitmap == NULL) return -EINVAL;
p = fs->bitmap;
for (i = 0; i < fs->sb.num_bitmap; i++) {
block_write(fs->dev, p, 1 + i);
p += fs->sb.block_size;
}
return 1;
}
static int bitmap_get(struct file_system *fs, int num) {
int byte = num / 8;
int bit = num % 8;
return ((fs->bitmap[byte]) >> bit) & 1;
}
static void bitmap_set(struct file_system *fs, int num) {
int byte = num / 8;
int bit = num % 8;
fs->bitmap[byte] |= (1 << bit);
}
static void bitmap_clear(struct file_system *fs, int num) {
int byte = num / 8;
int bit = num % 8;
fs->bitmap[byte] &= ~(1 << bit);
}
static int inode_read(struct file_system *fs, struct disk_inode *ino, int inode_num) {
int size = fs->sb.block_size;
char *block = malloc(size);
int n;
if (block == NULL) return -ENOMEM;
if (inode_num > fs->sb.num_inodes) return -EINVAL;
n = 1 + fs->sb.num_bitmap + inode_num;
if (block_read(fs->dev, block, n) < size) return -EIO;
memcpy(ino, block, sizeof(struct disk_inode));
return 1;
}
static int inode_write(struct file_system *fs, struct disk_inode *ino, int inode_num) {
int size = fs->sb.block_size;
char *block = malloc(size);
int n;
if (block == NULL) return -ENOMEM;
if (inode_num > fs->sb.num_inodes) return -EINVAL;
n = 1 + fs->sb.num_bitmap + inode_num;
memset(block, '\0', size);
memcpy(block, ino, sizeof(struct disk_inode));
return (block_write(fs->dev, block, n) == size);
}
static int data_read(struct file_system *fs, void *buffer, int block_num) {
int size = fs->sb.block_size;
int n;
if (block_num > fs->sb.num_data_blocks) return -EINVAL;
n = 1 + fs->sb.num_bitmap + fs->sb.num_inodes + block_num;
if (block_read(fs->dev, buffer, n) < size) return -EIO;
return 1;
}
static int data_write(struct file_system *fs, void *buffer, int block_num) {
int size = fs->sb.block_size;
int n;
if (block_num > fs->sb.num_data_blocks) return -EINVAL;
n = 1 + fs->sb.num_bitmap + fs->sb.num_inodes + block_num;
return (block_write(fs->dev, buffer, n) == size);
}
static int fs_init(void) {
int i;
if (fs != NULL) return 1;
fs = malloc(sizeof(struct file_system));
if (fs == NULL) return -ENOMEM;
memset(fs, '\0', sizeof(struct file_system));
fs->dev = block_open(filesystem_name);
if (fs->dev == NULL) {
printf("Error creating data files of the system: %s\n", filesystem_name);
perror("creating");
return -1;
}
if (sb_read(fs->dev, &fs->sb) < 0) return -EIO;
if (bitmap_read(fs) < 0) return -EIO;
if (inode_read(fs, &fs->root, fs->sb.root_inode) < 0) return -EIO;
for (i = 0; i < NUM_FILES; i++)
fs->file[i].num = -1;
fs->dir.num_inodo = -1;
return 1;
}
static int name(struct file_system *fs, struct disk_inode *d, const char *pathname) {
char block[fs->sb.block_size];
struct entry *dir = (struct entry *)block;
int i, j;
for (i = 0; i < d->e.size; i++) {
data_read(fs, block, d->e.start + i);
for (j = 0; j < fs->sb.block_size / sizeof(struct entry); j++)
if (dir[j].inode != -1 &&
strncmp(pathname, dir[j].name, ENTRY_SIZE) == 0)
return dir[j].inode;
}
return -1;
}
static char *number(struct file_system *fs, int inode) {
char block[fs->sb.block_size];
char *output = malloc(sizeof(char) * ENTRY_SIZE);
struct disk_inode ino;
struct entry *dir = (struct entry *)block;
int i, j, k;
if (inode != -1)
for (i = 0; i < fs->sb.num_inodes; i++) {
inode_read(fs, &ino, i);
for (j = 0; j < ino.e.size; j++) {
data_read(fs, block, ino.e.start + j);
for (k = 0; k < fs->sb.block_size / sizeof(struct entry); k++)
if (dir[k].inode == inode) {
strcpy(output, dir[k].name);
return output;
}
}
}
return output;
}
static int get_free_inode(struct file_system *fs) {
int i, j, k;
for (i = 0; i < fs->sb.num_inodes; i++) {
struct disk_inode ino;
inode_read(fs, &ino, i);
if (ino.size != -1) continue;
ino.size = 0;
j = 0;
while (j < fs->sb.num_data_blocks) {
if (bitmap_get(fs, j) == 0) {
ino.e.start = j;
ino.e.size = 0;
for (k = 0; k < 8; k++) {
if (bitmap_get(fs, k + j) != 0) {
break;
}
bitmap_set(fs, k + j);
ino.e.size++;
}
break;
}
j++;
}
bitmap_write(fs);
inode_write(fs, &ino, i);
return i;
}
return -1;
}