]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
sbuff: Implementation for doing streaming reads on `FILE *`
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 7 Aug 2020 23:31:45 +0000 (19:31 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 7 Aug 2020 23:31:52 +0000 (19:31 -0400)
No idea if it works

src/lib/util/sbuff.c
src/lib/util/sbuff.h

index 94a39f97707370a0bee94511fc65ad5bafbc04cc..b600b320c9dfeaaa812cf52c15817e8cdbdf0050 100644 (file)
@@ -25,6 +25,7 @@ RCSID("$Id$")
 #include <freeradius-devel/util/print.h>
 #include <freeradius-devel/util/sbuff.h>
 #include <freeradius-devel/util/strerror.h>
+#include <freeradius-devel/util/syserror.h>
 #include <freeradius-devel/util/talloc.h>
 #include <freeradius-devel/util/thread_local.h>
 
@@ -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.
index 05ea43cae4c9b0db5165f99e4e812500b9f0e6bc..6564420a4cd85884f5c65c194966649484d8c4e0 100644 (file)
@@ -34,6 +34,7 @@ extern "C" {
 #include <limits.h>
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <talloc.h>
@@ -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.