1 #define PY_SSIZE_T_CLEAN
3 #include <attr/xattr.h>
5 /* Compatibility with python 2.4 regarding python size type (PEP 353) */
6 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
7 typedef int Py_ssize_t;
8 #define PY_SSIZE_T_MAX INT_MAX
9 #define PY_SSIZE_T_MIN INT_MIN
12 typedef enum {T_FD, T_PATH, T_LINK} target_e;
22 /** Converts from a string, file or int argument to what we need. */
23 static int convertObj(PyObject *myobj, target_t *tgt, int nofollow) {
25 if(PyString_Check(myobj)) {
26 tgt->type = nofollow ? T_LINK : T_PATH;
27 tgt->name = PyString_AS_STRING(myobj);
28 } else if((fd = PyObject_AsFileDescriptor(myobj)) != -1) {
32 PyErr_SetString(PyExc_TypeError, "argument must be string or int");
38 static ssize_t _list_obj(target_t *tgt, char *list, size_t size) {
40 return flistxattr(tgt->fd, list, size);
41 else if (tgt->type == T_LINK)
42 return llistxattr(tgt->name, list, size);
44 return listxattr(tgt->name, list, size);
47 static ssize_t _get_obj(target_t *tgt, char *name, void *value, size_t size) {
49 return fgetxattr(tgt->fd, name, value, size);
50 else if (tgt->type == T_LINK)
51 return lgetxattr(tgt->name, name, value, size);
53 return getxattr(tgt->name, name, value, size);
56 static int _set_obj(target_t *tgt, char *name, void *value, size_t size,
59 return fsetxattr(tgt->fd, name, value, size, flags);
60 else if (tgt->type == T_LINK)
61 return lsetxattr(tgt->name, name, value, size, flags);
63 return setxattr(tgt->name, name, value, size, flags);
66 static int _remove_obj(target_t *tgt, char *name) {
68 return fremovexattr(tgt->fd, name);
69 else if (tgt->type == T_LINK)
70 return lremovexattr(tgt->name, name);
72 return removexattr(tgt->name, name);
75 /* Wrapper for getxattr */
76 static char __pygetxattr_doc__[] =
77 "Get the value of a given extended attribute.\n"
80 " - a string representing filename, or a file-like object,\n"
81 " or a file descriptor; this represents the file on \n"
83 " - a string, representing the attribute whose value to retrieve;\n"
84 " usually in form of system.posix_acl or user.mime_type\n"
85 " - (optional) a boolean value (defaults to false), which, if\n"
86 " the file name given is a symbolic link, makes the\n"
87 " function operate on the symbolic link itself instead\n"
92 pygetxattr(PyObject *self, PyObject *args)
102 /* Parse the arguments */
103 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &nofollow))
105 if(!convertObj(myarg, &tgt, nofollow))
108 /* Find out the needed size of the buffer */
109 if((nalloc = _get_obj(&tgt, attrname, NULL, 0)) == -1) {
110 return PyErr_SetFromErrno(PyExc_IOError);
113 /* Try to allocate the memory, using Python's allocator */
114 if((buf = PyMem_Malloc(nalloc)) == NULL) {
119 /* Now retrieve the attribute value */
120 if((nret = _get_obj(&tgt, attrname, buf, nalloc)) == -1) {
122 return PyErr_SetFromErrno(PyExc_IOError);
125 /* Create the string which will hold the result */
126 res = PyString_FromStringAndSize(buf, nret);
128 /* Free the buffer, now it is no longer needed */
131 /* Return the result */
135 static char __pysetxattr_doc__[] =
136 "Set the value of a given extended attribute.\n"
137 "Be carefull in case you want to set attributes on symbolic\n"
138 "links, you have to use all the 5 parameters; use 0 for the \n"
139 "flags value if you want the default behavior (create or "
143 " - a string representing filename, or a file-like object,\n"
144 " or a file descriptor; this represents the file on \n"
146 " - a string, representing the attribute whose value to set;\n"
147 " usually in form of system.posix_acl or user.mime_type\n"
148 " - a string, possibly with embedded NULLs; note that there\n"
149 " are restrictions regarding the size of the value, for\n"
150 " example, for ext2/ext3, maximum size is the block size\n"
151 " - (optional) flags; if 0 or ommited the attribute will be \n"
152 " created or replaced; if XATTR_CREATE, the attribute \n"
153 " will be created, giving an error if it already exists;\n"
154 " of XATTR_REPLACE, the attribute will be replaced,\n"
155 " giving an error if it doesn't exists;\n"
156 " - (optional) a boolean value (defaults to false), which, if\n"
157 " the file name given is a symbolic link, makes the\n"
158 " function operate on the symbolic link itself instead\n"
162 /* Wrapper for setxattr */
164 pysetxattr(PyObject *self, PyObject *args)
175 /* Parse the arguments */
176 if (!PyArg_ParseTuple(args, "Oss#|bi", &myarg, &attrname,
177 &buf, &bufsize, &flags, &nofollow))
179 if(!convertObj(myarg, &tgt, nofollow))
182 /* Set the attribute's value */
183 if((nret = _set_obj(&tgt, attrname, buf, bufsize, flags)) == -1) {
184 return PyErr_SetFromErrno(PyExc_IOError);
187 /* Return the result */
191 static char __pyremovexattr_doc__[] =
192 "Remove an attribute from a file\n"
195 " - a string representing filename, or a file-like object,\n"
196 " or a file descriptor; this represents the file on \n"
198 " - a string, representing the attribute to be removed;\n"
199 " usually in form of system.posix_acl or user.mime_type\n"
200 " - (optional) a boolean value (defaults to false), which, if\n"
201 " the file name given is a symbolic link, makes the\n"
202 " function operate on the symbolic link itself instead\n"
206 /* Wrapper for removexattr */
208 pyremovexattr(PyObject *self, PyObject *args)
216 /* Parse the arguments */
217 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &nofollow))
220 if(!convertObj(myarg, &tgt, nofollow))
223 /* Remove the attribute */
224 if((nret = _remove_obj(&tgt, attrname)) == -1) {
225 return PyErr_SetFromErrno(PyExc_IOError);
228 /* Return the result */
232 static char __pylistxattr_doc__[] =
233 "Return the list of attribute names for a file\n"
236 " - a string representing filename, or a file-like object,\n"
237 " or a file descriptor; this represents the file to \n"
239 " - (optional) a boolean value (defaults to false), which, if\n"
240 " the file name given is a symbolic link, makes the\n"
241 " function operate on the symbolic link itself instead\n"
245 /* Wrapper for listxattr */
247 pylistxattr(PyObject *self, PyObject *args)
251 ssize_t nalloc, nret;
258 /* Parse the arguments */
259 if (!PyArg_ParseTuple(args, "O|i", &myarg, &nofollow))
261 if(!convertObj(myarg, &tgt, nofollow))
264 /* Find out the needed size of the buffer */
265 if((nalloc = _list_obj(&tgt, NULL, 0)) == -1) {
266 return PyErr_SetFromErrno(PyExc_IOError);
269 /* Try to allocate the memory, using Python's allocator */
270 if((buf = PyMem_Malloc(nalloc)) == NULL) {
275 /* Now retrieve the list of attributes */
276 if((nret = _list_obj(&tgt, buf, nalloc)) == -1) {
278 return PyErr_SetFromErrno(PyExc_IOError);
281 /* Compute the number of attributes in the list */
282 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
286 /* Create the list which will hold the result */
287 mylist = PyList_New(nattrs);
289 /* Create and insert the attributes as strings in the list */
290 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
291 PyList_SET_ITEM(mylist, nattrs, PyString_FromString(s));
295 /* Free the buffer, now it is no longer needed */
298 /* Return the result */
302 static PyMethodDef xattr_methods[] = {
303 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
304 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
305 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
306 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
307 {NULL, NULL, 0, NULL} /* Sentinel */
310 static char __xattr_doc__[] = \
311 "Access extended filesystem attributes\n"
313 "This module gives access to the extended attributes present\n"
314 "in some operating systems/filesystems. You can list attributes,\n"
315 "get, set and remove them.\n"
316 "The last and optional parameter for all functions is a boolean \n"
317 "value which enables the 'l-' version of the functions - acting\n"
318 "on symbolic links and not their destination.\n"
321 " >>> import xattr\n"
322 " >>> xattr.listxattr(\"file.txt\")\n"
323 " ['user.mime_type']\n"
324 " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
326 " >>> xattr.setxattr(\"file.txt\", \"user.comment\", "
327 "\"Simple text file\")\n"
328 " >>> xattr.listxattr(\"file.txt\")\n"
329 " ['user.mime_type', 'user.comment']\n"
330 " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
337 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
339 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
340 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
342 /* namespace constants */
343 PyModule_AddStringConstant(m, "NS_SECURITY", "security");
344 PyModule_AddStringConstant(m, "NS_SYSTEM", "system");
345 PyModule_AddStringConstant(m, "NS_TRUSTED", "trusted");
346 PyModule_AddStringConstant(m, "NS_USER", "user");