]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.4-20181130
authorWietse Venema <wietse@porcupine.org>
Fri, 30 Nov 2018 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sun, 9 Dec 2018 21:17:20 +0000 (16:17 -0500)
17 files changed:
postfix/HISTORY
postfix/src/global/mail_version.h
postfix/src/global/memcache_proto.c
postfix/src/global/record.c
postfix/src/global/smtp_stream.c
postfix/src/global/smtp_stream.h
postfix/src/global/uxtext.c
postfix/src/global/xtext.c
postfix/src/milter/milter8.c
postfix/src/smtp/smtp_session.c
postfix/src/smtpd/smtpd.c
postfix/src/tlsproxy/tlsproxy.c
postfix/src/util/dict_file.c
postfix/src/util/hex_quote.c
postfix/src/util/netstring.c
postfix/src/util/vstream.c
postfix/src/util/vstream.h

index 7dd3a7ddfa02cf12d72783f1cd47e30b93cfcc6b..a93aa03f562f4c09f98129770d2d1d52dbb2e82b 100644 (file)
@@ -23854,3 +23854,21 @@ Apologies for any names omitted.
        Cleanup: dict_file_to_xxx() takes a list of file names
        separated by CHARS_COMMA_SP. Shoe-horned into the existing
        API, make it nicer when there is time. File: util/dict_file.c.
+
+20181127
+
+       Cleanup: encapsulated clumsy 'read into VSTRING' code with
+       easier-to-use vstream_fread_buf() and vstream_fread_app()
+       primitives. Files: global/memcache_proto.c, global/record.c,
+       global/smtp_stream.c, global/smtp_stream.h, global/uxtext.c,
+       global/xtext.c, milter/milter8.c, util/dict_file.c,
+       util/hex_quote.c, util/netstring.c, util/vstream.c,
+       util/vstream.h. Verified with "make tests".
+
+       Cleanup: simplified the smtp_fread() API (introduced for
+       BDAT support), and changed the name to smtp_fread_buf().
+       Files: global/smtp_stream.c, smtpd/smtpd.c. Verified with
+       ~megabyte BDAT commands.
+
+       Cleanup: simplified a tlsproxy-internal API. File:
+       tlsproxy/tlsproxy.c.
index 592785ce5071761f0c39b86201fb1995b64dfcc0..06548378f9d6936cd0c2a52b1de81da4495cc584 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20181125"
+#define MAIL_RELEASE_DATE      "20181130"
 #define MAIL_VERSION_NUMBER    "3.4"
 
 #ifdef SNAPSHOT
index 8262269c73eadf35a1200819ed454ce835c0fb7a..58a7e3cba7796073d2f78ef3d5a8aa427b36fef1 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 #include <sys_defs.h>
@@ -143,16 +148,13 @@ int     memcache_fread(VSTREAM *stream, VSTRING *buf, ssize_t todo)
     /*
      * Do the I/O.
      */
-    VSTRING_SPACE(buf, todo);
-    VSTRING_AT_OFFSET(buf, todo);
-    if (vstream_fread(stream, STR(buf), todo) != todo
+    if (vstream_fread_buf(stream, buf, todo) != todo
        || VSTREAM_GETC(stream) != '\r'
        || VSTREAM_GETC(stream) != '\n') {
        if (msg_verbose)
            msg_info("%s read: error", VSTREAM_PATH(stream));
        return (-1);
     } else {
-       vstring_truncate(buf, todo);
        VSTRING_TERMINATE(buf);
        if (msg_verbose)
            msg_info("%s read: %s", VSTREAM_PATH(stream), STR(buf));
index 82ca8ec7f3b2267c367079420cc40d72d6b057fb..1dc9b757f2e0250f8ab516c8c928b1905a5e9cc3 100644 (file)
@@ -287,14 +287,11 @@ int     rec_get_raw(VSTREAM *stream, VSTRING *buf, ssize_t maxsize, int flags)
         * Reserve buffer space for the result, and read the record data into
         * the buffer.
         */
-       VSTRING_RESET(buf);
-       VSTRING_SPACE(buf, len);
-       if (vstream_fread(stream, vstring_str(buf), len) != len) {
+       if (vstream_fread_buf(stream, buf, len) != len) {
            msg_warn("%s: unexpected EOF in data, record type %d length %ld",
                     VSTREAM_PATH(stream), type, (long) len);
            return (REC_TYPE_ERROR);
        }
-       VSTRING_AT_OFFSET(buf, len);
        VSTRING_TERMINATE(buf);
        if (msg_verbose > 2)
            msg_info("%s: type %c len %ld data %.10s", myname,
index b72e20d31ec3d8406286aaec104bffd2268113c8..a42cdcfd25f0beb3187793abed898e42042e6756 100644 (file)
@@ -37,7 +37,7 @@
 /*     ssize_t len;
 /*     VSTREAM *stream;
 /*
-/*     void    smtp_fread(vp, len, stream)
+/*     void    smtp_fread_buf(vp, len, stream)
 /*     VSTRING *vp;
 /*     ssize_t len;
 /*     VSTREAM *stream;
 /*     Long strings are not broken. No CR LF is appended. The stream
 /*     is not flushed.
 /*
-/*     smtp_fread() appends the specified number of bytes from the
-/*     stream to the buffer. The result is not null-terminated.
+/*     smtp_fread_buf() invokes vstream_fread_buf() to read the
+/*     specified number of unformatted bytes from the stream. The
+/*     result is not null-terminated. NOTE: do not skip calling
+/*     smtp_fread_buf() when len == 0. This function has side
+/*     effects including resetting the buffer write position, and
+/*     skipping the call would invalidate the buffer state.
 /*
 /*     smtp_fputc() writes one character to the named stream.
 /*     The stream is not flushed.
@@ -474,23 +478,25 @@ void    smtp_fwrite(const char *cp, ssize_t todo, VSTREAM *stream)
        smtp_longjmp(stream, SMTP_ERR_EOF, "smtp_fwrite");
 }
 
-/* smtp_fread - read one buffer from SMTP peer */
+/* smtp_fread_buf - read one buffer from SMTP peer */
 
-void    smtp_fread(VSTRING *vp, ssize_t todo, VSTREAM *stream)
+void    smtp_fread_buf(VSTRING *vp, ssize_t todo, VSTREAM *stream)
 {
     int     err;
 
-    if (todo <= 0)
-       msg_panic("smtp_fread: zero or negative todo %ld", (long) todo);
+    /*
+     * Do not return early if todo == 0. We still need the side effects from
+     * calling vstream_fread_buf() including resetting the buffer write
+     * position. Skipping the call would invalidate the buffer state.
+     */
+    if (todo < 0)
+       msg_panic("smtp_fread_buf: negative todo %ld", (long) todo);
 
     /*
      * Do the I/O, protected against timeout.
      */
     smtp_timeout_reset(stream);
-    VSTRING_SPACE(vp, todo);
-    err = (vstream_fread(stream, vstring_end(vp), todo) != todo);
-    if (err == 0)
-       VSTRING_AT_OFFSET(vp, VSTRING_LEN(vp) + todo);
+    err = (vstream_fread_buf(stream, vp, todo) != todo);
 
     /*
      * See if there was a problem.
index 3df6180f27cf14f0157eaa3561b920933d601c1b..ec824b3c35ab2e29437aa259e089afd0b19b1aee 100644 (file)
@@ -41,7 +41,7 @@ extern int smtp_get(VSTRING *, VSTREAM *, ssize_t, int);
 extern int smtp_get_noexcept(VSTRING *, VSTREAM *, ssize_t, int);
 extern void smtp_fputs(const char *, ssize_t len, VSTREAM *);
 extern void smtp_fwrite(const char *, ssize_t len, VSTREAM *);
-extern void smtp_fread(VSTRING *, ssize_t len, VSTREAM *);
+extern void smtp_fread_buf(VSTRING *, ssize_t len, VSTREAM *);
 extern void smtp_fputc(int, VSTREAM *);
 
 extern void smtp_vprintf(VSTREAM *, const char *, va_list);
index 23baaa76d102319dfbd82a564a729b086d33f5bc..6dfe94c7ef7c517005873cdf1c3d2683dc50c6d2 100644 (file)
@@ -235,9 +235,7 @@ static ssize_t read_buf(VSTREAM *fp, VSTRING *buf)
 {
     ssize_t len;
 
-    VSTRING_RESET(buf);
-    len = vstream_fread(fp, STR(buf), vstring_avail(buf));
-    VSTRING_AT_OFFSET(buf, len);               /* XXX */
+    len = vstream_fread_buf(fp, buf, BUFLEN);
     VSTRING_TERMINATE(buf);
     return (len);
 }
index 90b355dc9c298624d5185b51cf5cad3f42a7b211..e0d3ed598d6780e12ab0428acfbf47201c818da7 100644 (file)
@@ -155,9 +155,7 @@ static ssize_t read_buf(VSTREAM *fp, VSTRING *buf)
 {
     ssize_t len;
 
-    VSTRING_RESET(buf);
-    len = vstream_fread(fp, STR(buf), vstring_avail(buf));
-    VSTRING_AT_OFFSET(buf, len);               /* XXX */
+    len = vstream_fread_buf(fp, buf, BUFLEN);
     VSTRING_TERMINATE(buf);
     return (len);
 }
index 47966da46437d82629b87ab2906c82de52b68966..57abc3b21620740812e9eebca1320c2cda51381b 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */
@@ -663,14 +668,11 @@ static int vmilter8_read_data(MILTER8 *milter, ssize_t *data_len, va_list ap)
                return (milter8_comm_error(milter));
            }
            buf = va_arg(ap, VSTRING *);
-           VSTRING_RESET(buf);
-           VSTRING_SPACE(buf, *data_len);
-           if (vstream_fread(milter->fp, (void *) STR(buf), *data_len)
+           if (vstream_fread_buf(milter->fp, buf, *data_len)
                != *data_len) {
                msg_warn("milter %s: EOF while reading data: %m", milter->m.name);
                return (milter8_comm_error(milter));
            }
-           VSTRING_AT_OFFSET(buf, *data_len);
            *data_len = 0;
            break;
 
index 3b73e88660873ed8f1f6dafac78754c42020215f..6983b17b11d7273c3977a90915ebef506cc0a8f0 100644 (file)
@@ -280,8 +280,10 @@ int     smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
      */
     if ((mp = vstream_memopen(endp_prop, O_WRONLY)) == 0
        || attr_print_plain(mp, ATTR_FLAG_NONE,
+#ifdef USE_TLS
                            SEND_ATTR_INT(SESS_ATTR_TLS_LEVEL,
                                          session->state->tls->level),
+#endif
                            SEND_ATTR_INT(SESS_ATTR_REUSE_COUNT,
                                          session->reuse_count),
                            SEND_ATTR_INT(SESS_ATTR_ENDP_FEATURES,
@@ -329,9 +331,9 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter,
     int     dest_features;             /* server features */
     long    expire_time;               /* session re-use expiration time */
     int     reuse_count;               /* # times reused */
-    TLS_SESS_STATE *tls_context = 0;
 
 #ifdef USE_TLS
+    TLS_SESS_STATE *tls_context = 0;
     SMTP_TLS_POLICY *tls = iter->parent->tls;
 
 #endif
@@ -348,8 +350,10 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter,
      */
     if ((mp = vstream_memopen(endp_prop, O_RDONLY)) == 0
        || attr_scan_plain(mp, ATTR_FLAG_NONE,
+#ifdef USE_TLS
                           RECV_ATTR_INT(SESS_ATTR_TLS_LEVEL,
                                         &tls->level),
+#endif
                           RECV_ATTR_INT(SESS_ATTR_REUSE_COUNT,
                                         &reuse_count),
                           RECV_ATTR_INT(SESS_ATTR_ENDP_FEATURES,
index c974864b644d56bb3d5b480fb6afe5d47d093b90..6d03c486afb1bc114eaa1a0f7b8d1fe84629b641 100644 (file)
@@ -3727,10 +3727,9 @@ static int skip_bdat(SMTPD_STATE *state, off_t chunk_size,
      * connection in case of overload.
      */
     for (done = 0; done < chunk_size; done += len) {
-       VSTRING_RESET(state->buffer);
        if ((len = chunk_size - done) > VSTREAM_BUFSIZE)
            len = VSTREAM_BUFSIZE;
-       smtp_fread(state->buffer, len, state->client);
+       smtp_fread_buf(state->buffer, len, state->client);
     }
 
     /*
@@ -3918,12 +3917,17 @@ static int bdat_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
      */
     done = 0;
     do {
+
+       /*
+        * Do not skip the smtp_fread_buf() call if read_len == 0. We still
+        * need the side effects which include resetting the buffer write
+        * position. Skipping the call would invalidate the buffer state.
+        * 
+        * Caution: smtp_fread_buf() will long jump after EOF or timeout.
+        */
        if ((read_len = chunk_size - done) > VSTREAM_BUFSIZE)
            read_len = VSTREAM_BUFSIZE;
-       /* Caution: smtp_fread() makes a long jump in case of EOF or timeout. */
-       VSTRING_RESET(state->buffer);
-       if (read_len > 0)
-           smtp_fread(state->buffer, read_len, state->client);
+       smtp_fread_buf(state->buffer, read_len, state->client);
        state->bdat_get_stream = vstream_memreopen(
                           state->bdat_get_stream, state->buffer, O_RDONLY);
 
index 64e88ff112c63e745aaf0577a711399d3a37ff3f..05253ec7eebfed9a8be64ba364ea0fdeadb6af41 100644 (file)
@@ -1009,15 +1009,14 @@ static void tlsp_get_fd_event(int event, void *context)
  /*
   * Macro for readability.
   */
-#define TLSP_CLIENT_INIT(ctx, props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
+#define TLSP_CLIENT_INIT(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
     a10, a11, a12, a13) \
-    tlsp_client_init((ctx), TLS_CLIENT_INIT_ARGS((props), a1, a2, a3, a4, \
+    tlsp_client_init(TLS_CLIENT_INIT_ARGS((props), a1, a2, a3, a4, \
     a5, a6, a7, a8, a9, a10, a11, a12, a13))
 
 /* tlsp_client_init - initialize a TLS client engine */
 
-static int tlsp_client_init(TLS_APPL_STATE **client_appl_state,
-                                   TLS_CLIENT_INIT_PROPS *init_props)
+static TLS_APPL_STATE *tlsp_client_init(TLS_CLIENT_INIT_PROPS *init_props)
 {
     TLS_APPL_STATE *appl_state;
     VSTRING *buf;
@@ -1070,8 +1069,8 @@ static int tlsp_client_init(TLS_APPL_STATE **client_appl_state,
                 "making this tls_client_init request, 2) configure a "
                 "custom tlsproxy service with tlsproxy_client_* settings "
                 "that match that SMTP client, and 3) configure that SMTP "
-                "client with a tlsproxy_service setting that resolves to "
-                "that custom tlsproxy service");
+                "client with a tlsproxy_service_name setting that resolves "
+                "to that custom tlsproxy service");
     }
 
     /*
@@ -1099,9 +1098,8 @@ static int tlsp_client_init(TLS_APPL_STATE **client_appl_state,
                             SSL_MODE_ENABLE_PARTIAL_WRITE
                             | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
     }
-    *client_appl_state = appl_state;
     vstring_free(buf);
-    return (appl_state != 0);
+    return (appl_state);
 }
 
 /* tlsp_close_event - pre-handshake plaintext-client close event */
@@ -1197,7 +1195,8 @@ static void tlsp_get_request_event(int event, void *context)
            tlsp_state_free(state);
            return;
        }
-       ready = tlsp_client_init(&state->appl_state, state->client_init_props);
+       state->appl_state = tlsp_client_init(state->client_init_props);
+       ready = state->appl_state != 0;
        break;
     case TLS_PROXY_FLAG_ROLE_SERVER:
        state->is_server_role = 1;
@@ -1468,7 +1467,8 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
         * Large parameter lists are error-prone, so we emulate a language
         * feature that C does not have natively: named parameter lists.
         */
-       if (TLSP_CLIENT_INIT(&tlsp_client_ctx, &props,
+       tlsp_client_ctx =
+           TLSP_CLIENT_INIT(&props,
                             log_param = var_tlsp_clnt_logparam,
                             log_level = var_tlsp_clnt_loglevel,
                             verifydepth = var_tlsp_clnt_scert_vd,
@@ -1481,7 +1481,8 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
                             eckey_file = var_tlsp_clnt_eckey_file,
                             CAfile = var_tlsp_clnt_CAfile,
                             CApath = var_tlsp_clnt_CApath,
-                            mdalg = var_tlsp_clnt_fpt_dgst) == 0)
+                            mdalg = var_tlsp_clnt_fpt_dgst);
+       if (tlsp_client_ctx == 0)
            msg_warn("TLS client initialization failed");
     }
 
index 809af9f65a20fe0d89f74ff6c47c47590398c9c1..57a84dea351782e1d32fb1c3cad16682a3dc67ca 100644 (file)
 /*     void    dict_file_purge_buffers(
 /*     DICT    *dict)
 /* DESCRIPTION
-/*     dict_file_to_buf() reads the content of the specified
-/*     files, with names separated by CHARS_COMMA_SP, while inserting
-/*     a gratuitous newline character between files.
-/*     It returns a pointer to a buffer which is owned by the DICT,
-/*     or a null pointer in case of error.
+/*     dict_file_to_buf() reads the content of the specified files,
+/*     with names separated by CHARS_COMMA_SP, while inserting a
+/*     gratuitous newline character between files. It returns a
+/*     pointer to a buffer which is owned by the DICT, or a null
+/*     pointer in case of error.
 /*
-/*     dict_file_to_b64() reads the content of the specified
-/*     files, with names separated by CHARS_COMMA_SP, while inserting
-/*     a gratuitous newline character between files,
-/*     and converts the result to base64.
-/*     It returns a pointer to a buffer which is owned by the DICT,
-/*     or a null pointer in case of error.
+/*     dict_file_to_b64() invokes dict_file_to_buf() and converts
+/*     the result to base64. It returns a pointer to a buffer which
+/*     is owned by the DICT, or a null pointer in case of error.
 /*
 /*     dict_file_from_b64() converts a value from base64. It returns
 /*     a pointer to a buffer which is owned by the DICT, or a null
@@ -121,14 +118,11 @@ VSTRING *dict_file_to_buf(DICT *dict, const char *pathnames)
            vstring_sprintf(dict->file_buf, "file too large: %s", pathnames);
            DICT_FILE_ERR_RETURN;
        }
-       VSTRING_SPACE(dict->file_buf, st.st_size);
-       if (vstream_fread(fp, STR(dict->file_buf) + LEN(dict->file_buf),
-                         st.st_size) != st.st_size) {
+       if (vstream_fread_app(fp, dict->file_buf, st.st_size) != st.st_size) {
            vstring_sprintf(dict->file_buf, "read %s: %m", *cpp);
            DICT_FILE_ERR_RETURN;
        }
        (void) vstream_fclose(fp);
-       VSTRING_AT_OFFSET(dict->file_buf, LEN(dict->file_buf) + st.st_size);
        if (cpp[1] != 0)
            VSTRING_ADDCH(dict->file_buf, '\n');
     }
index 08d4746b540d44007491ff1cbbbdecf474d5877d..7089385dadf25405eb86568a59d8dbb88df6753d 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */
@@ -119,9 +124,7 @@ static ssize_t read_buf(VSTREAM *fp, VSTRING *buf)
 {
     ssize_t len;
 
-    VSTRING_RESET(buf);
-    len = vstream_fread(fp, STR(buf), vstring_avail(buf));
-    VSTRING_AT_OFFSET(buf, len);               /* XXX */
+    len = vstream_fread_buf(fp, buf, BUFLEN);
     VSTRING_TERMINATE(buf);
     return (len);
 }
index 1865197ead8ef4e031f58d85f2a3b1daf71af9da..fae8757dc553bad01f497ac747e0b25f3d16af95 100644 (file)
@@ -231,16 +231,10 @@ VSTRING *netstring_get_data(VSTREAM *stream, VSTRING *buf, ssize_t len)
 {
     const char *myname = "netstring_get_data";
 
-    /*
-     * Allocate buffer space.
-     */
-    VSTRING_RESET(buf);
-    VSTRING_SPACE(buf, len);
-
     /*
      * Read the payload and absorb the terminator.
      */
-    if (vstream_fread(stream, STR(buf), len) != len)
+    if (vstream_fread_buf(stream, buf, len) != len)
        netstring_except(stream, vstream_ftimeout(stream) ?
                         NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
     if (msg_verbose > 1)
@@ -249,9 +243,8 @@ VSTRING *netstring_get_data(VSTREAM *stream, VSTRING *buf, ssize_t len)
     netstring_get_terminator(stream);
 
     /*
-     * Position the buffer.
+     * Return the buffer.
      */
-    VSTRING_AT_OFFSET(buf, len);
     return (buf);
 }
 
index 7af288271cd78f08bf99a6676f73c1b34d2c6757..513a561ab349a18861ac03b953aee7e1bbff24f6 100644 (file)
 /*
 /*     ssize_t vstream_fwrite(stream, buf, len)
 /*     VSTREAM *stream;
-/*     const void *buf;
+/*     void *buf;
+/*     ssize_t len;
+/*
+/*     ssize_t vstream_fread_app(stream, buf, len)
+/*     VSTREAM *stream;
+/*     VSTRING *buf;
+/*     ssize_t len;
+/*
+/*     ssize_t vstream_fread_buf(stream, buf, len)
+/*     VSTREAM *stream;
+/*     VSTRING *buf;
 /*     ssize_t len;
 /*
 /*     void    vstream_control(stream, name, ...)
 /*     transferred. A short count is returned in case of end-of-file
 /*     or error conditions.
 /*
+/*     vstream_fread_buf() resets the buffer write position,
+/*     allocates space for the specified number of bytes in the
+/*     buffer, reads the bytes from the specified VSTREAM, and
+/*     adjusts the buffer write position. The buffer is NOT
+/*     null-terminated. The result value is as with vstream_fread().
+/*      NOTE: do not skip calling vstream_fread_buf() when len == 0.
+/*      This function has side effects including resetting the buffer
+/*      write position, and skipping the call would invalidate the
+/*      buffer state.
+/*
+/*     vstream_fread_app() is like vstream_fread_buf() but appends
+/*     to existing buffer content, instead of writing over it.
+/*
 /*     vstream_control() allows the user to fine tune the behavior of
 /*     the specified stream.  The arguments are a list of macros with
 /*     zero or more arguments, terminated with CA_VSTREAM_CTL_END
@@ -1456,6 +1479,33 @@ int     vstream_fputs(const char *str, VSTREAM *stream)
     return (0);
 }
 
+/* vstream_fread_buf - unformatted read to VSTRING */
+
+ssize_t vstream_fread_buf(VSTREAM *fp, VSTRING *vp, ssize_t len)
+{
+    ssize_t ret;
+
+    VSTRING_RESET(vp);
+    VSTRING_SPACE(vp, len);
+    ret = vstream_fread(fp, vstring_str(vp), len);
+    if (ret > 0)
+       VSTRING_AT_OFFSET(vp, ret);
+    return (ret);
+}
+
+/* vstream_fread_app - unformatted read to VSTRING */
+
+ssize_t vstream_fread_app(VSTREAM *fp, VSTRING *vp, ssize_t len)
+{
+    ssize_t ret;
+
+    VSTRING_SPACE(vp, len);
+    ret = vstream_fread(fp, vstring_end(vp), len);
+    if (ret > 0)
+       VSTRING_AT_OFFSET(vp, VSTRING_LEN(vp) + ret);
+    return (ret);
+}
+
 /* vstream_control - fine control */
 
 void    vstream_control(VSTREAM *stream, int name,...)
index 60197a77a858bf625da9a40d2f0512cfc0dd08dd..6f99cf0dbb57eeacd83fa06867a926001c6865ba 100644 (file)
@@ -132,6 +132,8 @@ extern int vstream_fdclose(VSTREAM *);
 
 #define vstream_fstat(vp, fl)  ((vp)->buf.flags & (fl))
 
+extern ssize_t vstream_fread_buf(VSTREAM *, struct VSTRING *, ssize_t);
+extern ssize_t vstream_fread_app(VSTREAM *, struct VSTRING *, ssize_t);
 extern void vstream_control(VSTREAM *, int,...);
 
 /* Legacy API: type-unchecked arguments, internal use. */