+/* Allocate a new block big enough to expend to the given size and
+copy the current data into it. Free the old one if possible.
+
+This function is specifically provided for use when reading very
+long strings, e.g. header lines. When the string gets longer than a
+complete block, it gets copied to a new block. It is helpful to free
+the old block iff the previous copy of the string is at its start,
+and therefore the only thing in it. Otherwise, for very long strings,
+dead store can pile up somewhat disastrously. This function checks that
+the pointer it is given is the first thing in a block, and that nothing
+has been allocated since. If so, releases that block.
+
+Arguments:
+ block
+ newsize
+ len
+
+Returns: new location of data
+*/
+
+void *
+store_newblock_3(void * block, BOOL tainted, int newsize, int len,
+ const char * func, int linenumber)
+{
+int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
+BOOL release_ok = !tainted && store_last_get[pool] == block;
+uschar * newtext;
+
+#if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY)
+if (is_tainted(block) != tainted)
+ die_tainted(US"store_newblock", CUS func, linenumber);
+#endif
+
+newtext = store_get(newsize, tainted);
+memcpy(newtext, block, len);
+if (release_ok) store_release_3(block, pool, func, linenumber);
+return (void *)newtext;
+}
+
+
+
+
+/******************************************************************************/
+static void *
+store_alloc_tail(void * yield, int size, const char * func, int line,
+ const uschar * type)
+{
+if ((nonpool_malloc += size) > max_nonpool_malloc)
+ max_nonpool_malloc = nonpool_malloc;
+
+/* Cut out the debugging stuff for utilities, but stop picky compilers from
+giving warnings. */
+
+#ifdef COMPILE_UTILITY
+func = func; line = line; type = type;
+#else
+
+/* If running in test harness, spend time making sure all the new store
+is not filled with zeros so as to catch problems. */
+
+if (f.running_in_test_harness)
+ memset(yield, 0xF0, (size_t)size);
+DEBUG(D_memory) debug_printf("--%6s %6p %5d bytes\t%-14s %4d\tpool %5d nonpool %5d\n",
+ type, yield, size, func, line, pool_malloc, nonpool_malloc);
+#endif /* COMPILE_UTILITY */
+
+return yield;
+}
+
+/*************************************************
+* Mmap store *
+*************************************************/
+
+static void *
+store_mmap(int size, const char * func, int line)
+{
+void * yield, * top;
+
+if (size < 16) size = 16;
+
+if (!(yield = mmap(NULL, (size_t)size,
+ PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)))
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to mmap %d bytes of memory: "
+ "called from line %d of %s", size, line, func);
+
+if (yield < tainted_base) tainted_base = yield;
+if ((top = US yield + size) > tainted_top) tainted_top = top;
+if (!f.taint_check_slow) use_slow_taint_check();
+
+return store_alloc_tail(yield, size, func, line, US"Mmap");
+}