quinn-os/leanfs.c
2016-01-28 18:29:09 +10:00

265 lines
7.5 KiB
C

#include "leanfs.h"
unsigned int leanfs_compute_checksum(const void *data, unsigned int size) {
unsigned int res = 0;
const unsigned int* d = (const unsigned int*)(data);
size /= sizeof(unsigned int);
for (unsigned i = 1; i != size; ++i) res = (res << 31) + (res >> 1) + d[i];
return res;
}
int leanfs_load_superblock(struct vfs_device_t *device) {
int i;
struct leanfs_data *data = (struct leanfs_data *)malloc(sizeof(struct leanfs_data));
if (!data) {
kprintf("Out of memory!\n");
return 0;
}
for (i=1;i<=maxSuperblockSector;i++) {
if (device->device == 1) {
ramdisk_read_block(i, &data->sb, 512);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), i, &data->sb, 512);
}
if (data->sb.magic == superblockMagic) {
if (data->sb.primary_super == i && data->sb.checksum == leanfs_compute_checksum(&data->sb, sizeof(struct leanfs_superblock))) {
// it's a lean fs filesystem
if (data->sb.fs_version != fsVersion) {
kprintf("LeanFS: Unsupported version\n");
free(data);
return 0;
}
data->sectors_per_band = 1 << data->sb.log_sectors_per_band;
data->band_bitmap_size_ = data->sectors_per_band >> (3 + logSectorSize);
data->band_count = (data->sb.sector_count + data->sectors_per_band - 1) >> data->sb.log_sectors_per_band;
device->fs_data = data;
kprintf("LeanFS: Recognised Filesystem\n");
return 1;
}
}
}
free(data);
return 0;
}
unsigned long long leanfs_read_entire_file(struct vfs_device_t *device, leanfs_file_info *info, char **buffer) {
*buffer = (char *)malloc(info->inode->file_size - (sizeof(struct leanfs_inode)));
int bytes_read;
int extent_blocks;
char *extent;
char *buffer_loc;
char indirect_buffer[512];
if (!*buffer) {
return 0;
}
buffer_loc = *buffer;
for (i=0;i<info->inode->extent_count;i++) {
extent_blocks = info->inode->extent_sizes[i] / 512;
if (info->inode->extent_sizes[i] % 512) {
extent_blocks += 1;
}
extent = (char *)malloc(extent_blocks * 512);
if (device->device == 1) {
ramdisk_read_blocks(info->inode->extent_starts[i], extent_blocks, extent, 512);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), info->inode->extent_starts[i], extent_blocks, extent, 512);
}
if (i==0) {
memcpy(buffer_loc, &extent[sizeof(struct leanfs_inode)], info->inode->extent_sizes[i] - sizeof(struct leanfs_inode));
} else {
memcpy(&buffer_loc[bytes_read - sizeof(struct leanfs_inode)], extent, info->inode->extent_sizes[i]);
}
free(extent);
bytes_read += info->inode->extent_sizes[i];
}
unsigned long long indirect;
struct leanfs_indirect *indirect_s;
for (i=0;i<info->indirect_count;i++) {
if (i==0) {
indirect = info->inode->first_indirect;
} else {
indirect = indirect_d->next_indirect;
}
if (device->device == 1) {
ramdisk_read_block(indirect, indirect_buffer, 512);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), indirect, indirect_buffer, 512);
}
indirect_s = (struct leanfs_indirect *)indirect_buffer;
for (j=0;j<indirect_s->extent_count;j++) {
extent_blocks = indirect_s->extent_sizes[j] / 512;
if (indirect_s->extent_sizes[j] % 512) {
extent_blocks += 1;
}
extent = (char *)malloc(extent_blocks * 512);
if (device->device == 1) {
ramdisk_read_blocks(indirect_s->extent_starts[j], extent_blocks, extent, 512);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), indirect_s->extent_starts[j], extent_blocks, extent, 512);
}
memcpy(&buffer_loc[bytes_read - sizeof(struct leanfs_inode)], extent, info->inode->extent_sizes[j]);
free(extent);
bytes_read += indirect_s->extent_sizes[j];
}
}
return (bytes_read - sizeof(struct leanfs_inode));
}
struct leanfs_file_info *leanfs_find_sub_entry(struct vfs_device_t *device, struct leanfs_file_info *info, char **ptr, int part, int parts, int type) {
}
struct leanfs_file_info *leanfs_check_if_exists(struct vfs_device_t *device, char *path, int type) {
struct leanfs_data *data = (struct leanfs_data *)device->fs_data;
struct leanfs_file_info *info;
unsigned long long len;
char *buffer2;
// load root directory
char buffer[512];
if (device->device == 1) {
ramdisk_read_block(data->sb.root_inode, buffer, 512);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), data->sb.root_inode, buffer, 512);
}
info = (struct leanfs_file_info *)malloc(sizeof(struct leanfs_file_info));
info->ino = data->sb.root_inode;
info->inode = (struct leanfs_inode *)malloc(sizeof(struct leanfs_inode));
memcpy(info->inode, buffer, sizeof(struct leanfs_inode));
if (strcmp(path, "/") == 0) {
return info;
}
// info contains root inode...
// load info into buffer
len = leanfs_read_entire_file(device, info, &buffer2);
free(info->inode);
free(info);
// buffer2 contains the root directory contents...
int i;
int parts = 0;
char *path_copy = (char *)dbmalloc(strlen(path) + 1, "leanfs_check_if_exists");
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 , "leanfs_check_if_exists");
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';
}
}
struct leanfs_direntry *lfs_dir = (struct leanfs_direntry *)buffer2;
while (lfs_dir != (void *)0) {
if (strncmp(ptr[0], lfs_dir->name, lfs_dir->name_len) == 0) {
if (device->device == 1) {
ramdisk_read_block(lfs_dir->inode, buffer, 512);
} else if ((device->device & 0xff00) == 0x100) {
hd_read_block((device->device & 0xff), lfs_dir->inode, buffer, 512);
}
info = (struct leanfs_file_info *)malloc(sizeof(struct leanfs_file_info));
info->ino = lfs_dir->inode;
info->inode = (struct leanfs_inode *)malloc(sizeof(struct leanfs_inode));
memcpy(info->inode, buffer, sizeof(struct leanfs_inode));
if (parts == 1) {
if (type == 0) {
if (lfs_dir->type == ftDirectory) {
free(buffer2);
return info;
} else {
free(buffer2);
free(info->inode);
free(info);
return (void *)0;
}
} else if (type == 1) {
if (lfs_dir->type == ftFile) {
free(buffer2);
return info;
} else {
free(buffer2);
free(info->inode);
free(info);
return (void *)0;
}
} else {
free(buffer2);
return info;
}
} else {
free(buffer2);
return leanfs_find_sub_entry(device, info, ptr, 1, parts, type);
}
}
lfs_dir = (struct leanfs_direntry *)((char *)lfs_dir + lfs_dir->reclen);
}
}
int leanfs_get_dents(struct vfs_device_t *device, struct leanfs_file_info *info, char *buffer, int len, unsigned long long offset);
int leanfs_create_directory(struct vfs_device_t *device, char *path);
int leanfs_write_data(struct vfs_device_t *device, struct leanfs_file_info *info, char *filename, char *buffer, int len, unsigned long long offset);
int leanfs_trunc_file(struct vfs_device_t *device, struct leanfs_file_info *info, char *filename);
int leanfs_create_file(struct vfs_device_t *device, char *path);
int leanfs_read_data(struct vfs_device_t *device, struct leanfs_file_info *info, char *buffer, int len, unsigned long long offset);
int leanfs_change_directory(struct vfs_device_t *device, char *path);