{-# LINE 1 "System/DiskSpace.hsc" #-}
{-# LANGUAGE CPP #-}

{- |
Module      : System.DiskSpace

Stability   : provisional
Portability : portable
-}

module System.DiskSpace
    ( DiskUsage(..)
    , getDiskUsage
    , getAvailSpace
    ) where


{-# LINE 17 "System/DiskSpace.hsc" #-}

import Foreign
import Foreign.C



foreign import ccall safe statvfs :: CString -> Ptr a -> IO CInt

type FsBlkCnt = Word32
{-# LINE 26 "System/DiskSpace.hsc" #-}

getDiskUsage :: FilePath -> IO DiskUsage
getDiskUsage FilePath
path =
    FilePath -> (CString -> IO DiskUsage) -> IO DiskUsage
forall a. FilePath -> (CString -> IO a) -> IO a
withCString FilePath
path ((CString -> IO DiskUsage) -> IO DiskUsage)
-> (CString -> IO DiskUsage) -> IO DiskUsage
forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
        Int -> (Ptr Any -> IO DiskUsage) -> IO DiskUsage
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes ((Int
72)) ((Ptr Any -> IO DiskUsage) -> IO DiskUsage)
-> (Ptr Any -> IO DiskUsage) -> IO DiskUsage
forall a b. (a -> b) -> a -> b
$ \Ptr Any
stat -> do
{-# LINE 30 "System/DiskSpace.hsc" #-}
            FilePath -> FilePath -> IO CInt -> IO ()
forall a. (Eq a, Num a) => FilePath -> FilePath -> IO a -> IO ()
throwErrnoPathIfMinus1_ FilePath
"getDiskUsage" FilePath
path (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ CString -> Ptr Any -> IO CInt
forall a. CString -> Ptr a -> IO CInt
statvfs CString
cPath Ptr Any
stat
            CULong
bsize  <- ((\Ptr Any
hsc_ptr -> Ptr Any -> Int -> IO CULong
forall b. Ptr b -> Int -> IO CULong
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Any
hsc_ptr Int
0)) Ptr Any
stat :: IO CULong
{-# LINE 32 "System/DiskSpace.hsc" #-}
            CULong
frsize <- ((\Ptr Any
hsc_ptr -> Ptr Any -> Int -> IO CULong
forall b. Ptr b -> Int -> IO CULong
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Any
hsc_ptr Int
4)) Ptr Any
stat :: IO CULong
{-# LINE 33 "System/DiskSpace.hsc" #-}
            FsBlkCnt
blocks <- ((\Ptr Any
hsc_ptr -> Ptr Any -> Int -> IO FsBlkCnt
forall b. Ptr b -> Int -> IO FsBlkCnt
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Any
hsc_ptr Int
8)) Ptr Any
stat :: IO FsBlkCnt
{-# LINE 34 "System/DiskSpace.hsc" #-}
            FsBlkCnt
bfree  <- ((\Ptr Any
hsc_ptr -> Ptr Any -> Int -> IO FsBlkCnt
forall b. Ptr b -> Int -> IO FsBlkCnt
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Any
hsc_ptr Int
12)) Ptr Any
stat :: IO FsBlkCnt
{-# LINE 35 "System/DiskSpace.hsc" #-}
            FsBlkCnt
bavail <- ((\Ptr Any
hsc_ptr -> Ptr Any -> Int -> IO FsBlkCnt
forall b. Ptr b -> Int -> IO FsBlkCnt
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Any
hsc_ptr Int
16)) Ptr Any
stat :: IO FsBlkCnt
{-# LINE 36 "System/DiskSpace.hsc" #-}
            let frsize' :: Integer
frsize' = CULong -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULong
frsize
            DiskUsage -> IO DiskUsage
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return DiskUsage
                { diskTotal :: Integer
diskTotal = Integer
frsize' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* FsBlkCnt -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral FsBlkCnt
blocks
                , diskFree :: Integer
diskFree  = Integer
frsize' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* FsBlkCnt -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral FsBlkCnt
bfree
                , diskAvail :: Integer
diskAvail = Integer
frsize' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* FsBlkCnt -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral FsBlkCnt
bavail
                , blockSize :: Int
blockSize = CULong -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CULong
bsize
                }


{-# LINE 61 "System/DiskSpace.hsc" #-}

-- | Disk usage information. All fields are in bytes.
data DiskUsage = DiskUsage
    { DiskUsage -> Integer
diskTotal :: Integer -- ^ The total size of the file system.
    , DiskUsage -> Integer
diskFree  :: Integer -- ^ The amount of free space. You probably want to
                           --   use 'diskAvail' instead.
    , DiskUsage -> Integer
diskAvail :: Integer -- ^ The amount of space available to the user.
                           --   Might be less than 'diskFree'. On Windows,
                           --   this is always equal to 'diskFree'.
                           --   This is what most tools report as free
                           --   space (e.g. the unix @df@ tool).
    , DiskUsage -> Int
blockSize :: Int     -- ^ The optimal block size for I/O in this volume.
                           --   Some operating systems report incorrect values
                           --   for this field.
    }
  deriving (Int -> DiskUsage -> ShowS
[DiskUsage] -> ShowS
DiskUsage -> FilePath
(Int -> DiskUsage -> ShowS)
-> (DiskUsage -> FilePath)
-> ([DiskUsage] -> ShowS)
-> Show DiskUsage
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DiskUsage -> ShowS
showsPrec :: Int -> DiskUsage -> ShowS
$cshow :: DiskUsage -> FilePath
show :: DiskUsage -> FilePath
$cshowList :: [DiskUsage] -> ShowS
showList :: [DiskUsage] -> ShowS
Show, DiskUsage -> DiskUsage -> Bool
(DiskUsage -> DiskUsage -> Bool)
-> (DiskUsage -> DiskUsage -> Bool) -> Eq DiskUsage
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DiskUsage -> DiskUsage -> Bool
== :: DiskUsage -> DiskUsage -> Bool
$c/= :: DiskUsage -> DiskUsage -> Bool
/= :: DiskUsage -> DiskUsage -> Bool
Eq)

-- | Retrieve disk usage information about a volume. The volume is
-- specified with the @FilePath@ argument. The path can refer to the root
-- directory or any other directory inside the volume.
-- Unix systems also accept arbitrary files, but this
-- does not work under Windows and therefore should be avoided if
-- portability is desired.
getDiskUsage :: FilePath -> IO DiskUsage

-- | A convenience function that directly returns the 'diskAvail' field from
-- the result of 'getDiskUsage'. If a large amount of data is to be written
-- in a directory, calling this function for that directory can be used to
-- determine whether the operation will fail because of insufficient disk
-- space.
getAvailSpace :: FilePath -> IO Integer
getAvailSpace :: FilePath -> IO Integer
getAvailSpace = (DiskUsage -> Integer) -> IO DiskUsage -> IO Integer
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap DiskUsage -> Integer
diskAvail (IO DiskUsage -> IO Integer)
-> (FilePath -> IO DiskUsage) -> FilePath -> IO Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO DiskUsage
getDiskUsage