mirror of https://github.com/ericonr/purr-c.git
107 lines
2.4 KiB
C
107 lines
2.4 KiB
C
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "mmap_file.h"
|
|
|
|
struct mmap_file create_mmap_from_file(const char *name, int prot)
|
|
{
|
|
struct mmap_file rv = {.prot = prot};
|
|
int fd;
|
|
if (prot == PROT_READ) {
|
|
fd = open(name, O_RDONLY);
|
|
rv.flags = MAP_PRIVATE;
|
|
|
|
if (fd == -1) {
|
|
return rv;
|
|
}
|
|
|
|
struct stat st;
|
|
if (fstat(fd, &st) == -1) {
|
|
perror("fstat()");
|
|
return rv;
|
|
}
|
|
rv.size = st.st_size;
|
|
} else if (prot == PROT_WRITE) {
|
|
fd = open(name, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
|
|
rv.flags = MAP_PRIVATE;
|
|
|
|
if (fd == -1) {
|
|
return rv;
|
|
}
|
|
|
|
// ftruncate is good enough for now
|
|
// TODO: we can truncate again once we know the content-size,
|
|
// otherwise this will leave the file with the wrong size
|
|
if (0 && ftruncate(fd, OUTPUT_FILE_SIZE) == -1) {
|
|
return rv;
|
|
}
|
|
rv.size = OUTPUT_FILE_SIZE;
|
|
} else if (name == NULL && prot == PROT_MEM) {
|
|
fd = -1;
|
|
rv.flags = MAP_ANONYMOUS | MAP_PRIVATE;
|
|
rv.size = OUTPUT_FILE_SIZE;
|
|
} else {
|
|
fputs("unsupported prot flags\n", stderr);
|
|
errno = 0;
|
|
return rv;
|
|
}
|
|
|
|
rv.data = mmap(NULL, rv.size, rv.prot, rv.flags, fd, 0);
|
|
close(fd);
|
|
|
|
return rv;
|
|
}
|
|
|
|
int read_from_mmap(struct mmap_file *file, int n)
|
|
{
|
|
assert(file->prot & PROT_READ);
|
|
|
|
if (file->size == file->offset) {
|
|
// can't read any more
|
|
return 0;
|
|
}
|
|
|
|
ssize_t max = file->size - file->offset;
|
|
file->cursor = file->data + file->offset;
|
|
if (n < max) {
|
|
// can fit the read
|
|
file->offset += n;
|
|
} else {
|
|
// can read less than n
|
|
file->offset = file->size;
|
|
n = max;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
int write_into_mmap(struct mmap_file *file, const uint8_t *buffer, int n)
|
|
{
|
|
assert(file->prot & PROT_WRITE);
|
|
|
|
if (file->size == file->offset) {
|
|
return -1;
|
|
}
|
|
|
|
ssize_t max = file->size - file->offset;
|
|
file->cursor = file->data + file->offset;
|
|
if (n < max) {
|
|
file->offset += n;
|
|
} else {
|
|
file->offset = file->size;
|
|
n = max;
|
|
}
|
|
|
|
memcpy(file->cursor, buffer, n);
|
|
|
|
return n;
|
|
}
|