[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] tempname: new try_tempname function
From: |
Andreas Gruenbacher |
Subject: |
[PATCH] tempname: new try_tempname function |
Date: |
Sat, 31 Jan 2015 15:15:54 +0100 |
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 to do all that and 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.
---
lib/tempname.c | 126 +++++++++++++++++++++++++++++++++----------------------
lib/tempname.h | 7 ++++
modules/tempname | 2 +-
3 files changed, 84 insertions(+), 51 deletions(-)
diff --git a/lib/tempname.c b/lib/tempname.c
index 088b224..f5f2330 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, int flags, int (*try) (char *, int))
{
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, flags);
if (fd >= 0)
{
__set_errno (save_errno);
@@ -304,3 +257,76 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int
kind)
__set_errno (EEXIST);
return -1;
}
+
+static int
+try_file (char *tmpl, int flags)
+{
+ return __open (tmpl,
+ (flags & ~O_ACCMODE)
+ | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+}
+
+static int
+try_dir (char *tmpl, int flags)
+{
+ return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
+}
+
+static int
+try_nocreate (char *tmpl, int flags)
+{
+ struct_stat64 st;
+
+ if (__lxstat64 (_STAT_VER, tmpl, &st) < 0)
+ {
+ if (errno == ENOENT)
+ return 0;
+ else
+ /* Give up now. */
+ return -1;
+ }
+ else
+ {
+ errno = EEXIST;
+ return -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 *, int);
+
+ 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);
+}
diff --git a/lib/tempname.h b/lib/tempname.h
index b560ee5..81d1377 100644
--- a/lib/tempname.h
+++ b/lib/tempname.h
@@ -47,4 +47,11 @@
We use a clever algorithm to get hard-to-predict names. */
extern int gen_tempname (char *tmpl, int suffixlen, int flags, int kind);
+/* Similar to gen_tempname, but TRY is called for each temporary
+ name to try. If TRY returns a non-negative number, TRY_GEN_TEMPNAME
+ returns with this value. Otherwise, if errno is set to EEXIST, another
+ name is tried, or else TRY_GEN_TEMPNAME returns -1. */
+extern int try_tempname(char *tmpl, int suffixlen, int flags,
+ int (*try) (char *, int));
+
#endif /* GL_TEMPNAME_H */
diff --git a/modules/tempname b/modules/tempname
index 7fafd72..c589d70 100644
--- a/modules/tempname
+++ b/modules/tempname
@@ -1,5 +1,5 @@
Description:
-gen_tempname() function: create a private temporary file or directory.
+gen_tempname() and try_tempname() functions: create a private temporary file
or directory.
Files:
lib/tempname.c
--
2.1.0
- [PATCH] tempname: new try_tempname function,
Andreas Gruenbacher <=