diff --git a/components/fs/fat/fat.mk b/components/fs/fat/fat.mk index 5becaba9..f61928af 100644 --- a/components/fs/fat/fat.mk +++ b/components/fs/fat/fat.mk @@ -55,6 +55,9 @@ fat/$(FAT_LIBMICROKITCO_OBJ): fat LLVM:=1 \ LIBMICROKITCO_OPT_PATH=$(FAT_LIBMICROKITCO_OPT_PATH) +LIB_FS_SERVER_LIBC_INCLUDE := $(FAT_LIBC_INCLUDE) +include $(LIONSOS)/lib/fs/server/lib_fs_server.mk + fat: mkdir -p fat @@ -69,7 +72,7 @@ fat/%.o: CFLAGS += $(FAT_CFLAGS) fat/%.o: $(FAT_SRC_DIR)/%.c $(FAT_LIBC_INCLUDE) $(CHECK_FAT_FLAGS_MD5) |fat $(CC) -c $(CFLAGS) $< -o $@ -fat.elf: $(FAT_OBJ) fat/$(FAT_LIBMICROKITCO_OBJ) $(FAT_LIBC_LIB) +fat.elf: $(FAT_OBJ) fat/$(FAT_LIBMICROKITCO_OBJ) $(FAT_LIBC_LIB) lib_fs_server.a $(LD) $(LDFLAGS) $^ $(LIBS) -o $@ -include $(FAT_OBJ:.o=.d) diff --git a/components/fs/fat/op.c b/components/fs/fat/op.c index a205bba9..4f1d33b4 100644 --- a/components/fs/fat/op.c +++ b/components/fs/fat/op.c @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include #include /* @@ -17,83 +19,48 @@ This file define a bunch of wrapper functions of FATFs functions so those functi worker thread. */ -typedef enum : uint8_t { - FREE = 0, - INUSE = 1, - CLEANUP = 2, -} descriptor_status; - -descriptor_status fs_status; FATFS fatfs; -descriptor_status file_status[FAT_MAX_OPENED_FILENUM]; -FIL files[FAT_MAX_OPENED_FILENUM]; -descriptor_status dir_status[FAT_MAX_OPENED_DIRNUM]; -DIR dirs[FAT_MAX_OPENED_DIRNUM]; +bool fs_initialised; + +FIL files[MAX_OPEN_FILES]; +bool file_used[MAX_OPEN_FILES]; + +DIR dirs[MAX_OPEN_FILES]; +bool dir_used[MAX_OPEN_FILES]; /* Data shared with client */ extern char *fs_share; -// Sanity check functions -// Checking if the memory region that provided by request is within valid memory region -static inline FRESULT within_data_region(uint64_t offset, uint64_t buffer_size) { - LOG_FATFS("with_data_region check, input args: offset: %ld, buffer size: %ld\n", offset, buffer_size); - if ((offset < FAT_FS_DATA_REGION_SIZE) && (buffer_size <= FAT_FS_DATA_REGION_SIZE - offset)) { - return FR_OK; - } - return FR_INVALID_PARAMETER; -} - -// Checking if the descriptor is mapped to a valid object -static inline FRESULT validate_file_descriptor(uint64_t fd) { - if ((fd < FAT_MAX_OPENED_FILENUM) && file_status[fd] == INUSE) { - return FR_OK; +FIL *file_alloc(void) { + for (int i = 0; i < MAX_OPEN_FILES; i++) { + if (!file_used[i]) { + file_used[i] = true; + return &files[i]; + } } - return FR_INVALID_PARAMETER; + return NULL; } -// Checking if the descriptor is mapped to a valid object -static inline FRESULT validate_dir_descriptor(uint64_t fd) { - if ((fd < FAT_MAX_OPENED_DIRNUM) && dir_status[fd] == INUSE) { - return FR_OK; - } - return FR_INVALID_PARAMETER; +void file_free(FIL *file) { + uint32_t i = file - files; + assert(file_used[i]); + file_used[i] = false; } -static FRESULT validate_and_copy_path(uint64_t path, uint64_t len, char* memory) { - // Validate if the memory segment provided is in valid data region - if (within_data_region(path, len) != FR_OK) { - return FR_INVALID_PARAMETER; - } - // The length of the path provided most be under the upper bound - if (len > FS_MAX_PATH_LENGTH) { - return FR_INVALID_PARAMETER; - } - // Copy the string to our private memory - memcpy(memory, fs_share + path, len); - // Return error if the string is not NULL terminated - memory[len] = '\0'; - - return FR_OK; -} - -uint32_t find_free_file_obj(void) { - uint32_t i; - for (i = 0; i < FAT_MAX_OPENED_FILENUM; i++) { - if (file_status[i] == FREE) { - return i; +DIR *dir_alloc(void) { + for (int i = 0; i < MAX_OPEN_FILES; i++) { + if (!dir_used[i]) { + dir_used[i] = true; + return &dirs[i]; } } - return i; + return NULL; } -uint32_t find_free_dir_object(void) { - uint32_t i; - for (i = 0; i < FAT_MAX_OPENED_DIRNUM; i++) { - if (dir_status[i] == FREE) { - return i; - } - } - return i; +void dir_free(DIR *dir) { + uint32_t i = dir - dirs; + assert(dir_used[i]); + dir_used[i] = false; } // Function to convert the open flag from fs_protocol @@ -128,14 +95,14 @@ unsigned char map_fs_flags_to_fat_flags(uint64_t fs_flags) { void handle_initialise(void) { LOG_FATFS("Mounting file system!\n"); co_data_t *args = microkit_cothread_my_arg(); - if (fs_status != FREE) { + if (fs_initialised) { args->status = FS_STATUS_ERROR; return; } - fs_status = INUSE; + fs_initialised = true; FRESULT RET = f_mount(&fatfs, "", 1); if (RET != FR_OK) { - fs_status = FREE; + fs_initialised = false; } LOG_FATFS("Mounting file system result: %d\n", RET); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; @@ -143,17 +110,13 @@ void handle_initialise(void) { void handle_deinitialise(void) { co_data_t *args = microkit_cothread_my_arg(); - if (fs_status != INUSE) { + if (!fs_initialised) { args->status = FS_STATUS_ERROR; return; } - fs_status = CLEANUP; FRESULT RET = f_unmount(""); if (RET == FR_OK) { - fs_status = FREE; - } - else { - fs_status = INUSE; + fs_initialised = false; } args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } @@ -161,16 +124,14 @@ void handle_deinitialise(void) { void handle_file_open(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t buffer = args->params.file_open.path.offset; - uint64_t size = args->params.file_open.path.size; + fs_buffer_t buffer = args->params.file_open.path; uint64_t openflag = args->params.file_open.flags; // Copy the name to our name buffer char filepath[FS_MAX_NAME_LENGTH + 1]; - // Validate string - FRESULT RET = validate_and_copy_path(buffer, size, filepath); - if (RET != FR_OK) { + int err = fs_copy_client_path(filepath, fs_share, FAT_FS_DATA_REGION_SIZE, buffer); + if (err) { args->status = FS_STATUS_ERROR; return; } @@ -178,62 +139,66 @@ void handle_file_open(void) { // Add open flag checking and mapping here LOG_FATFS("fat_open: file path: %s\n", filepath); - uint32_t fd = find_free_file_obj(); - if (fd == FAT_MAX_OPENED_FILENUM) { + FIL *file = file_alloc(); + if (file == NULL) { args->status = FS_STATUS_TOO_MANY_OPEN_FILES; return; } - // Set the position to INUSE to indicate this file structure is in use - file_status[fd] = INUSE; - FIL* file = &(files[fd]); - unsigned char fat_flag = map_fs_flags_to_fat_flags(openflag); LOG_FATFS("fat_open: fs_protocol open flag: %lu\n", openflag); LOG_FATFS("fat_open: fat open flag: %hhu\n", fat_flag); // Micropython openflag still WIP, fixes this once that is completed - RET = f_open(file, filepath, fat_flag); + FRESULT RET = f_open(file, filepath, fat_flag); // Error handling if (RET != FR_OK) { - file_status[fd] = FREE; + file_free(file); + args->status = FS_STATUS_ERROR; + return; } + fd_t fd; + err = fd_alloc(&fd); + assert(!err); + fd_set_file(fd, file); + args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; args->result.file_open.fd = fd; } void handle_file_write(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t fd = args->params.file_write.fd; - uint64_t buffer = args->params.file_write.buf.offset; + fd_t fd = args->params.file_write.fd; + // uint64_t buffer = args->params.file_write.buf.offset; + fs_buffer_t buffer = args->params.file_write.buf; uint64_t btw = args->params.file_write.buf.size; uint64_t offset = args->params.file_write.offset; LOG_FATFS("fat_write: bytes to be write: %lu, write offset: %lu\n", btw, offset); - FRESULT RET = within_data_region(buffer, btw); - if (RET != FR_OK) { + char *data = fs_get_client_buffer(fs_share, FAT_FS_DATA_REGION_SIZE, buffer); + if (data == NULL) { LOG_FATFS("fat_write: invalid buffer\n"); args->result.file_write.len_written = 0; args->status = FS_STATUS_INVALID_BUFFER; return; } - if ((RET = validate_file_descriptor(fd)) != FR_OK) { - LOG_FATFS("fat_write: invalid fd provided\n"); - args->result.file_write.len_written = 0; + + FIL *file = NULL; + int err = fd_begin_op_file(fd, &file); + if (err) { + LOG_FATFS("invalid fd: %d\n", fd); args->status = FS_STATUS_INVALID_FD; return; } - void* data = fs_share + buffer; - - FIL* file = &(files[fd]); - RET = f_lseek(file, offset); + FRESULT RET = f_lseek(file, offset); if (RET != FR_OK) { + fd_end_op(fd); args->result.file_write.len_written = 0; args->status = FS_STATUS_ERROR; return; @@ -242,6 +207,7 @@ void handle_file_write(void) { uint32_t bw = 0; RET = f_write(file, data, btw, &bw); + fd_end_op(fd); if (RET == FR_OK) { LOG_FATFS("fat_write: byte written: %u, content written: \n%.*s\n", bw, bw, (char *)data); @@ -256,35 +222,33 @@ void handle_file_write(void) { void handle_file_read(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t fd = args->params.file_read.fd; - uint64_t buffer = args->params.file_read.buf.offset; + fd_t fd = args->params.file_read.fd; + fs_buffer_t buffer = args->params.file_read.buf; uint64_t btr = args->params.file_read.buf.size; uint64_t offset = args->params.file_read.offset; - FRESULT RET; - if ((RET = within_data_region(buffer, btr)) != FR_OK) { + char *data = fs_get_client_buffer(fs_share, FAT_FS_DATA_REGION_SIZE, buffer); + if (data == NULL) { LOG_FATFS("fat_read: invalid buffer provided\n"); args->status = FS_STATUS_INVALID_BUFFER; args->result.file_read.len_read = 0; return; } - if ((RET = validate_file_descriptor(fd)) != FR_OK) { - LOG_FATFS("fat_read: invalid fd provided\n"); + + FIL *file = NULL; + int err = fd_begin_op_file(fd, &file); + if (err) { + LOG_FATFS("invalid fd: %d\n", fd); args->status = FS_STATUS_INVALID_FD; - args->result.file_read.len_read = 0; return; } - void* data = fs_share + buffer; - - // Maybe add validation check of file descriptor here - FIL* file = &(files[fd]); - LOG_FATFS("fat_read: bytes to be read: %lu, read offset: %lu\n", btr, offset); - RET = f_lseek(file, offset); + FRESULT RET = f_lseek(file, offset); if (RET != FR_OK) { + fd_end_op(fd); args->status = FS_STATUS_ERROR; args->result.file_read.len_read = 0; return; @@ -293,6 +257,7 @@ void handle_file_read(void) { uint32_t br = 0; RET = f_read(file, data, btr, &br); + fd_end_op(fd); if (RET == FR_OK) { LOG_FATFS("fat_read: byte read: %u, content read: \n%.*s\n", br, br, (char *)data); @@ -307,23 +272,31 @@ void handle_file_read(void) { void handle_file_close(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t fd = args->params.file_close.fd; + fd_t fd = args->params.file_close.fd; - FRESULT RET = validate_file_descriptor(fd); - if (RET != FR_OK) { + FIL *file; + int err = fd_begin_op_file(fd, &file); + if (err) { LOG_FATFS("fat_close: Invalid file descriptor\n"); args->status = FS_STATUS_INVALID_FD; return; } + fd_end_op(fd); - file_status[fd] = CLEANUP; + err = fd_unset(fd); + if (err) { + LOG_FATFS("fd has outstanding operations\n"); + args->status = FS_STATUS_OUTSTANDING_OPERATIONS; + return; + } - RET = f_close(&(files[fd])); + FRESULT RET = f_close(file); if (RET == FR_OK) { - file_status[fd] = FREE; + file_free(file); + fd_free(fd); } else { - file_status[fd] = INUSE; + fd_set_file(fd, file); } args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; @@ -332,29 +305,29 @@ void handle_file_close(void) { void handle_stat(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t path = args->params.stat.path.offset; - uint64_t path_len = args->params.stat.path.size; - uint64_t output_buffer = args->params.stat.buf.offset; + fs_buffer_t path = args->params.stat.path; + fs_buffer_t output_buffer = args->params.stat.buf; uint64_t size = args->params.stat.buf.size; char filepath[FS_MAX_PATH_LENGTH + 1]; - FRESULT RET = within_data_region(output_buffer, sizeof(fs_stat_t)); - if (RET != FR_OK || size < sizeof(fs_stat_t)) { + fs_stat_t *file_stat = fs_get_client_buffer(fs_share, FAT_FS_DATA_REGION_SIZE, output_buffer); + if (file_stat == NULL || size < sizeof (fs_stat_t)) { + LOG_FATFS("invalid output buffer provided\n"); args->status = FS_STATUS_INVALID_BUFFER; return; } - if ((RET = validate_and_copy_path(path, path_len, filepath)) != FR_OK) { + + int err = fs_copy_client_path(filepath, fs_share, FAT_FS_DATA_REGION_SIZE, path); + if (err) { args->status = FS_STATUS_INVALID_PATH; return; } - fs_stat_t* file_stat = (fs_stat_t *)(fs_share + output_buffer); - LOG_FATFS("fat_stat:asking for filename: %s\n", filepath); FILINFO fileinfo; - RET = f_stat(filepath, &fileinfo); + FRESULT RET = f_stat(filepath, &fileinfo); if (RET != FR_OK) { args->status = FS_STATUS_ERROR; return; @@ -394,10 +367,18 @@ void handle_stat(void) { void handle_file_size(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t fd = args->params.file_size.fd; + fd_t fd = args->params.file_size.fd; - uint64_t size = f_size(&(files[fd])); + FIL *file = NULL; + int err = fd_begin_op_file(fd, &file); + if (err) { + LOG_FATFS("invalid fd: %d\n", fd); + args->status = FS_STATUS_INVALID_FD; + return; + } + uint64_t size = f_size(file); + fd_end_op(fd); args->status = FS_STATUS_SUCCESS; args->result.file_size.size = size; } @@ -405,23 +386,24 @@ void handle_file_size(void) { void handle_rename(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t oldpath_buffer = args->params.rename.old_path.offset; - uint64_t oldpath_len = args->params.rename.old_path.size; - - uint64_t newpath_buffer = args->params.rename.new_path.offset; - uint64_t newpath_len = args->params.rename.new_path.size; + fs_buffer_t oldpath_buffer = args->params.rename.old_path; + fs_buffer_t newpath_buffer = args->params.rename.new_path; char oldpath[FS_MAX_PATH_LENGTH + 1]; char newpath[FS_MAX_PATH_LENGTH + 1]; - // Buffer and string validation check - FRESULT RET = validate_and_copy_path(oldpath_buffer, oldpath_len, oldpath); - if (RET != FR_OK || (RET = validate_and_copy_path(newpath_buffer, newpath_len, newpath)) != FR_OK) { + int err = fs_copy_client_path(oldpath, fs_share, FAT_FS_DATA_REGION_SIZE, oldpath_buffer); + if (err) { + args->status = FS_STATUS_INVALID_PATH; + return; + } + err = fs_copy_client_path(newpath, fs_share, FAT_FS_DATA_REGION_SIZE, newpath_buffer); + if (err) { args->status = FS_STATUS_INVALID_PATH; return; } - RET = f_rename(oldpath, newpath); + FRESULT RET = f_rename(oldpath, newpath); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } @@ -429,20 +411,17 @@ void handle_rename(void) { void handle_file_remove(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t buffer = args->params.file_remove.path.offset; - uint64_t size = args->params.file_remove.path.size; + fs_buffer_t buffer = args->params.file_remove.path; char dirpath[FS_MAX_PATH_LENGTH + 1]; - FRESULT RET = validate_and_copy_path(buffer, size, dirpath); - - // Buffer validation check - if (RET != FR_OK) { - LOG_FATFS("fat_unlink: Invalid path buffer\n"); + int err = fs_copy_client_path(dirpath, fs_share, FAT_FS_DATA_REGION_SIZE, buffer); + if (err) { + LOG_FATFS("fat_unlink: invalid path buffer\n"); args->status = FS_STATUS_INVALID_PATH; return; } - RET = f_unlink(dirpath); + FRESULT RET = f_unlink(dirpath); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } @@ -450,27 +429,28 @@ void handle_file_remove(void) { void handle_file_truncate(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t fd = args->params.file_truncate.fd; + fd_t fd = args->params.file_truncate.fd; uint64_t len = args->params.file_truncate.length; - FRESULT RET = validate_file_descriptor(fd); - - // FD validation check - if (RET != FR_OK) { - LOG_FATFS("fat_mkdir: Invalid FD\n"); + FIL *file = NULL; + int err = fd_begin_op_file(fd, &file); + if (err) { + LOG_FATFS("invalid fd"); args->status = FS_STATUS_INVALID_FD; return; } - RET = f_lseek(&files[fd], len); + FRESULT RET = f_lseek(file, len); if (RET != FR_OK) { LOG_FATFS("fat_truncate: Invalid file offset\n"); + fd_end_op(fd); args->status = FS_STATUS_ERROR; return; } - RET = f_truncate(&files[fd]); + RET = f_truncate(file); + fd_end_op(fd); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } @@ -478,21 +458,17 @@ void handle_file_truncate(void) { void handle_dir_create(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t buffer = args->params.dir_create.path.offset; - uint64_t size = args->params.dir_create.path.size; + fs_buffer_t buffer = args->params.dir_create.path; char dirpath[FS_MAX_PATH_LENGTH + 1]; - FRESULT RET = validate_and_copy_path(buffer, size, dirpath); - - // Buffer validation check - if (RET != FR_OK) { + int err = fs_copy_client_path(dirpath, fs_share, FAT_FS_DATA_REGION_SIZE, buffer); + if (err) { LOG_FATFS("fat_mkdir: Invalid path buffer\n"); args->status = FS_STATUS_INVALID_PATH; return; } - RET = f_mkdir(dirpath); - + FRESULT RET = f_mkdir(dirpath); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } @@ -500,20 +476,18 @@ void handle_dir_create(void) { void handle_dir_remove(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t buffer = args->params.dir_remove.path.offset; - uint64_t size = args->params.dir_remove.path.size; + fs_buffer_t buffer = args->params.dir_remove.path; char dirpath[FS_MAX_PATH_LENGTH + 1]; - // Buffer validation check - FRESULT RET = validate_and_copy_path(buffer, size, dirpath); - if (RET != FR_OK) { + int err = fs_copy_client_path(dirpath, fs_share, FAT_FS_DATA_REGION_SIZE, buffer); + if (err) { LOG_FATFS("fat_mkdir: Invalid path buffer\n"); args->status = FS_STATUS_INVALID_PATH; return; } - RET = f_rmdir(dirpath); + FRESULT RET = f_rmdir(dirpath); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } @@ -521,42 +495,39 @@ void handle_dir_remove(void) { void handle_dir_open(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t buffer = args->params.dir_open.path.offset; - uint64_t size = args->params.dir_open.path.size; + fs_buffer_t buffer = args->params.dir_open.path; char dirpath[FS_MAX_PATH_LENGTH + 1]; - - FRESULT RET = validate_and_copy_path(buffer, size, dirpath); - - // Sanity check - if (RET != FR_OK) { + int err = fs_copy_client_path(dirpath, fs_share, FAT_FS_DATA_REGION_SIZE, buffer); + if (err) { LOG_FATFS("fat_readdir: Invalid buffer\n"); args->status = FS_STATUS_INVALID_PATH; return; } - uint32_t fd = find_free_dir_object(); - if (fd == FAT_MAX_OPENED_DIRNUM) { + DIR *dir = dir_alloc(); + if (dir == NULL) { args->status = FS_STATUS_TOO_MANY_OPEN_FILES; return; } - DIR* dir = &(dirs[fd]); - // Set the position to INUSE to indicate this file structure is in use - dir_status[fd] = INUSE; - LOG_FATFS("FAT opendir directory path: %s\n", dirpath); - RET = f_opendir(dir, dirpath); + FRESULT RET = f_opendir(dir, dirpath); // Error handling if (RET != FR_OK) { args->status = FS_STATUS_ERROR; // Free this Dir structure - dir_status[fd] = FREE; + dir_free(dir); return; } + fd_t fd; + err = fd_alloc(&fd); + assert(!err); + fd_set_dir(fd, dir); + args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; args->result.dir_open.fd = fd; } @@ -565,30 +536,29 @@ void handle_dir_read(void) { co_data_t *args = microkit_cothread_my_arg(); // Dir descriptor - uint64_t fd = args->params.dir_read.fd; - uint64_t buffer = args->params.dir_read.buf.offset; + fd_t fd = args->params.dir_read.fd; + fs_buffer_t buffer = args->params.dir_read.buf; uint64_t size = args->params.dir_read.buf.size; LOG_FATFS("FAT readdir file descriptor: %lu\n", fd); - FRESULT RET = within_data_region(buffer, size); - // Sanity check - if (RET != FR_OK) { - LOG_FATFS("fat_readdir: Invalid buffer\n"); + char *name = fs_get_client_buffer(fs_share, FAT_FS_DATA_REGION_SIZE, buffer); + if (name == NULL) { + LOG_FATFS("fat_readdir: invalid buffer\n"); args->status = FS_STATUS_INVALID_BUFFER; return; } - if ((RET = validate_dir_descriptor(fd)) != FR_OK) { - LOG_FATFS("fat_readdir: Invalid FD\n"); + + DIR *dir = NULL; + int err = fd_begin_op_dir(fd, &dir); + if (err) { + LOG_FATFS("invalid fd (%d)\n", fd); args->status = FS_STATUS_INVALID_FD; return; } - void* name = fs_share + buffer; - FILINFO fno; - RET = f_readdir(&dirs[fd], &fno); - + FRESULT RET = f_readdir(dir, &fno); uint64_t len = strlen(fno.fname); // The buffer most have a size that is minimum length of the name plus one @@ -606,61 +576,63 @@ void handle_dir_read(void) { } } + fd_end_op(fd); + args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } // Not sure if this one is implemented correctly void handle_dir_tell(void){ co_data_t *args = microkit_cothread_my_arg(); + fd_t fd = args->params.dir_tell.fd; - uint64_t fd = args->params.dir_tell.fd; - - FRESULT RET = validate_dir_descriptor(fd); - if (RET != FR_OK) { - LOG_FATFS("fat_telldir: Invalid dir descriptor\n"); + DIR *dir = NULL; + int err = fd_begin_op_dir(fd, &dir); + if (err) { + LOG_FATFS("invalid fd (%d)\n", fd); args->status = FS_STATUS_INVALID_FD; return; } - DIR* dp = &(dirs[fd]); - - uint32_t offset = f_telldir(dp); + uint32_t offset = f_telldir(dir); + fd_end_op(fd); - args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; + args->status = FS_STATUS_SUCCESS; args->result.dir_tell.location = offset; } void handle_dir_rewind(void) { co_data_t *args = microkit_cothread_my_arg(); + fd_t fd = args->params.dir_rewind.fd; - uint64_t fd = args->params.dir_rewind.fd; - - FRESULT RET = validate_dir_descriptor(fd); - if (RET != FR_OK) { - LOG_FATFS("fat_telldir: Invalid dir descriptor\n"); + DIR *dir = NULL; + int err = fd_begin_op_dir(fd, &dir); + if (err) { + LOG_FATFS("invalid fd (%d)\n", fd); args->status = FS_STATUS_INVALID_FD; return; } - RET = f_readdir(&dirs[fd], 0); + FRESULT RET = f_readdir(dir, 0); + fd_end_op(fd); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } void handle_file_sync(void) { co_data_t *args = microkit_cothread_my_arg(); + fd_t fd = args->params.file_sync.fd; - // Maybe add validation check of file descriptor here - uint64_t fd = args->params.file_sync.fd; - - FRESULT RET = validate_file_descriptor(fd); - if (RET != FR_OK) { - LOG_FATFS("fat_sync: Invalid file descriptor %lu\n", fd); + FIL *file = NULL; + int err = fd_begin_op_file(fd, &file); + if (err) { + LOG_FATFS("invalid fd (%d)\n", fd); args->status = FS_STATUS_INVALID_FD; return; } - RET = f_sync(&(files[fd])); + FRESULT RET = f_sync(file); + fd_end_op(fd); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } @@ -668,24 +640,29 @@ void handle_file_sync(void) { void handle_dir_close(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t fd = args->params.dir_close.fd; + fd_t fd = args->params.dir_close.fd; - FRESULT RET = validate_dir_descriptor(fd); - if (RET != FR_OK) { - LOG_FATFS("fat_closedir: Invalid dir descriptor\n"); + DIR *dir = NULL; + int err = fd_begin_op_dir(fd, &dir); + if (err) { + LOG_FATFS("invalid fd (%d)\n", fd); args->status = FS_STATUS_INVALID_FD; return; } + fd_end_op(fd); - dir_status[fd] = CLEANUP; + err = fd_unset(fd); + if (err) { + LOG_FATFS("trying to close fd with outstanding operations\n"); + args->status = FS_STATUS_OUTSTANDING_OPERATIONS; + return; + } - RET = f_closedir(&dirs[fd]); + FRESULT RET = f_closedir(dir); if (RET == FR_OK) { - dir_status[fd] = FREE; - } - else { - dir_status[fd] = INUSE; + fd_free(fd); + dir_free(dir); } args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; @@ -698,26 +675,29 @@ void handle_dir_close(void) { void handle_dir_seek(void) { co_data_t *args = microkit_cothread_my_arg(); - uint64_t fd = args->params.dir_seek.fd; + fd_t fd = args->params.dir_seek.fd; int64_t loc = args->params.dir_seek.loc; - FRESULT RET = validate_dir_descriptor(fd); - if (RET != FR_OK) { - LOG_FATFS("fat_seekdir: Invalid dir descriptor\n"); + DIR *dir = NULL; + int err = fd_begin_op_dir(fd, &dir); + if (err) { + LOG_FATFS("invalid fd (%d)\n", fd); args->status = FS_STATUS_INVALID_FD; return; } - RET = f_readdir(&dirs[fd], 0); + FRESULT RET = f_readdir(dir, 0); FILINFO fno; for (int64_t i = 0; i < loc; i++) { if (RET != FR_OK) { args->status = FS_STATUS_ERROR; + fd_end_op(fd); return; } - RET = f_readdir(&dirs[fd], &fno); + RET = f_readdir(&dir, &fno); } + fd_end_op(fd); args->status = (RET == FR_OK) ? FS_STATUS_SUCCESS : FS_STATUS_ERROR; } diff --git a/components/fs/nfs/fd.h b/components/fs/nfs/fd.h deleted file mode 100644 index a013b162..00000000 --- a/components/fs/nfs/fd.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2023, UNSW - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -#define MAX_OPEN_FILES 256 - -typedef uint64_t fd_t; - -struct nfsfh; -struct nfsdir; - -int fd_alloc(fd_t *fd); -int fd_free(fd_t fd); -int fd_set_file(fd_t fd, struct nfsfh *file); -int fd_set_dir(fd_t fd, struct nfsdir *dir); -int fd_unset(fd_t fd); -int fd_begin_op_file(fd_t fd, struct nfsfh **file); -int fd_begin_op_dir(fd_t fd, struct nfsdir **dir); -void fd_end_op(fd_t fd); diff --git a/components/fs/nfs/nfs.c b/components/fs/nfs/nfs.c index dc3c09a6..1e799bb1 100644 --- a/components/fs/nfs/nfs.c +++ b/components/fs/nfs/nfs.c @@ -17,9 +17,10 @@ #include #include +#include + #include "nfs.h" #include "util.h" -#include "fd.h" #include "tcp.h" #include "posix.h" diff --git a/components/fs/nfs/nfs.mk b/components/fs/nfs/nfs.mk index 59d6c6e0..d50a40a9 100644 --- a/components/fs/nfs/nfs.mk +++ b/components/fs/nfs/nfs.mk @@ -34,7 +34,7 @@ NFS_LWIP_OBJ := $(addprefix nfs/lwip/, $(NFS_LWIPFILES:.c=.o)) NFS_DIRS := nfs $(addprefix nfs/lwip/, api core core/ipv4 netif) -NFS_FILES := nfs.c fd.c op.c posix.c tcp.c +NFS_FILES := nfs.c op.c posix.c tcp.c NFS_OBJ := $(addprefix nfs/, $(NFS_FILES:.c=.o)) $(NFS_LWIP_OBJ) CHECK_NFS_FLAGS_MD5 := .nfs_cflags-$(shell echo -- $(CFLAGS) $(CFLAGS_nfs) | shasum | sed 's/ *-//') @@ -52,9 +52,12 @@ libnfs/lib/libnfs.a: $(LIBNFS)/CMakeLists.txt $(MUSL)/lib/libc.a MUSL=$(abspath $(MUSL)) cmake -S $(LIBNFS) -B libnfs cmake --build libnfs +LIB_FS_SERVER_LIBC_INCLUDE := $(MUSL)/include +include $(LIONSOS)/lib/fs/server/lib_fs_server.mk + nfs.elf: LDFLAGS += -L$(LIBGCC) nfs.elf: LIBS += -lgcc -nfs.elf: $(NFS_OBJ) $(MUSL)/lib/libc.a libnfs/lib/libnfs.a +nfs.elf: $(NFS_OBJ) $(MUSL)/lib/libc.a libnfs/lib/libnfs.a lib_fs_server.a $(LD) $(LDFLAGS) -o $@ $(LIBS) $^ $(NFS_DIRS): diff --git a/components/fs/nfs/op.c b/components/fs/nfs/op.c index 52b8b4eb..48684719 100644 --- a/components/fs/nfs/op.c +++ b/components/fs/nfs/op.c @@ -20,10 +20,10 @@ #include #include +#include #include "nfs.h" #include "util.h" -#include "fd.h" #define MAX_CONCURRENT_OPS FS_QUEUE_CAPACITY #define CLIENT_SHARE_SIZE 0x4000000 @@ -134,26 +134,9 @@ void continuation_free(struct continuation *cont) { first_free_cont = cont; } -void *get_buffer(fs_buffer_t buf) { - if (buf.offset >= CLIENT_SHARE_SIZE - || buf.size > CLIENT_SHARE_SIZE - buf.offset - || buf.size == 0) { - return NULL; - } - return (void *)(client_share + buf.offset); -} - -char *copy_path(int slot, fs_buffer_t buf) { - assert(0 <= slot && slot < 2); - - char *client_buf = get_buffer(buf); - if (client_buf == NULL || buf.size > FS_MAX_PATH_LENGTH) { - return NULL; - } - - memcpy(path_buffer[slot], client_buf, buf.size); - path_buffer[slot][buf.size] = '\0'; - return path_buffer[slot]; +char *get_path_buffer(int slot) { + assert(slot == 0 || slot == 1); + return &path_buffer[slot]; } static void initialise_cb(int status, struct nfs_context *nfs, void *data, void *private_data) { @@ -233,14 +216,15 @@ void handle_stat(fs_cmd_t cmd) { uint64_t status = FS_STATUS_ERROR; fs_cmd_params_stat_t params = cmd.params.stat; - char *path = copy_path(0, params.path); - if (path == NULL) { + char *path = get_path_buffer(0); + int err = fs_copy_client_path(path, client_share, CLIENT_SHARE_SIZE, params.path); + if (err) { dlog("invalid path buffer provided"); status = FS_STATUS_INVALID_PATH; goto fail_buffer; } - void *buf = get_buffer(params.buf); + void *buf = fs_get_client_buffer(client_share, CLIENT_SHARE_SIZE, params.buf); if (buf == NULL || params.buf.size < sizeof (fs_stat_t)) { dlog("invalid output buffer provided"); status = FS_STATUS_INVALID_BUFFER; @@ -252,7 +236,7 @@ void handle_stat(fs_cmd_t cmd) { cont->request_id = cmd.id; cont->data[0] = (uint64_t)buf; - int err = nfs_stat64_async(nfs, path, stat_cb, cont); + err = nfs_stat64_async(nfs, path, stat_cb, cont); if (err) { dlog("failed to enqueue command"); goto fail_enqueue; @@ -339,15 +323,16 @@ void handle_file_open(fs_cmd_t cmd) { uint64_t status = FS_STATUS_ERROR; struct fs_cmd_params_file_open params = cmd.params.file_open; - char *path = copy_path(0, params.path); - if (path == NULL) { + char *path = get_path_buffer(0); + int err = fs_copy_client_path(path, client_share, CLIENT_SHARE_SIZE, params.path); + if (err) { dlog("invalid path buffer provided"); status = FS_STATUS_INVALID_PATH; goto fail_buffer; } fd_t fd; - int err = fd_alloc(&fd); + err = fd_alloc(&fd); if (err) { dlog("no free fds"); status = FS_STATUS_ALLOCATION_ERROR; @@ -469,7 +454,7 @@ void handle_file_read(fs_cmd_t cmd) { uint64_t status = FS_STATUS_ERROR; fs_cmd_params_file_read_t params = cmd.params.file_read; - char *buf = get_buffer(params.buf); + char *buf = fs_get_client_buffer(client_share, CLIENT_SHARE_SIZE, params.buf); if (buf == NULL) { dlog("invalid output buffer provided"); status = FS_STATUS_INVALID_BUFFER; @@ -527,7 +512,7 @@ void handle_file_write(fs_cmd_t cmd) { uint64_t status = FS_STATUS_ERROR; fs_cmd_params_file_write_t params = cmd.params.file_write; - char *buf = get_buffer(params.buf); + char *buf = fs_get_client_buffer(client_share, CLIENT_SHARE_SIZE, params.buf); if (buf == NULL) { dlog("invalid output buffer provided"); status = FS_STATUS_INVALID_BUFFER; @@ -578,9 +563,16 @@ void handle_rename(fs_cmd_t cmd) { uint64_t status = FS_STATUS_ERROR; fs_cmd_params_rename_t params = cmd.params.rename; - char *old_path = copy_path(0, params.old_path); - char *new_path = copy_path(1, params.new_path); - if (old_path == NULL || new_path == NULL) { + char *old_path = get_path_buffer(0); + char *new_path = get_path_buffer(1); + int err = fs_copy_client_path(old_path, client_share, CLIENT_SHARE_SIZE, params.old_path); + if (err) { + dlog("invalid path buffer provided"); + status = FS_STATUS_INVALID_PATH; + goto fail_buffer; + } + err = fs_copy_client_path(new_path, client_share, CLIENT_SHARE_SIZE, params.old_path); + if (err) { dlog("invalid path buffer provided"); status = FS_STATUS_INVALID_PATH; goto fail_buffer; @@ -589,7 +581,7 @@ void handle_rename(fs_cmd_t cmd) { struct continuation *cont = continuation_alloc(); assert(cont != NULL); cont->request_id = cmd.id; - int err = nfs_rename_async(nfs, old_path, new_path, rename_cb, cont); + err = nfs_rename_async(nfs, old_path, new_path, rename_cb, cont); if (err) { dlog("failed to enqueue command"); goto fail_enqueue; @@ -618,8 +610,9 @@ void handle_file_remove(fs_cmd_t cmd) { uint64_t status = FS_STATUS_ERROR; fs_cmd_params_file_remove_t params = cmd.params.file_remove; - char *path = copy_path(0, params.path); - if (path == NULL) { + char *path = get_path_buffer(0); + int err = fs_copy_client_path(path, client_share, CLIENT_SHARE_SIZE, params.path); + if (err) { dlog("invalid path buffer provided"); status = FS_STATUS_INVALID_PATH; goto fail_buffer; @@ -628,7 +621,7 @@ void handle_file_remove(fs_cmd_t cmd) { struct continuation *cont = continuation_alloc(); assert(cont != NULL); cont->request_id = cmd.id; - int err = nfs_unlink_async(nfs, path, file_remove_cb, cont); + err = nfs_unlink_async(nfs, path, file_remove_cb, cont); if (err) { dlog("failed to enqueue command"); goto fail_enqueue; @@ -747,8 +740,9 @@ void handle_dir_create(fs_cmd_t cmd) { uint64_t status = FS_STATUS_ERROR; fs_cmd_params_dir_create_t params = cmd.params.dir_create; - char *path = copy_path(0, params.path); - if (path == NULL) { + char *path = get_path_buffer(0); + int err = fs_copy_client_path(path, client_share, CLIENT_SHARE_SIZE, params.path); + if (err) { dlog("invalid path buffer provided"); status = FS_STATUS_INVALID_PATH; goto fail_buffer; @@ -758,7 +752,7 @@ void handle_dir_create(fs_cmd_t cmd) { assert(cont != NULL); cont->request_id = cmd.id; - int err = nfs_mkdir_async(nfs, path, dir_create_cb, cont); + err = nfs_mkdir_async(nfs, path, dir_create_cb, cont); if (err) { dlog("failed to enqueue command"); goto fail_enqueue; @@ -787,8 +781,9 @@ void handle_dir_remove(fs_cmd_t cmd) { uint64_t status = FS_STATUS_ERROR; fs_cmd_params_dir_remove_t params = cmd.params.dir_remove; - char *path = copy_path(0, params.path); - if (path == NULL) { + char *path = get_path_buffer(0); + int err = fs_copy_client_path(path, client_share, CLIENT_SHARE_SIZE, params.path); + if (err) { dlog("invalid path buffer provided"); status = FS_STATUS_INVALID_PATH; goto fail_buffer; @@ -798,7 +793,7 @@ void handle_dir_remove(fs_cmd_t cmd) { assert(cont != NULL); cont->request_id = cmd.id; - int err = nfs_rmdir_async(nfs, path, dir_remove_cb, cont); + err = nfs_rmdir_async(nfs, path, dir_remove_cb, cont); if (err) { dlog("failed to enqueue command"); goto fail_enqueue; @@ -836,15 +831,16 @@ void handle_dir_open(fs_cmd_t cmd) { fs_cmd_params_dir_open_t params = cmd.params.dir_open; fs_cmpl_t cmpl = { .id = cmd.id, .status = FS_STATUS_ERROR, .data = {0} }; - char *path = copy_path(0, params.path); - if (path == NULL) { + char *path = get_path_buffer(0); + int err = fs_copy_client_path(path, client_share, CLIENT_SHARE_SIZE, params.path); + if (err) { dlog("invalid path buffer provided"); cmpl.status = FS_STATUS_INVALID_PATH; goto fail_buffer; } fd_t fd; - int err = fd_alloc(&fd); + err = fd_alloc(&fd); if (err) { dlog("no free fds"); cmpl.status = FS_STATUS_ALLOCATION_ERROR; @@ -903,7 +899,7 @@ void handle_dir_read(fs_cmd_t cmd) { fs_cmd_params_dir_read_t params = cmd.params.dir_read; fs_cmpl_t cmpl = { .id = cmd.id, .status = FS_STATUS_SUCCESS, .data = {0} }; - char *buf = get_buffer(params.buf); + char *buf = fs_get_client_buffer(client_share, CLIENT_SHARE_SIZE, params.buf); if (buf == NULL || params.buf.size < FS_MAX_NAME_LENGTH) { dlog("invalid output buffer provided"); cmpl.status = FS_STATUS_INVALID_BUFFER; diff --git a/include/lions/fs/server.h b/include/lions/fs/server.h new file mode 100644 index 00000000..5b359079 --- /dev/null +++ b/include/lions/fs/server.h @@ -0,0 +1,26 @@ +/* + * Copyright 2023, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#include + +#define MAX_OPEN_FILES 256 + +typedef uint64_t fd_t; + +int fd_alloc(fd_t *fd); +int fd_free(fd_t fd); +int fd_set_file(fd_t fd, void *file_handle); +int fd_set_dir(fd_t fd, void *dir_handle); +int fd_unset(fd_t fd); +int fd_begin_op_file(fd_t fd, void **file_handle); +int fd_begin_op_dir(fd_t fd, void **dir_handle); +void fd_end_op(fd_t fd); + +void *fs_get_client_buffer(char *client_share, size_t client_share_size, fs_buffer_t buf); +int fs_copy_client_path(char *dest, char *client_share, size_t client_share_size, fs_buffer_t buf); diff --git a/components/fs/nfs/fd.c b/lib/fs/server/fd.c similarity index 88% rename from components/fs/nfs/fd.c rename to lib/fs/server/fd.c index 37bd516b..3c610767 100644 --- a/components/fs/nfs/fd.c +++ b/lib/fs/server/fd.c @@ -7,7 +7,7 @@ #include #include -#include "fd.h" +#include struct oftable_slot { enum { @@ -50,24 +50,24 @@ static int of_free(struct oftable_slot *of) { } } -static int of_set_file(struct oftable_slot *of, struct nfsfh *file) { +static int of_set_file(struct oftable_slot *of, void *file_handle) { assert(of); switch (of->state) { case state_allocated: of->state = state_open_file; - of->handle = file; + of->handle = file_handle; return 0; default: return -1; } } -static int of_set_dir(struct oftable_slot *of, struct nfsdir *dir) { +static int of_set_dir(struct oftable_slot *of, void *dir_handle) { assert(of); switch (of->state) { case state_allocated: of->state = state_open_dir; - of->handle = dir; + of->handle = dir_handle; return 0; default: return -1; @@ -87,7 +87,7 @@ static int of_unset(struct oftable_slot *of) { } } -static int of_begin_op_file(struct oftable_slot *of, struct nfsfh **file_handle_p) { +static int of_begin_op_file(struct oftable_slot *of, void **file_handle_p) { assert(of); switch (of->state) { case state_open_file: @@ -104,7 +104,7 @@ static int of_begin_op_file(struct oftable_slot *of, struct nfsfh **file_handle_ } } -static int of_begin_op_dir(struct oftable_slot *of, struct nfsdir **dir_handle_p) { +static int of_begin_op_dir(struct oftable_slot *of, void **dir_handle_p) { assert(of); switch (of->state) { case state_open_dir: @@ -175,7 +175,7 @@ int fd_free(fd_t fd) { return of_free(of); } -int fd_set_file(fd_t fd, struct nfsfh *file) { +int fd_set_file(fd_t fd, void *file) { struct oftable_slot *of = fd_to_of(fd); if (of == NULL) { return -1; @@ -183,7 +183,7 @@ int fd_set_file(fd_t fd, struct nfsfh *file) { return of_set_file(of, file); } -int fd_set_dir(fd_t fd, struct nfsdir *dir) { +int fd_set_dir(fd_t fd, void *dir) { struct oftable_slot *of = fd_to_of(fd); if (of == NULL) { return -1; @@ -199,7 +199,7 @@ int fd_unset(fd_t fd) { return of_unset(of); } -int fd_begin_op_file(fd_t fd, struct nfsfh **file) { +int fd_begin_op_file(fd_t fd, void **file) { struct oftable_slot *of = fd_to_of(fd); if (of == NULL) { return -1; @@ -207,7 +207,7 @@ int fd_begin_op_file(fd_t fd, struct nfsfh **file) { return of_begin_op_file(of, file); } -int fd_begin_op_dir(fd_t fd, struct nfsdir **dir) { +int fd_begin_op_dir(fd_t fd, void **dir) { struct oftable_slot *of = fd_to_of(fd); if (of == NULL) { return -1; diff --git a/lib/fs/server/lib_fs_server.mk b/lib/fs/server/lib_fs_server.mk new file mode 100644 index 00000000..fdb6b48f --- /dev/null +++ b/lib/fs/server/lib_fs_server.mk @@ -0,0 +1,31 @@ +# +# Copyright 2024, UNSW +# +# SPDX-License-Identifier: BSD-2-Clause +# +# This Makefile snippet builds the FS server library +# +# NOTES: +# Requires variables +# CC +# AR +# RANLIB +# LIBFS_LIBC_INCLUDE + +LIB_FS_SERVER_DIR := $(LIONSOS)/lib/fs/server +LIB_FS_SERVER_OBJ := $(addprefix lib/fs/server/, fd.o memory.o) + +LIB_FS_SERVER_CFLAGS := -I$(LIB_FS_SERVER_LIBC_INCLUDE) + +lib_fs_server.a: $(LIB_FS_SERVER_OBJ) + $(AR) crv $@ $^ + $(RANLIB) $@ + +lib/fs/server/%.o: CFLAGS += $(LIB_FS_SERVER_CFLAGS) +lib/fs/server/%.o: $(LIB_FS_SERVER_DIR)/%.c |lib/fs/server + $(CC) -c $(CFLAGS) $< -o $@ + +lib/fs/server: + mkdir -p $@ + +-include $(LIB_FS_SERVER_OBJ:.o=.d) diff --git a/lib/fs/server/memory.c b/lib/fs/server/memory.c new file mode 100644 index 00000000..ec50fd86 --- /dev/null +++ b/lib/fs/server/memory.c @@ -0,0 +1,29 @@ +/* + * Copyright 2025, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include + +void *fs_get_client_buffer(char *client_share, size_t client_share_size, fs_buffer_t buf) { + if (buf.offset >= client_share_size + || buf.size > client_share_size - buf.offset + || buf.size == 0) { + return NULL; + } + return (void *)(client_share + buf.offset); +} + +int fs_copy_client_path(char *dest, char *client_share, size_t client_share_size, fs_buffer_t buf) { + char *client_buf = fs_get_client_buffer(client_share, client_share_size, buf); + if (client_buf == NULL || buf.size > FS_MAX_PATH_LENGTH) { + return -1; + } + + memcpy(dest, client_buf, buf.size); + dest[buf.size] = '\0'; + return 0; +}