#include "file.h" #include #include #include #include #include #include #define DEFAULT_BUFFER_SIZE 4096 static int ringbuf_init(struct ringbuf *buf) { if (buf->buf_ptr) { return SUCCESS; } if (!buf->buf_max) { buf->buf_max = DEFAULT_BUFFER_SIZE; } buf->buf_ptr = malloc(buf->buf_max); if (!buf->buf_ptr) { return ENOMEM; } memset(buf->buf_ptr, 0x0, buf->buf_max); return SUCCESS; } int __libc_ringbuf_get_read_buffer( struct ringbuf *buf, const char **out_bufp, size_t *out_len) { int r = ringbuf_init(buf); if (r != SUCCESS) { return r; } size_t contiguous_capacity = 0; if (buf->buf_readp > buf->buf_writep) { contiguous_capacity = buf->buf_max - buf->buf_readp; } else { contiguous_capacity = buf->buf_writep - buf->buf_readp; } kern_tracef( "OPEN READ: readp=%zu, writep=%zu, max=%zu -> %p cap=%zu", buf->buf_readp, buf->buf_writep, buf->buf_max, buf->buf_ptr + buf->buf_readp, contiguous_capacity); *out_len = contiguous_capacity; if (contiguous_capacity == 0) { *out_bufp = NULL; } else { *out_bufp = buf->buf_ptr + buf->buf_readp; } return SUCCESS; } void __libc_ringbuf_put_read_buffer( struct ringbuf *buf, const char **bufp, size_t *len) { buf->buf_readp += *len; if (buf->buf_readp == buf->buf_writep) { buf->buf_readp = buf->buf_writep = 0; } kern_tracef("CLOSE READ: %p r=%zu", *bufp, *len); *bufp = NULL; *len = 0; } int __libc_ringbuf_get_write_buffer( struct ringbuf *buf, char **out_bufp, size_t *out_len) { int r = ringbuf_init(buf); if (r != SUCCESS) { return r; } size_t contiguous_capacity = 0; if (buf->buf_writep >= buf->buf_readp) { contiguous_capacity = buf->buf_max - buf->buf_writep - 1; if (buf->buf_readp > 0) { contiguous_capacity++; } } else { contiguous_capacity = buf->buf_readp - buf->buf_writep - 1; } kern_tracef( "OPEN WRITE: readp=%zu, writep=%zu, max=%zu -> %p cap=%zu", buf->buf_readp, buf->buf_writep, buf->buf_max, buf->buf_ptr + buf->buf_readp, contiguous_capacity); *out_len = contiguous_capacity; if (contiguous_capacity == 0) { *out_bufp = NULL; } else { *out_bufp = buf->buf_ptr + buf->buf_writep; } return SUCCESS; } void __libc_ringbuf_put_write_buffer( struct ringbuf *buf, char **bufp, size_t *len) { buf->buf_writep += *len; if (buf->buf_readp == buf->buf_writep) { buf->buf_readp = buf->buf_writep = 0; } kern_tracef( "CLOSE WRITE: %p r=%zu (%c)", *bufp, *len, *(char *)(*bufp)); *bufp = NULL; *len = 0; } long __libc_ringbuf_read(struct ringbuf *buf, void *p, size_t count) { size_t nr_read = 0; long r = 0; while (nr_read < count) { const char *src = NULL; size_t available = 0; r = __libc_ringbuf_get_read_buffer(buf, &src, &available); if (r < 0) { break; } char *dest = p + nr_read; size_t to_copy = count - nr_read; if (available == 0) { __libc_ringbuf_put_read_buffer(buf, &src, &available); break; } if (to_copy > available) { to_copy = available; } memcpy(dest, src, to_copy); nr_read += available; __libc_ringbuf_put_read_buffer(buf, &src, &to_copy); } if (r < 0) { return r; } return nr_read; } long __libc_ringbuf_write(struct ringbuf *buf, const void *p, size_t count) { size_t nr_written = 0; long r = 0; while (nr_written < count) { char *dest = NULL; size_t available = 0; r = __libc_ringbuf_get_write_buffer(buf, &dest, &available); if (r < 0) { break; } const char *src = p + nr_written; size_t to_copy = count - nr_written; if (available == 0) { __libc_ringbuf_put_write_buffer(buf, &dest, &available); break; } if (to_copy > available) { to_copy = available; } memcpy(dest, src, to_copy); nr_written += available; __libc_ringbuf_put_write_buffer(buf, &dest, &to_copy); } if (r < 0) { return r; } return nr_written; } int __libc_ringbuf_clear(struct ringbuf *buf) { buf->buf_readp = buf->buf_writep = 0; return 0; } int __libc_ringbuf_resize(struct ringbuf *buf, size_t max) { if (!(buf->buf_flags & RINGBUF_STATIC)) { free(buf->buf_ptr); buf->buf_ptr = NULL; } buf->buf_readp = buf->buf_writep = 0; buf->buf_flags &= ~RINGBUF_STATIC; buf->buf_max = max; return 0; } int __libc_ringbuf_resize_static(struct ringbuf *buf, void *p, size_t max) { if (!(buf->buf_flags & RINGBUF_STATIC)) { free(buf->buf_ptr); buf->buf_ptr = NULL; } buf->buf_readp = buf->buf_writep = 0; buf->buf_flags |= RINGBUF_STATIC; buf->buf_ptr = p; buf->buf_max = max; return 0; } size_t __libc_ringbuf_available(const struct ringbuf *buf) { if (buf->buf_readp < buf->buf_writep) { return buf->buf_writep - buf->buf_readp; } else if (buf->buf_readp > buf->buf_writep) { return buf->buf_max - buf->buf_readp + buf->buf_writep; } else { return 0; } } size_t __libc_ringbuf_capacity(const struct ringbuf *buf) { if (buf->buf_readp > buf->buf_writep) { return buf->buf_readp - buf->buf_writep - 1; } else { return buf->buf_max - buf->buf_writep + buf->buf_readp - 1; } }