From 77d4f6d1ed90a2ccb5bc6fd6d19f67f19de7fbcd Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Mon, 24 Nov 2014 11:30:36 -0800 Subject: Generalize __gen_tempname. --- ChangeLog | 29 ++++++++++++++++ include/stdio.h | 22 ++++++++---- libio/oldtmpfile.c | 4 ++- misc/mkdtemp.c | 18 ++++++++-- misc/mkostemp.c | 11 ++---- misc/mkostemp64.c | 6 ++-- misc/mkostemps.c | 12 ++----- misc/mkostemps64.c | 13 ++----- misc/mkstemp.c | 10 ++---- misc/mkstemp64.c | 6 ++-- misc/mkstemps.c | 16 ++------- misc/mkstemps64.c | 12 ++----- misc/mktemp.c | 5 ++- stdio-common/tempnam.c | 5 +-- stdio-common/tempname.c | 25 ++++++-------- stdio-common/tmpfile.c | 3 +- stdio-common/tmpnam.c | 6 ++-- stdio-common/tmpnam_r.c | 5 +-- sysdeps/posix/tempname.c | 90 ++++++++++++++++++++++-------------------------- 19 files changed, 148 insertions(+), 150 deletions(-) diff --git a/ChangeLog b/ChangeLog index dac4ad15de..e37e0f487a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2014-11-24 Roland McGrath + + * sysdeps/posix/tempname.c (__gen_tempname): Instead of FLAGS and KIND + arguments, take a function pointer TRY_NAME and void *TRY_NAME_ARG. + Call that *TRY_NAME to try a candidate name. + (__gen_tempname_try_nocreate, __gen_tempname_try_file): New functions. + * stdio-common/tempname.c (__gen_tempname): Update signature. + * include/stdio.h: Update decl. + (__GT_FILE, __GT_NOCREATE, __GT_DIR): Macros removed. + (__GT_FILE_DEFAULTS): New macro. + * stdio-common/tmpnam.c: Update caller. + * stdio-common/tmpnam_r.c: Likewise. + * stdio-common/tmpfile.c: Likewise. + * misc/mktemp.c (__mktemp): Prototypify. Update caller. + * libio/oldtmpfile.c (__old_tmpfile): Update caller. + * misc/mkostemp.c: Prototypify. Update caller. + * misc/mkstemp.c: Likewise. + * misc/mkostemps.c: Likewise. + * misc/mkstemp64.c: Likewise. + * misc/mkdtemp.c (try_mkdir): New function. + (mkdtemp): Use it with new __gen_tempname signature. Prototypify. + * misc/mkostemp.c: Prototypify. Just call mkostemps. + * misc/mkstemps.c: Likewise. + * misc/mkstemps64.c: Likewise. + * misc/mkostemp64.c: Prototypify. + Just call mkostemp with modified flags. + * misc/mkostemps64.c: Prototypify. + Just call mkostemps with modified flags. + 2014-11-24 Ryan Cumming [BZ #17608] diff --git a/include/stdio.h b/include/stdio.h index 0010607949..327c7525a1 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -82,12 +82,22 @@ extern int __path_search (char *__tmpl, size_t __tmpl_len, const char *__dir, const char *__pfx, int __try_tempdir); -extern int __gen_tempname (char *__tmpl, int __suffixlen, int __flags, - int __kind); -/* The __kind argument to __gen_tempname may be one of: */ -# define __GT_FILE 0 /* create a file */ -# define __GT_DIR 1 /* create a directory */ -# define __GT_NOCREATE 2 /* just find a name not currently in use */ +/* The *TRY_NAME function is called repeatedly on candidate names until + it returns >= 0. If it returns -2, the next candidate name is tried. + If it returns -1 (with errno set), __gen_tempname fails immediately. */ +extern int __gen_tempname (char *__tmpl, int __suffixlen, + int (*__try_name) (const char *__name, void *__arg), + void *__try_name_arg); + +/* These are the common TRY_NAME functions. */ + +/* ARG is ignored. */ +extern int __gen_tempname_try_nocreate (const char *__name, void *__arg); + +/* ARG is int[2] of {flags, mode}. */ +extern int __gen_tempname_try_file (const char *__name, void *__arg); +#define __GT_FILE_DEFAULTS (&((int[2]) { 0, 0600 })) + /* Print out MESSAGE on the error output and abort. */ extern void __libc_fatal (const char *__message) diff --git a/libio/oldtmpfile.c b/libio/oldtmpfile.c index a6a5e71ae5..3c3af9c3ad 100644 --- a/libio/oldtmpfile.c +++ b/libio/oldtmpfile.c @@ -37,7 +37,9 @@ __old_tmpfile (void) if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0)) return NULL; - fd = __gen_tempname (buf, 0, 0, __GT_FILE); + + int flags_and_mode[2] = { 0, 0 }; + fd = __gen_tempname (buf, 0, &__gen_tempname_try_file, __GT_FILE_DEFAULTS); if (fd < 0) return NULL; diff --git a/misc/mkdtemp.c b/misc/mkdtemp.c index 6bd72cab49..302d2730f8 100644 --- a/misc/mkdtemp.c +++ b/misc/mkdtemp.c @@ -15,8 +15,21 @@ License along with the GNU C Library; if not, see . */ +#include #include #include +#include + + +static int +try_mkdir (const char *name, void *arg __attribute__ ((unused))) +{ + int result = __mkdir (name, S_IRUSR | S_IWUSR | S_IXUSR); + if (result < 0 && errno == EEXIST) + /* Nothing funny went wrong, it just already exists. Keep looking. */ + result = -2; + return result; +} /* Generate a unique temporary directory from TEMPLATE. The last six characters of TEMPLATE must be "XXXXXX"; @@ -24,10 +37,9 @@ The directory is created, mode 700, and its name is returned. (This function comes from OpenBSD.) */ char * -mkdtemp (template) - char *template; +mkdtemp (char *template) { - if (__gen_tempname (template, 0, 0, __GT_DIR)) + if (__gen_tempname (template, 0, &try_mkdir, NULL)) return NULL; else return template; diff --git a/misc/mkostemp.c b/misc/mkostemp.c index f0dc3c1b0d..695e87a95e 100644 --- a/misc/mkostemp.c +++ b/misc/mkostemp.c @@ -17,21 +17,16 @@ #include #include - -#ifndef __GT_FILE -# define __GT_FILE 0 -#endif +#include /* Generate a unique temporary file name from TEMPLATE. The last six characters of TEMPLATE must be "XXXXXX"; they are replaced with a string that makes the filename unique. Then open the file and return a fd. */ int -mkostemp (template, flags) - char *template; - int flags; +mkostemp (char *template, int flags) { - return __gen_tempname (template, 0, flags, __GT_FILE); + return mkostemps (template, 0, flags); } #if !defined O_LARGEFILE || O_LARGEFILE == 0 diff --git a/misc/mkostemp64.c b/misc/mkostemp64.c index c68e03dff5..a7bf00d9ef 100644 --- a/misc/mkostemp64.c +++ b/misc/mkostemp64.c @@ -27,11 +27,9 @@ they are replaced with a string that makes the filename unique. Then open the file and return a fd. */ int -mkostemp64 (template, flags) - char *template; - int flags; +mkostemp64 (char *template, int flags) { - return __gen_tempname (template, 0, flags | O_LARGEFILE, __GT_FILE); + return mkostemp (template, flags | O_LARGEFILE); } #endif diff --git a/misc/mkostemps.c b/misc/mkostemps.c index 2f9745ce14..330ff6c53d 100644 --- a/misc/mkostemps.c +++ b/misc/mkostemps.c @@ -19,19 +19,12 @@ #include #include -#ifndef __GT_FILE -# define __GT_FILE 0 -#endif - /* Generate a unique temporary file name from TEMPLATE. The last six characters before a suffix of length SUFFIXLEN of TEMPLATE must be "XXXXXX"; they are replaced with a string that makes the filename unique. Then open the file and return a fd. */ int -mkostemps (template, suffixlen, flags) - char *template; - int suffixlen; - int flags; +mkostemps (char *template, int suffixlen, int flags) { if (suffixlen < 0) { @@ -39,7 +32,8 @@ mkostemps (template, suffixlen, flags) return -1; } - return __gen_tempname (template, suffixlen, flags, __GT_FILE); + return __gen_tempname (template, suffixlen, &__gen_tempname_try_file, + &((int[2]) { flags, S_IRUSR | S_IWUSR })); } #if !defined O_LARGEFILE || O_LARGEFILE == 0 diff --git a/misc/mkostemps64.c b/misc/mkostemps64.c index 1d1d3faf2f..971afc22e9 100644 --- a/misc/mkostemps64.c +++ b/misc/mkostemps64.c @@ -28,18 +28,9 @@ "XXXXXX"; they are replaced with a string that makes the filename unique. Then open the file and return a fd. */ int -mkostemps64 (template, suffixlen, flags) - char *template; - int suffixlen; - int flags; +mkostemps64 (char *template, int suffixlen, int flags) { - if (suffixlen < 0) - { - __set_errno (EINVAL); - return -1; - } - - return __gen_tempname (template, suffixlen, flags | O_LARGEFILE, __GT_FILE); + return mkostemps (template, sufflixen, flags | O_LARGEFILE); } #endif diff --git a/misc/mkstemp.c b/misc/mkstemp.c index a01095b3b7..8657924806 100644 --- a/misc/mkstemp.c +++ b/misc/mkstemp.c @@ -18,19 +18,15 @@ #include #include -#ifndef __GT_FILE -# define __GT_FILE 0 -#endif - /* Generate a unique temporary file name from TEMPLATE. The last six characters of TEMPLATE must be "XXXXXX"; they are replaced with a string that makes the filename unique. Then open the file and return a fd. */ int -mkstemp (template) - char *template; +mkstemp (char *template) { - return __gen_tempname (template, 0, 0, __GT_FILE); + return __gen_tempname (template, 0, + &__gen_tempname_try_file, __GT_FILE_DEFAULTS); } #if !defined O_LARGEFILE || O_LARGEFILE == 0 diff --git a/misc/mkstemp64.c b/misc/mkstemp64.c index 3ca465722f..e15c7d6ad3 100644 --- a/misc/mkstemp64.c +++ b/misc/mkstemp64.c @@ -27,10 +27,10 @@ they are replaced with a string that makes the filename unique. Then open the file and return a fd. */ int -mkstemp64 (template) - char *template; +mkstemp64 (char *template) { - return __gen_tempname (template, 0, O_LARGEFILE, __GT_FILE); + return __gen_tempname (template, 0, &__gen_tempname_try_file, + (&((int[2]) { O_LARGEFILE, 0600 }))); } #endif diff --git a/misc/mkstemps.c b/misc/mkstemps.c index d58fce36da..3f2c01e488 100644 --- a/misc/mkstemps.c +++ b/misc/mkstemps.c @@ -19,26 +19,14 @@ #include #include -#ifndef __GT_FILE -# define __GT_FILE 0 -#endif - /* Generate a unique temporary file name from TEMPLATE. The last six characters before a suffix of length SUFFIXLEN of TEMPLATE must be "XXXXXX"; they are replaced with a string that makes the filename unique. Then open the file and return a fd. */ int -mkstemps (template, suffixlen) - char *template; - int suffixlen; +mkstemps (char *template, int suffixlen) { - if (suffixlen < 0) - { - __set_errno (EINVAL); - return -1; - } - - return __gen_tempname (template, suffixlen, 0, __GT_FILE); + return mkostemps (template, suffixlen, 0); } #if !defined O_LARGEFILE || O_LARGEFILE == 0 diff --git a/misc/mkstemps64.c b/misc/mkstemps64.c index 1b0f024257..d3d7013504 100644 --- a/misc/mkstemps64.c +++ b/misc/mkstemps64.c @@ -28,17 +28,9 @@ "XXXXXX"; they are replaced with a string that makes the filename unique. Then open the file and return a fd. */ int -mkstemps64 (template, suffixlen) - char *template; - int suffixlen; +mkstemps64 (char *template, int suffixlen) { - if (suffixlen < 0) - { - __set_errno (EINVAL); - return -1; - } - - return __gen_tempname (template, suffixlen, O_LARGEFILE, __GT_FILE); + return mkostemps (template, suffixlen, O_LARGEFILE); } #endif diff --git a/misc/mktemp.c b/misc/mktemp.c index a60f95c067..737e329fc3 100644 --- a/misc/mktemp.c +++ b/misc/mktemp.c @@ -22,10 +22,9 @@ The last six characters of TEMPLATE must be "XXXXXX"; they are replaced with a string that makes the filename unique. */ char * -__mktemp (template) - char *template; +__mktemp (char *template) { - if (__gen_tempname (template, 0, 0, __GT_NOCREATE) < 0) + if (__gen_tempname (template, 0, &__gen_tempname_try_nocreate, NULL) < 0) /* We return the null string if we can't find a unique file name. */ template[0] = '\0'; diff --git a/stdio-common/tempnam.c b/stdio-common/tempnam.c index dcbb0a92ee..1c17a467bd 100644 --- a/stdio-common/tempnam.c +++ b/stdio-common/tempnam.c @@ -30,10 +30,11 @@ tempnam (const char *dir, const char *pfx) { char buf[FILENAME_MAX]; - if (__path_search (buf, FILENAME_MAX, dir, pfx, 1)) + if (__glibc_unlikely (__path_search (buf, sizeof buf, dir, pfx, 1))) return NULL; - if (__gen_tempname (buf, 0, 0, __GT_NOCREATE)) + if (__glibc_unlikely (__gen_tempname (buf, 0, + __gen_tempname_try_nocreate, NULL))) return NULL; return __strdup (buf); diff --git a/stdio-common/tempname.c b/stdio-common/tempname.c index 7eeb089f14..18e6d35237 100644 --- a/stdio-common/tempname.c +++ b/stdio-common/tempname.c @@ -36,21 +36,18 @@ __path_search (tmpl, tmpl_len, dir, pfx, try_tmpdir) } stub_warning (__path_search) -/* Generate a (hopefully) unique temporary filename - in DIR (if applicable), using template TMPL. - KIND determines what to do with that name. It may be one of: - __GT_FILE: create a file and return a read-write fd. - __GT_BIGFILE: same, but use open64() (or equivalent). - __GT_DIR: create a directory. - __GT_NOCREATE: just find a name not currently in use. - */ - +/* Generate a temporary file name based on TMPL. TMPL must match the + rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix). + The name constructed does not exist at the time of the call to + __gen_tempname. TMPL is overwritten with the result. + + The *TRY_NAME function is called repeatedly on candidate names until + it returns >= 0. If it returns -2, the next candidate name is tried. + If it returns -1 (with errno set), __gen_tempname fails immediately. */ int -__gen_tempname (tmpl, suffixlen, flags, kind) - char *tmpl; - int suffixlen; - int flags; - int kind; +__gen_tempname (char *tmpl, int suffixlen, + int (*try_name) (const char *name, void *arg), + void *try_name_arg) { __set_errno (ENOSYS); return -1; diff --git a/stdio-common/tmpfile.c b/stdio-common/tmpfile.c index 022c2f650b..89689a625f 100644 --- a/stdio-common/tmpfile.c +++ b/stdio-common/tmpfile.c @@ -44,7 +44,8 @@ tmpfile (void) #ifdef FLAGS flags = FLAGS; #endif - fd = __gen_tempname (buf, 0, flags, __GT_FILE); + fd = __gen_tempname (buf, 0, &__gen_tempname_try_file, + &((int[2]) { flags, S_IRUSR | S_IWUSR })); if (fd < 0) return NULL; diff --git a/stdio-common/tmpnam.c b/stdio-common/tmpnam.c index d8cd50907f..810d0ff176 100644 --- a/stdio-common/tmpnam.c +++ b/stdio-common/tmpnam.c @@ -34,11 +34,11 @@ tmpnam (char *s) /* In the following call we use the buffer pointed to by S if non-NULL although we don't know the size. But we limit the size to L_tmpnam characters in any case. */ - if (__builtin_expect (__path_search (tmpbuf, L_tmpnam, NULL, NULL, 0), - 0)) + if (__glibc_unlikely (__path_search (tmpbuf, L_tmpnam, NULL, NULL, 0))) return NULL; - if (__glibc_unlikely (__gen_tempname (tmpbuf, 0, 0, __GT_NOCREATE))) + if (__glibc_unlikely (__gen_tempname (tmpbuf, 0, + __gen_tempname_try_nocreate, NULL))) return NULL; if (s == NULL) diff --git a/stdio-common/tmpnam_r.c b/stdio-common/tmpnam_r.c index aa2e24e732..ad7cc543f3 100644 --- a/stdio-common/tmpnam_r.c +++ b/stdio-common/tmpnam_r.c @@ -25,9 +25,10 @@ tmpnam_r (char *s) if (s == NULL) return NULL; - if (__path_search (s, L_tmpnam, NULL, NULL, 0)) + if (__glibc_unlikely (__path_search (s, L_tmpnam, NULL, NULL, 0))) return NULL; - if (__gen_tempname (s, 0, 0, __GT_NOCREATE)) + if (__glibc_unlikely (__gen_tempname (s, 0, + __gen_tempname_try_nocreate, NULL))) return NULL; return s; diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c index 3aa11b044b..b3d4ae7b66 100644 --- a/sysdeps/posix/tempname.c +++ b/sysdeps/posix/tempname.c @@ -180,25 +180,22 @@ static const char letters[] = The name constructed does not exist at the time of the call to __gen_tempname. TMPL is overwritten with the result. - KIND may be one of: - __GT_NOCREATE: simply verify that the name does not exist - at the time of the call. - __GT_FILE: create the file using open(O_CREAT|O_EXCL) - and return a read-write fd. The file is mode 0600. - __GT_DIR: create a directory, which will be mode 0700. + The *TRY_NAME function is called repeatedly on candidate names until + it returns >= 0. If it returns -2, the next candidate name is tried. + If it returns -1 (with errno set), __gen_tempname fails immediately. We use a clever algorithm to get hard-to-predict names. */ int -__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) +__gen_tempname (char *tmpl, int suffixlen, + int (*try_name) (const char *name, void *arg), + void *try_name_arg) { int len; char *XXXXXX; static uint64_t value; uint64_t random_time_bits; unsigned int count; - int fd = -1; int save_errno = errno; - struct_stat64 st; /* A lower bound on the number of temporary files to attempt to generate. The maximum total number of temporary file names that @@ -255,51 +252,46 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) v /= 62; XXXXXX[5] = letters[v % 62]; - switch (kind) - { - case __GT_FILE: - fd = __open (tmpl, - (flags & ~O_ACCMODE) - | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); - break; - - case __GT_DIR: - fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); - break; - - case __GT_NOCREATE: - /* This case is backward from the other three. __gen_tempname - succeeds if __xstat fails because the name does not exist. - Note the continue to bypass the common logic at the bottom - of the loop. */ - if (__lxstat64 (_STAT_VER, tmpl, &st) < 0) - { - if (errno == ENOENT) - { - __set_errno (save_errno); - return 0; - } - else - /* Give up now. */ - return -1; - } - continue; - - default: - assert (! "invalid KIND in __gen_tempname"); - abort (); - } - - if (fd >= 0) - { - __set_errno (save_errno); + int fd = (*try_name) (tmpl, try_name_arg); + if (fd != -2) + { + if (fd >= 0) + __set_errno (save_errno); return fd; } - else if (errno != EEXIST) - return -1; } /* We got out of the loop because we ran out of combinations to try. */ __set_errno (EEXIST); return -1; } + + +int +__gen_tempname_try_nocreate (const char *name, void *arg) +{ + struct stat64 st; + if (__lxstat64 (_STAT_VER, name, &st) == 0) + /* This name exists. Try another. */ + return -2; + return 0; +} + + +/* ARG is int[2] of {flags, mode}. */ +int +__gen_tempname_try_file (const char *name, void *arg) +{ + const int *args = arg; + int flags = args[0]; + mode_t mode = args[1]; + + int fd = __open (name, + (flags & ~O_ACCMODE) | O_RDWR | O_CREAT | O_EXCL, + mode); + if (fd < 0 && errno == EEXIST) + /* Nothing funny went wrong, it just already exists. Keep looking. */ + fd = -2; + + return fd; +} -- cgit 1.4.1