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. */