#2808: createDirectoryIfMissing should be atomic
------------------------------------+---------------------------------------
    Reporter:  EricKow              |        Owner:  igloo           
        Type:  merge                |       Status:  reopened        
    Priority:  normal               |    Milestone:  6.10.2          
   Component:  libraries/directory  |      Version:  6.10.1          
    Severity:  normal               |   Resolution:                  
    Keywords:                       |   Difficulty:  Unknown         
    Testcase:                       |           Os:  Unknown/Multiple
Architecture:  Unknown/Multiple     |  
------------------------------------+---------------------------------------
Comment (by duncan):

 Updated to address Simon's comments and to handle the two `create_parents`
 cases in a more similar way, especially when it comes to trailing
 directory separators.

 Ignoring comments it looks like:

 {{{
 createDirectoryIfMissing create_parents path0
   | create_parents = createDirs (parents path0)
   | otherwise      = createDirs (take 1 (parents path0))
   where
     parents = reverse . scanl1 (</>) . splitDirectories . normalise

     createDirs []         = return ()
     createDirs (dir:[])   = createDir dir throw
     createDirs (dir:dirs) =
       createDir dir $ \_ -> do
         createDirs dirs
         createDir dir throw

     createDir :: FilePath -> (IOException -> IO ()) -> IO ()
     createDir dir notExistHandler = do
       r <- try $ createDirectory dir
       case (r :: Either IOException ()) of
         Right ()                   -> return ()
         Left  e
           | isDoesNotExistError  e -> notExistHandler e
           | isAlreadyExistsError e -> do
               exists <- doesDirectoryExist dir
               if exists then return ()
                         else throw e
           | otherwise              -> throw e
 }}}

 There are two changes, one is to use `scanl1 (</>) . splitDirectories`
 instead of `scanl1 (++) . splitPath`. The other is to add a clause:
 {{{
     createDirs (dir:[])   = createDir dir throw
 }}}
 So that we do not attempt to create the last dir twice. When it fails
 there's not more parent dirs to try so it's a hard failure.

 That also means we can use `createDirs` in the `not create_parents` case.
 We don't just pass `head (parents path0)` because it will be empty when
 `path0 == ""`. Using `take 1` covers both cases.

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/2808#comment:8>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to