2 #include <attr/xattr.h>
4 /** Converts from a string, file or int argument to what we need. */
5 static int convertObj(PyObject *myobj, int *ishandle, int *filehandle,
7 if(PyString_Check(myobj)) {
9 *filename = PyString_AS_STRING(myobj);
10 } else if((*filehandle = PyObject_AsFileDescriptor(myobj)) != -1) {
13 PyErr_SetString(PyExc_TypeError, "argument 1 must be string or int");
19 /* Checks if an attribute name matches an optional namespace */
20 static int matches_ns(const char *name, const char *ns) {
26 if (strlen(name) > ns_size && !strncmp(name, ns, ns_size) &&
32 /* Wrapper for getxattr */
33 static char __pygetxattr_doc__[] =
34 "Get the value of a given extended attribute.\n"
37 " - a string representing filename, or a file-like object,\n"
38 " or a file descriptor; this represents the file on \n"
40 " - a string, representing the attribute whose value to retrieve;\n"
41 " usually in form of system.posix_acl or user.mime_type\n"
42 " - (optional) a boolean value (defaults to false), which, if\n"
43 " the file name given is a symbolic link, makes the\n"
44 " function operate on the symbolic link itself instead\n"
49 pygetxattr(PyObject *self, PyObject *args)
53 int filedes = -1, ishandle, dolink=0;
59 /* Parse the arguments */
60 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
62 if(!convertObj(myarg, &ishandle, &filedes, &file))
65 /* Find out the needed size of the buffer */
67 fgetxattr(filedes, attrname, NULL, 0) :
69 lgetxattr(file, attrname, NULL, 0) :
70 getxattr(file, attrname, NULL, 0);
72 return PyErr_SetFromErrno(PyExc_IOError);
75 /* Try to allocate the memory, using Python's allocator */
76 if((buf = PyMem_Malloc(nalloc)) == NULL) {
81 /* Now retrieve the attribute value */
83 fgetxattr(filedes, attrname, buf, nalloc) :
85 lgetxattr(file, attrname, buf, nalloc) :
86 getxattr(file, attrname, buf, nalloc);
89 return PyErr_SetFromErrno(PyExc_IOError);
92 /* Create the string which will hold the result */
93 res = PyString_FromStringAndSize(buf, nret);
95 /* Free the buffer, now it is no longer needed */
98 /* Return the result */
102 /* Wrapper for getxattr */
103 static char __get_all_doc__[] =
104 "Get all the extended attributes of an item.\n"
107 " - a string representing filename, or a file-like object,\n"
108 " or a file descriptor; this represents the file on \n"
110 " - (optional) a boolean value (defaults to false), which, if\n"
111 " the file name given is a symbolic link, makes the\n"
112 " function operate on the symbolic link itself instead\n"
117 get_all(PyObject *self, PyObject *args, PyObject *keywds)
121 int filedes = -1, ishandle, dolink=0;
123 char *buf_list, *buf_val;
125 int nalloc, nlist, nval, nattrs;
127 static char *kwlist[] = {"item", "noderef", "namespace", NULL};
129 /* Parse the arguments */
130 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|iz", kwlist,
131 &myarg, &dolink, &ns))
133 if(!convertObj(myarg, &ishandle, &filedes, &file))
136 /* Compute first the list of attributes */
138 /* Find out the needed size of the buffer for the attribute list */
140 flistxattr(filedes, NULL, 0) :
142 llistxattr(file, NULL, 0) :
143 listxattr(file, NULL, 0);
146 return PyErr_SetFromErrno(PyExc_IOError);
149 /* Try to allocate the memory, using Python's allocator */
150 if((buf_list = PyMem_Malloc(nalloc)) == NULL) {
155 /* Now retrieve the list of attributes */
157 flistxattr(filedes, buf_list, nalloc) :
159 llistxattr(file, buf_list, nalloc) :
160 listxattr(file, buf_list, nalloc);
163 return PyErr_SetFromErrno(PyExc_IOError);
166 /* Compute the number of attributes in the list */
167 for(s = buf_list, nattrs = 0; (s - buf_list) < nlist; s += strlen(s) + 1) {
168 if(matches_ns(s, ns))
172 /* Create the list which will hold the result */
173 mylist = PyList_New(nattrs);
175 /* Create and insert the attributes as strings in the list */
176 for(s = buf_list, nattrs = 0; s - buf_list < nlist; s += strlen(s) + 1) {
179 if(!matches_ns(s, ns))
182 /* Find out the needed size of the value buffer */
184 fgetxattr(filedes, s, NULL, 0) :
186 lgetxattr(file, s, NULL, 0) :
187 getxattr(file, s, NULL, 0);
189 PyMem_Free(buf_list);
190 return PyErr_SetFromErrno(PyExc_IOError);
193 /* Try to allocate the memory, using Python's allocator */
194 if((buf_val = PyMem_Malloc(nalloc)) == NULL) {
195 PyMem_Free(buf_list);
200 /* Now retrieve the attribute value */
202 fgetxattr(filedes, s, buf_val, nalloc) :
204 lgetxattr(file, s, buf_val, nalloc) :
205 getxattr(file, s, buf_val, nalloc);
208 PyMem_Free(buf_list);
210 return PyErr_SetFromErrno(PyExc_IOError);
212 my_tuple = Py_BuildValue("ss#", s, buf_val, nval);
214 /* Free the buffer, now it is no longer needed */
217 PyList_SET_ITEM(mylist, nattrs, my_tuple);
221 /* Free the buffer, now it is no longer needed */
222 PyMem_Free(buf_list);
224 /* Return the result */
230 static char __pysetxattr_doc__[] =
231 "Set the value of a given extended attribute.\n"
232 "Be carefull in case you want to set attributes on symbolic\n"
233 "links, you have to use all the 5 parameters; use 0 for the \n"
234 "flags value if you want the default behavior (create or "
238 " - a string representing filename, or a file-like object,\n"
239 " or a file descriptor; this represents the file on \n"
241 " - a string, representing the attribute whose value to set;\n"
242 " usually in form of system.posix_acl or user.mime_type\n"
243 " - a string, possibly with embedded NULLs; note that there\n"
244 " are restrictions regarding the size of the value, for\n"
245 " example, for ext2/ext3, maximum size is the block size\n"
246 " - (optional) flags; if 0 or ommited the attribute will be \n"
247 " created or replaced; if XATTR_CREATE, the attribute \n"
248 " will be created, giving an error if it already exists;\n"
249 " of XATTR_REPLACE, the attribute will be replaced,\n"
250 " giving an error if it doesn't exists;\n"
251 " - (optional) a boolean value (defaults to false), which, if\n"
252 " the file name given is a symbolic link, makes the\n"
253 " function operate on the symbolic link itself instead\n"
257 /* Wrapper for setxattr */
259 pysetxattr(PyObject *self, PyObject *args)
263 int ishandle, filedes, dolink=0;
269 /* Parse the arguments */
270 if (!PyArg_ParseTuple(args, "Oss#|bi", &myarg, &attrname,
271 &buf, &bufsize, &flags, &dolink))
273 if(!convertObj(myarg, &ishandle, &filedes, &file))
276 /* Set the attribute's value */
278 fsetxattr(filedes, attrname, buf, bufsize, flags) :
280 lsetxattr(file, attrname, buf, bufsize, flags) :
281 setxattr(file, attrname, buf, bufsize, flags);
284 return PyErr_SetFromErrno(PyExc_IOError);
287 /* Return the result */
292 static char __pyremovexattr_doc__[] =
293 "Remove an attribute from a file\n"
296 " - a string representing filename, or a file-like object,\n"
297 " or a file descriptor; this represents the file on \n"
299 " - a string, representing the attribute to be removed;\n"
300 " usually in form of system.posix_acl or user.mime_type\n"
301 " - (optional) a boolean value (defaults to false), which, if\n"
302 " the file name given is a symbolic link, makes the\n"
303 " function operate on the symbolic link itself instead\n"
307 /* Wrapper for removexattr */
309 pyremovexattr(PyObject *self, PyObject *args)
313 int ishandle, filedes, dolink=0;
317 /* Parse the arguments */
318 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
321 if(!convertObj(myarg, &ishandle, &filedes, &file))
324 /* Remove the attribute */
326 fremovexattr(filedes, attrname) :
328 lremovexattr(file, attrname) :
329 removexattr(file, attrname);
332 return PyErr_SetFromErrno(PyExc_IOError);
334 /* Return the result */
339 static char __pylistxattr_doc__[] =
340 "Return the list of attribute names for a file\n"
343 " - a string representing filename, or a file-like object,\n"
344 " or a file descriptor; this represents the file to \n"
346 " - (optional) a boolean value (defaults to false), which, if\n"
347 " the file name given is a symbolic link, makes the\n"
348 " function operate on the symbolic link itself instead\n"
352 /* Wrapper for listxattr */
354 pylistxattr(PyObject *self, PyObject *args)
359 int ishandle, dolink=0;
366 /* Parse the arguments */
367 if (!PyArg_ParseTuple(args, "O|i", &myarg, &dolink))
369 if(!convertObj(myarg, &ishandle, &filedes, &file))
372 /* Find out the needed size of the buffer */
374 flistxattr(filedes, NULL, 0) :
376 llistxattr(file, NULL, 0) :
377 listxattr(file, NULL, 0);
380 return PyErr_SetFromErrno(PyExc_IOError);
383 /* Try to allocate the memory, using Python's allocator */
384 if((buf = PyMem_Malloc(nalloc)) == NULL) {
389 /* Now retrieve the list of attributes */
391 flistxattr(filedes, buf, nalloc) :
393 llistxattr(file, buf, nalloc) :
394 listxattr(file, buf, nalloc);
397 return PyErr_SetFromErrno(PyExc_IOError);
400 /* Compute the number of attributes in the list */
401 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
405 /* Create the list which will hold the result */
406 mylist = PyList_New(nattrs);
408 /* Create and insert the attributes as strings in the list */
409 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
410 PyList_SET_ITEM(mylist, nattrs, PyString_FromString(s));
414 /* Free the buffer, now it is no longer needed */
417 /* Return the result */
421 static PyMethodDef xattr_methods[] = {
422 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
423 {"get_all", (PyCFunction) get_all, METH_VARARGS | METH_KEYWORDS,
425 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
426 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
427 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
428 {NULL, NULL, 0, NULL} /* Sentinel */
431 static char __xattr_doc__[] = \
432 "Access extended filesystem attributes\n"
434 "This module gives access to the extended attributes present\n"
435 "in some operating systems/filesystems. You can list attributes,\n"
436 "get, set and remove them.\n"
437 "The last and optional parameter for all functions is a boolean \n"
438 "value which enables the 'l-' version of the functions - acting\n"
439 "on symbolic links and not their destination.\n"
442 " >>> import xattr\n"
443 " >>> xattr.listxattr(\"file.txt\")\n"
444 " ['user.mime_type']\n"
445 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
447 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
448 "\"Simple text file\")\n"
449 " >>> xattr.listxattr(\"file.txt\")\n"
450 " ['user.mime_type', 'user.comment']\n"
451 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
458 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
460 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
461 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
463 /* namespace constants */
464 PyModule_AddStringConstant(m, "NS_SECURITY", "security");
465 PyModule_AddStringConstant(m, "NS_SYSTEM", "system");
466 PyModule_AddStringConstant(m, "NS_TRUSTED", "trusted");
467 PyModule_AddStringConstant(m, "NS_USER", "user");