From: Arran Cudbard-Bell Date: Fri, 7 Aug 2020 23:31:45 +0000 (-0400) Subject: sbuff: Implementation for doing streaming reads on `FILE *` X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cbd5f0d9eebb74d1d55ee6bcfbd95cd0e5a731f9;p=thirdparty%2Ffreeradius-server.git sbuff: Implementation for doing streaming reads on `FILE *` No idea if it works --- diff --git a/src/lib/util/sbuff.c b/src/lib/util/sbuff.c index 94a39f97707..b600b320c9d 100644 --- a/src/lib/util/sbuff.c +++ b/src/lib/util/sbuff.c @@ -25,6 +25,7 @@ RCSID("$Id$") #include #include #include +#include #include #include @@ -209,7 +210,7 @@ size_t fr_sbuff_shift(fr_sbuff_t *sbuff, size_t shift) * relative to content. */ update_ptr(buff, max_shift, sbuff_i->p); - + update_ptr(buff, max_shift, sbuff_i->end); sbuff_i->shifted += max_shift; for (m_i = sbuff_i->m; m_i; m_i = m_i->next) update_ptr(buff, max_shift, m_i->p); @@ -223,6 +224,47 @@ size_t fr_sbuff_shift(fr_sbuff_t *sbuff, size_t shift) return max_shift; } +/** Refresh the buffer with more data from the file + * + */ +size_t fr_sbuff_extend_file(fr_sbuff_t *sbuff, size_t extension) +{ + size_t shifted, read, available; + fr_sbuff_uctx_file_t *fctx = sbuff->uctx; + + if (extension == SIZE_MAX) extension = 0; + + if (fr_sbuff_used(sbuff)) { + /* + * Try and shift as much as we can out + * of the buffer to make space. + * + * Note: p and markers are constraints here. + */ + shifted = fr_sbuff_shift(sbuff, fr_sbuff_used(sbuff)); + } + + available = fctx->buff_end - sbuff->end; + if (available < extension) { + fr_strerror_printf("Can't satisfy extension request for %zu bytes", extension); + return 0; /* There's no way we could satisfy the extension request */ + } + + read = fread(sbuff->end, 1, available, fctx->file); + sbuff->end += read; /* Advance end, which increases fr_sbuff_remaining() */ + + /** Check for errors + */ + if (read < available) { + if (!feof(fctx->file)) { /* It's a real error */ + fr_strerror_printf("Error extending buffer: %s", fr_syserror(ferror(fctx->file))); + return 0; + } + } + + return read; +} + /** Reallocate the current buffer * * @param[in] sbuff to be extended. diff --git a/src/lib/util/sbuff.h b/src/lib/util/sbuff.h index 05ea43cae4c..6564420a4cd 100644 --- a/src/lib/util/sbuff.h +++ b/src/lib/util/sbuff.h @@ -34,6 +34,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -103,6 +104,17 @@ typedef struct { size_t max; //!< Maximum size of the buffer. } fr_sbuff_uctx_talloc_t; +/** File sbuff extension structure + * + * Holds the data necessary for creating dynamically + * extensible file buffers. + */ +typedef struct { + FILE *file; //!< FILE * we're reading from. + char *buff_end; //!< The true end of the buffer. + size_t max; //!< Maximum number of bytes to read. +} fr_sbuff_uctx_file_t; + /** Terminal element with pre-calculated lengths * */ @@ -280,6 +292,8 @@ void fr_sbuff_update(fr_sbuff_t *sbuff, char *new_buff, size_t new_len); size_t fr_sbuff_shift(fr_sbuff_t *sbuff, size_t shift); +size_t fr_sbuff_extend_file(fr_sbuff_t *sbuff, size_t extension); + size_t fr_sbuff_extend_talloc(fr_sbuff_t *sbuff, size_t extenison); int fr_sbuff_trim_talloc(fr_sbuff_t *sbuff, size_t len); @@ -318,6 +332,38 @@ _Generic((_len_or_end), \ char const * : _fr_sbuff_init(_out, _start, (char const *)(_len_or_end), true) \ ) +/** Initialise a special sbuff which automatically reads in more data as the buffer is exhausted + * + * @param[out] sbuff to initialise. + * @param[out] fctx to initialise. Must have a lifetime >= to the sbuff. + * @param[in] buff Temporary buffer to use for storing file contents. + * @param[in] len Length of the temporary buffer. + * @param[in] max The maximum length of data to read from the file. + * @return + * - The passed sbuff on success. + * - NULL on failure. + */ +static inline fr_sbuff_t *fr_sbuff_init_file(fr_sbuff_t *sbuff, fr_sbuff_uctx_file_t *fctx, + char *buff, size_t len, FILE *file, size_t max) +{ + *fctx = (fr_sbuff_uctx_file_t){ + .file = file, + .max = max, + .buff_end = buff + len //!< Store the real end + }; + + *sbuff = (fr_sbuff_t){ + .buff = buff, + .start = buff, + .p = buff, + .end = buff, //!< Starts with 0 bytes available + .extend = fr_sbuff_extend_file, + .uctx = fctx + }; + + return sbuff; +} + /** Initialise a special sbuff which automatically extends as additional data is written * * @param[in] ctx to allocate buffer in.