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 /* Wrapper for getxattr */
20 static char __pygetxattr_doc__[] =
21 "Get the value of a given extended attribute.\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"
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"
36 pygetxattr(PyObject *self, PyObject *args)
40 int filedes = -1, ishandle, dolink=0;
46 /* Parse the arguments */
47 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
49 if(!convertObj(myarg, &ishandle, &filedes, &file))
52 /* Find out the needed size of the buffer */
54 fgetxattr(filedes, attrname, NULL, 0) :
56 lgetxattr(file, attrname, NULL, 0) :
57 getxattr(file, attrname, NULL, 0);
59 return PyErr_SetFromErrno(PyExc_IOError);
62 /* Try to allocate the memory, using Python's allocator */
63 if((buf = PyMem_Malloc(nalloc)) == NULL) {
68 /* Now retrieve the attribute value */
70 fgetxattr(filedes, attrname, buf, nalloc) :
72 lgetxattr(file, attrname, buf, nalloc) :
73 getxattr(file, attrname, buf, nalloc);
76 return PyErr_SetFromErrno(PyExc_IOError);
79 /* Create the string which will hold the result */
80 res = PyString_FromStringAndSize(buf, nret);
82 /* Free the buffer, now it is no longer needed */
85 /* Return the result */
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 "
97 "\t- a string representing filename, or a file-like object,\n"
98 "\t or a file descriptor; this represents the file on \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"
116 /* Wrapper for setxattr */
118 pysetxattr(PyObject *self, PyObject *args)
122 int ishandle, filedes, dolink=0;
128 /* Parse the arguments */
129 if (!PyArg_ParseTuple(args, "Oss#|bi", &myarg, &attrname,
130 &buf, &bufsize, &flags, &dolink))
132 if(!convertObj(myarg, &ishandle, &filedes, &file))
135 /* Set the attribute's value */
137 fsetxattr(filedes, attrname, buf, bufsize, flags) :
139 lsetxattr(file, attrname, buf, bufsize, flags) :
140 setxattr(file, attrname, buf, bufsize, flags);
143 return PyErr_SetFromErrno(PyExc_IOError);
146 /* Return the result */
151 static char __pyremovexattr_doc__[] =
152 "Remove an attribute from a file\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"
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"
166 /* Wrapper for removexattr */
168 pyremovexattr(PyObject *self, PyObject *args)
172 int ishandle, filedes, dolink=0;
176 /* Parse the arguments */
177 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
180 if(!convertObj(myarg, &ishandle, &filedes, &file))
183 /* Remove the attribute */
185 fremovexattr(filedes, attrname) :
187 lremovexattr(file, attrname) :
188 removexattr(file, attrname);
191 return PyErr_SetFromErrno(PyExc_IOError);
193 /* Return the result */
198 static char __pylistxattr_doc__[] =
199 "Return the list of attribute names for a file\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"
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"
211 /* Wrapper for listxattr */
213 pylistxattr(PyObject *self, PyObject *args)
218 int ishandle, dolink=0;
225 /* Parse the arguments */
226 if (!PyArg_ParseTuple(args, "O|i", &myarg, &dolink))
228 if(!convertObj(myarg, &ishandle, &filedes, &file))
231 /* Find out the needed size of the buffer */
233 flistxattr(filedes, NULL, 0) :
235 llistxattr(file, NULL, 0) :
236 listxattr(file, NULL, 0);
239 return PyErr_SetFromErrno(PyExc_IOError);
242 /* Try to allocate the memory, using Python's allocator */
243 if((buf = PyMem_Malloc(nalloc)) == NULL) {
248 /* Now retrieve the list of attributes */
250 flistxattr(filedes, buf, nalloc) :
252 llistxattr(file, buf, nalloc) :
253 listxattr(file, buf, nalloc);
256 return PyErr_SetFromErrno(PyExc_IOError);
259 /* Compute the number of attributes in the list */
260 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
264 /* Create the list which will hold the result */
265 mylist = PyList_New(nattrs);
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));
273 /* Free the buffer, now it is no longer needed */
276 /* Return the result */
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 */
288 static char __xattr_doc__[] = \
289 "Access extended filesystem attributes\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"
300 ">>> xattr.listxattr(\"file.txt\")\n"
301 "('user.mime_type',)\n"
302 ">>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n"
304 ">>> xattr.setxattr(\"file.txt\", \"user.comment\", \"Simple text file\")"
306 ">>> xattr.listxattr(\"file.txt\")\n"
307 "('user.mime_type', 'user.comment')\n"
308 ">>> xattr.removexattr (\"file.txt\", \"user.comment\")\n"
315 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
317 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
318 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);