quinn-os/minix.c

1474 lines
40 KiB
C

#include "vfs.h"
#include "minix.h"
#include "memory.h"
#include "string.h"
#include "ramdisk.h"
#include "hd.h"
#include "console.h"
unsigned int minix_alloc_bit(struct vfs_device_t *device, int map, unsigned int bit);
struct minix_inode *minix_get_inode(struct vfs_device_t *device, int ino);
struct minix_file_info *minix_check_if_exists(struct vfs_device_t *device, char *path, int type);
struct minix_inode *minix_alloc_inode(struct vfs_device_t *device, unsigned short mode, unsigned int *ino);
unsigned int minix_alloc_zone(struct vfs_device_t *device, unsigned int z) {
return minix_alloc_bit(device, 1, z);
}
unsigned int minix_free_zone(struct vfs_device_t *device, unsigned int z) {
return minix_free_bit(device, 1, z);
}
unsigned int minix_rd_indir(char *buffer, int index) {
unsigned int *ptr = (unsigned int *)buffer;
return ptr[index];
}
void minix_wr_indir(char *buffer, int index, int value) {
unsigned int *ptr = (unsigned int *)buffer;
ptr[index] = value;
}
int minix_empty_indir(char *bp, struct minix_super_block *sb) {
unsigned int i;
for (i=0;i<(sb->s_blocksize / 4); i++) {
if (minix_rd_indir(bp, i) != 0) {
return 0;
}
}
return 1;
}
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;
int i, j, k;
char *buffer;
struct minix_dir_entry *direntry;
unsigned int blockstoread = dir->i_size / mdata->sb.s_blocksize;
unsigned int blockno;
if (dir->i_size % mdata->sb.s_blocksize) {
blockstoread++;
}
unsigned int old_entrys = dir->i_size / sizeof(struct minix_dir_entry);
unsigned int new_entrys = ((blockstoread * mdata->sb.s_blocksize) / sizeof(struct minix_dir_entry)) - old_entrys;
buffer = (char *)malloc(mdata->sb.s_blocksize);
if (!buffer) {
return 0;
}
for (k=0;k<blockstoread;k++) {
blockno = minix_read_map(device, dir, (unsigned long long)(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<60 && j < strlen(name);j++) {
direntry->name[j] = name[j];
}
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);
}
// kprintf("Found old entry old entrys %d, this entry %d\n", old_entrys, i);
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<60 && j < strlen(name);j++) {
direntry->name[j] = name[j];
}
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);
}
dir->i_size += sizeof(struct minix_dir_entry);
minix_write_inode(device, dir_ino, dir);
// kprintf("Found new entry on old block\n");
return 1;
}
}
}
// no free spaces, allocate some more space
unsigned int new_zone = minix_alloc_zone(device, blockno);
unsigned int old_size = dir->i_size;
dir->i_size += sizeof(struct minix_dir_entry);
minix_write_map(device, dir, dir_ino, 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<60 && j < strlen(name);j++) {
direntry->name[j] = name[j];
}
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);
}
// kprintf("Allocated new block for entry\n");
return 1;
}
static struct minix_inode *minix_new_node(struct vfs_device_t *device, struct minix_inode *dirp, unsigned int dir_ino, char *name, unsigned short mode, unsigned int z0) {
struct minix_inode *new_inode;
unsigned int ino;
if (dirp->i_nlinks == 0) {
return (void *)0;
}
if (mode & S_IFDIR && dirp->i_nlinks >= 32767) {
return (void *)0;
}
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 (void *)0;
}
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 *)malloc(strlen(path) + 1);
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;
}
}
// kprintf("DIR: %s. FILE: %s.\n", path_copy, basename);
struct minix_file_info *minfo;
struct minix_inode *dirp;
struct minix_inode *new_node;
if (strlen(path_copy) > 0) {
// kprintf("Not root\n");
minfo = minix_check_if_exists(device, path_copy, 0);
dirp = minix_get_inode(device, minfo->inode);
new_node = minix_new_node(device, dirp, minfo->inode, basename, S_IFREG, minix_alloc_zone(device, 0));
} else {
dirp = minix_get_inode(device, 1);
new_node = minix_new_node(device, dirp, 1, basename, S_IFREG, minix_alloc_zone(device, 0));
}
if (!new_node) {
return -1;
}
return 0;
}
int minix_write_map(struct vfs_device_t *device, struct minix_inode *inode, int ino, unsigned long long position, unsigned int new_zone, int op) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
unsigned int scale = mdata->sb.s_log_zone_size;
unsigned int zone = (position / mdata->sb.s_blocksize) >> scale;
unsigned int excess;
unsigned int nr_indirects = mdata->sb.s_blocksize / 4;
unsigned int z, z1, z2 = 0;
unsigned int old_zone;
int ex;
int single;
int new_ind;
int new_dbl;
int ind_ex;
unsigned int b, b_indr;
char *buffer_indr = (void *)0;
char *buffer = (void *)0;
if (zone < 7) {
if (inode->i_zone[zone] != 0 && (op == 1)) {
} 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);
if (ind_ex >= nr_indirects) return 0;
if (z == 0 && op == 1) {
z1 = 0;
} else {
b_indr = z << scale;
buffer_indr = (char *)malloc(mdata->sb.s_blocksize);
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, ind_ex, z1);
}
new_ind = 1;
if (buffer_indr) {
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);
}
free(buffer_indr);
buffer_indr = (void *)0;
}
if (z1 == 0) {
return 0;
}
}
if (z1 != 0) {
ex = (int)excess;
b = z1 << scale;
buffer = (char *)malloc(mdata->sb.s_blocksize);
if (!buffer) {
return 0;
}
if (!new_ind) {
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);
}
} 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 (minix_empty_indir(buffer, &mdata->sb)) {
minix_free_zone(device, z1);
z1 = 0;
if (single) {
inode->i_zone[7] = z1;
} else {
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(b, buffer, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_block((device->device & 0xff), b, 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;
}
free(buffer);
return 1;
}
int minix_read_map(struct vfs_device_t *device, struct minix_inode *inode, unsigned long long position) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
int scale = mdata->sb.s_log_zone_size;
int zind;
int index;
unsigned int block_pos = position / mdata->sb.s_blocksize;
unsigned int zone = block_pos >> scale;
unsigned int z;
unsigned int b;
unsigned int excess;
int boff = (int)(block_pos - (zone << scale));
unsigned int dzones = 7;
unsigned int nr_indirects = mdata->sb.s_blocksize / 4;
char *buffer;
if (zone < dzones) {
zind = (int) zone;
z = inode->i_zone[zind];
if (z == NO_ZONE) {
// kprintf("0.");
return NO_BLOCK;
}
b = (unsigned int)((z << scale) + boff);
return b;
}
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;
b = (unsigned int) z << scale;
index = (int)(excess/nr_indirects);
if ((unsigned int) index > nr_indirects) {
// kprintf("1.");
return NO_BLOCK;
}
buffer = (char *)malloc(mdata->sb.s_blocksize);
if (!buffer) {
// kprintf("2.");
return NO_BLOCK;
}
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);
}
z = minix_rd_indir(buffer, index);
free(buffer);
excess = excess % nr_indirects;
}
if (z == NO_ZONE) {
// kprintf("3.");
return NO_BLOCK;
}
b = z << scale;
buffer = (char *)malloc(mdata->sb.s_blocksize);
if (!buffer) {
// kprintf("4.");
return NO_BLOCK;
}
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);
}
z = minix_rd_indir(buffer, (int)excess);
free(buffer);
if (z == NO_ZONE) {
// kprintf("5.");
return NO_BLOCK;
}
b = (z << scale) + boff;
return b;
}
void minix_free_bit(struct vfs_device_t *device, int map, unsigned int bit) {
struct minix_data *mdata = (struct vfs_device_t *)device->fs_data;
unsigned long mask, offset, index;
index = bit / 8;
offset = bit % 8;
mask = ~(1<<offset);
if (map == 0) {
mdata->s_imap[index] &= mask;
if (device->device == 1) {
ramdisk_write_blocks(2, mdata->sb.s_imap_blocks, mdata->s_imap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_blocks((device->device & 0xff), 2, mdata->sb.s_imap_blocks, mdata->s_imap, mdata->sb.s_blocksize);
}
} else {
mdata->s_zmap[index] &= mask;
if (device->device == 1) {
ramdisk_write_blocks(2 + mdata->sb.s_imap_blocks, mdata->sb.s_zmap_blocks, mdata->s_zmap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_blocks((device->device & 0xff), 2 + mdata->sb.s_imap_blocks, mdata->sb.s_zmap_blocks, mdata->s_zmap, mdata->sb.s_blocksize);
}
}
}
unsigned int minix_alloc_bit(struct vfs_device_t *device, int map, unsigned int bit) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
unsigned int mask, offset, index, i;
int j;
int oldbit;
if (map == 0) {
oldbit = mdata->sb.s_ninodes;
} else {
oldbit = mdata->sb.s_zones;
}
for (j=0;j<2;j++) {
if (map == 0) {
// inode map
for (i=bit;i<oldbit;i++) {
mask = 1;
index = i / 8;
offset = i % 8;
if (!(mdata->s_imap[index] & (mask << offset))) {
mdata->s_imap[index] |= (mask << offset);
// write out inode table
if (device->device == 1) {
ramdisk_write_blocks(2, mdata->sb.s_imap_blocks, mdata->s_imap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_blocks((device->device & 0xff), 2, mdata->sb.s_imap_blocks, mdata->s_imap, mdata->sb.s_blocksize);
}
return i;
}
}
} else {
// zone map
for (i=bit;i<oldbit;i++) {
mask = 1;
index = i / 8;
offset = i % 8;
if (!(mdata->s_zmap[index] & (mask << offset))) {
mdata->s_zmap[index] |= (mask << offset);
// write out zone table
if (device->device == 1) {
ramdisk_write_blocks(2 + mdata->sb.s_imap_blocks, mdata->sb.s_zmap_blocks, mdata->s_zmap, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_write_blocks((device->device & 0xff), 2 + mdata->sb.s_imap_blocks, mdata->sb.s_zmap_blocks, mdata->s_zmap, mdata->sb.s_blocksize);
}
return i;
}
}
}
if (bit == 0) {
break;
}
oldbit = bit + 1;
bit = 0;
}
return 0;
}
int minix_write_inode(struct vfs_device_t *device, unsigned int ino, struct minix_inode *inode) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
ino--;
unsigned int block = mdata->inode_table_start_block + ino / (mdata->sb.s_blocksize / sizeof(struct minix_inode));
char *buffer = (char *)malloc(mdata->sb.s_blocksize);
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);
}
memcpy(&buffer[(ino % (mdata->sb.s_blocksize / sizeof(struct minix_inode))) * sizeof(struct minix_inode)], 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((device->device & 0xff), block, buffer, mdata->sb.s_blocksize);
}
free(buffer);
return 1;
}
char *minix_get_block_map(struct vfs_device_t *device, struct minix_inode *inode, unsigned long long position) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
char *buffer;
unsigned int b = minix_read_map(device, inode, position);
if (b == 0) {
return (void *)0;
}
buffer = (char *)malloc(mdata->sb.s_blocksize);
if (!buffer) {
return (void *)0;
}
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, unsigned long long position, char *buffer) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
unsigned int b = minix_read_map(device, inode, position);
if (b == 0) {
return (void *)0;
}
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);
}
free(buffer);
}
void minix_zerozone_range(struct vfs_device_t *device, struct minix_inode *inode, unsigned int pos, unsigned int len) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
char *buffer;
unsigned int offset;
unsigned int bytes;
if (!len) return;
while (len > 0) {
buffer = minix_get_block_map(device, inode, (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, (pos / mdata->sb.s_blocksize) * pos, buffer);
pos += bytes;
len -= bytes;
}
}
unsigned int minix_nextblock(unsigned int pos, int zone_size) {
unsigned int 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, unsigned int pos, int half, int zone_size) {
unsigned int 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, unsigned int start, unsigned int end) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
struct minix_inode *inode = minix_get_inode(device, ino);
unsigned int e;
unsigned int p;
int zone_size;
int zero_first, zero_last;
if (end > inode->i_size) {
end = inode->i_size;
}
if (end <= start) {
return 0;
}
zone_size = mdata->sb.s_blocksize << mdata->sb.s_log_zone_size;
zero_last = start % zone_size;
zero_first = end % zone_size && end < inode->i_size;
if (start / zone_size == (end - 1) / zone_size && (zero_last || zero_first)) {
minix_zerozone_range(device, inode, start, end - start);
} else {
if (zero_last)
minix_zerozone_half(device, inode, start, 1, zone_size);
if (zero_first)
minix_zerozone_half(device, inode, end, 0, zone_size);
e = end / zone_size;
if (end == inode->i_size && (end % zone_size)) e++;
for (p = minix_nextblock(start, zone_size) / zone_size; p < e; p++) {
minix_write_map(device, inode, ino, p * zone_size, 0, 1);
}
}
}
void minix_trunc_file(struct vfs_device_t *device, struct minix_file_info *finfo, char *path) {
minix_clear_zones(device, finfo->inode, 0, finfo->file_size);
}
void minix_free_inode(struct vfs_device_t *device, unsigned int ino) {
minix_free_bit(device, 0, ino);
}
struct minix_inode *minix_alloc_inode(struct vfs_device_t *device, unsigned short mode, unsigned int *ino) {
unsigned int b;
struct minix_inode *new_inode;
b = minix_alloc_bit(device, 0, 0);
if (b == 0) {
return (void *)0;
}
new_inode = (struct minix_inode *)malloc(sizeof(struct minix_inode));
if (!new_inode) {
minix_free_bit(device, 0, b);
}
memset(new_inode, 0, sizeof(struct minix_inode));
new_inode->i_mode = mode;
minix_write_inode(device, b, new_inode);
*ino = b;
// kprintf("INODE %d\n", 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);
unsigned int block;
char *buffer = (char *)malloc(mdata->sb.s_blocksize);
if (!buffer) {
return (void *)0;
}
struct minix_inode *inode = (struct minix_inode *)malloc(sizeof(struct minix_inode));
if (!inode) {
free(buffer);
return (void *)0;
}
if (ino == 0 || ino > mdata->sb.s_ninodes) {
free(buffer);
free(inode);
return (void *)0;
}
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));
free(buffer);
return inode;
}
unsigned int 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;
int i;
int blockstoread;
char *buffer2;
int blockno;
unsigned int size;
char *buffer_loc;
size = inode->i_size;
unsigned int bytesleft = size;
blockstoread = size / mdata->sb.s_blocksize;
if (size % mdata->sb.s_blocksize) {
blockstoread++;
}
*buffer = (char *)malloc(size);
if (!*buffer) {
return -1;
}
buffer_loc = *buffer;
buffer2 = (char *)malloc(mdata->sb.s_blocksize);
if (!buffer2) {
free(*buffer);
return -1;
}
for (i=0;i<blockstoread;i++) {
blockno = minix_read_map(device, inode, (unsigned long long)(i * mdata->sb.s_blocksize));
//kprintf("Blockno: %d To Read: %d\n", blockno, blockstoread);
if (device->device == 1) {
ramdisk_read_block(blockno, buffer2, mdata->sb.s_blocksize);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), blockno, buffer2, mdata->sb.s_blocksize);
}
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);
}
}
free(buffer2);
return size;
}
struct minix_file_info *minix_find_sub_entry(struct vfs_device_t *device, unsigned int 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 (void *)0;
}
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 != (void *)0) {
if (pinode->i_nlinks > 0) {
if (type == 0 && (pinode->i_mode & S_IFDIR)) {
fileinf = (struct minix_file_info *)malloc(sizeof(struct minix_file_info));
if (!fileinf) {
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
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;
free(inode);
free(pinode);
free(buffer);
return fileinf;
} else if (type == 1 && (pinode->i_mode & S_IFREG)) {
fileinf = (struct minix_file_info *)malloc(sizeof(struct minix_file_info));
if (!fileinf) {
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
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;
free(inode);
free(pinode);
free(buffer);
return fileinf;
} else if (type == -1) {
fileinf = (struct minix_file_info *)malloc(sizeof(struct minix_file_info));
if (!fileinf) {
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
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;
free(inode);
free(pinode);
free(buffer);
return fileinf;
} else {
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
} else {
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
}
}
} 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;
free(pinode);
free(inode);
free(buffer);
return minix_find_sub_entry(device, childinode, ptr, part + 1, parts, type);
} else {
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
}
}
}
} else {
free(inode);
return (void *)0;
}
} else {
// root directory is not a directory ??
free(inode);
return (void *)0;
}
return (void *)0;
}
struct minix_file_info *minix_check_if_exists(struct vfs_device_t *device, char *path, int type) {
int i;
int parts = 0;
char *path_copy = (char *)malloc(strlen(path) + 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 *)malloc(sizeof(struct minix_file_info));
if (!info) {
return (void *)0;
}
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;
free(inode);
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 **)malloc(sizeof(char *) * parts );
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) {
return (void *)0;
}
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 == 1) {
if (strcmp(dir->name, ptr[0]) == 0) {
pinode = minix_get_inode(device, dir->inode);
if (pinode != (void *)0) {
if (pinode->i_nlinks > 0) {
if (type == 0 && (pinode->i_mode & S_IFDIR)) {
fileinf = (struct minix_file_info *)malloc(sizeof(struct minix_file_info));
if (!fileinf) {
free(ptr);
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
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;
free(ptr);
free(inode);
free(pinode);
free(buffer);
return fileinf;
} else if (type == 1 && (pinode->i_mode & S_IFREG)) {
fileinf = (struct minix_file_info *)malloc(sizeof(struct minix_file_info));
if (!fileinf) {
free(ptr);
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
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;
free(ptr);
free(inode);
free(pinode);
free(buffer);
return fileinf;
} else if (type == -1) {
fileinf = (struct minix_file_info *)malloc(sizeof(struct minix_file_info));
if (!fileinf) {
free(inode);
free(pinode);
free(buffer);
free(ptr);
return (void *)0;
}
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;
free(ptr);
free(inode);
free(pinode);
free(buffer);
return fileinf;
} else {
free(inode);
free(pinode);
free(buffer);
free(ptr);
return (void *)0;
}
} else {
free(inode);
free(pinode);
free(buffer);
free(ptr);
return (void *)0;
}
}
}
} 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;
free(pinode);
free(inode);
free(buffer);
fileinf = minix_find_sub_entry(device, childinode, ptr, 1, parts, type);
free(ptr);
return fileinf;
} else {
free(inode);
free(pinode);
free(buffer);
return (void *)0;
}
}
}
}
} else {
free(inode);
return (void *)0;
}
} else {
// root directory is not a directory ??
free(inode);
return (void *)0;
}
return (void *)0;
}
int minix_change_directory(struct vfs_device_t *device, char *path) {
if (path[0] == '/' && path[1] == '\0') {
return 1;
} else {
if (minix_check_if_exists(device, path, 0)) {
return 1;
} else {
return 0;
}
}
}
int minix_read_data(struct vfs_device_t *device, struct minix_file_info *info, char *buffer, int len, unsigned long long offset) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
unsigned int blockcount;
unsigned int block_start;
unsigned int block_offset;
unsigned int j;
unsigned int blocks_read;
struct minix_inode *inode = minix_get_inode(device, info->inode);
unsigned int buffer_at;
char *tempbuffer;
if (!inode) {
return 0;
}
if (info->type == 0) {
free(inode);
return 0;
}
tempbuffer = (char *)malloc(mdata->sb.s_blocksize);
if (!tempbuffer) {
free(inode);
return 0;
}
if (len + offset > info->file_size) {
len = info->file_size - offset;
}
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;
}
if (device->device == 1) {
for (j=0;j<blockcount;j++) {
ramdisk_read_block(minix_read_map(device, inode, (unsigned long long)(j * mdata->sb.s_blocksize)), tempbuffer, mdata->sb.s_blocksize);
if (j==0) {
if (len + 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], len);
free(tempbuffer);
free(inode);
return len;
}
} else {
if (len - 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, len - buffer_at);
free(tempbuffer);
free(inode);
return len;
}
}
}
} else if ((device->device & 0xff00) == 0x100) {
for (j=0;j<blockcount;j++) {
hd_read_block((device->device & 0xff), minix_read_map(device, inode, (unsigned long long)(j * mdata->sb.s_blocksize)), tempbuffer, mdata->sb.s_blocksize);
if (j==0) {
if (len + 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], len);
free(tempbuffer);
free(inode);
return len;
}
} else {
if (len - 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, len - buffer_at);
free(tempbuffer);
free(inode);
return len;
}
}
}
}
}
free(tempbuffer);
free(inode);
return 0;
}
int minix_get_dents(struct vfs_device_t *device, struct minix_file_info *info, char *buffer, int len, unsigned long long offset, int *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;
unsigned int bytesread;
int buff_offset = 0;
int i;
if (offset >= dirlen) {
free(buffer2);
return 0;
}
dir_buffer = (char *)malloc(dirlen - offset + 1);
memcpy(dir_buffer, &buffer2[offset], dirlen - offset);
free(buffer2);
*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)) > len) {
free(dir_buffer);
return buff_offset;
}
dent->name_len = strlen(dir->name);
dent->rec_len = sizeof(struct quinn_dirent_t) + strlen(dir->name);
dent->next_offset = buff_offset + dent->rec_len;
strcpy(dent->name, dir->name);
buff_offset = dent->next_offset;
*newoffset += sizeof(struct minix_dir_entry);
}
free(dir_buffer);
return buff_offset;
}
int minix_write_data(struct vfs_device_t *device, struct minix_file_info *info, char *filename, char *buffer, int len, unsigned long long offset) {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
unsigned int zone_size = mdata->sb.s_blocksize << mdata->sb.s_log_zone_size;
struct minix_inode *inode = minix_get_inode(device, info->inode);
unsigned int blockcount;
unsigned int block_start;
unsigned int block_offset;
unsigned int i;
char *obuffer;
unsigned int block;
unsigned int last_block;
unsigned int buffer_at = 0;
obuffer = (char *)malloc(mdata->sb.s_blocksize);
if (!buffer) {
return 0;
}
if (info->type == 0) {
// it's a directory
free(inode);
free(obuffer);
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;
for (i=0;i<blockcount;i++) {
block = minix_read_map(device, inode, i * mdata->sb.s_blocksize);
if (block == 0) {
if (!minix_write_map(device, inode, info->inode, i * mdata->sb.s_blocksize, minix_alloc_zone(device, last_block), 0)) {
if (inode->i_size < offset + buffer_at) {
inode->i_size = offset + buffer_at;
minix_write_inode(device, info->inode, inode);
}
free(obuffer);
free(inode);
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);
}
free(obuffer);
free(inode);
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==0) {
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);
}
free(obuffer);
free(inode);
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);
}
free(obuffer);
free(inode);
return len;
}
}
}
}
return buffer_at;
}
int minix_load_superblock(struct vfs_device_t *device) {
unsigned char *buffer;
struct minix_data *mdata;
buffer = (char *)malloc(1024);
if (!buffer) {
return 0;
}
mdata = (struct minix_data *)malloc(sizeof(struct minix_data));
if (!mdata) {
free(buffer);
return 0;
}
if (device->device == 1) {
ramdisk_read_block(1, buffer, 1024);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), 1, buffer, 1024);
}
memcpy((char *)&mdata->sb, buffer, sizeof(struct minix_super_block));
if (mdata->sb.s_magic != 0x4d5a) {
// kprintf("MINIX FS: Unrecognized Filesystem %x\n", mdata->sb.s_magic);
free(buffer);
free(mdata);
return 0;
}
mdata->s_imap = (char *)malloc(mdata->sb.s_imap_blocks * mdata->sb.s_blocksize);
if (!mdata->s_imap) {
free(buffer);
free(mdata);
return 0;
}
mdata->s_zmap = (char *)malloc(mdata->sb.s_zmap_blocks * mdata->sb.s_blocksize);
if (!mdata->s_zmap) {
free(mdata->s_imap);
free(buffer);
free(mdata);
return 0;
}
if (device->device == 1) {
ramdisk_read_blocks(2, mdata->sb.s_imap_blocks, mdata->s_imap, mdata->sb.s_blocksize);
ramdisk_read_blocks(2 + mdata->sb.s_imap_blocks, mdata->sb.s_zmap_blocks, 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, mdata->s_imap, mdata->sb.s_blocksize);
hd_read_blocks((device->device & 0xff), 2 + mdata->sb.s_imap_blocks, mdata->sb.s_zmap_blocks, mdata->s_zmap, mdata->sb.s_blocksize);
}
mdata->inode_table_start_block = 2 + mdata->sb.s_imap_blocks + mdata->sb.s_zmap_blocks;
mdata->first_data_block = mdata->inode_table_start_block + ((mdata->sb.s_ninodes * sizeof(struct minix_inode)) / mdata->sb.s_blocksize);
kprintf("MINIX FS: Recognized Filesystem\n");
device->fs_data = mdata;
return 1;
}