magic.py revision 300899
150276Speter# coding: utf-8 2178866Srafan 350276Speter''' 450276SpeterPython bindings for libmagic 550276Speter''' 650276Speter 750276Speterimport ctypes 850276Speter 950276Speterfrom collections import namedtuple 1050276Speter 1150276Speterfrom ctypes import * 1250276Speterfrom ctypes.util import find_library 1350276Speter 1450276Speter 1550276Speterdef _init(): 1650276Speter """ 1750276Speter Loads the shared library through ctypes and returns a library 1850276Speter L{ctypes.CDLL} instance 1950276Speter """ 2050276Speter return ctypes.cdll.LoadLibrary(find_library('magic')) 2150276Speter 2250276Speter_libraries = {} 2350276Speter_libraries['magic'] = _init() 2450276Speter 2550276Speter# Flag constants for open and setflags 2650276SpeterMAGIC_NONE = NONE = 0 2750276SpeterMAGIC_DEBUG = DEBUG = 1 2850276SpeterMAGIC_SYMLINK = SYMLINK = 2 2950276SpeterMAGIC_COMPRESS = COMPRESS = 4 3050276SpeterMAGIC_DEVICES = DEVICES = 8 3150276SpeterMAGIC_MIME_TYPE = MIME_TYPE = 16 3250276SpeterMAGIC_CONTINUE = CONTINUE = 32 3350276SpeterMAGIC_CHECK = CHECK = 64 3450276SpeterMAGIC_PRESERVE_ATIME = PRESERVE_ATIME = 128 3550276SpeterMAGIC_RAW = RAW = 256 3650276SpeterMAGIC_ERROR = ERROR = 512 3750276SpeterMAGIC_MIME_ENCODING = MIME_ENCODING = 1024 3850276SpeterMAGIC_MIME = MIME = 1040 # MIME_TYPE + MIME_ENCODING 3976726SpeterMAGIC_APPLE = APPLE = 2048 4050276Speter 41184989SrafanMAGIC_NO_CHECK_COMPRESS = NO_CHECK_COMPRESS = 4096 4250276SpeterMAGIC_NO_CHECK_TAR = NO_CHECK_TAR = 8192 4376726SpeterMAGIC_NO_CHECK_SOFT = NO_CHECK_SOFT = 16384 4476726SpeterMAGIC_NO_CHECK_APPTYPE = NO_CHECK_APPTYPE = 32768 4550276SpeterMAGIC_NO_CHECK_ELF = NO_CHECK_ELF = 65536 46166124SrafanMAGIC_NO_CHECK_TEXT = NO_CHECK_TEXT = 131072 47166124SrafanMAGIC_NO_CHECK_CDF = NO_CHECK_CDF = 262144 48174993SrafanMAGIC_NO_CHECK_TOKENS = NO_CHECK_TOKENS = 1048576 49166124SrafanMAGIC_NO_CHECK_ENCODING = NO_CHECK_ENCODING = 2097152 50166124Srafan 51174993SrafanMAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824 52174993Srafan 53174993SrafanFileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name')) 54174993Srafan 55174993Srafan 56174993Srafanclass magic_set(Structure): 57174993Srafan pass 58174993Srafanmagic_set._fields_ = [] 59174993Srafanmagic_t = POINTER(magic_set) 60174993Srafan 61166124Srafan_open = _libraries['magic'].magic_open 62166124Srafan_open.restype = magic_t 63166124Srafan_open.argtypes = [c_int] 64174993Srafan 65174993Srafan_close = _libraries['magic'].magic_close 66166124Srafan_close.restype = None 67174993Srafan_close.argtypes = [magic_t] 68184989Srafan 69184989Srafan_file = _libraries['magic'].magic_file 70174993Srafan_file.restype = c_char_p 71166124Srafan_file.argtypes = [magic_t, c_char_p] 7250276Speter 7350276Speter_descriptor = _libraries['magic'].magic_descriptor 7476726Speter_descriptor.restype = c_char_p 7576726Speter_descriptor.argtypes = [magic_t, c_int] 7650276Speter 77166124Srafan_buffer = _libraries['magic'].magic_buffer 78166124Srafan_buffer.restype = c_char_p 79174993Srafan_buffer.argtypes = [magic_t, c_void_p, c_size_t] 80166124Srafan 81166124Srafan_error = _libraries['magic'].magic_error 82174993Srafan_error.restype = c_char_p 83174993Srafan_error.argtypes = [magic_t] 84174993Srafan 85174993Srafan_setflags = _libraries['magic'].magic_setflags 86174993Srafan_setflags.restype = c_int 87174993Srafan_setflags.argtypes = [magic_t, c_int] 88174993Srafan 89174993Srafan_load = _libraries['magic'].magic_load 90174993Srafan_load.restype = c_int 91174993Srafan_load.argtypes = [magic_t, c_char_p] 92174993Srafan 93174993Srafan_compile = _libraries['magic'].magic_compile 94166124Srafan_compile.restype = c_int 95166124Srafan_compile.argtypes = [magic_t, c_char_p] 96174993Srafan 97184989Srafan_check = _libraries['magic'].magic_check 98184989Srafan_check.restype = c_int 99166124Srafan_check.argtypes = [magic_t, c_char_p] 100166124Srafan 10150276Speter_list = _libraries['magic'].magic_list 10250276Speter_list.restype = c_int 10376726Speter_list.argtypes = [magic_t, c_char_p] 10476726Speter 10550276Speter_errno = _libraries['magic'].magic_errno 106184989Srafan_errno.restype = c_int 107184989Srafan_errno.argtypes = [magic_t] 10876726Speter 10950276Speter 110184989Srafanclass Magic(object): 111184989Srafan def __init__(self, ms): 112184989Srafan self._magic_t = ms 113184989Srafan 114184989Srafan def close(self): 11550276Speter """ 116184989Srafan Closes the magic database and deallocates any resources used. 117184989Srafan """ 11850276Speter _close(self._magic_t) 119184989Srafan 120184989Srafan def file(self, filename): 12150276Speter """ 122184989Srafan Returns a textual description of the contents of the argument passed 123184989Srafan as a filename or None if an error occurred and the MAGIC_ERROR flag 124184989Srafan is set. A call to errno() will return the numeric error code. 125184989Srafan """ 12650276Speter if isinstance(filename, bytes): 12750276Speter bi = filename 12876726Speter else: 12976726Speter try: # keep Python 2 compatibility 13050276Speter bi = bytes(filename, 'utf-8') 131184989Srafan except TypeError: 132184989Srafan bi = bytes(filename) 13376726Speter r = _file(self._magic_t, bi) 13450276Speter if isinstance(r, str): 135184989Srafan return r 136184989Srafan else: 137184989Srafan return str(r).encode('utf-8') 138184989Srafan 139184989Srafan def descriptor(self, fd): 14050276Speter """ 141184989Srafan Like the file method, but the argument is a file descriptor. 14250276Speter """ 143184989Srafan return _descriptor(self._magic_t, fd) 14450276Speter 145184989Srafan def buffer(self, buf): 146184989Srafan """ 147184989Srafan Returns a textual description of the contents of the argument passed 148184989Srafan as a buffer or None if an error occurred and the MAGIC_ERROR flag 14950276Speter is set. A call to errno() will return the numeric error code. 15050276Speter """ 15176726Speter r = _buffer(self._magic_t, buf, len(buf)) 15276726Speter if isinstance(r, str): 15350276Speter return r 15476726Speter else: 15550276Speter return str(r).encode('utf-8') 15676726Speter 157166124Srafan def error(self): 158166124Srafan """ 159166124Srafan Returns a textual explanation of the last error or None 160178866Srafan if there was no error. 161166124Srafan """ 162166124Srafan e = _error(self._magic_t) 163166124Srafan if isinstance(e, str): 16450276Speter return e 16576726Speter else: 16676726Speter return str(e).encode('utf-8') 16750276Speter 16850276Speter def setflags(self, flags): 16976726Speter """ 17076726Speter Set flags on the magic object which determine how magic checking 17150276Speter behaves; a bitwise OR of the flags described in libmagic(3), but 17276726Speter without the MAGIC_ prefix. 17350276Speter 17476726Speter Returns -1 on systems that don't support utime(2) or utimes(2) 17576726Speter when PRESERVE_ATIME is set. 176178866Srafan """ 17776726Speter return _setflags(self._magic_t, flags) 17876726Speter 17950276Speter def load(self, filename=None): 18076726Speter """ 18176726Speter Must be called to load entries in the colon separated list of database 18276726Speter files passed as argument or the default database file if no argument 18350276Speter before any magic queries can be performed. 18450276Speter 185174993Srafan Returns 0 on success and -1 on failure. 186174993Srafan """ 187174993Srafan return _load(self._magic_t, filename) 188174993Srafan 189174993Srafan def compile(self, dbs): 190174993Srafan """ 191174993Srafan Compile entries in the colon separated list of database files 192174993Srafan passed as argument or the default database file if no argument. 193174993Srafan Returns 0 on success and -1 on failure. 194174993Srafan The compiled files created are named from the basename(1) of each file 195174993Srafan argument with ".mgc" appended to it. 196174993Srafan """ 197174993Srafan return _compile(self._magic_t, dbs) 198174993Srafan 199174993Srafan def check(self, dbs): 200174993Srafan """ 20150276Speter Check the validity of entries in the colon separated list of 20250276Speter database files passed as argument or the default database file 20350276Speter if no argument. 20450276Speter Returns 0 on success and -1 on failure. 20550276Speter """ 20676726Speter return _check(self._magic_t, dbs) 20776726Speter 20850276Speter def list(self, dbs): 20976726Speter """ 21050276Speter Check the validity of entries in the colon separated list of 211174993Srafan database files passed as argument or the default database file 21250276Speter if no argument. 21350276Speter Returns 0 on success and -1 on failure. 21476726Speter """ 21576726Speter return _list(self._magic_t, dbs) 21650276Speter 21776726Speter def errno(self): 21850276Speter """ 219174993Srafan Returns a numeric error code. If return value is 0, an internal 22050276Speter magic error occurred. If return value is non-zero, the value is 221 an OS error code. Use the errno module or os.strerror() can be used 222 to provide detailed error information. 223 """ 224 return _errno(self._magic_t) 225 226 227def open(flags): 228 """ 229 Returns a magic object on success and None on failure. 230 Flags argument as for setflags. 231 """ 232 return Magic(_open(flags)) 233 234 235# Objects used by `detect_from_` functions 236mime_magic = Magic(_open(MAGIC_MIME)) 237mime_magic.load() 238none_magic = Magic(_open(MAGIC_NONE)) 239none_magic.load() 240 241 242def _create_filemagic(mime_detected, type_detected): 243 mime_type, mime_encoding = mime_detected.split('; ') 244 245 return FileMagic(name=type_detected, mime_type=mime_type, 246 encoding=mime_encoding.replace('charset=', '')) 247 248 249def detect_from_filename(filename): 250 '''Detect mime type, encoding and file type from a filename 251 252 Returns a `FileMagic` namedtuple. 253 ''' 254 255 return _create_filemagic(mime_magic.file(filename), 256 none_magic.file(filename)) 257 258 259def detect_from_fobj(fobj): 260 '''Detect mime type, encoding and file type from file-like object 261 262 Returns a `FileMagic` namedtuple. 263 ''' 264 265 file_descriptor = fobj.fileno() 266 return _create_filemagic(mime_magic.descriptor(file_descriptor), 267 none_magic.descriptor(file_descriptor)) 268 269 270def detect_from_content(byte_content): 271 '''Detect mime type, encoding and file type from bytes 272 273 Returns a `FileMagic` namedtuple. 274 ''' 275 276 return _create_filemagic(mime_magic.buffer(byte_content), 277 none_magic.buffer(byte_content)) 278