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