vis
a vi-like editor based on Plan 9's structural regular expressions
git clone https://9o.is/git/vis.git
commit a1aa693770859a730d5844150b41759d523863fd parent f7c6e281266943ce42dbf3cf8064d419d2cc704e Author: Marc André Tanner <mat@brain-dump.org> Date: Mon, 6 Jul 2015 11:13:57 +0200 text: overhaul file load implementation Files smaller than 8M are now copied into an internal buffer upon load. Thus they can be safely truncated. Larger files are memory mapped and use the file/virtual memory system as caching layer. Hence truncating them will corrupt the file content. Eventually the resulting SIGBUS should be handled gracefully. Diffstat:
| M | text.c | | | 37 | ++++++++++++++++++++++++++++++++++--- |
1 file changed, 34 insertions(+), 3 deletions(-)
diff --git a/text.c b/text.c @@ -35,6 +35,10 @@ #include "util.h" #define BUFFER_SIZE (1 << 20) +/* Files smaller than this value are copied on load, larger ones are mmap(2)-ed + * directely. Hence the former can be truncated, while doing so on the latter + * results in havoc. */ +#define BUFFER_MMAP_SIZE (1 << 23) struct Regex { const char *string; @@ -136,6 +140,7 @@ struct Text { /* buffer management */ static Buffer *buffer_alloc(Text *txt, size_t size); +static Buffer *buffer_read(Text *txt, size_t size, int fd); static Buffer *buffer_mmap(Text *txt, size_t size, int fd, off_t offset); static void buffer_free(Buffer *buf); static bool buffer_capacity(Buffer *buf, size_t len); @@ -203,6 +208,27 @@ static Buffer *buffer_alloc(Text *txt, size_t size) { return buf; } +static Buffer *buffer_read(Text *txt, size_t size, int fd) { + Buffer *buf = buffer_alloc(txt, size); + if (!buf) + return NULL; + while (size > 0) { + char data[4096]; + ssize_t len = read(fd, data, MIN(sizeof(data), size)); + if (len == -1) { + txt->buffers = buf->next; + buffer_free(buf); + return NULL; + } else if (len == 0) { + break; + } else { + buffer_append(buf, data, len); + size -= len; + } + } + return buf; +} + static Buffer *buffer_mmap(Text *txt, size_t size, int fd, off_t offset) { Buffer *buf = calloc(1, sizeof(Buffer)); if (!buf) @@ -993,15 +1019,20 @@ Text *text_load(const char *filename) { goto out; } // XXX: use lseek(fd, 0, SEEK_END); instead? - if (!(txt->buf = buffer_mmap(txt, txt->info.st_size, txt->fd, 0))) + size_t size = txt->info.st_size; + if (size < BUFFER_MMAP_SIZE) + txt->buf = buffer_read(txt, size, txt->fd); + else + txt->buf = buffer_mmap(txt, size, txt->fd, 0); + if (!txt->buf) goto out; Piece *p = piece_alloc(txt); if (!p) goto out; piece_init(&txt->begin, NULL, p, NULL, 0); - piece_init(p, &txt->begin, &txt->end, txt->buf->data, txt->buf->size); + piece_init(p, &txt->begin, &txt->end, txt->buf->data, txt->buf->len); piece_init(&txt->end, p, NULL, NULL, 0); - txt->size = txt->buf->size; + txt->size = txt->buf->len; } /* write an empty action */ change_alloc(txt, EPOS);