1/*
2   Python wrappers for magic functions.
3
4   Copyright (C) Brett Funderburg, Deepfile Corp. Austin, TX, US 2003
5
6   Redistribution and use in source and binary forms, with or without
7   modification, are permitted provided that the following conditions
8   are met:
9   1. Redistributions of source code must retain the above copyright
10      notice immediately at the beginning of the file, without modification,
11      this list of conditions, and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   3. The name of the author may not be used to endorse or promote products
16      derived from this software without specific prior written permission.
17
18   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21   ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22   ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28   SUCH DAMAGE.
29*/
30
31#include <Python.h>
32#include <magic.h>
33#include "py_magic.h"
34
35/* Exceptions raised by this module */
36
37PyObject* magic_error_obj;
38
39/* Create a new magic_cookie_hnd object */
40PyObject* new_magic_cookie_handle(magic_t cookie)
41{
42    magic_cookie_hnd* mch;
43
44    mch = PyObject_New(magic_cookie_hnd, &magic_cookie_type);
45
46    mch->cookie = cookie;
47
48    return (PyObject*)mch;
49}
50
51static char _magic_open__doc__[] =
52"Returns a magic cookie on success and None on failure.\n";
53static PyObject* py_magic_open(PyObject* self, PyObject* args)
54{
55    int flags = 0;
56    magic_t cookie;
57
58    if(!PyArg_ParseTuple(args, "i", &flags))
59        return NULL;
60
61    if(!(cookie = magic_open(flags))) {
62        PyErr_SetString(magic_error_obj, "failure initializing magic cookie");
63        return NULL;
64    }
65
66    return new_magic_cookie_handle(cookie);
67}
68
69static char _magic_close__doc__[] =
70"Closes the magic database and deallocates any resources used.\n";
71static PyObject* py_magic_close(PyObject* self, PyObject* args)
72{
73    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
74
75    magic_close(hnd->cookie);
76
77    Py_INCREF(Py_None);
78    return Py_None;
79}
80
81static char _magic_error__doc__[] =
82"Returns a textual explanation of the last error or None \
83 if there was no error.\n";
84static PyObject* py_magic_error(PyObject* self, PyObject* args)
85{
86    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
87    const char* message = NULL;
88    PyObject* result = Py_None;
89
90    message = magic_error(hnd->cookie);
91
92    if(message != NULL)
93        result = PyString_FromString(message);
94    else
95        Py_INCREF(Py_None);
96
97    return result;
98}
99
100static char _magic_errno__doc__[] =
101"Returns a numeric error code. If return value is 0, an internal \
102 magic error occurred. If return value is non-zero, the value is \
103 an OS error code. Use the errno module or os.strerror() can be used \
104 to provide detailed error information.\n";
105static PyObject* py_magic_errno(PyObject* self, PyObject* args)
106{
107    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
108    return PyInt_FromLong(magic_errno(hnd->cookie));
109}
110
111static char _magic_file__doc__[] =
112"Returns a textual description of the contents of the argument passed \
113 as a filename or None if an error occurred and the MAGIC_ERROR flag \
114 is set. A call to errno() will return the numeric error code.\n";
115static PyObject* py_magic_file(PyObject* self, PyObject* args)
116{
117    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
118    char* filename = NULL;
119    const char* message = NULL;
120    PyObject* result = Py_None;
121
122    if(!(PyArg_ParseTuple(args, "s", &filename)))
123        return NULL;
124
125    message = magic_file(hnd->cookie, filename);
126
127    if(message != NULL)
128        result = PyString_FromString(message);
129    else
130        Py_INCREF(Py_None);
131
132    return result;
133}
134
135static char _magic_buffer__doc__[] =
136"Returns a textual description of the contents of the argument passed \
137 as a buffer or None if an error occurred and the MAGIC_ERROR flag \
138 is set. A call to errno() will return the numeric error code.\n";
139static PyObject* py_magic_buffer(PyObject* self, PyObject* args)
140{
141    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
142    void* buffer = NULL;
143    int buffer_length = 0;
144    const char* message = NULL;
145    PyObject* result = Py_None;
146
147    if(!(PyArg_ParseTuple(args, "s#", (char**)&buffer, &buffer_length)))
148        return NULL;
149
150    message = magic_buffer(hnd->cookie, buffer, buffer_length);
151
152    if(message != NULL)
153        result = PyString_FromString(message);
154    else
155        Py_INCREF(Py_None);
156
157    return result;
158}
159
160static char _magic_setflags__doc__[] =
161"Set flags on the cookie object.\n \
162 Returns -1 on systems that don't support utime(2) or utimes(2) \
163 when MAGIC_PRESERVE_ATIME is set.\n";
164static PyObject* py_magic_setflags(PyObject* self, PyObject* args)
165{
166    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
167    int flags;
168    int result;
169
170    if(!(PyArg_ParseTuple(args, "i", &flags)))
171        return NULL;
172
173    result = magic_setflags(hnd->cookie, flags);
174
175    return PyInt_FromLong(result);
176}
177
178static char _magic_check__doc__[] =
179"Check the validity of entries in the colon separated list of \
180 database files passed as argument or the default database file \
181 if no argument.\n Returns 0 on success and -1 on failure.\n";
182static PyObject* py_magic_check(PyObject* self, PyObject* args)
183{
184    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
185    char* filename = NULL;
186    int result;
187
188    if(!(PyArg_ParseTuple(args, "|s", &filename)))
189        return NULL;
190
191    result = magic_check(hnd->cookie, filename);
192
193    return PyInt_FromLong(result);
194}
195
196static char _magic_compile__doc__[] =
197"Compile entries in the colon separated list of database files \
198 passed as argument or the default database file if no argument.\n \
199 Returns 0 on success and -1 on failure.\n \
200 The compiled files created are named from the basename(1) of each file \
201 argument with \".mgc\" appended to it.\n";
202static PyObject* py_magic_compile(PyObject* self, PyObject* args)
203{
204    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
205    char* filename = NULL;
206    int result;
207
208    if(!(PyArg_ParseTuple(args, "|s", &filename)))
209        return NULL;
210
211    result = magic_compile(hnd->cookie, filename);
212
213    return PyInt_FromLong(result);
214}
215
216static char _magic_load__doc__[] =
217"Must be called to load entries in the colon separated list of database files \
218 passed as argument or the default database file if no argument before \
219 any magic queries can be performed.\n \
220 Returns 0 on success and -1 on failure.\n";
221static PyObject* py_magic_load(PyObject* self, PyObject* args)
222{
223    magic_cookie_hnd* hnd = (magic_cookie_hnd*)self;
224    char* filename = NULL;
225    int result;
226
227    if(!(PyArg_ParseTuple(args, "|s", &filename)))
228        return NULL;
229
230    result = magic_load(hnd->cookie, filename);
231
232    return PyInt_FromLong(result);
233}
234
235/* object methods */
236
237static PyMethodDef magic_cookie_hnd_methods[] = {
238    { "close", (PyCFunction)py_magic_close,
239      METH_NOARGS, _magic_close__doc__ },
240    { "error", (PyCFunction)py_magic_error,
241      METH_NOARGS, _magic_error__doc__ },
242    { "file", (PyCFunction)py_magic_file,
243      METH_VARARGS, _magic_file__doc__ },
244    { "buffer", (PyCFunction)py_magic_buffer,
245      METH_VARARGS, _magic_buffer__doc__ },
246    { "setflags", (PyCFunction)py_magic_setflags,
247      METH_VARARGS, _magic_setflags__doc__ },
248    { "check", (PyCFunction)py_magic_check,
249      METH_VARARGS, _magic_check__doc__ },
250    { "compile", (PyCFunction)py_magic_compile,
251      METH_VARARGS, _magic_compile__doc__ },
252    { "load", (PyCFunction)py_magic_load,
253      METH_VARARGS, _magic_load__doc__ },
254    { "errno", (PyCFunction)py_magic_errno,
255      METH_NOARGS, _magic_errno__doc__ },
256    { NULL, NULL }
257};
258
259/* module level methods */
260
261static PyMethodDef magic_methods[] = {
262    { "open", (PyCFunction)py_magic_open,
263      METH_VARARGS, _magic_open__doc__ },
264    { NULL, NULL }
265};
266
267static void py_magic_dealloc(PyObject* self)
268{
269    PyObject_Del(self);
270}
271
272static PyObject* py_magic_getattr(PyObject* self, char* attrname)
273{
274    return Py_FindMethod(magic_cookie_hnd_methods, self, attrname);
275}
276
277PyTypeObject magic_cookie_type = {
278    PyObject_HEAD_INIT(NULL)
279    0,
280    "Magic cookie",
281    sizeof(magic_cookie_hnd),
282    0,
283    py_magic_dealloc, /* tp_dealloc */
284    0,                /* tp_print */
285    py_magic_getattr, /* tp_getattr */
286    0,                /* tp_setattr */
287    0,                /* tp_compare */
288    0,                /* tp_repr */
289    0,                /* tp_as_number */
290    0,                /* tp_as_sequence */
291    0,                /* tp_as_mapping */
292    0,                /* tp_hash */
293};
294
295/* Initialize constants */
296
297static struct const_vals {
298    const char* const name;
299    unsigned int value;
300} module_const_vals[] = {
301    { "MAGIC_NONE", MAGIC_NONE },
302    { "MAGIC_DEBUG", MAGIC_DEBUG },
303    { "MAGIC_SYMLINK", MAGIC_SYMLINK },
304    { "MAGIC_COMPRESS", MAGIC_COMPRESS },
305    { "MAGIC_DEVICES", MAGIC_DEVICES },
306    { "MAGIC_MIME", MAGIC_MIME },
307    { "MAGIC_CONTINUE", MAGIC_CONTINUE },
308    { "MAGIC_CHECK", MAGIC_CHECK },
309    { "MAGIC_PRESERVE_ATIME", MAGIC_PRESERVE_ATIME },
310    { "MAGIC_ERROR", MAGIC_ERROR},
311    { NULL }
312};
313
314static void const_init(PyObject* dict)
315{
316    struct const_vals* tmp;
317    PyObject *obj;
318
319    for(tmp = module_const_vals; tmp->name; ++tmp) {
320        obj = PyInt_FromLong(tmp->value);
321        PyDict_SetItemString(dict, tmp->name, obj);
322        Py_DECREF(obj);
323    }
324}
325
326/*
327 * Module initialization
328 */
329
330void initmagic(void)
331{
332    PyObject* module;
333    PyObject* dict;
334
335    /* Initialize module */
336
337    module = Py_InitModule("magic", magic_methods);
338    dict = PyModule_GetDict(module);
339
340    magic_error_obj = PyErr_NewException("magic.error", NULL, NULL);
341    PyDict_SetItemString(dict, "error", magic_error_obj);
342
343    magic_cookie_type.ob_type = &PyType_Type;
344
345    /* Initialize constants */
346
347    const_init(dict);
348
349    if(PyErr_Occurred())
350        Py_FatalError("can't initialize module magic");
351}
352