GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2019-07-07T19:06:16Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/2924createDirectory: permission denied2019-07-07T19:06:16ZSimon MarlowcreateDirectory: permission deniedThe following program results in an odd "permission denied" error from `createDirectory` on Windows. It is derived from the `createDirectoryIfMIssing001` test, but doesn't involve calling `createDirectoryIfMissing`, only `createDirectory...The following program results in an odd "permission denied" error from `createDirectory` on Windows. It is derived from the `createDirectoryIfMIssing001` test, but doesn't involve calling `createDirectoryIfMissing`, only `createDirectory`.
There are two threads, each of which is repeatedly creating a directory and using `removeDirectoryRecursive` to remove it.
Test program:
```
import System.IO
import System.Directory
import Control.Monad
import Control.Concurrent
import Control.Exception
import System.IO.Error
testdir = "foo"
main = do
cleanup
m <- newEmptyMVar
forkIO $ do replicateM_ 1000 (do create; cleanup); putMVar m ()
forkIO $ do replicateM_ 1000 (do create; cleanup); putMVar m ()
replicateM_ 2 $ takeMVar m
cleanup
create =
tryJust (guard . isAlreadyExistsError) $ createDirectory testdir
cleanup =
tryJust (guard . isDoesNotExistError) $ removeDirectoryRecursive testdir
```
The result is usually:
```
test.exe: CreateDirectory: permission denied (Access is denied.)
```
It's not clear (to me at least) why we get this error. Running the program under !ProcMon shows that there is a `CreateFile` call that returns `DELETE PENDING`, but as far as I can tell this doesn't give rise to an `ERROR_DELETE_PENDING` return from `CreateDirectory`, because that would give a different error message. Perhaps somewhere in the bowels of the Win32 API a `DELETE_PENDING` is being turned into a permission denied, or something.
This deserves investigation, because I think it might be related to other spurious "permission denied" errors we occasionally see on Windows.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------------- |
| Version | 6.10.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/directory |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"createDirectory: permission denied","status":"New","operating_system":"","component":"libraries/directory","related":[],"milestone":"6.10 branch","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.10.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The following program results in an odd \"permission denied\" error from `createDirectory` on Windows. It is derived from the `createDirectoryIfMIssing001` test, but doesn't involve calling `createDirectoryIfMissing`, only `createDirectory`.\r\n\r\nThere are two threads, each of which is repeatedly creating a directory and using `removeDirectoryRecursive` to remove it. \r\n\r\nTest program:\r\n\r\n{{{\r\nimport System.IO\r\nimport System.Directory\r\nimport Control.Monad\r\nimport Control.Concurrent\r\nimport Control.Exception\r\nimport System.IO.Error\r\n\r\ntestdir = \"foo\"\r\n\r\nmain = do\r\n cleanup\r\n m <- newEmptyMVar\r\n forkIO $ do replicateM_ 1000 (do create; cleanup); putMVar m ()\r\n forkIO $ do replicateM_ 1000 (do create; cleanup); putMVar m ()\r\n replicateM_ 2 $ takeMVar m\r\n cleanup\r\n\r\ncreate =\r\n tryJust (guard . isAlreadyExistsError) $ createDirectory testdir\r\n\r\ncleanup =\r\n tryJust (guard . isDoesNotExistError) $ removeDirectoryRecursive testdir\r\n}}}\r\n\r\nThe result is usually:\r\n\r\n{{{\r\ntest.exe: CreateDirectory: permission denied (Access is denied.)\r\n}}}\r\n\r\nIt's not clear (to me at least) why we get this error. Running the program under !ProcMon shows that there is a `CreateFile` call that returns `DELETE PENDING`, but as far as I can tell this doesn't give rise to an `ERROR_DELETE_PENDING` return from `CreateDirectory`, because that would give a different error message. Perhaps somewhere in the bowels of the Win32 API a `DELETE_PENDING` is being turned into a permission denied, or something.\r\n\r\nThis deserves investigation, because I think it might be related to other spurious \"permission denied\" errors we occasionally see on Windows.","type_of_failure":"OtherFailure","blocking":[]} -->6.12.3