From cf210655e2b4a176f998909611ba936b064afc26 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 22 May 2024 16:15:04 +0200 Subject: [PATCH 1/5] Clean up loader.py --- magic/loader.py | 78 ++++++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/magic/loader.py b/magic/loader.py index 228a35c..145fcfa 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -4,47 +4,65 @@ import glob import os.path -def _lib_candidates(): - yield find_library('magic') +def _lib_candidates_linux(): + """Yield possible libmagic library names on Linux. + + This is necessary because alpine is bad + """ + yield "libmagic.so.1" - if sys.platform == 'darwin': +def _lib_candidates_macos(): + """Yield possible libmagic library names on macOS.""" paths = [ - '/opt/local/lib', - '/usr/local/lib', - '/opt/homebrew/lib', - ] + glob.glob('/usr/local/Cellar/libmagic/*/lib') + "/opt/homebrew/lib", + "/opt/local/lib", + "/usr/local/lib", + ] + glob.glob("/usr/local/Cellar/libmagic/*/lib") + for path in paths: + yield os.path.join(path, "libmagic.dylib") - for i in paths: - yield os.path.join(i, 'libmagic.dylib') - elif sys.platform in ('win32', 'cygwin'): +def _lib_candidates_windows(): + """Yield possible libmagic library names on Windows.""" + prefixes = ( + "libmagic", + "magic1", + "magic-1", + "cygmagic-1", + "libmagic-1", + "msys-magic-1", + ) + for prefix in prefixes: + # find_library searches in %PATH% but not the current directory, + # so look for both + yield "./%s.dll" % (prefix,) + yield find_library(prefix) - prefixes = ['libmagic', 'magic1', 'magic-1', 'cygmagic-1', 'libmagic-1', 'msys-magic-1'] - for i in prefixes: - # find_library searches in %PATH% but not the current directory, - # so look for both - yield './%s.dll' % (i,) - yield find_library(i) +def _lib_candidates(): + yield find_library("magic") - elif sys.platform == 'linux': - # This is necessary because alpine is bad - yield 'libmagic.so.1' + func = { + "cygwin": _lib_candidates_windows, + "darwin": _lib_candidates_macos, + "linux": _lib_candidates_linux, + "win32": _lib_candidates_windows, + }[sys.platform] + # When we drop legacy Python, we can just `yield from func()` + for path in func(): + yield path def load_lib(): + for lib in _lib_candidates(): + # find_library returns None when lib not found + if lib: + try: + return ctypes.CDLL(lib) + except OSError: + pass - for lib in _lib_candidates(): - # find_library returns None when lib not found - if lib is None: - continue - try: - return ctypes.CDLL(lib) - except OSError: - pass - else: # It is better to raise an ImportError since we are importing magic module - raise ImportError('failed to find libmagic. Check your installation') - + raise ImportError("failed to find libmagic. Check your installation") From 0a2fda39ba235360b6a8ec6f1d531b08ab306b25 Mon Sep 17 00:00:00 2001 From: Adam Hupp Date: Sun, 26 May 2024 01:01:34 -0700 Subject: [PATCH 2/5] handle unknown platforms gracefully in loader.py --- magic/loader.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/magic/loader.py b/magic/loader.py index 145fcfa..33bf4d4 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -49,7 +49,9 @@ def _lib_candidates(): "darwin": _lib_candidates_macos, "linux": _lib_candidates_linux, "win32": _lib_candidates_windows, - }[sys.platform] + }.get(sys.platform) + if func is None: + raise ImportError("python-magic: Unsupported platform: " + sys.platform) # When we drop legacy Python, we can just `yield from func()` for path in func(): yield path @@ -65,4 +67,4 @@ def load_lib(): pass # It is better to raise an ImportError since we are importing magic module - raise ImportError("failed to find libmagic. Check your installation") + raise ImportError("python-magic: failed to find libmagic. Check your installation") From 4b776d72729b4a1cf87f6939089cacdeff171972 Mon Sep 17 00:00:00 2001 From: Adam Hupp Date: Sun, 26 May 2024 01:11:45 -0700 Subject: [PATCH 3/5] rename no_json test to avoid duplicate function definitions --- test/python_magic_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/python_magic_test.py b/test/python_magic_test.py index 633fcab..7ad15c8 100755 --- a/test/python_magic_test.py +++ b/test/python_magic_test.py @@ -202,7 +202,8 @@ def test_descriptions_no_json(self): buf_equals_file=True, ) - def test_descriptions_no_json(self): + def test_descriptions_no_json_unchanged(self): + # verify non-json results are unchanged m = magic.Magic(check_json=False) os.environ["TZ"] = "UTC" # To get last modified date of test.gz in UTC try: From 339eac0450f2fc87b48a9c62b21a874a9464bb05 Mon Sep 17 00:00:00 2001 From: Adam Hupp Date: Sun, 26 May 2024 01:15:00 -0700 Subject: [PATCH 4/5] smartos support, adapted from #132 --- README.md | 4 ++++ magic/loader.py | 1 + 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 02374d7..5fce8c1 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,10 @@ pip install python-magic-bin - When using Homebrew: `brew install libmagic` - When using macports: `port install file` +### SmartOS: +- Install libmagic for source https://github.com/threatstack/libmagic/ +- Depending on your ./configure --prefix settings set your LD_LIBRARY_PATH to /lib + ### Troubleshooting - 'MagicException: could not find any magic files!': some diff --git a/magic/loader.py b/magic/loader.py index 33bf4d4..3179c05 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -49,6 +49,7 @@ def _lib_candidates(): "darwin": _lib_candidates_macos, "linux": _lib_candidates_linux, "win32": _lib_candidates_windows, + "sunos5": _lib_candidates_linux, }.get(sys.platform) if func is None: raise ImportError("python-magic: Unsupported platform: " + sys.platform) From a9e627644efcee42b70cf7634f0ec6d2bab318c8 Mon Sep 17 00:00:00 2001 From: Adam Hupp Date: Sun, 26 May 2024 01:21:47 -0700 Subject: [PATCH 5/5] log warning on ctypes load error, adapted from #279 --- magic/loader.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/magic/loader.py b/magic/loader.py index 3179c05..e6edc7b 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -3,7 +3,9 @@ import sys import glob import os.path +import logging +logger = logging.getLogger(__name__) def _lib_candidates_linux(): """Yield possible libmagic library names on Linux. @@ -61,11 +63,15 @@ def _lib_candidates(): def load_lib(): for lib in _lib_candidates(): # find_library returns None when lib not found - if lib: - try: - return ctypes.CDLL(lib) - except OSError: - pass + if lib is None: + continue + if not os.path.exists(lib): + continue + + try: + return ctypes.CDLL(lib) + except OSError: + logger.warning("Failed to load: " + lib, exc_info=True) # It is better to raise an ImportError since we are importing magic module raise ImportError("python-magic: failed to find libmagic. Check your installation")