-
-
Notifications
You must be signed in to change notification settings - Fork 701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std.file: Fix race condition when mkdirRecurse runs concurrently #1818
Conversation
Excellent. |
{ | ||
if (CreateDirectoryW(std.utf.toUTF16z(pathname), null)) | ||
return true; | ||
enum ERROR_ALREADY_EXISTS = 183; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be in druntime somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argh, yes. But I already did two Druntime bindings pulls today :)
I'll move it.
@@ -1366,6 +1366,25 @@ void mkdir(in char[] pathname) | |||
} | |||
} | |||
|
|||
// Ignores "already exists" errors. | |||
private bool tryMkdir(in char[] pathname) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ensureDirExists
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
How about: void mkdir(in char[] pathname, bool recursive = false) I agree with the "mkdir -p" behavior of silently accepting existing leaf directories, since whenever I used it, it was to ensure that any missing directory is created. It is the more common use case for me by far. |
mkdirRecurse would crash if a directory was created between its exists() and mkdir() calls. This could occur if mkdirRecurse was called at the same time from mutiple threads or processes. Instead of relying on the exists() check to indicate whether the next mkdir() should succeed, we explicitly ignore "already exists" errors from the OS. Note that this changes the behavior of mkdirRecurse when the leaf directory already existed: previously it would throw, whereas now it will silently succeed. The new behavior is conformant with some other implementations of "recursive mkdir": the -p flag of the GNU tool, Ruby's mkpath, Java's mkdirs, and Perl's make_path. (On the other hand, the old behavior was equivalent to the behavior of Python's makedirs).
@mleise: boolean parameters suck. From the call site |
mkdirRecurse(path); | ||
mkdirRecurse(path); // should not throw | ||
|
||
assertThrown!FileException(mkdirRecurse(`1:\foobar`)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm not sure what you're testing here, but it's failing the autotester.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Derp, forgot to put it in version(Windows)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, 1:\foobar
, that's a 1, not an l, which confused me.
But how come on Posix this didn't fail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, both :
and \
are allowed in UNIX filenames...
The left.length != pathname.length check both takes care of the Windows-only check, and it avoids a pointless stat on the FS root.
Auto-merge toggled on |
LGTM. |
std.file: Fix race condition when mkdirRecurse runs concurrently
mkdirRecurse
would throw if a directory was created between itsexists()
andmkdir()
calls. This could occur ifmkdirRecurse
was called at the same time from mutiple threads or processes.Instead of relying on the
exists()
check to indicate whether the nextmkdir()
should succeed, we explicitly ignore "already exists" errors from the OS. Note that this changes the behavior ofmkdirRecurse
when the leaf directory already existed: previously it would throw, whereas now it will silently succeed. The new behavior is conformant with some other implementations of "recursive mkdir": the-p
flag of the GNU tool, Ruby'smkpath
, Java'smkdirs
, and Perl'smake_path
. (On the other hand, the old behavior was equivalent to the behavior of Python'smakedirs
).