1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2*8520a98dSArnaldo Carvalho de Melo #include "cache.h"
35cea57f3SMasami Hiramatsu #include "debug.h"
4*8520a98dSArnaldo Carvalho de Melo #include "strbuf.h"
5e7f01d1eSArnaldo Carvalho de Melo #include <linux/kernel.h>
6*8520a98dSArnaldo Carvalho de Melo #include <linux/string.h>
77f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
8a43783aeSArnaldo Carvalho de Melo #include <errno.h>
9*8520a98dSArnaldo Carvalho de Melo #include <stdio.h>
10215a0d30SArnaldo Carvalho de Melo #include <stdlib.h>
1191854f9aSArnaldo Carvalho de Melo #include <unistd.h>
1286470930SIngo Molnar
1386470930SIngo Molnar /*
1486470930SIngo Molnar * Used as the default ->buf value, so that people can always assume
1586470930SIngo Molnar * buf is non NULL and ->buf is NUL terminated even for a freshly
1686470930SIngo Molnar * initialized strbuf.
1786470930SIngo Molnar */
1886470930SIngo Molnar char strbuf_slopbuf[1];
1986470930SIngo Molnar
strbuf_init(struct strbuf * sb,ssize_t hint)205cea57f3SMasami Hiramatsu int strbuf_init(struct strbuf *sb, ssize_t hint)
2186470930SIngo Molnar {
2286470930SIngo Molnar sb->alloc = sb->len = 0;
2386470930SIngo Molnar sb->buf = strbuf_slopbuf;
2486470930SIngo Molnar if (hint)
255cea57f3SMasami Hiramatsu return strbuf_grow(sb, hint);
265cea57f3SMasami Hiramatsu return 0;
2786470930SIngo Molnar }
2886470930SIngo Molnar
strbuf_release(struct strbuf * sb)2986470930SIngo Molnar void strbuf_release(struct strbuf *sb)
3086470930SIngo Molnar {
3186470930SIngo Molnar if (sb->alloc) {
3274cf249dSArnaldo Carvalho de Melo zfree(&sb->buf);
3386470930SIngo Molnar strbuf_init(sb, 0);
3486470930SIngo Molnar }
3586470930SIngo Molnar }
3686470930SIngo Molnar
strbuf_detach(struct strbuf * sb,size_t * sz)3786470930SIngo Molnar char *strbuf_detach(struct strbuf *sb, size_t *sz)
3886470930SIngo Molnar {
3986470930SIngo Molnar char *res = sb->alloc ? sb->buf : NULL;
4086470930SIngo Molnar if (sz)
4186470930SIngo Molnar *sz = sb->len;
4286470930SIngo Molnar strbuf_init(sb, 0);
4386470930SIngo Molnar return res;
4486470930SIngo Molnar }
4586470930SIngo Molnar
strbuf_grow(struct strbuf * sb,size_t extra)465cea57f3SMasami Hiramatsu int strbuf_grow(struct strbuf *sb, size_t extra)
4786470930SIngo Molnar {
485cea57f3SMasami Hiramatsu char *buf;
495cea57f3SMasami Hiramatsu size_t nr = sb->len + extra + 1;
505cea57f3SMasami Hiramatsu
515cea57f3SMasami Hiramatsu if (nr < sb->alloc)
525cea57f3SMasami Hiramatsu return 0;
535cea57f3SMasami Hiramatsu
545cea57f3SMasami Hiramatsu if (nr <= sb->len)
555cea57f3SMasami Hiramatsu return -E2BIG;
565cea57f3SMasami Hiramatsu
575cea57f3SMasami Hiramatsu if (alloc_nr(sb->alloc) > nr)
585cea57f3SMasami Hiramatsu nr = alloc_nr(sb->alloc);
595cea57f3SMasami Hiramatsu
605cea57f3SMasami Hiramatsu /*
615cea57f3SMasami Hiramatsu * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
625cea57f3SMasami Hiramatsu * a static variable. Thus we have to avoid passing it to realloc.
635cea57f3SMasami Hiramatsu */
645cea57f3SMasami Hiramatsu buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));
655cea57f3SMasami Hiramatsu if (!buf)
665cea57f3SMasami Hiramatsu return -ENOMEM;
675cea57f3SMasami Hiramatsu
685cea57f3SMasami Hiramatsu sb->buf = buf;
695cea57f3SMasami Hiramatsu sb->alloc = nr;
705cea57f3SMasami Hiramatsu return 0;
7186470930SIngo Molnar }
7286470930SIngo Molnar
strbuf_addch(struct strbuf * sb,int c)735cea57f3SMasami Hiramatsu int strbuf_addch(struct strbuf *sb, int c)
740741208aSArnaldo Carvalho de Melo {
755cea57f3SMasami Hiramatsu int ret = strbuf_grow(sb, 1);
765cea57f3SMasami Hiramatsu if (ret)
775cea57f3SMasami Hiramatsu return ret;
785cea57f3SMasami Hiramatsu
790741208aSArnaldo Carvalho de Melo sb->buf[sb->len++] = c;
800741208aSArnaldo Carvalho de Melo sb->buf[sb->len] = '\0';
815cea57f3SMasami Hiramatsu return 0;
820741208aSArnaldo Carvalho de Melo }
830741208aSArnaldo Carvalho de Melo
strbuf_add(struct strbuf * sb,const void * data,size_t len)845cea57f3SMasami Hiramatsu int strbuf_add(struct strbuf *sb, const void *data, size_t len)
8586470930SIngo Molnar {
865cea57f3SMasami Hiramatsu int ret = strbuf_grow(sb, len);
875cea57f3SMasami Hiramatsu if (ret)
885cea57f3SMasami Hiramatsu return ret;
895cea57f3SMasami Hiramatsu
9086470930SIngo Molnar memcpy(sb->buf + sb->len, data, len);
915cea57f3SMasami Hiramatsu return strbuf_setlen(sb, sb->len + len);
9286470930SIngo Molnar }
9386470930SIngo Molnar
strbuf_addv(struct strbuf * sb,const char * fmt,va_list ap)945cea57f3SMasami Hiramatsu static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
9586470930SIngo Molnar {
965cea57f3SMasami Hiramatsu int len, ret;
97c7118369SNamhyung Kim va_list ap_saved;
9886470930SIngo Molnar
995cea57f3SMasami Hiramatsu if (!strbuf_avail(sb)) {
1005cea57f3SMasami Hiramatsu ret = strbuf_grow(sb, 64);
1015cea57f3SMasami Hiramatsu if (ret)
1025cea57f3SMasami Hiramatsu return ret;
1035cea57f3SMasami Hiramatsu }
104c7118369SNamhyung Kim
105c7118369SNamhyung Kim va_copy(ap_saved, ap);
106f787d951SNamhyung Kim len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
107ce49d843SSanskriti Sharma if (len < 0) {
108ce49d843SSanskriti Sharma va_end(ap_saved);
1095cea57f3SMasami Hiramatsu return len;
110ce49d843SSanskriti Sharma }
11186470930SIngo Molnar if (len > strbuf_avail(sb)) {
1125cea57f3SMasami Hiramatsu ret = strbuf_grow(sb, len);
113ce49d843SSanskriti Sharma if (ret) {
114ce49d843SSanskriti Sharma va_end(ap_saved);
1155cea57f3SMasami Hiramatsu return ret;
116ce49d843SSanskriti Sharma }
117c7118369SNamhyung Kim len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
11886470930SIngo Molnar if (len > strbuf_avail(sb)) {
1195cea57f3SMasami Hiramatsu pr_debug("this should not happen, your vsnprintf is broken");
120ce49d843SSanskriti Sharma va_end(ap_saved);
1215cea57f3SMasami Hiramatsu return -EINVAL;
12286470930SIngo Molnar }
12386470930SIngo Molnar }
124ce49d843SSanskriti Sharma va_end(ap_saved);
1255cea57f3SMasami Hiramatsu return strbuf_setlen(sb, sb->len + len);
12686470930SIngo Molnar }
12786470930SIngo Molnar
strbuf_addf(struct strbuf * sb,const char * fmt,...)1285cea57f3SMasami Hiramatsu int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
129c7118369SNamhyung Kim {
130c7118369SNamhyung Kim va_list ap;
1315cea57f3SMasami Hiramatsu int ret;
132c7118369SNamhyung Kim
133c7118369SNamhyung Kim va_start(ap, fmt);
1345cea57f3SMasami Hiramatsu ret = strbuf_addv(sb, fmt, ap);
135c7118369SNamhyung Kim va_end(ap);
1365cea57f3SMasami Hiramatsu return ret;
137c7118369SNamhyung Kim }
138c7118369SNamhyung Kim
strbuf_read(struct strbuf * sb,int fd,ssize_t hint)139f37a291cSIngo Molnar ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
14086470930SIngo Molnar {
14186470930SIngo Molnar size_t oldlen = sb->len;
14286470930SIngo Molnar size_t oldalloc = sb->alloc;
1435cea57f3SMasami Hiramatsu int ret;
14486470930SIngo Molnar
1455cea57f3SMasami Hiramatsu ret = strbuf_grow(sb, hint ? hint : 8192);
1465cea57f3SMasami Hiramatsu if (ret)
1475cea57f3SMasami Hiramatsu return ret;
1485cea57f3SMasami Hiramatsu
14986470930SIngo Molnar for (;;) {
15086470930SIngo Molnar ssize_t cnt;
15186470930SIngo Molnar
15286470930SIngo Molnar cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
15386470930SIngo Molnar if (cnt < 0) {
15486470930SIngo Molnar if (oldalloc == 0)
15586470930SIngo Molnar strbuf_release(sb);
15686470930SIngo Molnar else
15786470930SIngo Molnar strbuf_setlen(sb, oldlen);
1585cea57f3SMasami Hiramatsu return cnt;
15986470930SIngo Molnar }
16086470930SIngo Molnar if (!cnt)
16186470930SIngo Molnar break;
16286470930SIngo Molnar sb->len += cnt;
1635cea57f3SMasami Hiramatsu ret = strbuf_grow(sb, 8192);
1645cea57f3SMasami Hiramatsu if (ret)
1655cea57f3SMasami Hiramatsu return ret;
16686470930SIngo Molnar }
16786470930SIngo Molnar
16886470930SIngo Molnar sb->buf[sb->len] = '\0';
16986470930SIngo Molnar return sb->len - oldlen;
17086470930SIngo Molnar }
171