content: {-# LANGUAGE CPP #-}
  
  module Development.Shake.Internal.History.Symlink(
      copyFileLink,
      createLinkMaybe
      ) where
  
  import Control.Monad.Extra
  import General.Extra
  import System.Directory
  import System.FilePath
  
  
  #ifdef mingw32_HOST_OS
  import Foreign.Ptr
  import Foreign.C.String
  #else
  import System.Posix.Files(createLink)
  #endif
  
  createLinkMaybe :: FilePath -> FilePath -> IO (Maybe String)
  
  #ifdef mingw32_HOST_OS
  
  #ifdef x86_64_HOST_ARCH
  #define CALLCONV ccall
  #else
  #define CALLCONV stdcall
  #endif
  
  foreign import CALLCONV unsafe "Windows.h CreateHardLinkW " c_CreateHardLinkW :: CWString -> CWString -> Ptr () -> IO Bool
  
  createLinkMaybe from to = withCWString from $ \cfrom -> withCWString to $ \cto -> do
      res <- c_CreateHardLinkW cto cfrom nullPtr
      pure $ if res then Nothing else Just "CreateHardLink failed."
  
  #else
  
  createLinkMaybe from to = handleIO (pure . Just . show) $ createLink from to >> pure Nothing
  
  #endif
  
  
  copyFileLink :: Bool -> FilePath -> FilePath -> IO ()
  copyFileLink useSymlink from to = do
      createDirectoryRecursive $ takeDirectory to
      removeFile_ to
      if not useSymlink then copyFile from to else do
          b <- createLinkMaybe from to
          whenJust b $ \_ ->
              copyFile from to
          -- making files read only stops them from inadvertently mutating the cache
          forM_ [from, to] $ \x -> do
              perm <- getPermissions x
              setPermissions x perm{writable=False}
  