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

107 lines
2.2 KiB
C
Raw Normal View History

#include "source.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
static void lf_free(loaded_file_t *lf)
{
if(lf) {
free(lf->path);
buffer_free(lf->buf);
}
free(lf);
}
static bool lf_read(void *_cookie, void *buf, off_t offset, size_t size)
{
loaded_file_t *lf = _cookie;
if(offset < 0 || offset + size > lf->buf->data_size)
return false;
memcpy(buf, lf->buf->mem + offset, size);
return true;
}
static bool lf_write(void *_cookie, void *data, size_t data_size, off_t offset,
size_t segment_size)
{
loaded_file_t *lf = _cookie;
return buffer_write(lf->buf, data, data_size, offset, segment_size);
}
static bool lf_save(void *_cookie)
{
loaded_file_t *lf = _cookie;
/* If the new file is larger than the original, we can just overwrite it
without truncating, which is much faster with Fugue */
int flags = O_WRONLY | O_TRUNC;
if(lf->buf->data_size >= lf->original_size)
flags = O_WRONLY;
int fd = open(lf->path, flags);
if(!fd) goto fail;
ssize_t rc = write(fd, lf->buf->mem, lf->buf->data_size);
if(rc < 0 || (size_t)rc != lf->buf->data_size) goto fail;
close(fd);
return true;
fail:
close(fd);
return false;
}
static void lf_close(void *_cookie)
{
loaded_file_t *lf = _cookie;
lf_free(lf);
}
static source_intf_t lf_intf = {
.cap = SOURCE_WRITE | SOURCE_EXPAND | SOURCE_SHRINK,
.read = lf_read,
.write = lf_write,
.save = lf_save,
.close = lf_close,
};
source_t *source_loaded_file_open(char const *path)
{
int fd = -1;
source_t *source = NULL;
loaded_file_t *lf = NULL;
lf = calloc(1, sizeof *lf);
if(!lf) goto fail;
lf->path = strdup(path);
if(!lf->path) goto fail;
fd = open(path, O_RDONLY);
if(fd < 0) goto fail;
int size = lseek(fd, 0, SEEK_END);
if(size < 0) goto fail;
lf->original_size = size;
lf->buf = buffer_create(size, 4096);
if(!lf->buf) goto fail;
ssize_t rc = pread(fd, lf->buf->mem, size, 0);
if(rc != size) goto fail;
source = source_open(&lf_intf, lf);
if(!source) goto fail;
close(fd);
return source;
fail:
free(source);
close(fd);
lf_free(lf);
return NULL;
}