#include "io.h" #include "common.h" #include #include #include unsigned reads = 0, reads_all = 0, writes = 0, writes_all = 0; page_cache_entry_t *_file_load_page(file_t* file, page_t page); void _file_flush_page(file_t *file, page_cache_entry_t *entry); file_t* file_open(const char* filename, const char* mode) { FILE* handle = fopen(filename, mode); if (!handle) { printfv(VERBOSITY_NORMAL, "[io] Can't open file %s.\n", filename); return NULL; } printfv(VERBOSITY_VERY_VERBOSE, "[io] File %s opened in %s with page size %zu.\n", filename, mode, PAGE_SIZE); file_t* result = malloc(sizeof(file_t)); memset(result, 0, sizeof(file_t)); result->file = handle; result->filename = malloc(strlen(filename) + 1); strcpy(result->filename, filename); return result; } void file_close(file_t* file) { file_flush(file); printfv(VERBOSITY_VERY_VERBOSE, "[io] Closing file %s.\n", file->filename); fclose(file->file); free(file->filename); free(file); } size_t file_read(file_t* file, page_t page, void* buffer, size_t length) { reads_all++; page_cache_entry_t *entry = _file_load_page(file, page); memcpy(buffer, entry->data, length); printfv(VERBOSITY_VERY_VERBOSE, "[io] Reading page %zu in %s (%zu bytes).\n", page, file->filename, entry->size); return entry->size; } size_t file_write(file_t* file, page_t page, const void* buffer, size_t length) { printfv(VERBOSITY_VERY_VERBOSE, "[io] Writing page %zu in %s (%zu bytes).\n", page, file->filename, length); writes_all++; page_cache_entry_t *entry = _file_load_page(file, page); memset(entry->data, 0, PAGE_SIZE); memcpy(entry->data, buffer, length); entry->flags |= PAGE_DIRTY; entry->size = length; return entry->size; } void file_flush(file_t* file) { for (unsigned i = 0; i < CACHE_ENTRIES; i++) { _file_flush_page(file, file->cache + i); } } page_cache_entry_t *_file_load_page(file_t* file, page_t page) { page_cache_entry_t *entry = file->cache + (page % CACHE_ENTRIES); if (entry->page == page && entry->flags & PAGE_PRESENT) { // already in cache return entry; } _file_flush_page(file, entry); int result = fseek(file->file, page * PAGE_SIZE, SEEK_SET); memset(entry->data, 0, PAGE_SIZE); entry->size = fread(entry->data, 1, PAGE_SIZE, file->file); if (entry->size) { printfv(VERBOSITY_VERY_VERBOSE, "[io] Loading page %u of %s (%zu bytes).\n", page, file->filename, entry->size); reads++; } entry->page = page; entry->flags |= PAGE_PRESENT; return entry; } void _file_flush_page(file_t *file, page_cache_entry_t *entry) { if (entry->flags & PAGE_PRESENT && entry->flags & PAGE_DIRTY) { printfv(VERBOSITY_VERY_VERBOSE, "[io] Flushing page %u to %s (%zu bytes).\n", entry->page, file->filename, entry->size); fseek(file->file, entry->page * PAGE_SIZE, SEEK_SET); fwrite(entry->data, 1, entry->size, file->file); // disable dirty flag entry->flags &= ~PAGE_DIRTY; writes++; } }