hex-editor/src/source-lazy-file.c

114 lines
2.5 KiB
C

#include "source.h"
#include <gint/gint.h>
#include <gint/defs/util.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
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;
}