import Control.Monad import Data.Digest.MD5 (hash) import Data.Word import List (sort) import Prelude import System.Directory import System.FilePath import System.IO import Text.Printf (printf) import qualified Data.ByteString.Lazy as BS main :: IO () main = putStr . unlines =<< getList "." getList :: FilePath -> IO [String] getList p = let getFileLine path = liftM (\c -> (hex c) ++ " " ++ path) (getFileHash path) in mapM getFileLine =<< getRecursiveContents p hex :: [Word8] -> String hex = concatMap (\x -> printf "%0.2x" (toInteger x)) getFileHash :: FilePath -> IO [Word8] getFileHash path = do handle <- openFile path ReadMode contents <- BS.hGetContents handle let !hashed = hash $ BS.unpack contents hClose handle return hashed getRecursiveContents :: FilePath -> IO [FilePath] getRecursiveContents topdir = do names <- getDirectoryContents topdir let properNames = filter (`notElem` [".", ".."]) names paths <- concatForM properNames $ \name -> do let path = topdir name isDirectory <- doesDirectoryExist path if isDirectory then getRecursiveContents path else do isFile <- doesFileExist path if isFile then return [path] else return [] return (sort paths) concatForM :: (Monad m) => [a1] -> (a1 -> m [a]) -> m [a] concatForM xs f = liftM concat (forM xs f)