quinn-os/minix.c
2022-07-21 14:52:54 +10:00

1946 lines
60 KiB
C

#include "inttypes.h"
#include "pvec.h"
#include "vfs.h"
#include "minix.h"
#include "memory.h"
#include "string.h"
#include "ramdisk.h"
#include "ahci.h"
#include "pata.h"
#include "hd.h"
#include "console.h"
#include "rtc.h"
uint32_t minix_alloc_bit(struct vfs_device_t *device, int map, uint32_t bit);
struct minix_inode *minix_alloc_inode(struct vfs_device_t *device, uint16_t mode, uint32_t *ino);
uint32_t minix_read_map(struct vfs_device_t *device, struct minix_inode *inode, uint64_t position);
void minix_free_inode(struct vfs_device_t *device, uint32_t ino);
void minix_free_bit(struct vfs_device_t *device, int map, uint32_t bit);
int minix_write_map(struct vfs_device_t *device, struct minix_inode *inode, int ino, uint64_t position, uint32_t new_zone, int op);
int minix_write_inode(struct vfs_device_t *device, uint32_t ino, struct minix_inode *inode);
uint32_t minix_alloc_zone(struct vfs_device_t *device, uint32_t z) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
return minix_alloc_bit(device, 1, z) + mdata->first_data_block - 1;
}
uint32_t minix_free_zone(struct vfs_device_t *device, uint32_t z) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
minix_free_bit(device, 1, z - (mdata->first_data_block - 1));
return 1;
}
uint32_t minix_rd_indir(char *buffer, int index) {
uint32_t *ptr = (uint32_t *)buffer;
return ptr[index];
}
void minix_wr_indir(char *buffer, int index, uint32_t value) {
uint32_t *ptr = (uint32_t *)buffer;
ptr[index] = value;
}
int minix_empty_indir(char *bp, struct minix_super_block *sb) {
uint32_t i;
for (i = 0; i < (sb->s_blocksize / 4); i++) {
if (minix_rd_indir(bp, i) != 0) {
return 0;
}
}
return 1;
}
int minix_remove_directory_entry(struct vfs_device_t *device, struct minix_inode *dir, char *name) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
int i, k;
char *buffer;
struct minix_dir_entry *direntry;
if (!(dir->i_mode & S_IFDIR)) {
kprintf("Trying to remove an entry from something not a directory\n");
return 0;
}
uint32_t blockstoread = dir->i_size / mdata->sb.s_blocksize;
uint32_t blockno;
if (dir->i_size % mdata->sb.s_blocksize) {
blockstoread++;
}
uint32_t old_entrys = dir->i_size / sizeof(struct minix_dir_entry);
buffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix remove directory entry");
if (!buffer) {
return 0;
}
for (k = 0; k < blockstoread; k++) {
blockno = minix_read_map(device, dir, (uint64_t)(k * mdata->sb.s_blocksize));
if (blockno == 0) {
kprintf("Unable to read map!\n");
return 0;
}
if (device->device == 1) {
ramdisk_read_block(blockno, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), blockno, buffer, mdata->sb.s_blocksize);
}
for (i = 0; i < mdata->sb.s_blocksize / sizeof(struct minix_dir_entry) && i + k * (mdata->sb.s_blocksize / sizeof(struct minix_dir_entry)) < old_entrys;
i++) {
direntry = (struct minix_dir_entry *)&buffer[i * sizeof(struct minix_dir_entry)];
if (strcmp(direntry->name, name) == 0) {
direntry->inode = 0;
if (device->device == 1) {
ramdisk_write_block(blockno, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), blockno, buffer, mdata->sb.s_blocksize);
}
free(buffer);
return 1;
}
}
}
free(buffer);
return 0;
}
int minix_add_directory_entry(struct vfs_device_t *device, struct minix_inode *dir, int dir_ino, char *name, int ino) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
uint32_t i, j, k;
char *buffer;
struct minix_dir_entry *direntry;
if (!(dir->i_mode & S_IFDIR)) {
kprintf("Trying to add an entry to something not a directory %d\n", dir_ino);
return 0;
}
uint32_t blockstoread = dir->i_size / mdata->sb.s_blocksize;
uint32_t blockno = 0;
if (dir->i_size % mdata->sb.s_blocksize) {
blockstoread++;
}
uint32_t old_entrys = dir->i_size / sizeof(struct minix_dir_entry);
uint32_t new_entrys = ((blockstoread * mdata->sb.s_blocksize) / sizeof(struct minix_dir_entry)) - old_entrys;
buffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix add directory entry");
if (!buffer) {
return 0;
}
for (k = 0; k < blockstoread; k++) {
blockno = minix_read_map(device, dir, (uint64_t)(k * mdata->sb.s_blocksize));
if (blockno == 0) {
kprintf("Unable to read map!\n");
return 0;
}
if (device->device == 1) {
ramdisk_read_block(blockno, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), blockno, buffer, mdata->sb.s_blocksize);
}
for (i = 0; i < mdata->sb.s_blocksize / sizeof(struct minix_dir_entry) && i + k * (mdata->sb.s_blocksize / sizeof(struct minix_dir_entry)) < old_entrys;
i++) {
direntry = (struct minix_dir_entry *)&buffer[i * sizeof(struct minix_dir_entry)];
if (direntry->inode == 0) {
direntry->inode = ino;
for (j = 0; j < 59 && j < strlen(name); j++) {
direntry->name[j] = name[j];
direntry->name[j + 1] = '\0';
}
if (device->device == 1) {
ramdisk_write_block(blockno, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), blockno, buffer, mdata->sb.s_blocksize);
}
free(buffer);
return 1;
}
}
if (i + k * (mdata->sb.s_blocksize / sizeof(struct minix_dir_entry)) == old_entrys) {
if (new_entrys > 0) {
direntry = (struct minix_dir_entry *)&buffer[i * sizeof(struct minix_dir_entry)];
direntry->inode = ino;
for (j = 0; j < 59 && j < strlen(name); j++) {
direntry->name[j] = name[j];
direntry->name[j + 1] = '\0';
}
if (device->device == 1) {
ramdisk_write_block(blockno, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block_sync((device->device & 0xff), blockno, buffer, mdata->sb.s_blocksize);
}
dir->i_size += sizeof(struct minix_dir_entry);
minix_write_inode(device, dir_ino, dir);
free(buffer);
return 1;
}
}
}
// no free spaces, allocate some more space
uint32_t new_zone = minix_alloc_zone(device, blockno);
uint32_t old_size = dir->i_size;
dir->i_size += sizeof(struct minix_dir_entry);
minix_write_map(device, dir, dir_ino, (uint64_t)old_size, new_zone, 0);
blockno = minix_read_map(device, dir, old_size);
memset(buffer, 0, sizeof(mdata->sb.s_blocksize));
direntry = (struct minix_dir_entry *)buffer;
direntry->inode = ino;
for (j = 0; j < 59 && j < strlen(name); j++) {
direntry->name[j] = name[j];
direntry->name[j + 1] = '\0';
}
if (device->device == 1) {
ramdisk_write_block(blockno, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block_sync((device->device & 0xff), blockno, buffer, mdata->sb.s_blocksize);
}
free(buffer);
return 1;
}
static struct minix_inode *minix_new_node(struct vfs_device_t *device, struct minix_inode *dirp, uint32_t dir_ino, char *name, uint16_t mode, uint32_t z0,
uint32_t *new_ino) {
struct minix_inode *new_inode;
uint32_t ino;
if (dirp->i_nlinks == 0) {
return NULL;
}
if (mode & S_IFDIR && dirp->i_nlinks >= 32767) {
return NULL;
}
new_inode = minix_alloc_inode(device, mode, &ino);
new_inode->i_nlinks++;
new_inode->i_zone[0] = z0;
minix_write_inode(device, ino, new_inode);
// add directory entry
if (!minix_add_directory_entry(device, dirp, dir_ino, name, ino)) {
// free inode
minix_free_inode(device, ino);
return NULL;
}
if (new_ino != NULL) {
*new_ino = ino;
}
return new_inode;
}
int minix_create_file(struct vfs_device_t *device, char *path) {
if (minix_check_if_exists(device, path, -1)) {
return -1;
}
char *path_copy = (char *)dbmalloc(strlen(path) + 1, "minix create file");
char *basename;
int i;
strcpy(path_copy, path);
for (i = strlen(path_copy) - 1; i >= 0; i--) {
if (path_copy[i] == '/') {
path_copy[i] = '\0';
basename = &path_copy[i + 1];
break;
}
}
struct minix_file_info *minfo;
struct minix_inode *dirp;
struct minix_inode *new_node = NULL;
uint32_t az = minix_alloc_zone(device, 0);
if (strlen(path_copy) > 0) {
minfo = minix_check_if_exists(device, path_copy, 0);
dirp = minix_get_inode(device, minfo->inode);
if (dirp->i_mode & S_IFDIR) {
new_node = minix_new_node(device, dirp, minfo->inode, basename, S_IFREG | 0644, az, NULL);
} else {
kprintf("Trying to create a file in a file!\n");
}
} else {
dirp = minix_get_inode(device, 1);
if (dirp->i_mode & S_IFDIR) {
new_node = minix_new_node(device, dirp, 1, basename, S_IFREG | 0644, az, NULL);
} else {
kprintf("Root directory is not a directory!\n");
}
}
if (!new_node) {
return -1;
}
dbfree(path_copy, "minix create file 2");
return 0;
}
int minix_write_map(struct vfs_device_t *device, struct minix_inode *inode, int ino, uint64_t position, uint32_t new_zone, int op) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
uint32_t zone = position / mdata->sb.s_blocksize;
uint32_t excess;
uint32_t nr_indirects = mdata->sb.s_blocksize / 4;
uint32_t z, z1, z2 = 0;
uint32_t old_zone;
int ex;
int single;
int new_ind;
int new_dbl;
int ind_ex;
uint32_t b_indr;
char *buffer_indr = NULL;
char *buffer = NULL;
if (zone < 7) {
if (inode->i_zone[zone] != 0 && op == 1) {
// free zone
minix_free_zone(device, inode->i_zone[zone]);
inode->i_zone[zone] = NO_ZONE;
} else {
inode->i_zone[zone] = new_zone;
}
minix_write_inode(device, ino, inode);
return 1;
}
excess = zone - 7;
new_dbl = 0;
new_ind = 0;
if (excess < nr_indirects) {
z1 = inode->i_zone[7];
single = 1;
} else {
if ((z2 = z = inode->i_zone[8]) == 0 && op == 0) {
if ((z = minix_alloc_zone(device, inode->i_zone[0])) == 0) {
return 0;
}
inode->i_zone[8] = z;
new_dbl = 1;
}
excess -= nr_indirects;
ind_ex = (int)(excess / nr_indirects);
excess = excess % nr_indirects;
if (ind_ex >= nr_indirects)
return 0;
if (z == 0 && op == 1) {
z1 = 0;
} else {
b_indr = z;
buffer_indr = (char *)dbmalloc(mdata->sb.s_blocksize, "minix create map 1");
if (!buffer_indr) {
return 0;
}
if (!new_dbl) {
if (device->device == 1) {
ramdisk_read_block(b_indr, buffer_indr, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), b_indr, buffer_indr, mdata->sb.s_blocksize);
}
} else {
memset(buffer_indr, 0, mdata->sb.s_blocksize);
}
z1 = minix_rd_indir(buffer_indr, ind_ex);
}
single = 0;
}
if (z1 == 0 && op == 0) {
z1 = minix_alloc_zone(device, inode->i_zone[0]);
if (single) {
inode->i_zone[7] = z1;
} else {
minix_wr_indir(buffer_indr, ind_ex, z1);
if (device->device == 1) {
ramdisk_write_block(b_indr, buffer_indr, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), b_indr, buffer_indr, mdata->sb.s_blocksize);
}
}
new_ind = 1;
if (z1 == 0) {
return 0;
}
}
if (z1 != 0) {
ex = (int)excess;
buffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix create map 2");
if (!buffer) {
return 0;
}
if (!new_ind) {
if (device->device == 1) {
ramdisk_read_block(z1, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), z1, buffer, mdata->sb.s_blocksize);
}
} else {
memset(buffer, 0, mdata->sb.s_blocksize);
}
if (op == 1) {
if ((old_zone = minix_rd_indir(buffer, ex)) != 0) {
minix_free_zone(device, old_zone);
minix_wr_indir(buffer, ex, 0);
if (device->device == 1) {
ramdisk_write_block(z1, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), z1, buffer, mdata->sb.s_blocksize);
}
}
if (minix_empty_indir(buffer, &mdata->sb)) {
minix_free_zone(device, z1);
z1 = 0;
if (single) {
inode->i_zone[7] = z1;
} else {
minix_wr_indir(buffer_indr, ind_ex, z1);
if (device->device == 1) {
ramdisk_write_block(b_indr, buffer_indr, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), b_indr, buffer_indr, mdata->sb.s_blocksize);
}
}
}
} else {
minix_wr_indir(buffer, ex, new_zone);
}
if (z1 != 0) {
if (device->device == 1) {
ramdisk_write_block(z1, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), z1, buffer, mdata->sb.s_blocksize);
}
}
}
if (z1 == 0 && !single && z2 != 0 && minix_empty_indir(buffer, &mdata->sb)) {
minix_free_zone(device, z2);
inode->i_zone[8] = 0;
}
dbfree(buffer_indr, "minix create map 3");
dbfree(buffer, "minix create map 3");
return 1;
}
uint32_t minix_read_map(struct vfs_device_t *device, struct minix_inode *inode, uint64_t position) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
int zind;
int index;
uint32_t block_pos = position / mdata->sb.s_blocksize;
uint32_t zone = block_pos;
uint32_t z;
uint32_t excess;
uint32_t dzones = 7;
uint32_t nr_indirects = mdata->sb.s_blocksize / 4;
char *buffer;
if (zone < dzones) {
zind = (int)zone;
z = inode->i_zone[zind];
if (z == NO_ZONE) {
return NO_BLOCK;
}
return z;
}
excess = zone - dzones;
if (excess < nr_indirects) {
z = inode->i_zone[dzones];
} else {
if ((z = inode->i_zone[dzones + 1]) == NO_ZONE) {
// kprintf("A.");
return NO_BLOCK;
}
excess -= nr_indirects;
index = excess / nr_indirects;
if ((uint32_t)index > nr_indirects) {
// kprintf("1.");
return NO_BLOCK;
}
buffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix read map 1");
if (!buffer) {
// kprintf("2.");
return NO_BLOCK;
}
if (device->device == 1) {
ramdisk_read_block(z, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), z, buffer, mdata->sb.s_blocksize);
}
z = minix_rd_indir(buffer, index);
dbfree(buffer, "minix read map 2");
excess = excess % nr_indirects;
}
if (z == NO_ZONE) {
// kprintf("3.");
return NO_BLOCK;
}
buffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix read map 3");
if (!buffer) {
// kprintf("4.");
return NO_BLOCK;
}
if (device->device == 1) {
ramdisk_read_block(z, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), z, buffer, mdata->sb.s_blocksize);
}
z = minix_rd_indir(buffer, excess);
dbfree(buffer, "minix read map 4");
if (z == NO_ZONE) {
// kprintf("5.");
return NO_BLOCK;
}
return z;
}
void minix_free_bit(struct vfs_device_t *device, int map, uint32_t bit) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
uint32_t offset, index;
uint32_t mask;
uint32_t startblock;
uint32_t block;
uint32_t *bp;
if (map == 0) {
startblock = 2;
} else {
startblock = 2 + mdata->sb.s_imap_blocks;
}
index = (bit % 8192) / 32;
offset = bit % 32;
block = bit / 8192;
mask = 1 << offset;
if (map == 0) {
bp = &mdata->s_imap[(block * mdata->sb.s_blocksize) / 4];
bp[index] &= ~mask;
if (device->device == 1) {
ramdisk_write_blocks(startblock, mdata->sb.s_imap_blocks, (char *)mdata->s_imap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_blocks((device->device & 0xff), startblock + block, 1, (char *)bp, mdata->sb.s_blocksize);
}
} else {
bp = &mdata->s_zmap[(block * mdata->sb.s_blocksize) / 4];
bp[index] &= ~mask;
if (device->device == 1) {
ramdisk_write_blocks(startblock, mdata->sb.s_zmap_blocks, (char *)mdata->s_zmap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_blocks((device->device & 0xff), startblock + block, 1, (char *)bp, mdata->sb.s_blocksize);
}
}
}
uint32_t minix_alloc_bit(struct vfs_device_t *device, int map, uint32_t bit) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
uint32_t i, x, b;
int j;
int oldbit;
uint32_t startblock;
uint32_t block;
if (map == 0) {
oldbit = mdata->sb.s_ninodes;
startblock = 2;
} else {
startblock = 2 + mdata->sb.s_imap_blocks;
oldbit = mdata->sb.s_zones; //(mdata->sb.s_zones - (mdata->first_data_block - 1));
}
if (bit >= oldbit)
bit = 0;
for (j = 0; j < 2; j++) {
if (map == 0) {
// inode map
uint32_t count = (mdata->sb.s_imap_blocks * mdata->sb.s_blocksize) / 4;
for (i = bit / 32; i < count; i++) {
uint32_t mi = mdata->s_imap[i];
if (mi == 0xFFFFFFFF)
continue;
// there's a free bit in here
for (x = 0; (mi & (1U << x)) != 0; x++) {
if (x >= 32) {
kprintf("x >= 32!!!");
}
}
b = i * 32 + x;
if (b >= oldbit)
break;
mi |= 1 << x;
mdata->s_imap[i] = mi;
block = b / (mdata->sb.s_blocksize * 8);
// write out inode table
if (device->device == 1) {
ramdisk_write_blocks(startblock, mdata->sb.s_imap_blocks, (char *)mdata->s_imap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
// hd_write_blocks((device->device & 0xff), startblock, mdata->sb.s_imap_blocks, mdata->s_imap, mdata->sb.s_blocksize);
hd_write_blocks((device->device & 0xff), startblock + block, 1, &((char *)mdata->s_imap)[block * mdata->sb.s_blocksize], mdata->sb.s_blocksize);
}
return b;
}
} else {
// zone map
uint32_t count = mdata->sb.s_zmap_blocks * mdata->sb.s_blocksize / 4;
for (i = bit / 32; i < count; i++) {
uint32_t mi = mdata->s_zmap[i];
if (mi == 0xFFFFFFFF) {
continue;
}
// there's a free bit in here
for (x = 0; (mi & (1 << x)) != 0; x++) {
if (x >= 32) {
kprintf("x >= 32!!!");
}
}
b = i * 32 + x;
if (b >= oldbit)
break;
mi |= 1 << x;
mdata->s_zmap[i] = mi;
block = b / (mdata->sb.s_blocksize * 8);
// write out zone table
if (device->device == 1) {
ramdisk_write_blocks(startblock, mdata->sb.s_zmap_blocks, (char *)mdata->s_zmap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_blocks((device->device & 0xff), startblock + block, 1, &((char *)mdata->s_zmap)[block * mdata->sb.s_blocksize], mdata->sb.s_blocksize);
}
return b;
}
}
if (bit == 0) {
break;
}
oldbit = bit + 1;
bit = 0;
}
kprintf("Failed to get bit!!!\n");
return 0;
}
int minix_write_inode(struct vfs_device_t *device, uint32_t ino, struct minix_inode *inode) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
ino--;
uint32_t offset = mdata->inode_table_start_block;
uint32_t block = ino / (mdata->sb.s_blocksize / sizeof(struct minix_inode)) + offset;
char *buffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix write inode 1");
if (!buffer) {
return 0;
}
if (device->device == 1) {
ramdisk_read_block(block, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), block, buffer, mdata->sb.s_blocksize);
}
uint32_t ino_offset = (ino % (mdata->sb.s_blocksize / sizeof(struct minix_inode))) * sizeof(struct minix_inode);
if (ino_offset >= mdata->sb.s_blocksize) {
kprintf("ino_offset >= block size!\n");
} else {
memcpy(buffer + ino_offset, inode, sizeof(struct minix_inode));
}
if (device->device == 1) {
ramdisk_write_block(block, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block_sync((device->device & 0xff), block, buffer, mdata->sb.s_blocksize);
}
dbfree(buffer, "minix write inode 2");
return 1;
}
char *minix_get_block_map(struct vfs_device_t *device, struct minix_inode *inode, uint64_t position) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
char *buffer;
uint32_t b = minix_read_map(device, inode, position);
if (b == 0) {
return NULL;
}
buffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix get block map 1");
if (!buffer) {
return NULL;
}
if (device->device == 1) {
ramdisk_read_block(b, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), b, buffer, mdata->sb.s_blocksize);
}
return buffer;
}
void minix_put_block_map(struct vfs_device_t *device, struct minix_inode *inode, uint64_t position, char *buffer) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
uint32_t b = minix_read_map(device, inode, position);
if (b == 0) {
kprintf("Error reading map\n");
return;
}
if (device->device == 1) {
ramdisk_write_block(b, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), b, buffer, mdata->sb.s_blocksize);
}
dbfree(buffer, "minix put block map 1");
}
void minix_zerozone_range(struct vfs_device_t *device, struct minix_inode *inode, uint64_t pos, uint32_t len) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
char *buffer;
uint32_t offset;
uint32_t bytes;
if (!len)
return;
while (len > 0) {
buffer = minix_get_block_map(device, inode, (uint64_t)((pos / mdata->sb.s_blocksize) * pos));
offset = pos % mdata->sb.s_blocksize;
bytes = mdata->sb.s_blocksize - offset;
if (bytes > len) {
bytes = len;
}
memset(buffer + offset, 0, bytes);
minix_put_block_map(device, inode, (uint64_t)((pos / mdata->sb.s_blocksize) * pos), buffer);
pos += bytes;
len -= bytes;
}
}
uint32_t minix_nextblock(uint32_t pos, int zone_size) {
uint32_t p;
p = (pos / zone_size) * zone_size;
if ((pos % zone_size))
p += zone_size;
return p;
}
void minix_zerozone_half(struct vfs_device_t *device, struct minix_inode *inode, uint64_t pos, int half, int zone_size) {
uint32_t offset, len;
offset = pos % zone_size;
if (half == 1) {
len = zone_size - offset;
} else {
len = offset;
}
minix_zerozone_range(device, inode, pos, len);
}
int minix_clear_zones(struct vfs_device_t *device, int ino, uint64_t start, uint64_t end) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
struct minix_inode *inode = minix_get_inode(device, ino);
uint64_t e;
uint64_t p;
int zero_first, zero_last;
if (end > inode->i_size) {
end = inode->i_size;
}
if (end <= start) {
return 0;
}
zero_last = start % mdata->sb.s_blocksize;
zero_first = end % mdata->sb.s_blocksize && end < inode->i_size;
if (start / mdata->sb.s_blocksize == (end - 1) / mdata->sb.s_blocksize && (zero_last || zero_first)) {
minix_zerozone_range(device, inode, start, end - start);
} else {
if (zero_last)
minix_zerozone_half(device, inode, start, 1, mdata->sb.s_blocksize);
if (zero_first)
minix_zerozone_half(device, inode, end, 0, mdata->sb.s_blocksize);
e = end / mdata->sb.s_blocksize;
if (end == inode->i_size && (end % mdata->sb.s_blocksize))
e++;
for (p = minix_nextblock(start, mdata->sb.s_blocksize) / mdata->sb.s_blocksize; p < e; p++) {
if (!minix_write_map(device, inode, ino, (uint64_t)(p * mdata->sb.s_blocksize), 0, 1)) {
kprintf("Failed to free block %d\n", p);
}
}
}
return 1;
}
void minix_wipe_inode(struct vfs_device_t *device, struct minix_file_info *finfo) {
struct minix_inode *inode = minix_get_inode(device, finfo->inode);
inode->i_size = 0;
for (int i = 0; i < 10; i++) {
inode->i_zone[i] = NO_ZONE;
}
minix_write_inode(device, finfo->inode, inode);
}
void minix_trunc_file(struct vfs_device_t *device, struct minix_file_info *finfo) { minix_clear_zones(device, finfo->inode, 0, finfo->file_size); }
void minix_free_inode(struct vfs_device_t *device, uint32_t ino) { minix_free_bit(device, 0, ino); }
struct minix_inode *minix_alloc_inode(struct vfs_device_t *device, uint16_t mode, uint32_t *ino) {
uint32_t b;
struct minix_inode *new_inode;
b = minix_alloc_bit(device, 0, 0);
if (b == 0) {
return NULL;
}
new_inode = (struct minix_inode *)dbmalloc(sizeof(struct minix_inode), "minix alloc inode 1");
if (!new_inode) {
minix_free_bit(device, 0, b);
return NULL;
}
memset(new_inode, 0, sizeof(struct minix_inode));
new_inode->i_mode = mode;
new_inode->i_atime = rtc_get_time();
new_inode->i_mtime = new_inode->i_atime;
new_inode->i_ctime = new_inode->i_atime;
minix_write_inode(device, b, new_inode);
*ino = b;
return new_inode;
}
struct minix_inode *minix_get_inode(struct vfs_device_t *device, int ino) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
int inodes_per_block = mdata->sb.s_blocksize / sizeof(struct minix_inode);
uint32_t block;
char *buffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix get inode 1");
if (!buffer) {
return NULL;
}
struct minix_inode *inode = (struct minix_inode *)dbmalloc(sizeof(struct minix_inode), "minix get inode 2");
if (!inode) {
dbfree(buffer, "minix get inode 3");
return NULL;
}
if (ino == 0 || ino > mdata->sb.s_ninodes) {
dbfree(buffer, "minix get inode 4");
dbfree(inode, "minix get inode 5");
return NULL;
}
ino--;
block = mdata->inode_table_start_block + ino / inodes_per_block;
if (device->device == 1) {
ramdisk_read_block(block, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), block, buffer, mdata->sb.s_blocksize);
}
memcpy(inode, &buffer[(ino % inodes_per_block) * sizeof(struct minix_inode)], sizeof(struct minix_inode));
dbfree(buffer, "minix get inode 6");
return inode;
}
uint32_t minix_read_entire_file(struct vfs_device_t *device, struct minix_inode *inode, char **buffer) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
uint64_t i;
uint32_t blockstoread;
char *buffer2;
int blockno;
uint32_t size;
char *buffer_loc;
size = inode->i_size;
uint32_t bytesleft = size;
blockstoread = size / mdata->sb.s_blocksize;
if (size % mdata->sb.s_blocksize) {
blockstoread++;
}
buffer_loc = (char *)dbmalloc(size, "minix_read_entire_file malloc 1");
if (!buffer_loc) {
return -1;
}
*buffer = buffer_loc;
buffer2 = (char *)dbmalloc(mdata->sb.s_blocksize, "minix_read_entire_file malloc 2");
if (!buffer2) {
dbfree(buffer_loc, "minix_read_entire_file free 1");
*buffer = NULL;
return -1;
}
for (i = 0; i < blockstoread; i++) {
blockno = minix_read_map(device, inode, (uint64_t)(i * mdata->sb.s_blocksize));
if (device->device == 1) {
ramdisk_read_block(blockno, buffer2, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
if (hd_read_block((device->device & 0xff), blockno, buffer2, mdata->sb.s_blocksize) == NULL) {
kprintf("hd_read_block returned NULL\n");
}
}
if (bytesleft >= mdata->sb.s_blocksize) {
memcpy(&buffer_loc[i * mdata->sb.s_blocksize], buffer2, mdata->sb.s_blocksize);
bytesleft -= mdata->sb.s_blocksize;
} else {
memcpy(&buffer_loc[i * mdata->sb.s_blocksize], buffer2, bytesleft);
bytesleft = 0;
}
}
dbfree(buffer2, "minix_read_entire_file free 2");
return size;
}
struct minix_file_info *minix_find_sub_entry(struct vfs_device_t *device, uint32_t ino, char **ptr, int part, int parts, int type) {
int i;
char *buffer;
struct minix_inode *inode;
struct minix_inode *pinode;
struct minix_dir_entry *dir;
struct minix_file_info *fileinf;
int size;
int childinode;
inode = minix_get_inode(device, ino);
if (!inode) {
return NULL;
}
if (S_IFDIR & inode->i_mode) {
// find direntry for part 0;
size = minix_read_entire_file(device, inode, &buffer);
if (size > 0) {
for (i = 0; i < size / sizeof(struct minix_dir_entry); i++) {
dir = &((struct minix_dir_entry *)buffer)[i];
if (parts == part + 1) {
if (strcmp(dir->name, ptr[part]) == 0) {
pinode = minix_get_inode(device, dir->inode);
if (pinode != NULL) {
if (pinode->i_nlinks > 0) {
if (type == 0 && (pinode->i_mode & S_IFDIR)) {
fileinf = (struct minix_file_info *)dbmalloc(sizeof(struct minix_file_info), "minix find sub entry 1");
if (!fileinf) {
dbfree(inode, "minix find sub entry 2");
dbfree(pinode, "minix find sub entry 3");
dbfree(buffer, "minix find sub entry 4");
return NULL;
}
fileinf->inode = dir->inode;
fileinf->file_size = pinode->i_size;
fileinf->type = 0;
fileinf->atime = pinode->i_atime;
fileinf->ctime = pinode->i_ctime;
fileinf->mtime = pinode->i_mtime;
dbfree(inode, "minix find sub entry 5");
dbfree(pinode, "minix find sub entry 6");
dbfree(buffer, "minix find sub entry 7");
return fileinf;
} else if (type == 1 && (pinode->i_mode & S_IFREG)) {
fileinf = (struct minix_file_info *)dbmalloc(sizeof(struct minix_file_info), "minix find sub entry 8");
if (!fileinf) {
dbfree(inode, "minix find sub entry 9");
dbfree(pinode, "minix find sub entry 10");
dbfree(buffer, "minix find sub entry 11");
return NULL;
}
fileinf->inode = dir->inode;
fileinf->file_size = pinode->i_size;
fileinf->type = 1;
fileinf->atime = pinode->i_atime;
fileinf->ctime = pinode->i_ctime;
fileinf->mtime = pinode->i_mtime;
dbfree(inode, "minix find sub entry 12");
dbfree(pinode, "minix find sub entry 13");
dbfree(buffer, "minix find sub entry 14");
return fileinf;
} else if (type == -1) {
fileinf = (struct minix_file_info *)dbmalloc(sizeof(struct minix_file_info), "minix find sub entry 15");
if (!fileinf) {
dbfree(inode, "minix find sub entry 16");
dbfree(pinode, "minix find sub entry 17");
dbfree(buffer, "minix find sub entry 18");
return NULL;
}
fileinf->inode = dir->inode;
fileinf->file_size = pinode->i_size;
if (pinode->i_mode & S_IFDIR) {
fileinf->type = 0;
} else {
fileinf->type = 1;
}
fileinf->atime = pinode->i_atime;
fileinf->ctime = pinode->i_ctime;
fileinf->mtime = pinode->i_mtime;
dbfree(inode, "minix find sub entry 19");
dbfree(pinode, "minix find sub entry 20");
dbfree(buffer, "minix find sub entry 21");
return fileinf;
} else {
dbfree(inode, "minix find sub entry 22");
dbfree(pinode, "minix find sub entry 23");
dbfree(buffer, "minix find sub entry 24");
return NULL;
}
} else {
dbfree(inode, "minix find sub entry 25");
dbfree(pinode, "minix find sub entry 26");
dbfree(buffer, "minix find sub entry 27");
return NULL;
}
}
}
} else {
if (strcmp(dir->name, ptr[part]) == 0) {
pinode = minix_get_inode(device, dir->inode);
if (pinode->i_nlinks > 0 && pinode->i_mode & S_IFDIR) {
childinode = dir->inode;
dbfree(pinode, "minix find sub entry 28");
dbfree(inode, "minix find sub entry 29");
dbfree(buffer, "minix find sub entry 30");
return minix_find_sub_entry(device, childinode, ptr, part + 1, parts, type);
} else {
dbfree(inode, "minix find sub entry 31");
dbfree(pinode, "minix find sub entry 32");
dbfree(buffer, "minix find sub entry 33");
return NULL;
}
}
}
}
} else {
dbfree(inode, "minix find sub entry 34");
return NULL;
}
} else {
// root directory is not a directory ??
dbfree(inode, "minix find sub entry 35");
return NULL;
}
return NULL;
}
struct minix_file_info *minix_check_if_exists(struct vfs_device_t *device, const char *path, int type) {
int i;
int parts = 0;
char *path_copy = (char *)dbmalloc(strlen(path) + 1, "check if exists 1");
char *buffer;
struct minix_inode *inode;
struct minix_inode *pinode;
struct minix_dir_entry *dir;
struct minix_file_info *fileinf;
int size;
int childinode;
if (strcmp(path, "/") == 0) {
struct minix_file_info *info = (struct minix_file_info *)dbmalloc(sizeof(struct minix_file_info), "check if exists 2");
if (!info) {
dbfree(path_copy, "check if exists 3");
return NULL;
}
inode = minix_get_inode(device, 1);
info->inode = 1;
info->file_size = inode->i_size;
info->type = 0;
info->atime = inode->i_atime;
info->ctime = inode->i_ctime;
info->mtime = inode->i_mtime;
dbfree(inode, "check if exists 4");
return info;
}
strcpy(path_copy, path);
if (path_copy[strlen(path_copy) - 1] == '/') {
path_copy[strlen(path_copy) - 1] = '\0';
}
parts = 1;
for (i = 1; i < strlen(path_copy); i++) {
if (path_copy[i] == '/') {
parts++;
}
}
char **ptr = (char **)dbmalloc(sizeof(char *) * parts, "check if exists 5");
ptr[0] = &path_copy[1];
int j = 0;
int k = strlen(path_copy);
for (i = 1; i < k; i++) {
if (path_copy[i] == '/') {
ptr[++j] = &path_copy[i + 1];
path_copy[i] = '\0';
}
}
inode = minix_get_inode(device, 1);
if (!inode) {
dbfree(ptr, "check if exists 6");
dbfree(path_copy, "check if exists 7");
return NULL;
}
if (S_IFDIR & inode->i_mode) {
// find direntry for part 0;
size = minix_read_entire_file(device, inode, &buffer);
if (size > 0) {
for (i = 0; i < size / 64; i++) {
dir = (struct minix_dir_entry *)(buffer + (i * 64));
if (parts == 1) {
if (strcmp(dir->name, ptr[0]) == 0) {
pinode = minix_get_inode(device, dir->inode);
if (pinode != NULL) {
if (pinode->i_nlinks > 0) {
if (type == 0 && (pinode->i_mode & S_IFDIR)) {
fileinf = (struct minix_file_info *)dbmalloc(sizeof(struct minix_file_info), "check if exists 8");
if (!fileinf) {
dbfree(ptr, "check if exists 9");
dbfree(inode, "check if exists 10");
dbfree(pinode, "check if exists 11");
dbfree(buffer, "check if exists 12");
dbfree(path_copy, "check if exists 13");
return NULL;
}
fileinf->inode = dir->inode;
fileinf->file_size = pinode->i_size;
fileinf->type = 0;
fileinf->atime = pinode->i_atime;
fileinf->ctime = pinode->i_ctime;
fileinf->mtime = pinode->i_mtime;
dbfree(ptr, "check if exists 14");
dbfree(inode, "check if exists 15");
dbfree(pinode, "check if exists 16");
dbfree(buffer, "check if exists 17");
dbfree(path_copy, "check if exists 18");
return fileinf;
} else if (type == 1 && (pinode->i_mode & S_IFREG)) {
fileinf = (struct minix_file_info *)dbmalloc(sizeof(struct minix_file_info), "check if exists 19");
if (!fileinf) {
dbfree(ptr, "check if exists 20");
dbfree(inode, "check if exists 21");
dbfree(pinode, "check if exists 22");
dbfree(buffer, "check if exists 23");
dbfree(path_copy, "check if exists 24");
return NULL;
}
fileinf->inode = dir->inode;
fileinf->file_size = pinode->i_size;
fileinf->type = 1;
fileinf->atime = pinode->i_atime;
fileinf->ctime = pinode->i_ctime;
fileinf->mtime = pinode->i_mtime;
dbfree(ptr, "check if exists 25");
dbfree(inode, "check if exists 26");
dbfree(pinode, "check if exists 27");
dbfree(buffer, "check if exists 28");
dbfree(path_copy, "check if exists 29");
return fileinf;
} else if (type == -1) {
fileinf = (struct minix_file_info *)dbmalloc(sizeof(struct minix_file_info), "check if exists 30");
if (!fileinf) {
dbfree(inode, "check if exists 31");
dbfree(pinode, "check if exists 32");
dbfree(buffer, "check if exists 33");
dbfree(ptr, "check if exists 34");
dbfree(path_copy, "check if exists 35");
return NULL;
}
fileinf->inode = dir->inode;
fileinf->file_size = pinode->i_size;
if (pinode->i_mode & S_IFDIR) {
fileinf->type = 0;
} else {
fileinf->type = 1;
}
fileinf->atime = pinode->i_atime;
fileinf->ctime = pinode->i_ctime;
fileinf->mtime = pinode->i_mtime;
dbfree(ptr, "check if exists 36");
dbfree(inode, "check if exists 37");
dbfree(pinode, "check if exists 38");
dbfree(buffer, "check if exists 39");
dbfree(path_copy, "check if exists 40");
return fileinf;
} else {
dbfree(inode, "check if exists 41");
dbfree(pinode, "check if exists 42");
dbfree(buffer, "check if exists 43");
dbfree(ptr, "check if exists 44");
dbfree(path_copy, "check if exists 45");
return NULL;
}
} else {
dbfree(inode, "check if exists 46");
dbfree(pinode, "check if exists 47");
dbfree(buffer, "check if exists 48");
dbfree(ptr, "check if exists 49");
dbfree(path_copy, "check if exists 50");
return NULL;
}
}
}
} else {
if (strcmp(dir->name, ptr[0]) == 0) {
pinode = minix_get_inode(device, dir->inode);
if (pinode->i_nlinks > 0 && pinode->i_mode & S_IFDIR) {
childinode = dir->inode;
dbfree(pinode, "check if exists 51");
dbfree(inode, "check if exists 52");
dbfree(buffer, "check if exists 53");
fileinf = minix_find_sub_entry(device, childinode, ptr, 1, parts, type);
dbfree(ptr, "check if exists 54");
dbfree(path_copy, "check if exists 55");
return fileinf;
} else {
dbfree(inode, "check if exists 56");
dbfree(pinode, "check if exists 57");
dbfree(buffer, "check if exists 58");
dbfree(path_copy, "check if exists 59");
return NULL;
}
}
}
}
dbfree(buffer, "check if exists 60");
dbfree(ptr, "check if exists 61");
dbfree(inode, "check if exists 62");
} else {
dbfree(inode, "check if exists 63");
dbfree(path_copy, "check if exists 64");
return NULL;
}
} else {
// root directory is not a directory ??
dbfree(inode, "check if exists 65");
dbfree(path_copy, "check if exists 66");
return NULL;
}
dbfree(path_copy, "check if exists 67");
return NULL;
}
int minix_change_directory(struct vfs_device_t *device, char *path) {
struct minix_file_info *mi;
if (path[0] == '/' && path[1] == '\0') {
return 1;
} else {
mi = minix_check_if_exists(device, path, 0);
if (mi) {
free(mi);
return 1;
} else {
return 0;
}
}
}
int minix_read_data(struct vfs_device_t *device, struct minix_file_info *info, char *buffer, int len, uint64_t offset) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
uint32_t blockcount;
uint32_t block_start;
uint32_t block_offset;
uint32_t j;
struct minix_inode *inode = minix_get_inode(device, info->inode);
uint32_t buffer_at;
char *tempbuffer;
int count = 0;
if (!inode) {
return 0;
}
if (info->type == 0) {
dbfree(inode, "minix read data 0");
return 0;
}
tempbuffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix read data 1");
if (!tempbuffer) {
dbfree(inode, "minix read data 1.5");
return 0;
}
if (len + offset > info->file_size) {
count = info->file_size - offset;
} else {
count = len;
}
if (count > 0) {
block_start = offset / mdata->sb.s_blocksize;
block_offset = offset % mdata->sb.s_blocksize;
blockcount = (count + block_offset) / mdata->sb.s_blocksize;
if ((count + block_offset) % mdata->sb.s_blocksize > 0) {
blockcount += 1;
}
if (device->device == 1) {
for (j = block_start; j < block_start + blockcount; j++) {
ramdisk_read_block(minix_read_map(device, inode, (uint64_t)(j * mdata->sb.s_blocksize)), tempbuffer, mdata->sb.s_blocksize);
if (j == block_start) {
if (count + block_offset > mdata->sb.s_blocksize) {
memcpy(buffer, &tempbuffer[block_offset], mdata->sb.s_blocksize - block_offset);
buffer_at = mdata->sb.s_blocksize - block_offset;
} else {
memcpy(buffer, &tempbuffer[block_offset], count);
dbfree(tempbuffer, "minix read data 2");
dbfree(inode, "minix read data 3");
return count;
}
} else {
if (count - buffer_at > mdata->sb.s_blocksize) {
memcpy(&buffer[buffer_at], tempbuffer, mdata->sb.s_blocksize);
buffer_at += mdata->sb.s_blocksize;
} else {
memcpy(&buffer[buffer_at], tempbuffer, count - buffer_at);
dbfree(tempbuffer, "minix read data 4");
dbfree(inode, "minix read data 5");
return count;
}
}
}
} else if ((device->device & 0xff00) == 0x100) {
for (j = block_start; j < block_start + blockcount; j++) {
hd_read_block((device->device & 0xff), minix_read_map(device, inode, (uint64_t)(j * mdata->sb.s_blocksize)), tempbuffer, mdata->sb.s_blocksize);
if (j == block_start) {
if (count + block_offset > mdata->sb.s_blocksize) {
memcpy(buffer, &tempbuffer[block_offset], mdata->sb.s_blocksize - block_offset);
buffer_at = mdata->sb.s_blocksize - block_offset;
} else {
memcpy(buffer, &tempbuffer[block_offset], count);
dbfree(tempbuffer, "minix read data 6");
dbfree(inode, "minix read data 7");
return count;
}
} else {
if (count - buffer_at > mdata->sb.s_blocksize) {
memcpy(&buffer[buffer_at], tempbuffer, mdata->sb.s_blocksize);
buffer_at += mdata->sb.s_blocksize;
} else {
memcpy(&buffer[buffer_at], tempbuffer, count - buffer_at);
dbfree(tempbuffer, "minix read data 8");
dbfree(inode, "minix read data 9");
return count;
}
}
}
}
}
dbfree(tempbuffer, "minix read data 10");
dbfree(inode, "minix read data 11");
return 0;
}
int minix_get_dents(struct vfs_device_t *device, struct minix_file_info *info, char *buffer, int len, uint64_t offset, uint64_t *newoffset) {
struct minix_inode *inode = minix_get_inode(device, info->inode);
char *buffer2;
int dirlen = minix_read_entire_file(device, inode, &buffer2);
char *dir_buffer;
uint32_t bytesread;
int buff_offset = 0;
int i;
if (offset >= dirlen) {
dbfree(buffer2, "minix get dents 1");
return 0;
}
dir_buffer = (char *)dbmalloc(dirlen - offset + 1, "minix get dents 2");
memcpy(dir_buffer, &buffer2[offset], dirlen - offset);
dbfree(buffer2, "minix get dents 3");
*newoffset = 0;
bytesread = dirlen - offset;
for (i = 0; i < bytesread / sizeof(struct minix_dir_entry); i++) {
struct minix_dir_entry *dir = (struct minix_dir_entry *)(dir_buffer + (i * sizeof(struct minix_dir_entry)));
struct quinn_dirent_t *dent = (struct quinn_dirent_t *)(&buffer[buff_offset]);
if (buff_offset + sizeof(struct quinn_dirent_t) + strlen(dir->name) + 1 > len) {
dbfree(dir_buffer, "minix get dents 4");
return buff_offset;
}
dent->name_len = strlen(dir->name);
dent->rec_len = sizeof(struct quinn_dirent_t) + strlen(dir->name) + 1;
dent->next_offset = buff_offset + dent->rec_len;
strcpy(dent->name, dir->name);
buff_offset = dent->next_offset;
*newoffset += sizeof(struct minix_dir_entry);
}
dbfree(dir_buffer, "minix get dents 5");
return buff_offset;
}
int minix_write_data(struct vfs_device_t *device, struct minix_file_info *info, char *filename, char *buffer, int len, uint64_t offset) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
struct minix_inode *inode = minix_get_inode(device, info->inode);
uint32_t blockcount;
uint32_t block_start;
uint32_t block_offset;
uint32_t i;
char *obuffer;
uint32_t block;
uint32_t last_block = 0;
uint32_t buffer_at = 0;
obuffer = (char *)dbmalloc(mdata->sb.s_blocksize, "minix write data 1");
if (!obuffer) {
return 0;
}
if (info->type == 0) {
// it's a directory
dbfree(inode, "minix write data 2");
dbfree(obuffer, "minix write data 3");
return 0;
}
if (len > 0) {
block_start = offset / mdata->sb.s_blocksize;
block_offset = offset % mdata->sb.s_blocksize;
blockcount = (len + block_offset) / mdata->sb.s_blocksize;
if ((len + block_offset) % mdata->sb.s_blocksize > 0) {
blockcount += 1;
}
for (i = block_start; i < blockcount + block_start; i++) {
block = minix_read_map(device, inode, i * mdata->sb.s_blocksize);
if (block == 0) {
uint32_t az = minix_alloc_zone(device, last_block);
if (!minix_write_map(device, inode, info->inode, (uint64_t)(i * mdata->sb.s_blocksize), az, 0)) {
if (inode->i_size < offset + buffer_at) {
inode->i_size = offset + buffer_at;
minix_write_inode(device, info->inode, inode);
}
dbfree(obuffer, "minix write data 4");
dbfree(inode, "minix write data 5");
return buffer_at;
}
block = minix_read_map(device, inode, i * mdata->sb.s_blocksize);
if (block == 0) {
if (inode->i_size < offset + buffer_at) {
inode->i_size = offset + buffer_at;
minix_write_inode(device, info->inode, inode);
}
dbfree(obuffer, "minix write data 6");
dbfree(inode, "minix write data 7");
return buffer_at;
}
} else {
last_block = block;
if (device->device == 1) {
ramdisk_read_block(block, obuffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), block, obuffer, mdata->sb.s_blocksize);
}
}
if (i == block_start) {
if (len + block_offset > mdata->sb.s_blocksize) {
memcpy(&obuffer[block_offset], buffer, mdata->sb.s_blocksize - block_offset);
buffer_at = mdata->sb.s_blocksize - block_offset;
if (device->device == 1) {
ramdisk_write_block(block, obuffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), block, obuffer, mdata->sb.s_blocksize);
}
} else {
memcpy(&obuffer[block_offset], buffer, len);
if (device->device == 1) {
ramdisk_write_block(block, obuffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), block, obuffer, mdata->sb.s_blocksize);
}
if (inode->i_size < offset + len) {
inode->i_size = offset + len;
minix_write_inode(device, info->inode, inode);
}
dbfree(obuffer, "minix write data 8");
dbfree(inode, "minix write data 9");
return len;
}
} else {
if (len - buffer_at > mdata->sb.s_blocksize) {
memcpy(obuffer, &buffer[buffer_at], mdata->sb.s_blocksize);
buffer_at += mdata->sb.s_blocksize;
if (device->device == 1) {
ramdisk_write_block(block, obuffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), block, obuffer, mdata->sb.s_blocksize);
}
} else {
memcpy(obuffer, &buffer[buffer_at], len - buffer_at);
if (device->device == 1) {
ramdisk_write_block(block, obuffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), block, obuffer, mdata->sb.s_blocksize);
}
if (inode->i_size < offset + len) {
inode->i_size = offset + len;
minix_write_inode(device, info->inode, inode);
}
dbfree(obuffer, "minix write data 10");
dbfree(inode, "minix write data 11");
return len;
}
}
}
}
return 0;
}
int minix_link_file(struct vfs_device_t *device, const char *src, const char *dest) {
struct minix_file_info *mi1 = minix_check_if_exists(device, src, 1);
char *dest_dir;
char *dest_file;
char *dest_copy;
char *src_copy;
int dest_dir_ino;
int src_file_ino;
if (!mi1) {
return -2; // enoent
}
src_file_ino = mi1->inode;
dest_copy = (char *)dbmalloc(strlen(dest) + 1, "minix link file 1");
if (!dest_copy) {
dbfree(mi1, "minix link file 2");
return -1;
}
strcpy(dest_copy, dest);
src_copy = (char *)dbmalloc(strlen(src) + 1, "minix link file 3");
if (!src_copy) {
dbfree(dest_copy, "minix link file 4");
dbfree(mi1, "minix link file 5");
return -1;
}
strcpy(src_copy, src);
for (int i = strlen(src_copy) - 1; i >= 0; i--) {
if (src_copy[i] == '/') {
src_copy[i] = '\0';
break;
}
}
struct minix_file_info *mi2 = minix_check_if_exists(device, dest, -1);
if (mi2) {
// dest exists bail..
dbfree(src_copy, "minix link file 6");
dbfree(dest_copy, "minix link file 7");
dbfree(mi1, "minix link file 8");
dbfree(mi2, "minix link file 9");
return -3; // EEXIST
}
for (int i = strlen(dest_copy) - 1; i >= 0; i--) {
if (dest_copy[i] == '/') {
dest_copy[i] = '\0';
dest_file = &dest_copy[i + 1];
break;
}
}
dest_dir = dest_copy;
if (strlen(dest_dir) == 0) {
dest_dir_ino = 1;
} else {
struct minix_file_info *mi3 = minix_check_if_exists(device, dest_dir, 0);
if (!mi3) {
dbfree(src_copy, "minix link file 10");
dbfree(dest_copy, "minix link file 11");
dbfree(mi1, "minix link file 12");
dbfree(mi2, "minix link file 13");
kprintf("Error 5\n");
return -4; // ENOTDIR
}
dest_dir_ino = mi3->inode;
dbfree(mi3, "minix link file 14");
}
struct minix_inode *dir_i = minix_get_inode(device, dest_dir_ino);
if (!dir_i) {
dbfree(src_copy, "minix link file 15");
dbfree(dest_copy, "minix link file 16");
dbfree(mi1, "minix link file 17");
dbfree(mi2, "minix link file 18");
return -4;
}
struct minix_inode *file_i = minix_get_inode(device, src_file_ino);
if (!file_i) {
dbfree(dir_i, "minix link file 19");
dbfree(src_copy, "minix link file 20");
dbfree(dest_copy, "minix link file 21");
dbfree(mi1, "minix link file 22");
dbfree(mi2, "minix link file 23");
return -2;
}
if (!minix_add_directory_entry(device, dir_i, dest_dir_ino, dest_file, src_file_ino)) {
dbfree(file_i, "minix link file 24");
dbfree(dir_i, "minix link file 25");
dbfree(src_copy, "minix link file 26");
dbfree(dest_copy, "minix link file 27");
dbfree(mi1, "minix link file 28");
dbfree(mi2, "minix link file 29");
return -1;
}
file_i->i_nlinks++;
minix_write_inode(device, src_file_ino, file_i);
dbfree(file_i, "minix link file 30");
dbfree(dir_i, "minix link file 31");
dbfree(src_copy, "minix link file 32");
dbfree(dest_copy, "minix link file 33");
dbfree(mi1, "minix link file 34");
dbfree(mi2, "minix link file 35");
return 0;
}
int minix_unlink_file(struct vfs_device_t *device, const char *path) {
struct minix_file_info *mi = minix_check_if_exists(device, path, 1);
if (!mi) {
return -2;
}
struct minix_inode *fileinode = minix_get_inode(device, mi->inode);
char *oldfile = NULL;
int dir_ino;
char *path_copy = (char *)dbmalloc(strlen(path) + 1, "minix unlink file 1");
if (!path_copy) {
dbfree(mi, "minix unlink file 2");
kprintf("error 1\n");
return -1;
}
strcpy(path_copy, path);
if (strlen(path_copy) > 1 && path_copy[strlen(path_copy) - 1] == '/') {
path_copy[strlen(path_copy) - 1] = '\0';
}
for (int i = strlen(path_copy) - 1; i >= 0; i--) {
if (path_copy[i] == '/') {
path_copy[i] = '\0';
oldfile = &path_copy[i] + 1;
break;
}
}
if (oldfile == NULL) {
dbfree(path_copy, "minix unlink file 3");
dbfree(mi, "minix unlink file 4");
kprintf("error 2\n");
return -1;
}
if (strlen(path_copy) == 0) {
dir_ino = 1;
} else {
struct minix_file_info *info = minix_check_if_exists(device, path_copy, 0);
dir_ino = info->inode;
free(info);
}
struct minix_inode *dirp = minix_get_inode(device, dir_ino);
if (!minix_remove_directory_entry(device, dirp, oldfile)) {
dbfree(dirp, "minix unlink file 5");
dbfree(path_copy, "minix unlink file 6");
dbfree(fileinode, "minix unlink file 7");
dbfree(mi, "minix unlink file 8");
kprintf("error 3\n");
return -1;
}
fileinode->i_nlinks--;
if (fileinode->i_nlinks == 0) {
minix_trunc_file(device, mi);
minix_free_inode(device, mi->inode);
} else {
minix_write_inode(device, mi->inode, fileinode);
}
dbfree(dirp, "minix unlink file 9");
dbfree(path_copy, "minix unlink file 10");
dbfree(fileinode, "minix unlink file 11");
dbfree(mi, "minix unlink file 12");
return 0;
}
int minix_create_directory(struct vfs_device_t *device, const char *new_path) {
struct minix_file_info *mi = minix_check_if_exists(device, new_path, -1);
if (mi) {
dbfree(mi, "minix create directory 2");
return -2;
}
char *path_copy = (char *)dbmalloc(strlen(new_path) + 1, "minix create directory 2");
char *newdir = NULL;
int dir_ino;
int dot_dot_ino;
int dot_ino;
int new_ino;
if (!path_copy) {
return -1;
}
strcpy(path_copy, new_path);
if (strlen(path_copy) > 1 && path_copy[strlen(path_copy) - 1] == '/') {
path_copy[strlen(path_copy) - 1] = '\0';
}
for (int i = strlen(path_copy) - 1; i >= 0; i--) {
if (path_copy[i] == '/') {
path_copy[i] = '\0';
newdir = &path_copy[i] + 1;
break;
}
}
if (newdir == NULL) {
dbfree(path_copy, "minix create directory 3");
return -1;
}
if (strlen(path_copy) == 0) {
dir_ino = 1;
} else {
struct minix_file_info *info = minix_check_if_exists(device, path_copy, 0);
dir_ino = info->inode;
dbfree(info, "minix create directory 4");
}
struct minix_inode *dirp = minix_get_inode(device, dir_ino);
if (!dirp) {
dbfree(path_copy, "minix create directory 5");
kprintf("Unable to get inode for %s\n", path_copy);
return -1;
}
struct minix_inode *newinode = minix_new_node(device, dirp, dir_ino, newdir, S_IFDIR | 0755, 0, (uint32_t *)&new_ino);
if (newinode == NULL) {
dbfree(dirp, "minix create directory 6");
dbfree(path_copy, "minix create directory 7");
return -2;
}
dot_dot_ino = dir_ino;
dot_ino = new_ino;
if (!minix_add_directory_entry(device, newinode, new_ino, ".", dot_ino)) {
// TODO: remove directory entry
dirp->i_nlinks--;
}
if (!minix_add_directory_entry(device, newinode, new_ino, "..", dot_dot_ino)) {
// TODO: remove directory entry
dirp->i_nlinks--;
}
dirp->i_nlinks++;
newinode->i_nlinks++;
minix_write_inode(device, dir_ino, dirp);
minix_write_inode(device, new_ino, newinode);
dbfree(newinode, "minix create directory 8");
dbfree(dirp, "minix create directory 9");
dbfree(path_copy, "minix create directory 10");
return 0;
}
int minix_load_superblock(struct vfs_device_t *device) {
uint8_t *buffer;
struct minix_data *mdata;
buffer = (uint8_t *)dbmalloc(1024, "minix load superblock 1");
if (!buffer) {
return 0;
}
mdata = (struct minix_data *)dbmalloc(sizeof(struct minix_data), "minix load superblock 2");
if (!mdata) {
dbfree(buffer, "minix load superblock 3");
return 0;
}
if (device->device == 1) {
ramdisk_read_block(1, (char *)buffer, 1024);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), 1, (char *)buffer, 1024);
}
memcpy((char *)&mdata->sb, buffer, sizeof(struct minix_super_block));
if (mdata->sb.s_magic != 0x4d5a || mdata->sb.s_log_zone_size != 0) {
kprintf("MINIX FS: Unrecognized Filesystem (Magic: %x)\n", mdata->sb.s_magic);
dbfree(buffer, "minix load superblock 4");
dbfree(mdata, "minix load superblock 5");
return 0;
}
mdata->s_imap = (uint32_t *)dbmalloc(mdata->sb.s_imap_blocks * mdata->sb.s_blocksize, "minix load superblock 6");
if (!mdata->s_imap) {
dbfree(buffer, "minix load superblock 7");
dbfree(mdata, "minix load superblock 8");
return 0;
}
mdata->s_zmap = (uint32_t *)dbmalloc(mdata->sb.s_zmap_blocks * mdata->sb.s_blocksize, "minix load superblock 9");
if (!mdata->s_zmap) {
dbfree(mdata->s_imap, "minix load superblock 10");
dbfree(buffer, "minix load superblock 11");
dbfree(mdata, "minix load superblock 12");
return 0;
}
if (device->device == 1) {
ramdisk_read_blocks(2, mdata->sb.s_imap_blocks, (char *)mdata->s_imap, mdata->sb.s_blocksize);
ramdisk_read_blocks(2 + mdata->sb.s_imap_blocks, mdata->sb.s_zmap_blocks, (char *)mdata->s_zmap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_blocks((device->device & 0xff), 2, mdata->sb.s_imap_blocks, (char *)mdata->s_imap, mdata->sb.s_blocksize);
hd_read_blocks((device->device & 0xff), 2 + mdata->sb.s_imap_blocks, mdata->sb.s_zmap_blocks, (char *)mdata->s_zmap, mdata->sb.s_blocksize);
}
mdata->inode_table_start_block = 2 + mdata->sb.s_imap_blocks + mdata->sb.s_zmap_blocks;
if (mdata->sb.s_first_data_zone == 0) {
mdata->first_data_block = mdata->inode_table_start_block + ((mdata->sb.s_ninodes * sizeof(struct minix_inode)) / mdata->sb.s_blocksize);
if ((mdata->sb.s_ninodes * sizeof(struct minix_inode)) % mdata->sb.s_blocksize != 0) {
kprintf("More inodes than blocksize\n");
mdata->first_data_block += 1;
}
} else {
mdata->first_data_block = (uint32_t)mdata->sb.s_first_data_zone;
}
kprintf("MINIX FS: Recognized Filesystem (Blocksize: %d)\n", mdata->sb.s_blocksize);
device->fs_data = mdata;
return 1;
}