463 lines
11 KiB
C
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;
|
|
}
|