{-# LANGUAGE CPP #-} {- | Module : System.Win32.HardLink Copyright : 2013 shelarcy License : BSD-style Maintainer : [email protected] Stability : Provisional Portability : Non-portable (Win32 API) Handling hard link using Win32 API. [NTFS only] Note: You should worry about file system type when use this module's function in your application: * NTFS only supprts this functionality. * ReFS doesn't support hard link currently. -} module System.Win32.HardLink ( module System.Win32.HardLink ) where import System.Win32.File ( LPSECURITY_ATTRIBUTES, failIfFalseWithRetry_ ) import System.Win32.String ( LPCTSTR, withTString ) import System.Win32.Types ( BOOL, nullPtr ) #include "windows_cconv.h" -- | NOTE: createHardLink is /flipped arguments/ to provide compatiblity for Unix. -- -- If you want to create hard link by Windows way, use 'createHardLink'' instead. createHardLink :: FilePath -- ^ Target file path -> FilePath -- ^ Hard link name -> IO () createHardLink = flip createHardLink' createHardLink' :: FilePath -- ^ Hard link name -> FilePath -- ^ Target file path -> IO () createHardLink' link target = withTString target $ \c_target -> withTString link $ \c_link -> failIfFalseWithRetry_ (unwords ["CreateHardLinkW",show link,show target]) $ c_CreateHardLink c_link c_target nullPtr foreign import WINDOWS_CCONV unsafe "windows.h CreateHardLinkW" c_CreateHardLink :: LPCTSTR -- ^ Hard link name -> LPCTSTR -- ^ Target file path -> LPSECURITY_ATTRIBUTES -- ^ This parameter is reserved. You should pass just /nullPtr/. -> IO BOOL {- -- We plan to check file system type internally. -- We are thinking about API design, currently... data VolumeInformation = VolumeInformation { volumeName :: String , volumeSerialNumber :: DWORD , maximumComponentLength :: DWORD , fileSystemFlags :: DWORD , fileSystemName :: String } deriving Show getVolumeInformation :: Maybe String -> IO VolumeInformation getVolumeInformation drive = maybeWith withTString drive $ \c_drive -> withTStringBufferLen 256 $ \(vnBuf, vnLen) -> alloca $ \serialNum -> alloca $ \maxLen -> alloca $ \fsFlags -> withTStringBufferLen 256 $ \(fsBuf, fsLen) -> do failIfFalse_ (unwords ["GetVolumeInformationW", drive]) $ c_GetVolumeInformation c_drive vnBuf (fromIntegral vnLen) serialNum maxLen fsFlags fsBuf (fromIntegral fsLen) return VolumeInformation <*> peekTString vnBuf <*> peek serialNum <*> peek maxLen <*> peek fsFlags <*> peekTString fsBuf -- Which is better? getVolumeFileType :: String -> IO String getVolumeFileType drive = fileSystemName <$> getVolumeInformation drive getVolumeFileType :: String -> IO String getVolumeFileType drive = withTString drive $ \c_drive -> withTStringBufferLen 256 $ \(buf, len) -> do failIfFalse_ (unwords ["GetVolumeInformationW", drive]) $ c_GetVolumeInformation c_drive nullPtr 0 nullPtr nullPtr nullPtr buf (fromIntegral len) peekTString buf foreign import WINDOWS_CCONV unsafe "windows.h GetVolumeInformationW" c_GetVolumeInformation :: LPCTSTR -> LPTSTR -> DWORD -> LPDWORD -> LPDWORD -> LPDWORD -> LPTSTR -> DWORD -> IO BOOL -}