quinn-os/sfs.c
2021-12-23 21:41:16 +10:00

463 lines
11 KiB
C

#include "pvec.h"
#include "vfs.h"
#include "string.h"
#include "memory.h"
#include "string.h"
#include "ramdisk.h"
#include "console.h"
struct sfs_superblock_t {
long long last_alteration;
unsigned long long data_area_blocks;
unsigned long long index_area_bytes;
char magic[3];
unsigned char version;
unsigned long long volume_blocks;
unsigned long reserved_blocks;
unsigned char blocksize;
unsigned char checksum;
}__attribute__((packed));
struct sfs_volume_identifier_t {
unsigned char type;
unsigned char zero[3];
long long timestamp;
char name[52];
} __attribute__((packed));
struct sfs_directory_entry_t {
unsigned char type;
unsigned char continuations;
long long timestamp;
unsigned char name[54];
} __attribute__((packed));
struct sfs_file_entry_t {
unsigned char type;
unsigned char continuations;
long long timestamp;
unsigned long long starting_block;
unsigned long long ending_block;
unsigned long long bytes;
char name[30];
} __attribute__((packed));
struct sfs_continuation_t {
char name[64];
} __attribute__((packed));
struct sfs_dummy_entry_t {
unsigned char type;
char data[63];
} __attribute__((packed));
struct sfs_data {
struct sfs_superblock_t superblock;
unsigned int blocksize;
char *index_area;
int index_area_top;
};
int powi(int number, int exp) {
int i, product = 1;
for (i=0;i<exp;i++) {
product *= number;
}
return product;
}
struct sfs_dummy_entry_t *sfs_get_entry(struct vfs_device_t *device, char *path, int type) {
int i;
struct sfs_data *data = (struct sfs_data *)device->fs_data;
struct sfs_dummy_entry_t *entry;
int state = 0;
char *filename;
int filetype;
int continuations;
char *sfs_path = &path[1];
struct sfs_directory_entry_t *currdir;
struct sfs_file_entry_t *currfile;
struct sfs_continuation_t *currcont;
// root path always exists
if (strcmp(path, "/") == 0) {
return (struct sfs_dummy_entry_t *)1;
}
for (i=data->index_area_top-64;i>=data->index_area_top - data->superblock.index_area_bytes ;i-=64) {
entry = (struct sfs_dummy_entry_t *)&data->index_area[i];
if (state == 0) {
switch (entry->type) {
case 0x01:
//kprintf("Volume Identifier\n");
break;
case 0x02:
//kprintf("Starting marker\n");
break;
case 0x10:
//kprintf("Unused Entry\n");
break;
case 0x11:
//kprintf("Directory Entry\n");
filetype = 0;
currdir = (struct sfs_directory_entry_t *)entry;
filename = (char *)malloc(sizeof(char *) * (strlen((const char *)currdir->name) + 1));
strcpy(filename, (const char *)currdir->name);
continuations = currdir->continuations;
if (continuations == 0) {
if (type == 0) {
state = 2;
} else {
free(filename);
}
}
break;
case 0x12:
//kprintf("File Entry\n");
currfile = (struct sfs_file_entry_t *)entry;
filetype = 1; //file
filename = (char *)malloc(sizeof(char *) * (strlen(currfile->name) + 1));
strcpy(filename, currfile->name);
continuations = currfile->continuations;
if (continuations == 0) {
if (type == 1) {
state = 2;
} else {
free(filename);
}
}
break;
case 0x18:
//kprintf("Unsuable Entry\n");
break;
case 0x19:
//kprintf("Deleted Directory\n");
break;
case 0x1a:
//kprintf("Deleted File\n");
break;
default:
if (entry->type >= 0x20 && entry->type <= 0xff) {
//kprintf("Continuation Entry\n");
currcont = (struct sfs_continuation_t *)entry;
filename = (char *)realloc(filename, sizeof(char *) * (strlen(filename) + strlen(currcont->name + 1)));
strcat(filename, currcont->name);
continuations--;
if (continuations == 0) {
if (type == filetype) {
state = 2;
} else {
free(filename);
}
}
} else {
//kprintf("Unknown!\n");
}
break;
}
}
if (state == 2) {
//kprintf("\"%s\" ? \"%s\"\n", filename, sfs_path);
if (strcmp(filename, sfs_path) == 0) {
free(filename);
if (type == 0) {
return (struct sfs_dummy_entry_t *)currdir;
} else {
return (struct sfs_dummy_entry_t *)currfile;
}
}
free(filename);
state = 0;
}
}
return (struct sfs_dummy_entry_t *)0;
}
int sfs_check_if_exists(struct vfs_device_t *device, char *path, int type) {
struct sfs_dummy_entry_t *entry = sfs_get_entry(device, path, type);
if (!entry) {
return 0;
} else {
return 1;
}
}
int sfs_change_directory(struct vfs_device_t *device, char *path) {
if (sfs_check_if_exists(device, path, 0)) {
//kprintf("Path exists\n");
return 1;
} else {
//kprintf("Path does not exist\n");
return 0;
}
}
void sfs_list_contents(struct vfs_device_t *device, char *cwd) {
struct sfs_data *data = (struct sfs_data *)device->fs_data;
int i;
struct sfs_dummy_entry_t *entry;
int state = 0;
char *filename;
int filetype;
unsigned long long filesize;
int continuations;
char *sfs_cwd = &cwd[1];
struct sfs_directory_entry_t *currdir;
struct sfs_file_entry_t *currfile;
struct sfs_continuation_t *currcont;
for (i=data->index_area_top-64;i>=data->index_area_top - data->superblock.index_area_bytes ;i-=64) {
entry = (struct sfs_dummy_entry_t *)&data->index_area[i];
if (state == 0) {
switch (entry->type) {
case 0x01:
//kprintf("Volume Identifier\n");
break;
case 0x02:
//kprintf("Starting marker\n");
break;
case 0x10:
//kprintf("Unused Entry\n");
break;
case 0x11:
//kprintf("Directory Entry\n");
currdir = (struct sfs_directory_entry_t *)entry;
filetype = 0; //directory
filesize = 0;
filename = (char *)malloc(sizeof(char *) * (strlen((const char *)currdir->name) + 1));
strcpy(filename, (const char *)currdir->name);
continuations = currdir->continuations;
if (continuations == 0) {
state = 2;
}
break;
case 0x12:
//kprintf("File Entry\n");
currfile = (struct sfs_file_entry_t *)entry;
filetype = 1; //file
filesize = currfile->bytes;
filename = (char *)malloc(sizeof(char *) * (strlen(currfile->name) + 1));
strcpy(filename, currfile->name);
continuations = currfile->continuations;
if (continuations == 0) {
state = 2;
}
break;
case 0x18:
//kprintf("Unsuable Entry\n");
break;
case 0x19:
//kprintf("Deleted Directory\n");
break;
case 0x1a:
//kprintf("Deleted File\n");
break;
default:
if (entry->type >= 0x20 && entry->type <= 0xff) {
//kprintf("Continuation Entry\n");
currcont = (struct sfs_continuation_t *)entry;
filename = (char *)realloc(filename, sizeof(char *) * (strlen(filename) + strlen(currcont->name + 1)));
strcat(filename, currcont->name);
continuations--;
if (continuations == 0) {
state = 2;
}
} else {
//kprintf("Unknown!\n");
}
break;
}
}
if (state == 2) {
char *fptr;
char *cptr;
fptr = filename;
cptr = sfs_cwd;
int match = 0;
int j,k;
for (j=0;j<strlen(cptr);j++) {
if (cptr[j] != fptr[j]) {
match = -1;
break;
}
}
if (match == 0) {
if (strcmp(cwd, "/") == 0) {
k = j+1;
} else {
k = j+2;
}
if (k < strlen(fptr)) {
for (;k<strlen(fptr);k++) {
if (fptr[k] == '/') {
//kprintf("no match %s %s %d %d\n", filename, sfs_cwd, k, j);
match = -1;
break;
}
}
} else {
match = -1;
}
if (match == 0) {
if (filetype == 0) {
kprintf("%s (directory)\n", filename);
} else {
kprintf("%s (%dk)\n", filename, filesize / 1024);
}
}
}
free(filename);
state = 0;
}
}
}
int sfs_check_magic(int device) {
char buffer[512];
//int i;
// int start_of_index_area;
struct sfs_superblock_t superblock;
//unsigned int index_area_bytes = superblock.index_area_bytes;
switch (device) {
case 1:
ramdisk_read_block(0, buffer, 512);
break;
}
memcpy((char *)&superblock, &buffer[0x194], sizeof(struct sfs_superblock_t));
if (superblock.magic[0] == 'S' && superblock.magic[1] == 'F' && superblock.magic[2] == 'S') {
return 1;
}
return 0;
}
int sfs_load_superblock(struct vfs_device_t *device) {
char *buffer;
int i;
int start_of_index_area;
if (!sfs_check_magic(device->device)) {
return 0;
}
struct sfs_data *data = (struct sfs_data *)malloc(sizeof(struct sfs_data));
buffer = (char *)malloc(sizeof(char) * 512);
//unsigned int index_area_bytes = superblock.index_area_bytes;
switch (device->device) {
case 1:
ramdisk_read_block(0, buffer, 512);
break;
}
memcpy((char *)&data->superblock, &buffer[0x194], sizeof(struct sfs_superblock_t));
data->blocksize = powi(2, data->superblock.blocksize + 7);
buffer = (char *)realloc(buffer, sizeof(char) * data->blocksize);
data->index_area_top = (data->superblock.index_area_bytes / data->blocksize + 1) * data->blocksize;
data->index_area = (char *)malloc(data->index_area_top);
switch (device->device) {
case 1:
start_of_index_area = data->superblock.volume_blocks - ((data->superblock.index_area_bytes / data->blocksize) + 1);
for (i=0;i<data->superblock.index_area_bytes/data->blocksize + 1;i++) {
ramdisk_read_block(start_of_index_area + i, &data->index_area[i * data->blocksize], data->blocksize);
}
break;
}
device->fs_data = (void *)data;
free(buffer);
return 1;
}
int sfs_read_data(struct vfs_device_t *device, char *filepath, char *buffer, int len, int offset) {
struct sfs_data *data = (struct sfs_data *)device->fs_data;
struct sfs_file_entry_t *fentry = (struct sfs_file_entry_t *)sfs_get_entry(device, filepath, 1);
int i;
if (!fentry) {
return -1;
}
if (len > fentry->bytes - offset) {
len = fentry->bytes - offset;
}
if (len == 0) {
return 0;
}
//kprintf("blocks, offset %d, size %d %d\n", offset, len, fentry->bytes);
int count = 0;
unsigned long long startblock = fentry->starting_block + (offset / data->blocksize);
unsigned long long blockcount = len / data->blocksize + 1;
// kprintf("R");
char *blockbuffer = (char *)malloc(sizeof(char) * (blockcount * data->blocksize));
// kprintf("R");
for (i=0;i<blockcount;i++) {
switch (device->device) {
case 1:
//kprintf("R");
ramdisk_read_block((unsigned int)(startblock + i), blockbuffer, data->blocksize);
break;
}
if (i==0) {
//kprintf("G");
if (len > data->blocksize - (offset % data->blocksize)) {
memcpy(buffer, &blockbuffer[offset % data->blocksize], data->blocksize - (offset % data->blocksize));
count += data->blocksize - (offset % data->blocksize);
} else {
memcpy(buffer, &blockbuffer[offset % data->blocksize], len);
//kprintf( "I");
count += len;
}
} else {
if (len - count >= data->blocksize) {
memcpy(&buffer[count], blockbuffer, data->blocksize);
count += data->blocksize;
} else {
memcpy(&buffer[count], blockbuffer, len - count);
count += len - count;
}
}
}
//kprintf ("J");
free(blockbuffer);
//kprintf ("K");
return count;
}