summaryrefslogtreecommitdiff
path: root/lib/tempname.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@gnu.org>2015-01-31 23:49:13 +0100
committerAndreas Gruenbacher <agruenba@schleppi.home>2015-02-04 10:49:13 +0100
commit56e31f06e11972fc8335152717c5cf7d07d40998 (patch)
tree854d967f3f32164cc575f43e5ce308891b20f81e /lib/tempname.c
parent6c8f206bb39e9d4c322d6f12d532f38c9df2dac3 (diff)
downloadgnulib-56e31f06e11972fc8335152717c5cf7d07d40998.tar.gz
tempname: new try_tempname function
The way how gen_tempname() creates files is not always sufficient. For example, it may make sense to create directories when creating the temporary file or directory fails with errno set to ENOENT. Add a try_tempname() variant of gen_tempname() that allows that. Implement gen_tempname() on top of it. * lib/tempname.c (try_tempname): New function and backend of gen_tempname(). (try_file, try_dir, try_nocreate): Callbacks to use for the different kinds that gen_tempname supports (GT_FILE, GT_DIR, GT_NOCREATE). * lib/tempname.h (try_tempname): Declare here. * modules/tempname: Mention try_tempname.
Diffstat (limited to 'lib/tempname.c')
-rw-r--r--lib/tempname.c117
1 files changed, 67 insertions, 50 deletions
diff --git a/lib/tempname.c b/lib/tempname.c
index 088b224ab9..fa8b01899f 100644
--- a/lib/tempname.c
+++ b/lib/tempname.c
@@ -62,6 +62,7 @@
# define struct_stat64 struct stat64
#else
# define struct_stat64 struct stat
+# define __try_tempname try_tempname
# define __gen_tempname gen_tempname
# define __getpid getpid
# define __gettimeofday gettimeofday
@@ -176,21 +177,8 @@ __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
static const char letters[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-/* 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.
-
- 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.
-
- We use a clever algorithm to get hard-to-predict names. */
int
-__gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
+__try_tempname (char *tmpl, int suffixlen, void *args, int (*try) (char *, void *))
{
int len;
char *XXXXXX;
@@ -199,7 +187,6 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
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
@@ -256,41 +243,7 @@ __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 ();
- }
-
+ fd = try (tmpl, args);
if (fd >= 0)
{
__set_errno (save_errno);
@@ -304,3 +257,67 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
__set_errno (EEXIST);
return -1;
}
+
+static int
+try_file (char *tmpl, void *flags)
+{
+ int *openflags = flags;
+ return __open (tmpl,
+ (*openflags & ~O_ACCMODE)
+ | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+}
+
+static int
+try_dir (char *tmpl, void *flags)
+{
+ return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
+}
+
+static int
+try_nocreate (char *tmpl, void *flags)
+{
+ struct_stat64 st;
+
+ if (__lxstat64 (_STAT_VER, tmpl, &st) == 0)
+ __set_errno (EEXIST);
+ return errno == ENOENT ? 0 : -1;
+}
+
+/* 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.
+
+ 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.
+
+ We use a clever algorithm to get hard-to-predict names. */
+int
+__gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
+{
+ int (*try) (char *, void *);
+
+ switch (kind)
+ {
+ case __GT_FILE:
+ try = try_file;
+ break;
+
+ case __GT_DIR:
+ try = try_dir;
+ break;
+
+ case __GT_NOCREATE:
+ try = try_nocreate;
+ break;
+
+ default:
+ assert (! "invalid KIND in __gen_tempname");
+ abort ();
+ }
+ return __try_tempname (tmpl, suffixlen, &flags, try);
+}