quinn-os/vfs.c
2022-07-20 21:00:19 +10:00

1315 lines
38 KiB
C

#include <stddef.h>
#include "inttypes.h"
#include "pvec.h"
#include "ahci.h"
#include "pata.h"
#include "hd.h"
#include "vfs.h"
#include "multiboot.h"
#include "memory.h"
#include "string.h"
#include "schedule.h"
#include "tty_fs.h"
#include "console.h"
#include "minix.h"
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
extern struct task_t *current_task;
struct vfs_device_t **vfs_devices;
int vfs_device_count;
struct quinn_pipe_t **vfs_pipes;
int vfs_pipe_count;
int vfs_stat_dev(struct vfs_device_t *device, char *path, struct stat *s);
int vfs_open_file_dev(struct vfs_device_t *device, char *path, int flags, int mode);
char *vfs_read_entire_file_dev(struct vfs_device_t *device, char *path, char **buffer);
int vfs_mkdir_dev(struct vfs_device_t *device, char *path);
int vfs_change_directory_dev(struct vfs_device_t *device, char *path);
int vfs_unlink_dev(struct vfs_device_t *device, char *path);
int vfs_link_dev(struct vfs_device_t *device, char *src, char *dest);
void init_vfs(void) {
vfs_devices = NULL;
vfs_device_count = 0;
vfs_pipes = NULL;
vfs_pipe_count = 0;
}
int vfs_getcwd(char *buffer, int len) {
if (current_task->cwd[strlen(current_task->cwd) - 1] == '/') {
if (strlen(current_task->cwd) + strlen(current_task->selected_device->name) + 2 < len) {
strcpy(buffer, current_task->selected_device->name);
buffer[strlen(current_task->selected_device->name)] = ':';
strcpy(&buffer[strlen(current_task->selected_device->name) + 1], current_task->cwd);
return 0;
}
} else {
if (strlen(current_task->cwd) + strlen(current_task->selected_device->name) + 3 < len) {
strcpy(buffer, current_task->selected_device->name);
buffer[strlen(current_task->selected_device->name)] = ':';
strcpy(&buffer[strlen(current_task->selected_device->name) + 1], current_task->cwd);
buffer[strlen(current_task->selected_device->name) + 1 + strlen(current_task->cwd)] = '/';
buffer[strlen(current_task->selected_device->name) + 1 + strlen(current_task->cwd) + 1] = '\0';
return 0;
}
}
return -1;
}
int vfs_lseek(int fileno, uint64_t offset, int whence) {
if (fileno > 255 || fileno < 0) {
return -1;
}
if (current_task->filehandles[fileno].free == 1) {
return -1;
}
switch (whence) {
case SEEK_SET:
current_task->filehandles[fileno].info->position = offset;
return current_task->filehandles[fileno].info->position;
case SEEK_CUR:
current_task->filehandles[fileno].info->position += offset;
return current_task->filehandles[fileno].info->position;
case SEEK_END:
current_task->filehandles[fileno].info->position = current_task->filehandles[fileno].info->size + offset;
return current_task->filehandles[fileno].info->position;
}
return -1;
}
struct vfs_device_t *vfs_register_device(uint32_t device, char *name, uint8_t fstype) {
struct vfs_device_t *new_device;
int ret;
new_device = (struct vfs_device_t *)dbmalloc(sizeof(struct vfs_device_t), "vfs register device 1");
new_device->device = device;
strcpy(new_device->name, name);
new_device->fs = fstype;
switch (fstype) {
case 0:
ret = tty_init(new_device);
break;
case 3:
ret = minix_load_superblock(new_device);
break;
default:
ret = 0;
break;
}
if (ret == 0) {
dbfree(new_device, "vfs register device 2");
return NULL;
}
if (vfs_device_count == 0) {
vfs_devices = (struct vfs_device_t **)dbmalloc(sizeof(struct vfs_device_t *), "vfs register device 3");
} else {
vfs_devices = (struct vfs_device_t **)dbrealloc(vfs_devices, sizeof(struct vfs_device_t *) * (vfs_device_count + 1), "vfs register device 4");
}
vfs_devices[vfs_device_count] = new_device;
vfs_device_count++;
kprintf("VFS: Registered %s\n", name);
return new_device;
}
int vfs_unlink(char *path) {
int i;
char *device_ptr;
char *path_ptr;
char *path_copy;
int ret;
path_copy = (char *)dbmalloc(strlen(path) + 1, "vfs unlink 1");
strcpy(path_copy, path);
device_ptr = path_copy;
for (i = 0; i < strlen(path_copy); i++) {
if (path_copy[i] == ':') {
path_copy[i] = '\0';
path_ptr = &path_copy[i + 1];
for (i = 0; i < vfs_device_count; i++) {
if (strcmp(vfs_devices[i]->name, device_ptr) == 0) {
if (path_ptr[strlen(path_ptr) - 1] == '/') {
path_ptr[strlen(path_ptr) - 1] = '\0';
}
vfs_select_device(vfs_devices[i]->name);
ret = vfs_unlink_dev(vfs_devices[i], path_ptr);
dbfree(path_copy, "vfs unlink 2");
return ret;
}
}
dbfree(path_copy, "vfs unlink 3");
return 0;
}
if (path_copy[i] == '/') {
break;
}
}
if (path_copy[strlen(path_copy) - 1] == '/') {
path_copy[strlen(path_copy) - 1] = '\0';
}
ret = vfs_unlink_dev(current_task->selected_device, path_copy);
dbfree(path_copy, "vfs unlink 4");
return ret;
}
int vfs_unlink_dev(struct vfs_device_t *device, char *path) {
char *temppath;
int ret = -1;
if (path[0] != '/') {
temppath = (char *)dbmalloc(strlen(current_task->cwd) + strlen(path) + 2, "vfs unlink dev 1");
memset(temppath, 0, strlen(current_task->cwd) + strlen(path) + 2);
if (current_task->cwd[1] == '\0') {
temppath[0] = '/';
memcpy(&temppath[1], path, strlen(path));
} else {
memcpy(temppath, current_task->cwd, strlen(current_task->cwd));
temppath[strlen(current_task->cwd)] = '/';
memcpy(&temppath[strlen(current_task->cwd) + 1], path, strlen(path));
}
} else {
temppath = (char *)dbmalloc(strlen(path) + 1, "vfs unlink dev 1.5");
strcpy(temppath, path);
}
switch (device->fs) {
case 3:
ret = minix_unlink_file(device, temppath);
break;
default:
ret = -1;
}
dbfree(temppath, "vfs unlink dev 2");
return ret;
}
int vfs_change_directory(char *path) {
int i;
char *device_ptr;
char *path_ptr;
char *path_copy;
int ret;
path_copy = (char *)dbmalloc(strlen(path) + 1, "vfs change directory 1");
strcpy(path_copy, path);
device_ptr = path_copy;
for (i = 0; i < strlen(path_copy); i++) {
if (path_copy[i] == ':') {
path_copy[i] = '\0';
path_ptr = &path_copy[i + 1];
for (i = 0; i < vfs_device_count; i++) {
if (strcmp(vfs_devices[i]->name, device_ptr) == 0) {
if (path_ptr[strlen(path_ptr) - 1] == '/') {
path_ptr[strlen(path_ptr) - 1] = '\0';
}
vfs_select_device(vfs_devices[i]->name);
ret = vfs_change_directory_dev(vfs_devices[i], path_ptr);
dbfree(path_copy, "vfs change directory 2");
return ret;
}
}
dbfree(path_copy, "vfs change directory 3");
return 0;
}
if (path_copy[i] == '/') {
break;
}
}
if (path_copy[strlen(path_copy) - 1] == '/' && strlen(path_copy) > 1) {
path_copy[strlen(path_copy) - 1] = '\0';
}
ret = vfs_change_directory_dev(current_task->selected_device, path_copy);
dbfree(path_copy, "vfs change directory 4");
return ret;
}
int vfs_change_directory_dev(struct vfs_device_t *device, char *path) {
switch (device->fs) {
case 3:
if (minix_change_directory(device, path)) {
free(current_task->cwd);
current_task->cwd = (char *)dbmalloc(sizeof(char) * (strlen(path) + 1), "vfs change directory dev 1");
strcpy(current_task->cwd, path);
}
break;
default:
break;
}
return 0;
}
int vfs_write_file(int fileno, char *buffer, int len) {
int count;
if (fileno < 0 || fileno >= 256) {
return -1;
}
if (current_task->filehandles[fileno].free) {
return -1;
}
if (current_task->filehandles[fileno].device == NULL) {
if (strcmp(current_task->filehandles[fileno].filepath, "PIPE") == 0) {
struct quinn_pipe_t *pipe = (struct quinn_pipe_t *)current_task->filehandles[fileno].fs_specific;
if (pipe->buffer_size == 0) {
pipe->buffer = (char *)dbmalloc(len, "vfs write file 1");
} else {
pipe->buffer = (char *)dbrealloc(pipe->buffer, pipe->buffer_size + len, "vfs write file 2");
}
if (!pipe->buffer) {
pipe->buffer_size = 0;
return -1;
}
memcpy(&pipe->buffer[pipe->buffer_size], buffer, len);
pipe->buffer_size += len;
return len;
}
} else {
switch (current_task->filehandles[fileno].device->fs) {
case 0:
count = tty_write_data(current_task->filehandles[fileno].device, buffer, len, 0);
return count;
case 3:
count = minix_write_data(current_task->filehandles[fileno].device, (struct minix_file_info *)current_task->filehandles[fileno].fs_specific,
current_task->filehandles[fileno].filepath, buffer, len, current_task->filehandles[fileno].info->position);
current_task->filehandles[fileno].info->position += count;
return count;
default:
return -1;
}
}
return -1;
}
int vfs_read_file(int fileno, char *buffer, int len) {
int count;
if (fileno < 0 || fileno >= 256) {
return -1;
}
if (current_task->filehandles[fileno].free) {
return -1;
}
if (current_task->filehandles[fileno].device == NULL) {
if (strcmp(current_task->filehandles[fileno].filepath, "PIPE") == 0) {
struct quinn_pipe_t *pipe = (struct quinn_pipe_t *)current_task->filehandles[fileno].fs_specific;
if (pipe->buffer_size == 0 && pipe->ref > 1) {
return -2;
} else if (pipe->buffer_size == 0) {
return 0;
}
if (len > pipe->buffer_size) {
len = pipe->buffer_size;
}
memcpy(buffer, pipe->buffer, len);
if (len < pipe->buffer_size) {
char *buffer2 = (char *)dbmalloc(pipe->buffer_size - len, "vfs read file 1");
memcpy(buffer2, &pipe->buffer[len], pipe->buffer_size - len);
dbfree(pipe->buffer, "vfs read file 2");
pipe->buffer = buffer2;
} else {
dbfree(pipe->buffer, "vfs read file 3");
}
pipe->buffer_size -= len;
return len;
}
} else {
switch (current_task->filehandles[fileno].device->fs) {
case 0:
count = tty_read_data(current_task->filehandles[fileno].device, buffer, len, 0);
return count;
case 3:
count = minix_read_data(current_task->filehandles[fileno].device, (struct minix_file_info *)current_task->filehandles[fileno].fs_specific, buffer, len,
current_task->filehandles[fileno].info->position);
current_task->filehandles[fileno].info->position += count;
return count;
default:
return -1;
}
}
return -1;
}
void vfs_close_file(int fno) {
if (fno < 0 || fno >= 256) {
return;
}
if (current_task->filehandles[fno].free == 1) {
return;
}
if (current_task->filehandles[fno].device == NULL) {
if (strcmp(current_task->filehandles[fno].filepath, "PIPE") == 0) {
struct quinn_pipe_t *pipe = (struct quinn_pipe_t *)current_task->filehandles[fno].fs_specific;
pipe->ref--;
if (pipe->ref == 0) {
for (int i = 0; i < vfs_pipe_count; i++) {
if (vfs_pipes[i] == pipe) {
for (int j = i; j < vfs_pipe_count - 1; j++) {
vfs_pipes[j] = vfs_pipes[j + 1];
}
vfs_pipe_count--;
if (vfs_pipe_count == 0) {
free(vfs_pipes);
} else {
vfs_pipes = (struct quinn_pipe_t **)dbrealloc(vfs_pipes, sizeof(struct quinn_pipe_t *) * vfs_pipe_count, "pipe close");
}
break;
}
}
}
return;
}
} else {
switch (current_task->filehandles[fno].device->fs) {
case 0:
current_task->filehandles[fno].free = 1;
current_task->filehandles[fno].info->ref--;
if (current_task->filehandles[fno].info->ref == 0) {
free(current_task->filehandles[fno].info);
}
free(current_task->filehandles[fno].filepath);
current_task->filehandles[fno].device = NULL;
break;
case 3:
if ((current_task->filehandles[fno].device->device & 0xff00) == 0x100) {
hd_sync(current_task->filehandles[fno].device->device & 0xff);
}
current_task->filehandles[fno].info->ref--;
if (current_task->filehandles[fno].info->ref == 0) {
free(current_task->filehandles[fno].info);
}
free(current_task->filehandles[fno].filepath);
free(current_task->filehandles[fno].fs_specific);
current_task->filehandles[fno].free = 1;
break;
default:
break;
}
}
}
void vfs_close_all() {
int i;
for (i = 0; i < 256; i++) {
if (current_task->filehandles[i].free == 0) {
vfs_close_file(i);
}
}
}
void vfs_sync_all() {
for (int i = 0; i < vfs_device_count; i++) {
if ((vfs_devices[i]->device & 0xff00) == 0x100) {
hd_sync(vfs_devices[i]->device & 0xff);
}
}
}
int vfs_link(char *src, char *dest) {
char *copy_1;
char *copy_2;
char *path_1;
char *path_2;
char *sel_dev1 = NULL;
char *sel_dev2 = NULL;
if (current_task->selected_device != NULL) {
sel_dev1 = current_task->selected_device->name;
sel_dev2 = current_task->selected_device->name;
}
copy_1 = (char *)dbmalloc(strlen(src) + 1, "vfs link 1");
if (!copy_1) {
return -1;
}
strcpy(copy_1, src);
copy_2 = (char *)dbmalloc(strlen(dest) + 1, "vfs link 1.5");
if (!copy_2) {
dbfree(copy_1, "vfs link 2");
return -1;
}
strcpy(copy_2, dest);
path_1 = copy_1;
path_2 = copy_2;
for (int i = 0; i < strlen(copy_1); i++) {
if (copy_1[i] == ':') {
copy_1[i] = '\0';
sel_dev1 = copy_1;
path_1 = &copy_1[i + 1];
break;
}
}
for (int i = 0; i < strlen(copy_2); i++) {
if (copy_2[i] == ':') {
copy_2[i] = '\0';
sel_dev2 = copy_2;
path_2 = &copy_2[i + 1];
break;
}
}
if (sel_dev1 == NULL || (sel_dev2 != NULL && strcmp(sel_dev2, sel_dev1) != 0)) {
dbfree(copy_1, "vfs link 3");
dbfree(copy_2, "vfs link 4");
return -2;
}
int ret = -1;
for (int i = 0; i < vfs_device_count; i++) {
if (strcmp(sel_dev1, vfs_devices[i]->name) == 0) {
ret = vfs_link_dev(vfs_devices[i], path_1, path_2);
break;
}
}
dbfree(copy_1, "vfs link 5");
dbfree(copy_2, "vfs link 6");
return ret;
}
int vfs_link_dev(struct vfs_device_t *device, char *src, char *dest) {
char *temppath1;
char *temppath2;
if (src[0] != '/') {
temppath1 = (char *)dbmalloc(strlen(current_task->cwd) + strlen(src) + 2, "vfs link dev 1");
memset(temppath1, 0, strlen(current_task->cwd) + strlen(src) + 2);
if (current_task->cwd[1] == '\0') {
temppath1[0] = '/';
memcpy(&temppath1[1], src, strlen(src));
} else {
memcpy(temppath1, current_task->cwd, strlen(current_task->cwd));
temppath1[strlen(current_task->cwd)] = '/';
memcpy(&temppath1[strlen(current_task->cwd) + 1], src, strlen(src));
}
} else {
temppath1 = (char *)dbmalloc(strlen(src) + 1, "vfs link dev 2");
strcpy(temppath1, src);
}
if (dest[0] != '/') {
temppath2 = (char *)dbmalloc(strlen(current_task->cwd) + strlen(dest) + 2, "vfs link dev 3");
memset(temppath2, 0, strlen(current_task->cwd) + strlen(dest) + 2);
if (current_task->cwd[1] == '\0') {
temppath2[0] = '/';
memcpy(&temppath2[1], dest, strlen(dest));
} else {
memcpy(temppath2, current_task->cwd, strlen(current_task->cwd));
temppath2[strlen(current_task->cwd)] = '/';
memcpy(&temppath2[strlen(current_task->cwd) + 1], dest, strlen(dest));
}
} else {
temppath2 = (char *)dbmalloc(strlen(dest) + 1, "vfs link dev 4");
strcpy(temppath2, dest);
}
switch (device->fs) {
case 1:
break;
case 2:
break;
case 3: {
int res = minix_link_file(device, temppath1, temppath2);
dbfree(temppath1, "vfs link dev 5");
dbfree(temppath2, "vfs link dev 6");
return res;
} break;
}
dbfree(temppath1, "vfs link dev 7");
dbfree(temppath2, "vfs link dev 8");
return -1;
}
int vfs_mkdir(char *path) {
int i;
char *device_ptr;
char *path_ptr;
char *path_copy;
int ret;
path_copy = (char *)dbmalloc(strlen(path) + 1, "vfs mkdir 1");
strcpy(path_copy, path);
device_ptr = path_copy;
for (i = 0; i < strlen(path_copy); i++) {
if (path_copy[i] == ':') {
path_copy[i] = '\0';
path_ptr = &path_copy[i + 1];
for (i = 0; i < vfs_device_count; i++) {
if (strcmp(vfs_devices[i]->name, device_ptr) == 0) {
ret = vfs_mkdir_dev(vfs_devices[i], path_ptr);
dbfree(path_copy, "vfs mkdir 2");
return ret;
}
}
dbfree(path_copy, "vfs mkdir 3");
return 0;
}
if (path_copy[i] == '/') {
break;
}
}
ret = vfs_mkdir_dev(current_task->selected_device, path);
dbfree(path_copy, "vfs mkdir 4");
return ret;
}
int vfs_mkdir_dev(struct vfs_device_t *device, char *path) {
char *temppath;
if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) {
return -1;
}
if (path[0] != '/') {
temppath = (char *)dbmalloc(strlen(current_task->cwd) + strlen(path) + 2, "vfs mkdir dev 1");
memset(temppath, 0, strlen(current_task->cwd) + strlen(path) + 2);
if (current_task->cwd[1] == '\0') {
temppath[0] = '/';
memcpy(&temppath[1], path, strlen(path));
} else {
memcpy(temppath, current_task->cwd, strlen(current_task->cwd));
temppath[strlen(current_task->cwd)] = '/';
memcpy(&temppath[strlen(current_task->cwd) + 1], path, strlen(path));
}
} else {
temppath = (char *)dbmalloc(strlen(path) + 1, "vfs mkdir dev 2");
strcpy(temppath, path);
}
switch (device->fs) {
case 3: {
int res = minix_create_directory(device, temppath);
dbfree(temppath, "vfs mkdir dev 3");
return res;
} break;
default:
break;
}
dbfree(temppath, "vfs mkdir dev 4");
return -1;
}
char *vfs_read_entire_file(char *path, char **buffer) {
int i;
char *device_ptr;
char *path_ptr;
char *path_copy;
char *ret;
path_copy = (char *)dbmalloc(strlen(path) + 1, "read_entire_file malloc");
strcpy(path_copy, path);
device_ptr = path_copy;
for (i = 0; i < strlen(path_copy); i++) {
if (path_copy[i] == ':') {
path_copy[i] = '\0';
path_ptr = &path_copy[i + 1];
for (i = 0; i < vfs_device_count; i++) {
if (strcmp(vfs_devices[i]->name, device_ptr) == 0) {
ret = vfs_read_entire_file_dev(vfs_devices[i], path_ptr, buffer);
dbfree(path_copy, "read_entire_file free");
return ret;
}
}
return 0;
}
if (path_copy[i] == '/') {
break;
}
}
ret = vfs_read_entire_file_dev(current_task->selected_device, path, buffer);
dbfree(path_copy, "read_entire_file free 2");
return ret;
}
char *vfs_read_entire_file_dev(struct vfs_device_t *device, char *path, char **buffer) {
char *temppath;
if (path[0] != '/') {
temppath = (char *)dbmalloc(strlen(current_task->cwd) + strlen(path) + 2, "vfs read entire file dev 1");
memset(temppath, 0, strlen(current_task->cwd) + strlen(path) + 2);
if (current_task->cwd[1] == '\0') {
temppath[0] = '/';
memcpy(&temppath[1], path, strlen(path));
} else {
memcpy(temppath, current_task->cwd, strlen(current_task->cwd));
temppath[strlen(current_task->cwd)] = '/';
memcpy(&temppath[strlen(current_task->cwd) + 1], path, strlen(path));
}
} else {
temppath = (char *)dbmalloc(strlen(path) + 1, "vfs read entire file dev 2");
strcpy(temppath, path);
}
switch (device->fs) {
case 3: {
struct minix_file_info *info = minix_check_if_exists(device, temppath, 1);
if (!info) {
dbfree(temppath, "vfs read entire file dev 3");
return NULL;
}
struct minix_inode *inode = minix_get_inode(device, info->inode);
minix_read_entire_file(device, inode, buffer);
dbfree(inode, "vfs read entire file dev 4");
dbfree(temppath, "vfs read entire file dev 5");
dbfree(info, "vfs read entire file dev 6");
return *buffer;
} break;
default:
break;
}
dbfree(temppath, "vfs read entire file dev 7");
return NULL;
}
int vfs_open_file(char *path, int flags, int mode) {
int i;
char *device_ptr;
char *path_ptr;
char *path_copy;
int ret;
path_copy = (char *)dbmalloc(strlen(path) + 1, "vfs_open file 1");
strcpy(path_copy, path);
device_ptr = path_copy;
for (i = 0; i < strlen(path_copy); i++) {
if (path_copy[i] == ':') {
path_copy[i] = '\0';
path_ptr = &path_copy[i + 1];
for (i = 0; i < vfs_device_count; i++) {
if (strcmp(vfs_devices[i]->name, device_ptr) == 0) {
ret = vfs_open_file_dev(vfs_devices[i], path_ptr, flags, mode);
dbfree(path_copy, "vfs_open file 2");
return ret;
}
}
dbfree(path_copy, "vfs_open file 3");
return 0;
}
if (path_copy[i] == '/') {
break;
}
}
ret = vfs_open_file_dev(current_task->selected_device, path_copy, flags, mode);
dbfree(path_copy, "vfs_open file 4");
return ret;
}
int vfs_open_file_dev(struct vfs_device_t *device, char *path, int flags, int mode) {
int i;
char *temppath;
if (path[0] != '/') {
temppath = (char *)dbmalloc(strlen(current_task->cwd) + strlen(path) + 2, "vfs_open file dev 1");
memset(temppath, 0, strlen(current_task->cwd) + strlen(path) + 2);
if (current_task->cwd[1] == '\0') {
temppath[0] = '/';
memcpy(&temppath[1], path, strlen(path));
} else {
memcpy(temppath, current_task->cwd, strlen(current_task->cwd));
temppath[strlen(current_task->cwd)] = '/';
memcpy(&temppath[strlen(current_task->cwd) + 1], path, strlen(path));
}
} else {
temppath = (char *)dbmalloc(strlen(path) + 1, "vfs_open file dev 2");
strcpy(temppath, path);
}
switch (device->fs) {
case 0:
for (i = 0; i < 256; i++) {
if (current_task->filehandles[i].free) {
break;
}
}
if (i == 256) {
dbfree(temppath, "vfs_open file dev 4");
return -1;
}
current_task->filehandles[i].free = 0;
current_task->filehandles[i].device = device;
current_task->filehandles[i].filepath = (char *)dbmalloc(strlen(temppath) + 1, "vfs_open file dev 4");
strcpy(current_task->filehandles[i].filepath, temppath);
current_task->filehandles[i].info = (struct vfs_file_handle_info_t *)dbmalloc(sizeof(struct vfs_file_handle_info_t), "vfs_open file dev 3");
current_task->filehandles[i].info->position = 0;
current_task->filehandles[i].info->size = 0;
current_task->filehandles[i].info->ref = 1;
dbfree(temppath, "vfs_open file dev 4");
return i;
case 3: {
struct minix_file_info *info = minix_check_if_exists(device, temppath, -1);
if (info != NULL) {
for (i = 0; i < 256; i++) {
if (current_task->filehandles[i].free) {
break;
}
}
if (i == 256) {
dbfree(temppath, "vfs_open file dev 5");
return -1;
}
if (flags & O_TRUNC) {
if (info->file_size > 0) {
minix_trunc_file(device, info);
minix_wipe_inode(device, info);
info->file_size = 0;
}
}
current_task->filehandles[i].free = 0;
current_task->filehandles[i].device = device;
current_task->filehandles[i].filepath = (char *)dbmalloc(sizeof(char) * (strlen(temppath) + 1), "vfs_open file dev 6");
strcpy(current_task->filehandles[i].filepath, temppath);
current_task->filehandles[i].info = (struct vfs_file_handle_info_t *)dbmalloc(sizeof(struct vfs_file_handle_info_t), "vfs_open file dev 7");
current_task->filehandles[i].info->position = 0;
current_task->filehandles[i].info->size = info->file_size;
current_task->filehandles[i].info->ref = 1;
current_task->filehandles[i].fs_specific = (void *)info;
dbfree(temppath, "vfs_open file dev 8");
return i;
} else {
if (flags & O_CREAT) {
minix_create_file(device, temppath);
info = minix_check_if_exists(device, temppath, -1);
if (info != NULL) {
for (i = 0; i < 256; i++) {
if (current_task->filehandles[i].free) {
break;
}
}
if (i == 256) {
dbfree(temppath, "vfs_open file dev 9");
return -1;
}
current_task->filehandles[i].free = 0;
current_task->filehandles[i].device = device;
current_task->filehandles[i].filepath = (char *)dbmalloc(sizeof(char) * (strlen(temppath) + 1), "vfs_open file dev 10");
strcpy(current_task->filehandles[i].filepath, temppath);
current_task->filehandles[i].info = (struct vfs_file_handle_info_t *)dbmalloc(sizeof(struct vfs_file_handle_info_t), "vfs_open file dev 11");
current_task->filehandles[i].info->position = 0;
current_task->filehandles[i].info->size = info->file_size;
current_task->filehandles[i].info->ref = 1;
current_task->filehandles[i].fs_specific = (void *)info;
dbfree(temppath, "vfs_open file dev 12");
return i;
}
}
dbfree(temppath, "vfs_open file dev 13");
return -1; // ENOENT
}
} break;
default:
return -1;
}
dbfree(temppath, "vfs_open file dev 14");
return -1;
}
uint8_t vfs_select_device(char *name) {
int i;
for (i = 0; i < vfs_device_count; i++) {
if (strcmp(vfs_devices[i]->name, name) == 0) {
current_task->selected_device = vfs_devices[i];
return 1;
}
}
return 0;
}
int vfs_getdents(int fileno, char *buffer, int count) {
int len;
if (fileno < 0 || fileno >= 256) {
return -1;
}
if (current_task->filehandles[fileno].free) {
return -1;
}
switch (current_task->filehandles[fileno].device->fs) {
case 0:
return 0;
case 3: {
uint64_t newoff;
len = minix_get_dents(current_task->filehandles[fileno].device, (struct minix_file_info *)current_task->filehandles[fileno].fs_specific, buffer, count,
current_task->filehandles[fileno].info->position, &newoff);
current_task->filehandles[fileno].info->position += newoff;
return len;
}
default:
break;
}
return 0;
}
int vfs_statfs_dev(struct vfs_device_t *device, struct statfs *sfs) {
memset(sfs, 0, sizeof(struct statfs));
sfs->fs_type = device->fs;
switch (device->fs) {
case 3: {
struct minix_data *mdata = (struct minix_data *)device->fs_data;
sfs->total_inodes = mdata->sb.s_ninodes;
sfs->total_blocks = mdata->sb.s_zones;
sfs->blocksize = mdata->sb.s_blocksize;
sfs->free_inodes = 0;
for (int i = 0; i < (mdata->sb.s_imap_blocks * mdata->sb.s_blocksize) / 4; i++) {
if (mdata->s_imap[i] == 0xffffffff) {
continue;
}
if (mdata->s_imap[i] == 0) {
sfs->free_inodes += 32;
continue;
} else {
for (size_t x = 0; x < 32; x++) {
if (!(mdata->s_imap[i] & (1u << x))) {
sfs->free_inodes++;
}
}
}
}
sfs->free_blocks = 0;
for (int i = 0; i < (mdata->sb.s_zmap_blocks * mdata->sb.s_blocksize) / 4; i++) {
if (mdata->s_zmap[i] == 0xffffffff) {
continue;
}
if (mdata->s_zmap[i] == 0) {
sfs->free_blocks += 32;
continue;
} else {
for (size_t x = 0; x < 32; x++) {
if (!(mdata->s_zmap[i] & (1u << x))) {
sfs->free_blocks++;
}
}
}
}
} break;
default:
return -1;
}
return 0;
}
int vfs_statfs(char *path, struct statfs *sfs) {
int i;
char *device_ptr;
char *path_copy;
int ret;
path_copy = (char *)dbmalloc(strlen(path) + 1, "vfs statfs 1");
strcpy(path_copy, path);
device_ptr = path_copy;
for (i = 0; i < strlen(path_copy); i++) {
if (path_copy[i] == ':') {
path_copy[i] = '\0';
for (i = 0; i < vfs_device_count; i++) {
if (strcmp(vfs_devices[i]->name, device_ptr) == 0) {
ret = vfs_statfs_dev(vfs_devices[i], sfs);
dbfree(path_copy, "vfs statfs 2");
return ret;
}
}
dbfree(path_copy, "vfs statfs 3");
return 0;
}
if (path_copy[i] == '/') {
break;
}
}
ret = vfs_statfs_dev(current_task->selected_device, sfs);
dbfree(path_copy, "vfs statfs 4");
return ret;
}
int vfs_fstat(int fileno, struct stat *s) {
if (fileno < 0 || fileno >= 256) {
return -1;
}
if (current_task->filehandles[fileno].free) {
return -1;
}
switch (current_task->filehandles[fileno].device->fs) {
case 0:
s->st_dev = current_task->filehandles[fileno].device->device; // ID of device containing file
s->st_ino = 0; // file serial number
s->st_mode = S_IFCHR; // mode of file (see below)
s->st_nlink = 0; // number of links to the file
s->st_uid = 0; // user ID of file
s->st_gid = 0; // group ID of file
s->st_rdev = 0; // device ID (if file is character or block special)
s->st_size = 0; // file size in bytes (if file is a regular file)
s->st_atime = 0; // time of last access
s->st_mtime = 0; // time of last data modification
s->st_ctime = 0; // time of last status change
s->st_blksize = 0; // a filesystem-specific preferred I/O block size for
s->st_blocks = 0; // number of blocks allocated for this object
break;
case 3: {
struct minix_data *data = (struct minix_data *)current_task->filehandles[fileno].device->fs_data;
struct minix_file_info *info = (struct minix_file_info *)current_task->filehandles[fileno].fs_specific;
s->st_dev = current_task->filehandles[fileno].device->device;
s->st_ino = info->inode;
s->st_mode = (info->type == 0 ? S_IFDIR : S_IFREG);
s->st_nlink = 1;
s->st_uid = 0;
s->st_gid = 0;
s->st_rdev = 0;
s->st_size = info->file_size;
s->st_atime = info->atime;
s->st_mtime = info->mtime;
s->st_ctime = info->ctime;
s->st_blksize = data->sb.s_blocksize;
s->st_blocks = info->file_size / data->sb.s_blocksize;
if (info->file_size % data->sb.s_blocksize)
s->st_blocks++;
} break;
default:
return -1;
}
return 0;
}
int vfs_pipe(int *pipe) {
int i, j;
for (i = 0; i < 256; i++) {
if (current_task->filehandles[i].free) {
break;
}
}
if (i == 256) {
return -1;
}
current_task->filehandles[i].free = 0;
for (j = 0; j < 256; j++) {
if (current_task->filehandles[j].free) {
break;
}
}
if (j == 256) {
current_task->filehandles[i].free = 1;
return -1;
}
current_task->filehandles[j].free = 0;
struct quinn_pipe_t *pipe_ptr = (struct quinn_pipe_t *)dbmalloc(sizeof(struct quinn_pipe_t), "vfs pipe 1");
if (!pipe_ptr) {
current_task->filehandles[i].free = 1;
current_task->filehandles[j].free = 1;
return -1;
}
pipe_ptr->in_fno = i;
pipe_ptr->out_fno = j;
pipe_ptr->buffer_size = 0;
pipe_ptr->ref = 2;
current_task->filehandles[i].filepath = (char *)dbmalloc(5, "vfs pipe 2");
strcpy(current_task->filehandles[i].filepath, "PIPE");
current_task->filehandles[i].device = NULL;
current_task->filehandles[i].info = (struct vfs_file_handle_info_t *)dbmalloc(sizeof(struct vfs_file_handle_info_t), "vfs pipe 3");
current_task->filehandles[i].info->position = 0;
current_task->filehandles[i].info->size = 0;
current_task->filehandles[i].info->ref = 1;
current_task->filehandles[i].fs_specific = pipe_ptr;
current_task->filehandles[j].filepath = (char *)dbmalloc(5, "vfs pipe 4");
strcpy(current_task->filehandles[j].filepath, "PIPE");
current_task->filehandles[j].device = NULL;
current_task->filehandles[j].info = (struct vfs_file_handle_info_t *)dbmalloc(sizeof(struct vfs_file_handle_info_t), "vfs pipe 5");
current_task->filehandles[j].info->position = 0;
current_task->filehandles[j].info->size = 0;
current_task->filehandles[j].info->ref = 1;
current_task->filehandles[j].fs_specific = pipe_ptr;
if (vfs_pipe_count == 0) {
vfs_pipes = (struct quinn_pipe_t **)dbmalloc(sizeof(struct quinn_pipe_t *), "vfs pipe 6");
} else {
vfs_pipes = (struct quinn_pipe_t **)dbrealloc(vfs_pipes, sizeof(struct quinn_pipe_t *) * (vfs_pipe_count + 1), "vfs pipe 7");
}
vfs_pipes[vfs_pipe_count] = pipe_ptr;
vfs_pipe_count++;
pipe[0] = pipe_ptr->out_fno;
pipe[1] = pipe_ptr->in_fno;
return 0;
}
int vfs_stat(char *path, struct stat *s) {
int i;
char *device_ptr;
char *path_ptr;
char *path_copy;
int ret;
path_copy = (char *)dbmalloc(strlen(path) + 1, "vfs stat 1");
strcpy(path_copy, path);
device_ptr = path_copy;
for (i = 0; i < strlen(path_copy); i++) {
if (path_copy[i] == ':') {
path_copy[i] = '\0';
path_ptr = &path_copy[i + 1];
for (i = 0; i < vfs_device_count; i++) {
if (strcmp(vfs_devices[i]->name, device_ptr) == 0) {
ret = vfs_stat_dev(vfs_devices[i], path_ptr, s);
dbfree(path_copy, "vfs stat 2");
return ret;
}
}
dbfree(path_copy, "vfs stat 3");
return 0;
}
if (path_copy[i] == '/') {
break;
}
}
ret = vfs_stat_dev(current_task->selected_device, path_copy, s);
dbfree(path_copy, "vfs stat 4");
return ret;
}
int vfs_stat_dev(struct vfs_device_t *device, char *path, struct stat *s) {
char *temppath;
if (path[0] != '/') {
temppath = (char *)dbmalloc(strlen(current_task->cwd) + strlen(path) + 2, "vfs stat dev 1");
memset(temppath, 0, strlen(current_task->cwd) + strlen(path) + 2);
if (current_task->cwd[1] == '\0') {
temppath[0] = '/';
memcpy(&temppath[1], path, strlen(path));
} else {
memcpy(temppath, current_task->cwd, strlen(current_task->cwd));
temppath[strlen(current_task->cwd)] = '/';
memcpy(&temppath[strlen(current_task->cwd) + 1], path, strlen(path));
}
} else {
temppath = (char *)dbmalloc(strlen(path) + 1, "vfs stat dev 2");
strcpy(temppath, path);
}
switch (device->fs) {
case 0:
s->st_dev = device->device; // ID of device containing file
s->st_ino = 0; // file serial number
s->st_mode = S_IFCHR; // mode of file (see below)
s->st_nlink = 0; // number of links to the file
s->st_uid = 0; // user ID of file
s->st_gid = 0; // group ID of file
s->st_rdev = 0; // device ID (if file is character or block special)
s->st_size = 0; // file size in bytes (if file is a regular file)
s->st_atime = 0; // time of last access
s->st_mtime = 0; // time of last data modification
s->st_ctime = 0; // time of last status change
s->st_blksize = 0; // a filesystem-specific preferred I/O block size for
s->st_blocks = 0; // number of blocks allocated for this object
break;
case 3: {
struct minix_file_info *info = minix_check_if_exists(device, temppath, -1);
struct minix_data *data = (struct minix_data *)device->fs_data;
if (info != NULL) {
s->st_dev = device->device;
s->st_ino = info->inode;
s->st_mode = (info->type == 0 ? S_IFDIR : S_IFREG);
s->st_nlink = 1;
s->st_uid = 0;
s->st_gid = 0;
s->st_rdev = 0;
s->st_size = info->file_size;
s->st_atime = info->atime;
s->st_mtime = info->mtime;
s->st_ctime = info->ctime;
s->st_blksize = data->sb.s_blocksize;
s->st_blocks = info->file_size / data->sb.s_blocksize;
if (info->file_size % data->sb.s_blocksize)
s->st_blocks++;
} else {
dbfree(temppath, "vfs stat dev 3");
return -1;
}
break;
}
default:
dbfree(temppath, "vfs stat dev 4");
return -1;
}
dbfree(temppath, "vfs stat dev 5");
return 0;
}
int vfs_dup2(int oldfno, int newfno) {
if (current_task->filehandles[newfno].free == 0) {
// close
vfs_close_file(newfno);
}
current_task->filehandles[newfno].free = 0;
current_task->filehandles[newfno].filepath = (char *)dbmalloc(strlen(current_task->filehandles[oldfno].filepath) + 1, "vfs dup2 1");
strcpy(current_task->filehandles[newfno].filepath, current_task->filehandles[oldfno].filepath);
current_task->filehandles[newfno].device = current_task->filehandles[oldfno].device;
current_task->filehandles[newfno].info = current_task->filehandles[oldfno].info;
current_task->filehandles[newfno].info->ref++;
current_task->filehandles[newfno].fs_specific = current_task->filehandles[oldfno].fs_specific;
if (current_task->filehandles[oldfno].device == NULL) {
struct quinn_pipe_t *pipe = (struct quinn_pipe_t *)current_task->filehandles[newfno].fs_specific;
pipe->ref++;
}
return newfno;
}
int vfs_dup(int fno) {
int i;
if (current_task->filehandles[fno].device != NULL) {
// only works for pipes atm.
return -1;
}
if (fno < 0 || fno >= 256) {
return -1;
}
if (current_task->filehandles[fno].free == 1) {
return -1;
}
for (i = 0; i < 256; i++) {
if (current_task->filehandles[i].free) {
break;
}
}
if (i == 256) {
return -1;
}
current_task->filehandles[i].free = 0;
current_task->filehandles[i].filepath = (char *)dbmalloc(strlen(current_task->filehandles[fno].filepath) + 1, "vfs dup 1");
strcpy(current_task->filehandles[i].filepath, current_task->filehandles[fno].filepath);
current_task->filehandles[i].device = current_task->filehandles[fno].device;
current_task->filehandles[i].info = current_task->filehandles[fno].info;
current_task->filehandles[i].info->ref++;
current_task->filehandles[i].fs_specific = current_task->filehandles[fno].fs_specific;
struct quinn_pipe_t *pipe = (struct quinn_pipe_t *)current_task->filehandles[i].fs_specific;
pipe->ref++;
return i;
}