#include #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 = ©_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 = ©_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; }