forked from Lephenixnoir/hex-editor
114 lines
2.5 KiB
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;
|
|
}
|