]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/file/python/magic.py
Update file(1) to new version with security update. [EN-18:02.file]
[FreeBSD/releng/10.3.git] / contrib / file / python / magic.py
1 # coding: utf-8
2
3 '''
4 Python bindings for libmagic
5 '''
6
7 import ctypes
8
9 from collections import namedtuple
10
11 from ctypes import *
12 from ctypes.util import find_library
13
14
15 def _init():
16     """
17     Loads the shared library through ctypes and returns a library
18     L{ctypes.CDLL} instance
19     """
20     return ctypes.cdll.LoadLibrary(find_library('magic'))
21
22 _libraries = {}
23 _libraries['magic'] = _init()
24
25 # Flag constants for open and setflags
26 MAGIC_NONE = NONE = 0
27 MAGIC_DEBUG = DEBUG = 1
28 MAGIC_SYMLINK = SYMLINK = 2
29 MAGIC_COMPRESS = COMPRESS = 4
30 MAGIC_DEVICES = DEVICES = 8
31 MAGIC_MIME_TYPE = MIME_TYPE = 16
32 MAGIC_CONTINUE = CONTINUE = 32
33 MAGIC_CHECK = CHECK = 64
34 MAGIC_PRESERVE_ATIME = PRESERVE_ATIME = 128
35 MAGIC_RAW = RAW = 256
36 MAGIC_ERROR = ERROR = 512
37 MAGIC_MIME_ENCODING = MIME_ENCODING = 1024
38 MAGIC_MIME = MIME = 1040  # MIME_TYPE + MIME_ENCODING
39 MAGIC_APPLE = APPLE = 2048
40
41 MAGIC_NO_CHECK_COMPRESS = NO_CHECK_COMPRESS = 4096
42 MAGIC_NO_CHECK_TAR = NO_CHECK_TAR = 8192
43 MAGIC_NO_CHECK_SOFT = NO_CHECK_SOFT = 16384
44 MAGIC_NO_CHECK_APPTYPE = NO_CHECK_APPTYPE = 32768
45 MAGIC_NO_CHECK_ELF = NO_CHECK_ELF = 65536
46 MAGIC_NO_CHECK_TEXT = NO_CHECK_TEXT = 131072
47 MAGIC_NO_CHECK_CDF = NO_CHECK_CDF = 262144
48 MAGIC_NO_CHECK_TOKENS = NO_CHECK_TOKENS = 1048576
49 MAGIC_NO_CHECK_ENCODING = NO_CHECK_ENCODING = 2097152
50
51 MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824
52
53 FileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name'))
54
55
56 class magic_set(Structure):
57     pass
58 magic_set._fields_ = []
59 magic_t = POINTER(magic_set)
60
61 _open = _libraries['magic'].magic_open
62 _open.restype = magic_t
63 _open.argtypes = [c_int]
64
65 _close = _libraries['magic'].magic_close
66 _close.restype = None
67 _close.argtypes = [magic_t]
68
69 _file = _libraries['magic'].magic_file
70 _file.restype = c_char_p
71 _file.argtypes = [magic_t, c_char_p]
72
73 _descriptor = _libraries['magic'].magic_descriptor
74 _descriptor.restype = c_char_p
75 _descriptor.argtypes = [magic_t, c_int]
76
77 _buffer = _libraries['magic'].magic_buffer
78 _buffer.restype = c_char_p
79 _buffer.argtypes = [magic_t, c_void_p, c_size_t]
80
81 _error = _libraries['magic'].magic_error
82 _error.restype = c_char_p
83 _error.argtypes = [magic_t]
84
85 _setflags = _libraries['magic'].magic_setflags
86 _setflags.restype = c_int
87 _setflags.argtypes = [magic_t, c_int]
88
89 _load = _libraries['magic'].magic_load
90 _load.restype = c_int
91 _load.argtypes = [magic_t, c_char_p]
92
93 _compile = _libraries['magic'].magic_compile
94 _compile.restype = c_int
95 _compile.argtypes = [magic_t, c_char_p]
96
97 _check = _libraries['magic'].magic_check
98 _check.restype = c_int
99 _check.argtypes = [magic_t, c_char_p]
100
101 _list = _libraries['magic'].magic_list
102 _list.restype = c_int
103 _list.argtypes = [magic_t, c_char_p]
104
105 _errno = _libraries['magic'].magic_errno
106 _errno.restype = c_int
107 _errno.argtypes = [magic_t]
108
109
110 class Magic(object):
111     def __init__(self, ms):
112         self._magic_t = ms
113
114     def close(self):
115         """
116         Closes the magic database and deallocates any resources used.
117         """
118         _close(self._magic_t)
119
120     @staticmethod
121     def __tostr(s):
122         if s is None:
123             return None
124         if isinstance(s, str):
125             return s
126         try:  # keep Python 2 compatibility
127             return str(s, 'utf-8')
128         except TypeError:
129             return str(s)
130
131     @staticmethod
132     def __tobytes(b):
133         if b is None:
134             return None
135         if isinstance(b, bytes):
136             return b
137         try:  # keep Python 2 compatibility
138             return bytes(b, 'utf-8')
139         except TypeError:
140             return bytes(b)
141
142     def file(self, filename):
143         """
144         Returns a textual description of the contents of the argument passed
145         as a filename or None if an error occurred and the MAGIC_ERROR flag
146         is set. A call to errno() will return the numeric error code.
147         """
148         return Magic.__tostr(_file(self._magic_t, Magic.__tobytes(filename)))
149
150     def descriptor(self, fd):
151         """
152         Returns a textual description of the contents of the argument passed
153         as a file descriptor or None if an error occurred and the MAGIC_ERROR
154         flag is set. A call to errno() will return the numeric error code.
155         """
156         return Magic.__tostr(_descriptor(self._magic_t, fd))
157
158     def buffer(self, buf):
159         """
160         Returns a textual description of the contents of the argument passed
161         as a buffer or None if an error occurred and the MAGIC_ERROR flag
162         is set. A call to errno() will return the numeric error code.
163         """
164         return Magic.__tostr(_buffer(self._magic_t, buf, len(buf)))
165
166     def error(self):
167         """
168         Returns a textual explanation of the last error or None
169         if there was no error.
170         """
171         return Magic.__tostr(_error(self._magic_t))
172
173     def setflags(self, flags):
174         """
175         Set flags on the magic object which determine how magic checking
176         behaves; a bitwise OR of the flags described in libmagic(3), but
177         without the MAGIC_ prefix.
178
179         Returns -1 on systems that don't support utime(2) or utimes(2)
180         when PRESERVE_ATIME is set.
181         """
182         return _setflags(self._magic_t, flags)
183
184     def load(self, filename=None):
185         """
186         Must be called to load entries in the colon separated list of database
187         files passed as argument or the default database file if no argument
188         before any magic queries can be performed.
189
190         Returns 0 on success and -1 on failure.
191         """
192         return _load(self._magic_t, Magic.__tobytes(filename))
193
194     def compile(self, dbs):
195         """
196         Compile entries in the colon separated list of database files
197         passed as argument or the default database file if no argument.
198         The compiled files created are named from the basename(1) of each file
199         argument with ".mgc" appended to it.
200
201         Returns 0 on success and -1 on failure.
202         """
203         return _compile(self._magic_t, Magic.__tobytes(dbs))
204
205     def check(self, dbs):
206         """
207         Check the validity of entries in the colon separated list of
208         database files passed as argument or the default database file
209         if no argument.
210
211         Returns 0 on success and -1 on failure.
212         """
213         return _check(self._magic_t, Magic.__tobytes(dbs))
214
215     def list(self, dbs):
216         """
217         Check the validity of entries in the colon separated list of
218         database files passed as argument or the default database file
219         if no argument.
220
221         Returns 0 on success and -1 on failure.
222         """
223         return _list(self._magic_t, Magic.__tobytes(dbs))
224
225     def errno(self):
226         """
227         Returns a numeric error code. If return value is 0, an internal
228         magic error occurred. If return value is non-zero, the value is
229         an OS error code. Use the errno module or os.strerror() can be used
230         to provide detailed error information.
231         """
232         return _errno(self._magic_t)
233
234
235 def open(flags):
236     """
237     Returns a magic object on success and None on failure.
238     Flags argument as for setflags.
239     """
240     return Magic(_open(flags))
241
242
243 # Objects used by `detect_from_` functions
244 mime_magic = Magic(_open(MAGIC_MIME))
245 mime_magic.load()
246 none_magic = Magic(_open(MAGIC_NONE))
247 none_magic.load()
248
249
250 def _create_filemagic(mime_detected, type_detected):
251     mime_type, mime_encoding = mime_detected.split('; ')
252
253     return FileMagic(name=type_detected, mime_type=mime_type,
254                      encoding=mime_encoding.replace('charset=', ''))
255
256
257 def detect_from_filename(filename):
258     '''Detect mime type, encoding and file type from a filename
259
260     Returns a `FileMagic` namedtuple.
261     '''
262
263     return _create_filemagic(mime_magic.file(filename),
264                              none_magic.file(filename))
265
266
267 def detect_from_fobj(fobj):
268     '''Detect mime type, encoding and file type from file-like object
269
270     Returns a `FileMagic` namedtuple.
271     '''
272
273     file_descriptor = fobj.fileno()
274     return _create_filemagic(mime_magic.descriptor(file_descriptor),
275                              none_magic.descriptor(file_descriptor))
276
277
278 def detect_from_content(byte_content):
279     '''Detect mime type, encoding and file type from bytes
280
281     Returns a `FileMagic` namedtuple.
282     '''
283
284     return _create_filemagic(mime_magic.buffer(byte_content),
285                              none_magic.buffer(byte_content))