#include "source.h" #include #include #include #include #include static void lz_free(lazy_file_t *lz) { if(lz && lz->fd >= 0) close(lz->fd); free(lz); } static ssize_t lz_read(void *_cookie, void *buf, off_t offset, size_t size) { lazy_file_t *lz = _cookie; /* Here we need to be careful. We can't just lseek() or pread() because the file is open in read/Write mode, so that would extend the file. */ if(offset < 0 || offset >= lz->size) return -1; size = min(size, lz->size - offset); int rc = lseek(lz->fd, offset, SEEK_SET); if(rc < 0) return -1; return read(lz->fd, buf, size); } static bool lz_write(void *_cookie, void *data, size_t data_size, off_t offset, size_t segment_size) { lazy_file_t *lz = _cookie; if(data_size != segment_size) return false; if(offset < 0 || offset >= lz->size) return -1; data_size = min(data_size, lz->size - offset); int rc = lseek(lz->fd, offset, SEEK_SET); if(rc < 0) return -1; return write(lz->fd, data, data_size); } static size_t lz_size(void *_cookie) { lazy_file_t *lz = _cookie; return lz->size; } static bool lz_dirty(void *_cookie) { /* The file itself cannot be dirty, it's *the* file in Flash */ (void)_cookie; return false; } static bool lz_save(void *_cookie, char const *outfile) { /* When `outfile` is NULL we have nothing to do since your backing is the live file. When it's not then we don't support the save because it would need to do a chunked copy, which I don't want to write yet */ (void)_cookie; return (outfile == NULL); } static void lz_close(void *_cookie) { lazy_file_t *lz = _cookie; lz_free(lz); } static source_intf_t lz_intf = { .name = "Lazy File", .close_on_return_to_menu = true, .read = lz_read, .write = lz_write, .size = lz_size, .dirty = lz_dirty, .save = lz_save, .close = lz_close, }; source_t *source_lazy_file_open(char const *path) { source_t *source = NULL; lazy_file_t *lz = NULL; lz = malloc(sizeof *lz); if(!lz) goto fail; lz->fd = open(path, O_RDWR); if(lz->fd < 0) goto fail; lz->size = lseek(lz->fd, 0, SEEK_END); if(lz->size <= 0) goto fail; source = source_open(&lz_intf, lz, path); if(!source) goto fail; source->cap = SOURCE_WRITE; return source; fail: free(source); lz_close(lz); return NULL; }