1 {-# LANGUAGE CPP #-}
    2 
    3 module Bundled.Posix( getFdStatus, getSymbolicLinkStatus, getFileStatus
    4                     , getFileStatusBS
    5                     , fileExists
    6                     , modificationTime, fileSize, FileStatus
    7                     , EpochTime, isDirectory, isRegularFile ) where
    8 
    9 import qualified Data.ByteString.Char8 as BS
   10 import Data.ByteString.Unsafe( unsafeUseAsCString )
   11 import Foreign.Marshal.Alloc ( allocaBytes )
   12 import Foreign.C.Error ( throwErrno, getErrno, eNOENT )
   13 import Foreign.C.Types ( CTime, CInt )
   14 import Foreign.Ptr ( Ptr )
   15 
   16 import System.Posix.Internals
   17           ( CStat, c_fstat, c_stat, sizeof_stat
   18           , st_mode, st_size, st_mtime, s_isdir, s_isreg )
   19 
   20 import System.Posix.Types ( Fd(..), CMode, EpochTime )
   21 
   22 #if mingw32_HOST_OS && __GLASGOW_HASKELL__ >= 612
   23 import Foreign.C.String( withCWString )
   24 #else
   25 import Foreign.C.String ( withCString )
   26 #endif
   27 
   28 #if mingw32_HOST_OS
   29 import Data.Int ( Int64 )
   30 
   31 type FileOffset = Int64
   32 lstat = c_stat
   33 #else
   34 import System.Posix.Types ( FileOffset )
   35 import System.Posix.Internals( lstat )
   36 #endif
   37 
   38 #if mingw32_HOST_OS && __GLASGOW_HASKELL__ >= 612
   39 bsToPath s f = withCWString (BS.unpack s) f
   40 strToPath = withCWString
   41 #else
   42 bsToPath = unsafeUseAsCString
   43 strToPath = withCString
   44 #endif
   45 
   46 data FileStatus = FileStatus {
   47     fst_exists :: !Bool,
   48     fst_mode :: !CMode,
   49     fst_mtime :: !CTime,
   50     fst_size :: !FileOffset
   51  }
   52 
   53 getFdStatus :: Fd -> IO FileStatus
   54 getFdStatus (Fd fd) = do
   55   do_stat (c_fstat fd)
   56 
   57 do_stat :: (Ptr CStat -> IO CInt) -> IO FileStatus
   58 do_stat stat_func = do
   59   allocaBytes sizeof_stat $! \p -> do
   60      ret <- stat_func p
   61      if (ret == -1) then do err <- getErrno
   62                             if (err == eNOENT)
   63                                then return $! (FileStatus False 0 0 0)
   64                                else throwErrno "do_stat"
   65                     else do mode <- st_mode p
   66                             mtime <- st_mtime p
   67                             size <- st_size p
   68                             return $! FileStatus True mode mtime size
   69 {-# INLINE  do_stat #-}
   70 
   71 isDirectory :: FileStatus -> Bool
   72 isDirectory = s_isdir . fst_mode
   73 
   74 isRegularFile :: FileStatus -> Bool
   75 isRegularFile = s_isreg . fst_mode
   76 
   77 modificationTime :: FileStatus -> EpochTime
   78 modificationTime = fst_mtime
   79 
   80 fileSize :: FileStatus -> FileOffset
   81 fileSize = fst_size
   82 
   83 fileExists :: FileStatus -> Bool
   84 fileExists = fst_exists
   85 
   86 #include <sys/stat.h>
   87 
   88 -- lstat is broken on win32 with at least GHC 6.10.3
   89 getSymbolicLinkStatus :: FilePath -> IO FileStatus
   90 ##if mingw32_HOST_OS
   91 getSymbolicLinkStatus = getFileStatus
   92 ##else
   93 getSymbolicLinkStatus fp =
   94   do_stat (\p -> (fp `strToPath` (`lstat` p)))
   95 ##endif
   96 
   97 getFileStatus :: FilePath -> IO FileStatus
   98 getFileStatus fp =
   99   do_stat (\p -> (fp `strToPath` (`lstat` p)))
  100 
  101 -- | Requires NULL-terminated bytestring -> unsafe! Use with care.
  102 getFileStatusBS :: BS.ByteString -> IO FileStatus
  103 getFileStatusBS fp =
  104   do_stat (\p -> (fp `bsToPath` (`lstat` p)))
  105 {-# INLINE getFileStatusBS #-}