* lib/tmpdir.c (path_search_alloc): Define new function similar to path_search, but which allocates the buffer for the result instead of relying on the caller to preallocate it. *lib/tmpdir.h (path_search_alloc): Declare it. --- lib/tmpdir.c | 127 +++++++++++++++++++++++++++++++++++---------------- lib/tmpdir.h | 6 +++ 2 files changed, 93 insertions(+), 40 deletions(-)
diff --git a/lib/tmpdir.c b/lib/tmpdir.c index 28ff99f58..70ab7007f 100644 --- a/lib/tmpdir.c +++ b/lib/tmpdir.c @@ -83,43 +83,23 @@ direxists (const char *dir) return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); } -/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is - non-null and exists, uses it; otherwise uses the first of $TMPDIR, - P_tmpdir, /tmp that exists. Copies into TMPL a template suitable - for use with mk[s]temp. Will fail (-1) if DIR is non-null and - doesn't exist, none of the searched dirs exists, or there's not - enough space in TMPL. */ -int -path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, - bool try_tmpdir) + +static int +__path_search (char *tmpl, const char **dirx, const char *pfx, bool try_tmpdir) { const char *d; - size_t dlen, plen; - bool add_slash; - - if (!pfx || !pfx[0]) - { - pfx = "file"; - plen = 4; - } - else - { - plen = strlen (pfx); - if (plen > 5) - plen = 5; - } if (try_tmpdir) { d = __libc_secure_getenv ("TMPDIR"); if (d != NULL && direxists (d)) - dir = d; - else if (dir != NULL && direxists (dir)) + *dirx = d; + else if (*dirx != NULL && direxists (*dirx)) /* nothing */ ; else - dir = NULL; + *dirx = NULL; } - if (dir == NULL) + if (*dirx == NULL) { #if defined _WIN32 && ! defined __CYGWIN__ char dirbuf[PATH_MAX]; @@ -131,26 +111,63 @@ path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, directory (unless $TMPDIR is set). */ retval = GetTempPath (PATH_MAX, dirbuf); if (retval > 0 && retval < PATH_MAX && direxists (dirbuf)) - dir = dirbuf; + *dirx = dirbuf; else #endif - if (direxists (P_tmpdir)) - dir = P_tmpdir; - else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) - dir = "/tmp"; - else - { - __set_errno (ENOENT); - return -1; - } + if (direxists (P_tmpdir)) + *dirx = P_tmpdir; + else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) + *dirx = "/tmp"; + else + { + __set_errno (ENOENT); + return -1; + } } - dlen = strlen (dir); + return 0; +} + +static void +__impute_lengths (const char *pfx, const char *dir, size_t *plen, size_t *dlen, bool *add_slash) +{ + if (!pfx || !pfx[0]) + { + pfx = "file"; + *plen = 4; + } + else + { + *plen = strlen (pfx); + if (*plen > 5) + *plen = 5; + } + + *dlen = strlen (dir); #ifdef __VMS - add_slash = 0; + *add_slash = 0; #else - add_slash = dlen != 0 && !ISSLASH (dir[dlen - 1]); + *add_slash = *dlen != 0 && !ISSLASH (dir[*dlen - 1]); #endif +} + +/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is + non-null and exists, uses it; otherwise uses the first of $TMPDIR, + P_tmpdir, /tmp that exists. Copies into TMPL a template suitable + for use with mk[s]temp. Will fail (-1) if DIR is non-null and + doesn't exist, none of the searched dirs exists, or there's not + enough space in TMPL. */ +int +path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, + bool try_tmpdir) +{ + if (0 != __path_search (tmpl, &dir, pfx, try_tmpdir)) + return -1; + + size_t plen; + size_t dlen; + bool add_slash; + __impute_lengths (pfx, dir, &plen, &dlen, &add_slash); /* check we have room for "${dir}/${pfx}XXXXXX\0" */ if (tmpl_len < dlen + add_slash + plen + 6 + 1) @@ -163,3 +180,33 @@ path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, sprintf (tmpl + dlen, &"/%.*sXXXXXX"[!add_slash], (int) plen, pfx); return 0; } + + +/* Like path_search, but this function will allocate TMPL and fill + TMPL_LEN with the allocated length. The caller must free TMPL when + no longer required. */ +int +path_search_alloc (char **tmpl, size_t *tmpl_len, const char *dir, const char *pfx, + bool try_tmpdir) +{ + if (0 != __path_search (*tmpl, &dir, pfx, try_tmpdir)) + return -1; + + size_t plen; + size_t dlen; + bool add_slash; + __impute_lengths (pfx, dir, &plen, &dlen, &add_slash); + + /* check we have room for "${dir}/${pfx}XXXXXX\0" */ + *tmpl = malloc (dlen + add_slash + plen + 6 + 1); + if (!*tmpl) + { + __set_errno (ENOMEM); + return -1; + } + *tmpl_len = dlen + add_slash + plen + 6 + 1; + + memcpy (*tmpl, dir, dlen); + sprintf (*tmpl + dlen, &"/%.*sXXXXXX"[!add_slash], (int) plen, pfx); + return 0; +} diff --git a/lib/tmpdir.h b/lib/tmpdir.h index 4d694a3d9..28c62fcc2 100644 --- a/lib/tmpdir.h +++ b/lib/tmpdir.h @@ -24,3 +24,9 @@ doesn't exist, none of the searched dirs exists, or there's not enough space in TMPL. */ extern int path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, bool try_tmpdir); + +/* Like path_search, except that TMPL is allocated automatically. + TMPL may not be null. *TMPL must be freed by the caller, when no longer needed. + After calling this function *TMPL_LEN will be set to the lenght of *TMPL. */ +extern int path_search_alloc (char **tmpl, size_t *tmpl_len, const char *dir, const char *pfx, + bool try_tmpdir); -- 2.20.1