git-annex/Annex/Magic.hs

75 lines
1.8 KiB
Haskell
Raw Normal View History

2019-01-23 16:39:02 +00:00
{- Interface to libmagic
-
- Copyright 2019-2020 Joey Hess <id@joeyh.name>
2019-01-23 16:39:02 +00:00
-
- Licensed under the GNU AGPL version 3 or higher.
2019-01-23 16:39:02 +00:00
-}
{-# LANGUAGE CPP #-}
module Annex.Magic (
Magic,
MimeType,
MimeEncoding,
initMagicMime,
2019-01-23 16:39:02 +00:00
getMagicMimeType,
getMagicMimeEncoding,
2019-01-23 16:39:02 +00:00
) where
2019-05-03 14:58:34 +00:00
import Types.Mime
import Control.Monad.IO.Class
2019-01-23 16:39:02 +00:00
#ifdef WITH_MAGICMIME
import Magic
import Utility.Env
import Control.Concurrent
import System.IO.Unsafe (unsafePerformIO)
2019-01-23 16:39:02 +00:00
import Common
#else
type Magic = ()
#endif
initMagicMime :: IO (Maybe Magic)
2019-01-23 16:39:02 +00:00
#ifdef WITH_MAGICMIME
initMagicMime = catchMaybeIO $ do
m <- magicOpen [MagicMime]
2019-01-23 16:39:02 +00:00
liftIO $ getEnv "GIT_ANNEX_DIR" >>= \case
Nothing -> magicLoadDefault m
Just d -> magicLoad m
(d </> "magic" </> "magic.mgc")
return m
#else
initMagicMime = return Nothing
2019-01-23 16:39:02 +00:00
#endif
getMagicMime :: Magic -> FilePath -> IO (Maybe (MimeType, MimeEncoding))
2019-01-23 16:39:02 +00:00
#ifdef WITH_MAGICMIME
getMagicMime m f = Just . parse <$> magicConcurrentSafe (magicFile m f)
where
parse s =
let (mimetype, rest) = separate (== ';') s
in case rest of
(' ':'c':'h':'a':'r':'s':'e':'t':'=':mimeencoding) ->
(mimetype, mimeencoding)
_ -> (mimetype, "")
2019-01-23 16:39:02 +00:00
#else
getMagicMime _ _ = return Nothing
2019-01-23 16:39:02 +00:00
#endif
getMagicMimeType :: MonadIO m => Magic -> FilePath -> m (Maybe MimeType)
getMagicMimeType m f = liftIO $ fmap fst <$> getMagicMime m f
getMagicMimeEncoding :: MonadIO m => Magic -> FilePath -> m(Maybe MimeEncoding)
getMagicMimeEncoding m f = liftIO $ fmap snd <$> getMagicMime m f
#ifdef WITH_MAGICMIME
{-# NOINLINE mutex #-}
mutex :: MVar ()
mutex = unsafePerformIO $ newMVar ()
-- Work around a bug, the library is not concurrency safe and will
-- sometimes access the wrong memory if multiple ones are called at the
-- same time.
magicConcurrentSafe :: IO a -> IO a
magicConcurrentSafe = bracket_ (takeMVar mutex) (putMVar mutex ())
#endif