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;
}