diff options
author | Joey Hess <joeyh@joeyh.name> | 2015-01-20 16:58:48 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2015-01-20 17:09:24 -0400 |
commit | c7e67aa29183c7fe7bb14b909cf953a89c531b08 (patch) | |
tree | e63f341fb51375faf9a0928af00703bcef584306 /Utility | |
parent | 68c8b9b7592a7c407bdd6a0fe8b5f49241118926 (diff) |
add getFileSize, which can get the real size of a large file on Windows
Avoid using fileSize which maxes out at just 2 gb on Windows.
Instead, use hFileSize, which doesn't have a bounded size.
Fixes support for files > 2 gb on Windows.
Note that the InodeCache code only needs to compare a file size,
so it doesn't matter it the file size wraps. So it has been
left as-is. This was necessary both to avoid invalidating existing inode
caches, and because the code passed FileStatus around and would have become
more expensive if it called getFileSize.
This commit was sponsored by Christian Dietrich.
Diffstat (limited to 'Utility')
-rw-r--r-- | Utility/FileSize.hs | 33 | ||||
-rw-r--r-- | Utility/InodeCache.hs | 3 | ||||
-rw-r--r-- | Utility/Url.hs | 7 |
3 files changed, 41 insertions, 2 deletions
diff --git a/Utility/FileSize.hs b/Utility/FileSize.hs new file mode 100644 index 000000000..3113695d3 --- /dev/null +++ b/Utility/FileSize.hs @@ -0,0 +1,33 @@ +{- File size. + - + - License: BSD-2-clause + -} + +{-# LANGUAGE CPP #-} + +module Utility.FileSize where + +import System.PosixCompat.Files +import Control.Exception (bracket) +import System.IO + +{- Gets the size of a file. + - + - This is better than using fileSize, because on Windows that returns a + - FileOffset which maxes out at 2 gb. + - See https://github.com/jystic/unix-compat/issues/16 + -} +getFileSize :: FilePath -> IO Integer +#ifndef mingw32_HOST_OS +getFileSize f = fromIntegral . fileSize <$> getFileStatus f +#else +getFileSize f = bracket (openFile f ReadMode) hClose hFileSize +#endif + +{- Gets the size of the file, when its FileStatus is already known. -} +getFileSize' :: FilePath -> FileStatus -> IO Integer +#ifndef mingw32_HOST_OS +getFileSize' _ s = return $ fromIntegral $ fileSize s +#else +getFileSize' f _ = getFileSize f +#endif diff --git a/Utility/InodeCache.hs b/Utility/InodeCache.hs index 8a182449b..0b0b040cb 100644 --- a/Utility/InodeCache.hs +++ b/Utility/InodeCache.hs @@ -40,6 +40,9 @@ module Utility.InodeCache ( import Common import System.PosixCompat.Types import Utility.QuickCheck +-- While fileSize overflows and wraps at 2gb on Windows, +-- it's ok for purposes of comparison. +import System.PosixCompat.Files (fileSize) #ifdef mingw32_HOST_OS import Data.Word (Word64) diff --git a/Utility/Url.hs b/Utility/Url.hs index cc15c82d0..a8828e048 100644 --- a/Utility/Url.hs +++ b/Utility/Url.hs @@ -102,9 +102,12 @@ exists url uo = case parseURIRelaxed url of -- so fall back to reading files and using curl. Nothing | uriScheme u == "file:" -> do - s <- catchMaybeIO $ getFileStatus (unEscapeString $ uriPath u) + let f = unEscapeString (uriPath u) + s <- catchMaybeIO $ getFileStatus f case s of - Just stat -> return (True, Just $ fromIntegral $ fileSize stat) + Just stat -> do + sz <- getFileSize' f stat + return (True, Just sz) Nothing -> dne | Build.SysConfig.curl -> do output <- catchDefaultIO "" $ |