cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

strbuf.c (3218B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include "cache.h"
      3#include "debug.h"
      4#include "strbuf.h"
      5#include <linux/kernel.h>
      6#include <linux/string.h>
      7#include <linux/zalloc.h>
      8#include <errno.h>
      9#include <stdio.h>
     10#include <stdlib.h>
     11#include <unistd.h>
     12
     13/*
     14 * Used as the default ->buf value, so that people can always assume
     15 * buf is non NULL and ->buf is NUL terminated even for a freshly
     16 * initialized strbuf.
     17 */
     18char strbuf_slopbuf[1];
     19
     20int strbuf_init(struct strbuf *sb, ssize_t hint)
     21{
     22	sb->alloc = sb->len = 0;
     23	sb->buf = strbuf_slopbuf;
     24	if (hint)
     25		return strbuf_grow(sb, hint);
     26	return 0;
     27}
     28
     29void strbuf_release(struct strbuf *sb)
     30{
     31	if (sb->alloc) {
     32		zfree(&sb->buf);
     33		strbuf_init(sb, 0);
     34	}
     35}
     36
     37char *strbuf_detach(struct strbuf *sb, size_t *sz)
     38{
     39	char *res = sb->alloc ? sb->buf : NULL;
     40	if (sz)
     41		*sz = sb->len;
     42	strbuf_init(sb, 0);
     43	return res;
     44}
     45
     46int strbuf_grow(struct strbuf *sb, size_t extra)
     47{
     48	char *buf;
     49	size_t nr = sb->len + extra + 1;
     50
     51	if (nr < sb->alloc)
     52		return 0;
     53
     54	if (nr <= sb->len)
     55		return -E2BIG;
     56
     57	if (alloc_nr(sb->alloc) > nr)
     58		nr = alloc_nr(sb->alloc);
     59
     60	/*
     61	 * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
     62	 * a static variable. Thus we have to avoid passing it to realloc.
     63	 */
     64	buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));
     65	if (!buf)
     66		return -ENOMEM;
     67
     68	sb->buf = buf;
     69	sb->alloc = nr;
     70	return 0;
     71}
     72
     73int strbuf_addch(struct strbuf *sb, int c)
     74{
     75	int ret = strbuf_grow(sb, 1);
     76	if (ret)
     77		return ret;
     78
     79	sb->buf[sb->len++] = c;
     80	sb->buf[sb->len] = '\0';
     81	return 0;
     82}
     83
     84int strbuf_add(struct strbuf *sb, const void *data, size_t len)
     85{
     86	int ret = strbuf_grow(sb, len);
     87	if (ret)
     88		return ret;
     89
     90	memcpy(sb->buf + sb->len, data, len);
     91	return strbuf_setlen(sb, sb->len + len);
     92}
     93
     94static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
     95{
     96	int len, ret;
     97	va_list ap_saved;
     98
     99	if (!strbuf_avail(sb)) {
    100		ret = strbuf_grow(sb, 64);
    101		if (ret)
    102			return ret;
    103	}
    104
    105	va_copy(ap_saved, ap);
    106	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
    107	if (len < 0) {
    108		va_end(ap_saved);
    109		return len;
    110	}
    111	if (len > strbuf_avail(sb)) {
    112		ret = strbuf_grow(sb, len);
    113		if (ret) {
    114			va_end(ap_saved);
    115			return ret;
    116		}
    117		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
    118		if (len > strbuf_avail(sb)) {
    119			pr_debug("this should not happen, your vsnprintf is broken");
    120			va_end(ap_saved);
    121			return -EINVAL;
    122		}
    123	}
    124	va_end(ap_saved);
    125	return strbuf_setlen(sb, sb->len + len);
    126}
    127
    128int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
    129{
    130	va_list ap;
    131	int ret;
    132
    133	va_start(ap, fmt);
    134	ret = strbuf_addv(sb, fmt, ap);
    135	va_end(ap);
    136	return ret;
    137}
    138
    139ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
    140{
    141	size_t oldlen = sb->len;
    142	size_t oldalloc = sb->alloc;
    143	int ret;
    144
    145	ret = strbuf_grow(sb, hint ? hint : 8192);
    146	if (ret)
    147		return ret;
    148
    149	for (;;) {
    150		ssize_t cnt;
    151
    152		cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
    153		if (cnt < 0) {
    154			if (oldalloc == 0)
    155				strbuf_release(sb);
    156			else
    157				strbuf_setlen(sb, oldlen);
    158			return cnt;
    159		}
    160		if (!cnt)
    161			break;
    162		sb->len += cnt;
    163		ret = strbuf_grow(sb, 8192);
    164		if (ret)
    165			return ret;
    166	}
    167
    168	sb->buf[sb->len] = '\0';
    169	return sb->len - oldlen;
    170}