1204076Spjd/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 5204076Spjd * All rights reserved. 6204076Spjd * 7204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 8204076Spjd * the FreeBSD Foundation. 9204076Spjd * 10204076Spjd * Redistribution and use in source and binary forms, with or without 11204076Spjd * modification, are permitted provided that the following conditions 12204076Spjd * are met: 13204076Spjd * 1. Redistributions of source code must retain the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer. 15204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 16204076Spjd * notice, this list of conditions and the following disclaimer in the 17204076Spjd * documentation and/or other materials provided with the distribution. 18204076Spjd * 19204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29204076Spjd * SUCH DAMAGE. 30204076Spjd */ 31204076Spjd 32204076Spjd#include <sys/cdefs.h> 33204076Spjd__FBSDID("$FreeBSD: stable/11/sbin/hastd/ebuf.c 330449 2018-03-05 07:26:05Z eadler $"); 34204076Spjd 35204076Spjd#include <sys/param.h> 36204076Spjd 37204076Spjd#include <errno.h> 38204076Spjd#include <stdbool.h> 39204076Spjd#include <stdint.h> 40204076Spjd#include <strings.h> 41204076Spjd#include <unistd.h> 42204076Spjd 43225787Spjd#include <pjdlog.h> 44225787Spjd 45204076Spjd#include "ebuf.h" 46204076Spjd 47225787Spjd#ifndef PJDLOG_ASSERT 48225787Spjd#include <assert.h> 49225787Spjd#define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 50225787Spjd#endif 51225787Spjd 52204076Spjd#define EBUF_MAGIC 0xeb0f41c 53204076Spjdstruct ebuf { 54204076Spjd /* Magic to assert the caller uses valid structure. */ 55204076Spjd int eb_magic; 56204076Spjd /* Address where we did the allocation. */ 57204076Spjd unsigned char *eb_start; 58204076Spjd /* Allocation end address. */ 59204076Spjd unsigned char *eb_end; 60204076Spjd /* Start of real data. */ 61204076Spjd unsigned char *eb_used; 62204076Spjd /* Size of real data. */ 63204076Spjd size_t eb_size; 64204076Spjd}; 65204076Spjd 66209184Spjdstatic int ebuf_head_extend(struct ebuf *eb, size_t size); 67209184Spjdstatic int ebuf_tail_extend(struct ebuf *eb, size_t size); 68204076Spjd 69204076Spjdstruct ebuf * 70204076Spjdebuf_alloc(size_t size) 71204076Spjd{ 72204076Spjd struct ebuf *eb; 73204076Spjd int rerrno; 74204076Spjd 75204076Spjd eb = malloc(sizeof(*eb)); 76204076Spjd if (eb == NULL) 77204076Spjd return (NULL); 78204076Spjd size += PAGE_SIZE; 79204076Spjd eb->eb_start = malloc(size); 80204076Spjd if (eb->eb_start == NULL) { 81204076Spjd rerrno = errno; 82204076Spjd free(eb); 83204076Spjd errno = rerrno; 84204076Spjd return (NULL); 85204076Spjd } 86204076Spjd eb->eb_end = eb->eb_start + size; 87204076Spjd /* 88204076Spjd * We set start address for real data not at the first entry, because 89204076Spjd * we want to be able to add data at the front. 90204076Spjd */ 91204076Spjd eb->eb_used = eb->eb_start + PAGE_SIZE / 4; 92204076Spjd eb->eb_size = 0; 93204076Spjd eb->eb_magic = EBUF_MAGIC; 94204076Spjd 95204076Spjd return (eb); 96204076Spjd} 97204076Spjd 98204076Spjdvoid 99204076Spjdebuf_free(struct ebuf *eb) 100204076Spjd{ 101204076Spjd 102225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 103204076Spjd 104204076Spjd eb->eb_magic = 0; 105204076Spjd 106204076Spjd free(eb->eb_start); 107204076Spjd free(eb); 108204076Spjd} 109204076Spjd 110204076Spjdint 111204076Spjdebuf_add_head(struct ebuf *eb, const void *data, size_t size) 112204076Spjd{ 113204076Spjd 114225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 115204076Spjd 116204076Spjd if (size > (size_t)(eb->eb_used - eb->eb_start)) { 117204076Spjd /* 118204076Spjd * We can't add more entries at the front, so we have to extend 119204076Spjd * our buffer. 120204076Spjd */ 121229945Spjd if (ebuf_head_extend(eb, size) == -1) 122204076Spjd return (-1); 123204076Spjd } 124225787Spjd PJDLOG_ASSERT(size <= (size_t)(eb->eb_used - eb->eb_start)); 125204076Spjd 126204076Spjd eb->eb_size += size; 127204076Spjd eb->eb_used -= size; 128204076Spjd /* 129204076Spjd * If data is NULL the caller just wants to reserve place. 130204076Spjd */ 131204076Spjd if (data != NULL) 132204076Spjd bcopy(data, eb->eb_used, size); 133204076Spjd 134204076Spjd return (0); 135204076Spjd} 136204076Spjd 137204076Spjdint 138204076Spjdebuf_add_tail(struct ebuf *eb, const void *data, size_t size) 139204076Spjd{ 140204076Spjd 141225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 142204076Spjd 143204076Spjd if (size > (size_t)(eb->eb_end - (eb->eb_used + eb->eb_size))) { 144204076Spjd /* 145204076Spjd * We can't add more entries at the back, so we have to extend 146204076Spjd * our buffer. 147204076Spjd */ 148229945Spjd if (ebuf_tail_extend(eb, size) == -1) 149204076Spjd return (-1); 150204076Spjd } 151225787Spjd PJDLOG_ASSERT(size <= 152225787Spjd (size_t)(eb->eb_end - (eb->eb_used + eb->eb_size))); 153204076Spjd 154204076Spjd /* 155209184Spjd * If data is NULL the caller just wants to reserve space. 156204076Spjd */ 157204076Spjd if (data != NULL) 158204076Spjd bcopy(data, eb->eb_used + eb->eb_size, size); 159204076Spjd eb->eb_size += size; 160204076Spjd 161204076Spjd return (0); 162204076Spjd} 163204076Spjd 164204076Spjdvoid 165204076Spjdebuf_del_head(struct ebuf *eb, size_t size) 166204076Spjd{ 167204076Spjd 168225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 169225787Spjd PJDLOG_ASSERT(size <= eb->eb_size); 170204076Spjd 171204076Spjd eb->eb_used += size; 172204076Spjd eb->eb_size -= size; 173204076Spjd} 174204076Spjd 175204076Spjdvoid 176204076Spjdebuf_del_tail(struct ebuf *eb, size_t size) 177204076Spjd{ 178204076Spjd 179225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 180225787Spjd PJDLOG_ASSERT(size <= eb->eb_size); 181204076Spjd 182204076Spjd eb->eb_size -= size; 183204076Spjd} 184204076Spjd 185204076Spjd/* 186204076Spjd * Return pointer to the data and data size. 187204076Spjd */ 188204076Spjdvoid * 189204076Spjdebuf_data(struct ebuf *eb, size_t *sizep) 190204076Spjd{ 191204076Spjd 192225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 193204076Spjd 194204076Spjd if (sizep != NULL) 195204076Spjd *sizep = eb->eb_size; 196204076Spjd return (eb->eb_size > 0 ? eb->eb_used : NULL); 197204076Spjd} 198204076Spjd 199204076Spjd/* 200204076Spjd * Return data size. 201204076Spjd */ 202204076Spjdsize_t 203204076Spjdebuf_size(struct ebuf *eb) 204204076Spjd{ 205204076Spjd 206225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 207204076Spjd 208204076Spjd return (eb->eb_size); 209204076Spjd} 210204076Spjd 211204076Spjd/* 212204076Spjd * Function adds size + (PAGE_SIZE / 4) bytes at the front of the buffer.. 213204076Spjd */ 214204076Spjdstatic int 215209184Spjdebuf_head_extend(struct ebuf *eb, size_t size) 216204076Spjd{ 217204076Spjd unsigned char *newstart, *newused; 218204076Spjd size_t newsize; 219204076Spjd 220225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 221204076Spjd 222204076Spjd newsize = eb->eb_end - eb->eb_start + (PAGE_SIZE / 4) + size; 223204076Spjd 224204076Spjd newstart = malloc(newsize); 225204076Spjd if (newstart == NULL) 226204076Spjd return (-1); 227204076Spjd newused = 228204076Spjd newstart + (PAGE_SIZE / 4) + size + (eb->eb_used - eb->eb_start); 229204076Spjd 230204076Spjd bcopy(eb->eb_used, newused, eb->eb_size); 231204076Spjd 232204076Spjd eb->eb_start = newstart; 233204076Spjd eb->eb_used = newused; 234204076Spjd eb->eb_end = newstart + newsize; 235204076Spjd 236204076Spjd return (0); 237204076Spjd} 238204076Spjd 239204076Spjd/* 240204076Spjd * Function adds size + ((3 * PAGE_SIZE) / 4) bytes at the back. 241204076Spjd */ 242204076Spjdstatic int 243209184Spjdebuf_tail_extend(struct ebuf *eb, size_t size) 244204076Spjd{ 245204076Spjd unsigned char *newstart; 246204076Spjd size_t newsize; 247204076Spjd 248225787Spjd PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 249204076Spjd 250204076Spjd newsize = eb->eb_end - eb->eb_start + size + ((3 * PAGE_SIZE) / 4); 251204076Spjd 252204076Spjd newstart = realloc(eb->eb_start, newsize); 253204076Spjd if (newstart == NULL) 254204076Spjd return (-1); 255204076Spjd 256204076Spjd eb->eb_used = newstart + (eb->eb_used - eb->eb_start); 257204076Spjd eb->eb_start = newstart; 258204076Spjd eb->eb_end = newstart + newsize; 259204076Spjd 260204076Spjd return (0); 261204076Spjd} 262