#include "file.h" #include "file_common.h" static void file_backing_lock(struct cch_backing *backing) { struct cch_backing_file *file = (struct cch_backing_file *)backing; nn_mutex_lock(&file->mutex); } static void maybe_seek_to_index(struct cch_backing_file *file, off_t index) { if (file->u.pointer != index) { file->u.pointer = nn_file_seek(&file->file, index, SEEK_SET); al_assert(file->u.pointer == index); } } static void file_backing_write(struct cch_backing *backing, u8 *buf, off_t index, size_t *count) { struct cch_backing_file *file = (struct cch_backing_file *)backing; off_t n = (off_t)*count; nn_mutex_lock(&file->mutex); maybe_seek_to_index(file, index); off_t size = file->backing.size; if (size > 0 && index + n >= size) { n = MAX(size - index, (off_t)0); } if (n > 0) { nn_file_write(&file->file, buf, n); file->u.pointer += n; cch_backing_fill_range(&file->backing, index, n); } *count = (size_t)n; nn_mutex_unlock(&file->mutex); } static void file_backing_read(struct cch_backing *backing, u8 *buf, off_t index, size_t *count) { struct cch_backing_file *file = (struct cch_backing_file *)backing; off_t n = (off_t)*count; nn_mutex_lock(&file->mutex); maybe_seek_to_index(file, index); off_t size = file->backing.size; if (size > 0 && index + n >= size) { n = MAX(size - index, (off_t)0); } if (n > 0) { nn_file_read(&file->file, buf, n); file->u.pointer += n; } *count = (size_t)n; nn_mutex_unlock(&file->mutex); } static void file_backing_unlock(struct cch_backing *backing) { struct cch_backing_file *file = (struct cch_backing_file *)backing; nn_mutex_unlock(&file->mutex); } static void file_backing_set_size(struct cch_backing *backing, off_t size, bool expand_to_size) { struct cch_backing_file *file = (struct cch_backing_file *)backing; nn_mutex_lock(&file->mutex); file->backing.size = size; if (expand_to_size && (size_t)size > file->file.size) { nn_file_truncate(&file->file, size); } nn_mutex_unlock(&file->mutex); } static void file_backing_free(struct cch_backing **backing) { struct cch_backing_file *file = (struct cch_backing_file *)*backing; nn_file_close(&file->file); al_array_free(file->backing.available); al_free(file); *backing = NULL; } struct cch_backing *cch_backing_file_create(str *path, size_t size) { struct cch_backing_file *file = al_alloc_object(struct cch_backing_file); file->backing.mode = CACHE_BACKING_READ; file->backing.size = -1; file->backing.lock = file_backing_lock; file->backing.write = file_backing_write; file->backing.read = file_backing_read; file->backing.get_ptr = NULL; file->backing.unlock = file_backing_unlock; file->backing.set_size = file_backing_set_size; file->backing.get_size_if_known = file_backing_get_size_if_known; file->backing.finalize = file_backing_finalize; file->backing.free = file_backing_free; al_array_init(file->backing.available); if (!file_open_internal(file, path, size)) { goto err; } file->u.pointer = 0; nn_mutex_init(&file->mutex); return (struct cch_backing *)file; err: al_free(file); return NULL; }