bug-gnulib
[Top][All Lists]
Advanced

[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: Tue, 3 Feb 2015 09:23:07 +0100

From: Andreas Gruenbacher <address@hidden>

2015-02-03 2:11 GMT+01:00 Paul Eggert <address@hidden>:
> Thanks, one further suggestion.  The above can be simplified to:
>
>   if (__lxstat64 (_STAT_VER, tmpl, &st) == 0)
>     __set_errno (EEXIST);
>   return errno == ENOENT ? 0 : -1;

Here's one (hopefully last) update.

Andreas

--

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.
---
 lib/tempname.c   | 117 +++++++++++++++++++++++++++++++------------------------
 lib/tempname.h   |   7 ++++
 modules/tempname |   2 +-
 3 files changed, 75 insertions(+), 51 deletions(-)

diff --git a/lib/tempname.c b/lib/tempname.c
index 088b224..fa8b018 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);
+}
diff --git a/lib/tempname.h b/lib/tempname.h
index b560ee5..f7c98d0 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, void *args,
+                       int (*try) (char *, void *));
+
 #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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]