What causes CreateDirectory to return ERROR_ACCESS_DENIED?
In another question, we established that yes, CreateDirectory
occasionally fails with the undocumented GetLastError
value of ERROR_ACCESS_DENIED
, and that the right way to handle the situation is probably to try again a few times. It's easy to implement such an algorithm, but it's not so easy to test it when you don't know how to reproduce it.
I don't need theories for why this happens. It might be a bug in Windows, yeah. It might also be by design. Ultimately, at this point, it doesn't matter, because Microsoft shipped the behavior, and I must cope.
I also don't need an explanation of multi-tasking operating system t开发者_如何学Pythonheory and how Windows implements it in general. I write system software for a living. I understand little else.
What I need now is a reliable way to reproduce the failure so I can write a test case for the code which copes. Here's what I've tried so far:
- I wrote test program P1, which slowly and repeatedly enumerates the contents of the would-be parent. As well, I wrote test program P2 which does nothing but repeatedly attempt to delete and create a directory in the would-be parent. I figured keeping an enumeration open a long time might make the problem more likely. Running P2 by itself produces an occasional period of failures (on the order of every several minutes for approximately 10 milliseconds). Running P1 and P2 at the same time does not seem to make the failures any more frequent or long.
- I ran two instances of P2 at the same time, and that does not seem to make the failures any more frequent or long.
- I modified P2 so that it can create files in addition to directories, and running that at the same time as P1 does not seem to make the failures any more frequent or long.
- I ran P1 and multiple instances of P2 with different parameters all at the same time, and that does not seem to make the failures any more frequent or long.
- I wrote test program P3 which moves items into and out of the would-be parent and ran P3 at the same time as P2, and that does not seem to make the failures any more frequent or long.
Any other ideas?
Let me start by double-checking that I understand the question. If you run something like the below snippet, you expect it to fail eventually, right?
while (true)
{
System.IO.Directory.CreateDirectory( ".\\FooDir" );
System.IO.Directory.Delete( ".\\FooDir" );
}
If your application is the only thing running on the system that has a handle open to that file, then this feels like a bug. So knowing the OS version would help.
On the other hand, if there is something else in the system that is keeping the handle open for just a little while, then whether this is a bug or not becomes a little more fuzzy. The number of things that try to blindly grok files and directories might surprise you. A naive indexer, for example, might be walking into that directory, enumerating it, looking for files to index and so on -- and if you collide with him, blammo. A similarly naive anti-virus filter, or some other file system filter, might be poking it as well (in this case, it still feels like a bug).
There are little things we've done in the OS to try and give services like these ways to get out of your way. Does it repro if you turn the indexer off, if you turn off any anti-virus, any anti-malware? We can go from there, and hopefully we will find that newer bits have it fixed already (that statement had a lot of assumptions in it, I know).
One other relatively interesting piece of trivia is that ERROR_ACCESS_DENIED is a Win32 error that is mapped from more than one underlying status in the system (see this article for example). So if we can dig a little deeper, we may be able to find out what the file system is trying to tell the app (if it's more than access denied).
We might end up getting into a conversation about whether you can, in the wild, assume that your app is the only thing poking at your files and directories. You can probably guess where that one will go.
I would wager a guess that your enumeration / deletion / creation is causing some synchronization problems with the handles. If CreateDirectory is anything like CreateFile (and I would assume the logic behind it would be shared), then you would see similar behaviour to CreateFile:
If you call CreateFile on a file that is pending deletion as a result of a previous call to DeleteFile, the function fails. The operating system delays file deletion until all handles to the file are closed. GetLastError returns ERROR_ACCESS_DENIED.
精彩评论