]> git.k1024.org Git - debian-pyxattr.git/blob - xattr.c
Merge commit 'upstream/0.3.0'
[debian-pyxattr.git] / xattr.c
1 #include <Python.h>
2 #include <attr/xattr.h>
3
4 /** Converts from a string, file or int argument to what we need. */
5 static int convertObj(PyObject *myobj, int *ishandle, int *filehandle,
6                       char **filename) {
7     if(PyString_Check(myobj)) {
8         *ishandle = 0;
9         *filename = PyString_AS_STRING(myobj);
10     } else if((*filehandle = PyObject_AsFileDescriptor(myobj)) != -1) {
11         *ishandle = 1;
12     } else {
13         PyErr_SetString(PyExc_TypeError, "argument 1 must be string or int");
14         return 0;
15     }
16     return 1;
17 }
18
19 /* Wrapper for getxattr */
20 static char __pygetxattr_doc__[] =
21     "Get the value of a given extended attribute.\n"
22     "\n"
23     "Parameters:\n"
24     "\t- a string representing filename, or a file-like object,\n"
25     "\t      or a file descriptor; this represents the file on \n"
26     "\t      which to act\n"
27     "\t- a string, representing the attribute whose value to retrieve;\n"
28     "\t      usually in form of system.posix_acl or user.mime_type\n"
29     "\t- (optional) a boolean value (defaults to false), which, if\n"
30     "\t      the file name given is a symbolic link, makes the\n"
31     "\t      function operate on the symbolic link itself instead\n"
32     "\t      of its target;"
33     ;
34
35 static PyObject *
36 pygetxattr(PyObject *self, PyObject *args)
37 {
38     PyObject *myarg;
39     char *file = NULL;
40     int filedes = -1, ishandle, dolink=0;
41     char *attrname;
42     char *buf;
43     int nalloc, nret;
44     PyObject *res;
45
46     /* Parse the arguments */
47     if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
48         return NULL;
49     if(!convertObj(myarg, &ishandle, &filedes, &file))
50         return NULL;
51
52     /* Find out the needed size of the buffer */
53     nalloc = ishandle ?
54         fgetxattr(filedes, attrname, NULL, 0) :
55         dolink ?
56         lgetxattr(file, attrname, NULL, 0) :
57         getxattr(file, attrname, NULL, 0);
58     if(nalloc == -1) {
59         return PyErr_SetFromErrno(PyExc_IOError);
60     }
61
62     /* Try to allocate the memory, using Python's allocator */
63     if((buf = PyMem_Malloc(nalloc)) == NULL) {
64         PyErr_NoMemory();
65         return NULL;
66     }
67
68     /* Now retrieve the attribute value */
69     nret = ishandle ?
70         fgetxattr(filedes, attrname, buf, nalloc) :
71         dolink ?
72         lgetxattr(file, attrname, buf, nalloc) :
73         getxattr(file, attrname, buf, nalloc);
74     if(nret == -1) {
75         PyMem_Free(buf);
76         return PyErr_SetFromErrno(PyExc_IOError);
77     }
78
79     /* Create the string which will hold the result */
80     res = PyString_FromStringAndSize(buf, nret);
81
82     /* Free the buffer, now it is no longer needed */
83     PyMem_Free(buf);
84
85     /* Return the result */
86     return res;
87 }
88
89 static char __pysetxattr_doc__[] =
90     "Set the value of a given extended attribute.\n"
91     "Be carefull in case you want to set attributes on symbolic\n"
92     "links, you have to use all the 5 parameters; use 0 for the \n"
93     "flags value if you want the default behavior (create or "
94     "replace)\n"
95     "\n"
96     "Parameters:\n"
97     "\t- a string representing filename, or a file-like object,\n"
98     "\t      or a file descriptor; this represents the file on \n"
99     "\t      which to act\n"
100     "\t- a string, representing the attribute whose value to set;\n"
101     "\t      usually in form of system.posix_acl or user.mime_type\n"
102     "\t- a string, possibly with embedded NULLs; note that there\n"
103     "\t      are restrictions regarding the size of the value, for\n"
104     "\t      example, for ext2/ext3, maximum size is the block size\n"
105     "\t- (optional) flags; if 0 or ommited the attribute will be \n"
106     "\t      created or replaced; if XATTR_CREATE, the attribute \n"
107     "\t      will be created, giving an error if it already exists;\n"
108     "\t      of XATTR_REPLACE, the attribute will be replaced,\n"
109     "\t      giving an error if it doesn't exists;\n"
110     "\t- (optional) a boolean value (defaults to false), which, if\n"
111     "\t      the file name given is a symbolic link, makes the\n"
112     "\t      function operate on the symbolic link itself instead\n"
113     "\t      of its target;"
114     ;
115
116 /* Wrapper for setxattr */
117 static PyObject *
118 pysetxattr(PyObject *self, PyObject *args)
119 {
120     PyObject *myarg;
121     char *file;
122     int ishandle, filedes, dolink=0;
123     char *attrname;
124     char *buf;
125     int bufsize, nret;
126     int flags = 0;
127
128     /* Parse the arguments */
129     if (!PyArg_ParseTuple(args, "Oss#|bi", &myarg, &attrname,
130                           &buf, &bufsize, &flags, &dolink))
131         return NULL;
132     if(!convertObj(myarg, &ishandle, &filedes, &file))
133         return NULL;
134
135     /* Set the attribute's value */
136     nret = ishandle ?
137         fsetxattr(filedes, attrname, buf, bufsize, flags) :
138         dolink ?
139         lsetxattr(file, attrname, buf, bufsize, flags) :
140         setxattr(file, attrname, buf, bufsize, flags);
141
142     if(nret == -1) {
143         return PyErr_SetFromErrno(PyExc_IOError);
144     }
145
146     /* Return the result */
147     Py_INCREF(Py_None);
148     return Py_None;
149 }
150
151 static char __pyremovexattr_doc__[] =
152     "Remove an attribute from a file\n"
153     "\n"
154     "Parameters:\n"
155     "\t- a string representing filename, or a file-like object,\n"
156     "\t      or a file descriptor; this represents the file on \n"
157     "\t      which to act\n"
158     "\t- a string, representing the attribute to be removed;\n"
159     "\t      usually in form of system.posix_acl or user.mime_type\n"
160     "\t- (optional) a boolean value (defaults to false), which, if\n"
161     "\t      the file name given is a symbolic link, makes the\n"
162     "\t      function operate on the symbolic link itself instead\n"
163     "\t      of its target;"
164     ;
165
166 /* Wrapper for removexattr */
167 static PyObject *
168 pyremovexattr(PyObject *self, PyObject *args)
169 {
170     PyObject *myarg;
171     char *file;
172     int ishandle, filedes, dolink=0;
173     char *attrname;
174     int nret;
175
176     /* Parse the arguments */
177     if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
178         return NULL;
179
180     if(!convertObj(myarg, &ishandle, &filedes, &file))
181         return NULL;
182
183     /* Remove the attribute */
184     nret = ishandle ?
185         fremovexattr(filedes, attrname) :
186         dolink ?
187         lremovexattr(file, attrname) :
188         removexattr(file, attrname);
189
190     if(nret == -1)
191         return PyErr_SetFromErrno(PyExc_IOError);
192
193     /* Return the result */
194     Py_INCREF(Py_None);
195     return Py_None;
196 }
197
198 static char __pylistxattr_doc__[] =
199     "Return the list of attribute names for a file\n"
200     "\n"
201     "Parameters:\n"
202     "\t- a string representing filename, or a file-like object,\n"
203     "\t      or a file descriptor; this represents the file to \n"
204     "\t      be queried\n"
205     "\t- (optional) a boolean value (defaults to false), which, if\n"
206     "\t      the file name given is a symbolic link, makes the\n"
207     "\t      function operate on the symbolic link itself instead\n"
208     "\t      of its target;"
209     ;
210
211 /* Wrapper for listxattr */
212 static PyObject *
213 pylistxattr(PyObject *self, PyObject *args)
214 {
215     char *file = NULL;
216     int filedes = -1;
217     char *buf;
218     int ishandle, dolink=0;
219     int nalloc, nret;
220     PyObject *myarg;
221     PyObject *mylist;
222     int nattrs;
223     char *s;
224
225     /* Parse the arguments */
226     if (!PyArg_ParseTuple(args, "O|i", &myarg, &dolink))
227         return NULL;
228     if(!convertObj(myarg, &ishandle, &filedes, &file))
229         return NULL;
230
231     /* Find out the needed size of the buffer */
232     nalloc = ishandle ?
233         flistxattr(filedes, NULL, 0) :
234         dolink ?
235         llistxattr(file, NULL, 0) :
236         listxattr(file, NULL, 0);
237
238     if(nalloc == -1) {
239         return PyErr_SetFromErrno(PyExc_IOError);
240     }
241
242     /* Try to allocate the memory, using Python's allocator */
243     if((buf = PyMem_Malloc(nalloc)) == NULL) {
244         PyErr_NoMemory();
245         return NULL;
246     }
247
248     /* Now retrieve the list of attributes */
249     nret = ishandle ?
250         flistxattr(filedes, buf, nalloc) :
251         dolink ?
252         llistxattr(file, buf, nalloc) :
253         listxattr(file, buf, nalloc);
254
255     if(nret == -1) {
256         return PyErr_SetFromErrno(PyExc_IOError);
257     }
258
259     /* Compute the number of attributes in the list */
260     for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
261         nattrs++;
262     }
263
264     /* Create the list which will hold the result */
265     mylist = PyList_New(nattrs);
266
267     /* Create and insert the attributes as strings in the list */
268     for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
269         PyList_SET_ITEM(mylist, nattrs, PyString_FromString(s));
270         nattrs++;
271     }
272
273     /* Free the buffer, now it is no longer needed */
274     PyMem_Free(buf);
275
276     /* Return the result */
277     return mylist;
278 }
279
280 static PyMethodDef xattr_methods[] = {
281     {"getxattr",  pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
282     {"setxattr",  pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
283     {"removexattr",  pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
284     {"listxattr",  pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
285     {NULL, NULL, 0, NULL}        /* Sentinel */
286 };
287
288 static char __xattr_doc__[] = \
289     "Access extended filesystem attributes\n"
290     "\n"
291     "This module gives access to the extended attributes present\n"
292     "in some operating systems/filesystems. You can list attributes,\n"
293     "get, set and remove them.\n"
294     "The last and optional parameter for all functions is a boolean \n"
295     "value which enables the 'l-' version of the functions - acting\n"
296     "on symbolic links and not their destination.\n"
297     "\n"
298     "Example: \n"
299     ">>> import xattr\n"
300     ">>> xattr.listxattr(\"file.txt\")\n"
301     "('user.mime_type',)\n"
302     ">>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
303     "'text/plain'\n"
304     ">>> xattr.setxattr(\"file.txt\", \"user.comment\", \"Simple text file\")"
305     "\n"
306     ">>> xattr.listxattr(\"file.txt\")\n"
307     "('user.mime_type', 'user.comment')\n"
308     ">>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
309     ""
310     ;
311
312 void
313 initxattr(void)
314 {
315     PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
316
317     PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
318     PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
319
320 }