+
+#if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY)
+/* exim_chown - in some NFSv4 setups *seemes* to be an issue with
+chown(<exim-uid>, <exim-gid>).
+
+Probably because the idmapping is broken, misconfigured or set up in
+an unusal way. (see Bug 2931). As I'm not sure, if this was a single
+case of misconfiguration, or if there are more such broken systems
+out, I try to impose as least impact as possible and for now just write
+a panic log entry pointing to the bug report. You're encouraged to
+contact the developers, if you experience this issue.
+
+fd the file descriptor (or -1 if not valid)
+name the file name for error messages or for file operations,
+ if fd is < 0
+owner the owner
+group the group
+
+returns 0 on success, -1 on failure */
+
+static inline int
+exim_fchown(int fd, uid_t owner, gid_t group, const uschar *name)
+{
+return fchown(fd, owner, group)
+ ? exim_chown_failure(fd, name, owner, group) : 0;
+}
+
+static inline int
+exim_chown(const uschar *name, uid_t owner, gid_t group)
+{
+return chown(CCS name, owner, group)
+ ? exim_chown_failure(-1, name, owner, group) : 0;
+}
+
+#endif /* !MACRO_PREDEF && !COMPILE_UTILITY */
+/******************************************************************************/
+/* String functions */
+
+#if !defined(MACRO_PREDEF)
+/*************************************************
+* Copy and save string *
+*************************************************/
+
+/* This function assumes that memcpy() is faster than strcpy().
+*/
+
+static inline uschar *
+string_copy_taint_trc(const uschar *s, BOOL tainted, const char * func, int line)
+{
+int len = Ustrlen(s) + 1;
+uschar *ss = store_get_3(len, tainted, func, line);
+memcpy(ss, s, len);
+return ss;
+}
+
+#define string_copy_taint(s, tainted) \
+ string_copy_taint_trc((s), tainted, __FUNCTION__, __LINE__)
+
+static inline uschar *
+string_copy(const uschar * s)
+{
+return string_copy_taint((s), is_tainted(s));
+}
+
+
+/*************************************************
+* Copy, lowercase and save string *
+*************************************************/
+
+/*
+Argument: string to copy
+Returns: copy of string in new store, with letters lowercased
+*/
+
+static inline uschar *
+string_copylc(const uschar *s)
+{
+uschar *ss = store_get(Ustrlen(s) + 1, is_tainted(s));
+uschar *p = ss;
+while (*s != 0) *p++ = tolower(*s++);
+*p = 0;
+return ss;
+}
+
+
+
+/*************************************************
+* Copy and save string, given length *
+*************************************************/
+
+/* It is assumed the data contains no zeros. A zero is added
+onto the end.
+
+Arguments:
+ s string to copy
+ n number of characters
+
+Returns: copy of string in new store
+
+This is an API for local_scan hence not static.
+*/
+
+static inline uschar *
+string_copyn(const uschar *s, int n)
+{
+uschar *ss = store_get(n + 1, is_tainted(s));
+Ustrncpy(ss, s, n);
+ss[n] = 0;
+return ss;
+}
+
+/*************************************************
+* Copy, lowercase, and save string, given length *
+*************************************************/
+
+/* It is assumed the data contains no zeros. A zero is added
+onto the end.
+
+Arguments:
+ s string to copy
+ n number of characters
+
+Returns: copy of string in new store, with letters lowercased
+*/
+
+static inline uschar *
+string_copynlc(uschar *s, int n)
+{
+uschar *ss = store_get(n + 1, is_tainted(s));
+uschar *p = ss;
+while (n-- > 0) *p++ = tolower(*s++);
+*p = 0;
+return ss;
+}
+
+
+# ifndef COMPILE_UTILITY
+/*************************************************
+* Copy and save string in longterm store *
+*************************************************/
+
+/* This function assumes that memcpy() is faster than strcpy().
+
+Argument: string to copy
+Returns: copy of string in new store
+*/
+
+static inline uschar *
+string_copy_perm(const uschar *s, BOOL force_taint)
+{
+int old_pool = store_pool;
+int len = Ustrlen(s) + 1;
+uschar *ss;
+
+store_pool = POOL_PERM;
+ss = store_get(len, force_taint || is_tainted(s));
+memcpy(ss, s, len);
+store_pool = old_pool;
+return ss;
+}
+# endif
+
+
+
+/* sprintf into a buffer, taint-unchecked */
+
+static inline void
+string_format_nt(uschar * buf, int siz, const char * fmt, ...)
+{
+gstring gs = { .size = siz, .ptr = 0, .s = buf };
+va_list ap;
+va_start(ap, fmt);
+(void) string_vformat(&gs, SVFMT_TAINT_NOCHK, fmt, ap);
+va_end(ap);
+}
+
+
+
+/******************************************************************************/
+/* Growable-string functions */
+
+/* Create a growable-string with some preassigned space */
+
+#define string_get_tainted(size, tainted) \
+ string_get_tainted_trc((size), (tainted), __FUNCTION__, __LINE__)
+
+static inline gstring *
+string_get_tainted_trc(unsigned size, BOOL tainted, const char * func, unsigned line)
+{
+gstring * g = store_get_3(sizeof(gstring) + size, tainted, func, line);
+g->size = size;
+g->ptr = 0;
+g->s = US(g + 1);
+return g;
+}
+
+#define string_get(size) \
+ string_get_trc((size), __FUNCTION__, __LINE__)
+
+static inline gstring *
+string_get_trc(unsigned size, const char * func, unsigned line)
+{
+return string_get_tainted_trc(size, FALSE, func, line);
+}
+
+/* NUL-terminate the C string in the growable-string, and return it. */
+
+static inline uschar *
+string_from_gstring(gstring * g)
+{
+if (!g) return NULL;
+g->s[g->ptr] = '\0';
+return g->s;
+}
+
+
+#define gstring_release_unused(g) \
+ gstring_release_unused_trc(g, __FUNCTION__, __LINE__)
+
+static inline void
+gstring_release_unused_trc(gstring * g, const char * file, unsigned line)
+{
+if (g) store_release_above_3(g->s + (g->size = g->ptr + 1), file, line);
+}
+
+
+/* sprintf-append to a growable-string */
+
+#define string_fmt_append(g, fmt, ...) \
+ string_fmt_append_f_trc(g, US __FUNCTION__, __LINE__, \
+ SVFMT_EXTEND|SVFMT_REBUFFER, fmt, __VA_ARGS__)
+
+#define string_fmt_append_f(g, flgs, fmt, ...) \
+ string_fmt_append_f_trc(g, US __FUNCTION__, __LINE__, \
+ flgs, fmt, __VA_ARGS__)
+
+static inline gstring *
+string_fmt_append_f_trc(gstring * g, const uschar * func, unsigned line,
+ unsigned flags, const char *format, ...)
+{
+va_list ap;
+va_start(ap, format);
+g = string_vformat_trc(g, func, line, STRING_SPRINTF_BUFFER_SIZE,
+ flags, format, ap);
+va_end(ap);
+return g;
+}
+
+/******************************************************************************/
+#endif /* !MACRO_PREDEF */
+
+#endif /* _FUNCTIONS_H_ */
+