2019-01-23 16:39:02 +00:00
|
|
|
{- Interface to libmagic
|
|
|
|
-
|
2020-09-17 21:27:42 +00:00
|
|
|
- Copyright 2019-2020 Joey Hess <id@joeyh.name>
|
2019-01-23 16:39:02 +00:00
|
|
|
-
|
2019-03-13 19:48:14 +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,
|
2019-04-30 15:58:06 +00:00
|
|
|
MimeEncoding,
|
|
|
|
initMagicMime,
|
2019-01-23 16:39:02 +00:00
|
|
|
getMagicMimeType,
|
2019-04-30 15:58:06 +00:00
|
|
|
getMagicMimeEncoding,
|
2019-01-23 16:39:02 +00:00
|
|
|
) where
|
|
|
|
|
2019-05-03 14:58:34 +00:00
|
|
|
import Types.Mime
|
2019-09-19 15:32:12 +00:00
|
|
|
import Control.Monad.IO.Class
|
2019-01-23 16:39:02 +00:00
|
|
|
#ifdef WITH_MAGICMIME
|
|
|
|
import Magic
|
|
|
|
import Utility.Env
|
2020-09-17 21:27:42 +00:00
|
|
|
import Control.Concurrent
|
|
|
|
import System.IO.Unsafe (unsafePerformIO)
|
2019-01-23 16:39:02 +00:00
|
|
|
import Common
|
|
|
|
#else
|
|
|
|
type Magic = ()
|
|
|
|
#endif
|
|
|
|
|
2019-04-30 15:58:06 +00:00
|
|
|
initMagicMime :: IO (Maybe Magic)
|
2019-01-23 16:39:02 +00:00
|
|
|
#ifdef WITH_MAGICMIME
|
2019-04-30 15:58:06 +00:00
|
|
|
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
|
2019-04-30 15:58:06 +00:00
|
|
|
initMagicMime = return Nothing
|
2019-01-23 16:39:02 +00:00
|
|
|
#endif
|
|
|
|
|
2019-04-30 15:58:06 +00:00
|
|
|
getMagicMime :: Magic -> FilePath -> IO (Maybe (MimeType, MimeEncoding))
|
2019-01-23 16:39:02 +00:00
|
|
|
#ifdef WITH_MAGICMIME
|
2020-09-17 21:27:42 +00:00
|
|
|
getMagicMime m f = Just . parse <$> magicConcurrentSafe (magicFile m f)
|
2019-04-30 15:58:06 +00:00
|
|
|
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
|
2019-04-30 15:58:06 +00:00
|
|
|
getMagicMime _ _ = return Nothing
|
2019-01-23 16:39:02 +00:00
|
|
|
#endif
|
2019-04-30 15:58:06 +00:00
|
|
|
|
2019-09-19 15:32:12 +00:00
|
|
|
getMagicMimeType :: MonadIO m => Magic -> FilePath -> m (Maybe MimeType)
|
|
|
|
getMagicMimeType m f = liftIO $ fmap fst <$> getMagicMime m f
|
2019-04-30 15:58:06 +00:00
|
|
|
|
2019-09-19 15:32:12 +00:00
|
|
|
getMagicMimeEncoding :: MonadIO m => Magic -> FilePath -> m(Maybe MimeEncoding)
|
|
|
|
getMagicMimeEncoding m f = liftIO $ fmap snd <$> getMagicMime m f
|
2020-09-17 21:27:42 +00:00
|
|
|
|
|
|
|
#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
|