Hi Daniel,

Daniel Shahaf writes:
> Ping, this doesn't seem to have been fixed yet?

Thanks for the ping, and sorry about the delay. I think this should
work -- I'll write a commit message if you think this is okay.

Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c (revision 1056662)
+++ subversion/libsvn_subr/io.c (working copy)
@@ -1299,59 +1299,64 @@ reown_file(const char *path,
   return svn_error_return(svn_io_remove_file2(unique_name, FALSE, pool));
 }
 
-/* Determine what the PERMS for a new file should be by looking at the
-   permissions of a temporary file that we create.
-   Unfortunately, umask() as defined in POSIX provides no thread-safe way
-   to get at the current value of the umask, so what we're doing here is
-   the only way we have to determine which combination of write bits
-   (User/Group/World) should be set by default.
-   Make temporary allocations in SCRATCH_POOL.  */
+/* the default permissions as read from the temp folder */
+static volatile apr_fileperms_t default_perms = 0;
+static volatile svn_atomic_t perms_init_state;
+
+/* Helper function to set default permissions. Passed to svn_atomic__init_once 
*/
 static svn_error_t *
-get_default_file_perms(apr_fileperms_t *perms, apr_pool_t *scratch_pool)
+set_default_perms(void *baton, apr_pool_t *scratch_pool)
 {
-  /* the default permissions as read from the temp folder */
-  static apr_fileperms_t default_perms = 0;
+  apr_fileperms_t *default_perms = (apr_fileperms_t *) baton;
 
-  /* Technically, this "racy": Multiple threads may use enter here and
-     try to figure out the default permisission concurrently. That's fine
-     since they will end up with the same results. Even more technical,
-     apr_fileperms_t is an atomic type on 32+ bit machines.
-   */
-  if (default_perms == 0)
-    {
-      apr_finfo_t finfo;
-      apr_file_t *fd;
+  if (default_perms != 0)
+    /* Nothing to do */
+    return SVN_NO_ERROR;
 
-      /* Get the perms for a newly created file to find out what bits
-        should be set.
+  apr_finfo_t finfo;
+  apr_file_t *fd;
 
-        Normally del_on_close can be problematic because APR might
-        delete the file if we spawned any child processes. In this
-        case, the lifetime of this file handle is about 3 lines of
-        code, so we can safely use del_on_close here.
+  /* Get the perms for a newly created file to find out what bits
+     should be set.
 
-        Not so fast! If some other thread forks off a child, then the
-        APR cleanups run, and the file will disappear. So use
-        del_on_pool_cleanup instead.
+     Normally del_on_close can be problematic because APR might
+     delete the file if we spawned any child processes. In this
+     case, the lifetime of this file handle is about 3 lines of
+     code, so we can safely use del_on_close here.
 
-        Using svn_io_open_uniquely_named() here because other tempfile
-        creation functions tweak the permission bits of files they create.
-      */
-      SVN_ERR(svn_io_open_uniquely_named(&fd, NULL, NULL, "svn-tempfile", 
".tmp",
-                                        svn_io_file_del_on_pool_cleanup,
-                                        scratch_pool, scratch_pool));
-      SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_PROT, fd, scratch_pool));
-      SVN_ERR(svn_io_file_close(fd, scratch_pool));
+     Not so fast! If some other thread forks off a child, then the
+     APR cleanups run, and the file will disappear. So use
+     del_on_pool_cleanup instead.
 
-      *perms = finfo.protection;
-      default_perms = finfo.protection;
-    }
-  else
-    *perms = default_perms;
+     Using svn_io_open_uniquely_named() here because other tempfile
+     creation functions tweak the permission bits of files they create.
+  */
+  SVN_ERR(svn_io_open_uniquely_named(&fd, NULL, NULL, "svn-tempfile", ".tmp",
+                                     svn_io_file_del_on_pool_cleanup,
+                                     scratch_pool, scratch_pool));
+  SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_PROT, fd, scratch_pool));
+  SVN_ERR(svn_io_file_close(fd, scratch_pool));
+  default_perms = finfo.protection;
 
   return SVN_NO_ERROR;
 }
 
+/* Determine what the PERMS for a new file should be by looking at the
+   permissions of a temporary file that we create.
+   Unfortunately, umask() as defined in POSIX provides no thread-safe way
+   to get at the current value of the umask, so what we're doing here is
+   the only way we have to determine which combination of write bits
+   (User/Group/World) should be set by default.
+   Make temporary allocations in SCRATCH_POOL.  */
+static svn_error_t *
+get_default_file_perms(apr_fileperms_t *perms, apr_pool_t *scratch_pool)
+{
+      SVN_ERR(svn_atomic__init_once(&perms_init_state, set_default_perms,
+                                    default_perms, scratch_pool));
+      *perms = default_perms;
+      return SVN_NO_ERROR;
+}
+
 /* OR together permission bits of the file FD and the default permissions
    of a file as determined by get_default_file_perms(). Do temporary
    allocations in SCRATCH_POOL. */

Reply via email to