ar-timestamp-wiper (empty) → 0.1.0
raw patch · 4 files changed
+115/−0 lines, 4 filesdep +basedep +bytestringsetup-changed
Dependencies added: base, bytestring
Files
- ArTimestampWiper.hs +55/−0
- Main.hs +13/−0
- Setup.hs +2/−0
- ar-timestamp-wiper.cabal +45/−0
+ ArTimestampWiper.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE OverloadedStrings #-}++module ArTimestampWiper where++import Control.Applicative+import Control.Monad+import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as BS8+import Data.Char+import System.IO+++-- | Removes the time stamps of all files in the .a file.+arFileWipeTimeStamps :: FilePath -> IO ()+arFileWipeTimeStamps path = withBinaryFile path ReadWriteMode $ \h -> do++ -- We iterate through the archive stepping from one file header to the next,+ -- setting the time stamp field to zero.+ -- The size field tells us where the next header is.+ -- See: http://en.wikipedia.org/wiki/Ar_%28Unix%29.++ archiveSize <- hFileSize h++ let go entryOffset | entryOffset == archiveSize = return () -- done, at end+ | entryOffset > archiveSize = die "Archive truncated"+ -- Headers are aligned to even bytes+ | odd entryOffset = go (entryOffset + 1)+ | otherwise = do++ -- Sanity check+ magic <- goto 58 >> BS.hGet h 2+ when (magic /= "\x60\x0a") $ die "Bad ar magic"++ -- Get size (to find following file)+ size <- goto 48 >> parseSize . BS8.unpack <$> BS.hGet h 10++ -- Wipe time stamp+ goto 16 >> BS.hPut h "0 " -- 12 chars++ -- Seek to next file at header + file size+ go (entryOffset + 60 + size)++ where+ goto pos = hSeek h AbsoluteSeek (entryOffset + pos)++ parseSize x = case reads x of+ [(s, r)] | all isSpace r -> s+ _ -> die "Malformed header"++ die msg = error $ "arFileWipeTimeStamps: " ++ path ++ ": "+ ++ msg ++ " at offset " ++ show entryOffset++ go 8 -- 8 == size of global header, before first file header++
+ Main.hs view
@@ -0,0 +1,13 @@+module Main where++import System.Environment (getArgs)++import ArTimestampWiper++main :: IO ()+main = do+ args <- getArgs+ case args of+ [file] -> arFileWipeTimeStamps file+ _ -> error "Usage: ar-timestamp-wiper [file.a]"+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ ar-timestamp-wiper.cabal view
@@ -0,0 +1,45 @@+name: ar-timestamp-wiper+version: 0.1.0+license: MIT+copyright: 2013 Niklas Hambüchen <mail@nh2.me>+author: Niklas Hambüchen <mail@nh2.me>+maintainer: Niklas Hambüchen <mail@nh2.me>+category: Application+build-type: Simple+stability: experimental+tested-with: GHC==7.6.3+cabal-version: >= 1.10+homepage: https://github.com/nh2/ar-timestamp-wiper+bug-reports: https://github.com/nh2/ar-timestamp-wiper/issues+synopsis: Wipes time stamps from .a files (like ar -D)+description:+ This application takes an archive (.a) file as created by the Unix ar tool,+ and sets all time stamps in it to zero.+ .+ These time stamps make ar generate different output for same input every time,+ which is problematic if you want to know if the contents actually changed+ as compared to the last time you created the archive (e.g. in build tools+ to avoid unnecessary linking).+ .+ Recent versions of GNU binutils and BSD ar af the -D flag for deterministic+ mode that creates the archive with all time stamps set to zero.+ However, these versions of ar are not wide spread yet, and this tool+ can help with that.++source-repository head+ type: git+ location: git://github.com/nh2/ar-timestamp-wiper.git+++library+ default-language: Haskell2010+ exposed-modules: ArTimestampWiper+ build-depends: base < 5, bytestring >= 0.9+ ghc-options: -Wall+++executable ar-timestamp-wiper+ default-language: Haskell2010+ main-is: Main.hs+ build-depends: base < 5, bytestring >= 0.9+ ghc-options: -Wall