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, char **filename) {
6 if(PyString_Check(myobj)) {
8 *filename = PyString_AS_STRING(myobj);
9 } else if((*filehandle = PyObject_AsFileDescriptor(myobj)) != -1) {
12 PyErr_SetString(PyExc_TypeError, "argument 1 must be string or int");
18 /* Wrapper for getxattr */
19 static char __pygetxattr_doc__[] = \
20 "Get the value of a given extended attribute.\n" \
23 "\t- a string representing filename, or a file-like object,\n" \
24 "\t or a file descriptor; this represents the file on \n" \
26 "\t- a string, representing the attribute whose value to retrieve;\n" \
27 "\t usually in form of system.posix_acl or user.mime_type\n" \
28 "\t- (optional) a boolean value (defaults to false), which, if\n" \
29 "\t the file name given is a symbolic link, makes the\n" \
30 "\t function operate on the symbolic link itself instead\n" \
35 pygetxattr(PyObject *self, PyObject *args)
39 int filedes = -1, ishandle, dolink=0;
45 /* Parse the arguments */
46 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
48 if(!convertObj(myarg, &ishandle, &filedes, &file))
51 /* Find out the needed size of the buffer */
53 fgetxattr(filedes, attrname, NULL, 0) :
55 lgetxattr(file, attrname, NULL, 0) :
56 getxattr(file, attrname, NULL, 0);
58 return PyErr_SetFromErrno(PyExc_IOError);
61 /* Try to allocate the memory, using Python's allocator */
62 if((buf = PyMem_Malloc(nalloc)) == NULL) {
67 /* Now retrieve the attribute value */
69 fgetxattr(filedes, attrname, buf, nalloc) :
71 lgetxattr(file, attrname, buf, nalloc) :
72 getxattr(file, attrname, buf, nalloc);
75 return PyErr_SetFromErrno(PyExc_IOError);
78 /* Create the string which will hold the result */
79 res = PyString_FromStringAndSize(buf, nret);
81 /* Free the buffer, now it is no longer needed */
84 /* Return the result */
88 static char __pysetxattr_doc__[] = \
89 "Set the value of a given extended attribute.\n" \
90 "Be carefull in case you want to set attributes on symbolic\n" \
91 "links, you have to use all the 5 parameters; use 0 for the \n" \
92 "flags value if you want the default behavior (create or " \
96 "\t- a string representing filename, or a file-like object,\n" \
97 "\t or a file descriptor; this represents the file on \n" \
99 "\t- a string, representing the attribute whose value to set;\n" \
100 "\t usually in form of system.posix_acl or user.mime_type\n" \
101 "\t- a string, possibly with embedded NULLs; note that there\n" \
102 "\t are restrictions regarding the size of the value, for\n" \
103 "\t example, for ext2/ext3, maximum size is the block size\n" \
104 "\t- (optional) flags; if 0 or ommited the attribute will be \n" \
105 "\t created or replaced; if XATTR_CREATE, the attribute \n" \
106 "\t will be created, giving an error if it already exists;\n" \
107 "\t of XATTR_REPLACE, the attribute will be replaced,\n" \
108 "\t giving an error if it doesn't exists;\n" \
109 "\t- (optional) a boolean value (defaults to false), which, if\n" \
110 "\t the file name given is a symbolic link, makes the\n" \
111 "\t function operate on the symbolic link itself instead\n" \
112 "\t of its target;" \
115 /* Wrapper for setxattr */
117 pysetxattr(PyObject *self, PyObject *args)
121 int ishandle, filedes, dolink=0;
127 /* Parse the arguments */
128 if (!PyArg_ParseTuple(args, "Oss#|bi", &myarg, &attrname, &buf, &bufsize, &flags, &dolink))
130 if(!convertObj(myarg, &ishandle, &filedes, &file))
133 /* Set the attribute's value */
135 fsetxattr(filedes, attrname, buf, bufsize, flags) :
137 lsetxattr(file, attrname, buf, bufsize, flags) :
138 setxattr(file, attrname, buf, bufsize, flags);
141 return PyErr_SetFromErrno(PyExc_IOError);
144 /* Return the result */
149 static char __pyremovexattr_doc__[] = \
150 "Remove an attribute from a file\n" \
153 "\t- a string representing filename, or a file-like object,\n" \
154 "\t or a file descriptor; this represents the file on \n" \
155 "\t which to act\n" \
156 "\t- a string, representing the attribute to be removed;\n" \
157 "\t usually in form of system.posix_acl or user.mime_type\n" \
158 "\t- (optional) a boolean value (defaults to false), which, if\n" \
159 "\t the file name given is a symbolic link, makes the\n" \
160 "\t function operate on the symbolic link itself instead\n" \
161 "\t of its target;" \
164 /* Wrapper for removexattr */
166 pyremovexattr(PyObject *self, PyObject *args)
170 int ishandle, filedes, dolink=0;
174 /* Parse the arguments */
175 if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
178 if(!convertObj(myarg, &ishandle, &filedes, &file))
181 /* Remove the attribute */
183 fremovexattr(filedes, attrname) :
185 lremovexattr(file, attrname) :
186 removexattr(file, attrname);
189 return PyErr_SetFromErrno(PyExc_IOError);
191 /* Return the result */
196 static char __pylistxattr_doc__[] = \
197 "Return the tuple of attribute names from a file\n" \
200 "\t- a string representing filename, or a file-like object,\n" \
201 "\t or a file descriptor; this represents the file to \n" \
203 "\t- (optional) a boolean value (defaults to false), which, if\n" \
204 "\t the file name given is a symbolic link, makes the\n" \
205 "\t function operate on the symbolic link itself instead\n" \
206 "\t of its target;" \
209 /* Wrapper for listxattr */
211 pylistxattr(PyObject *self, PyObject *args)
216 int ishandle, dolink=0;
223 /* Parse the arguments */
224 if (!PyArg_ParseTuple(args, "O|i", &myarg, &dolink))
226 if(!convertObj(myarg, &ishandle, &filedes, &file))
229 /* Find out the needed size of the buffer */
231 flistxattr(filedes, NULL, 0) :
233 llistxattr(file, NULL, 0) :
234 listxattr(file, NULL, 0);
237 return PyErr_SetFromErrno(PyExc_IOError);
240 /* Try to allocate the memory, using Python's allocator */
241 if((buf = PyMem_Malloc(nalloc)) == NULL) {
246 /* Now retrieve the list of attributes */
248 flistxattr(filedes, buf, nalloc) :
250 llistxattr(file, buf, nalloc) :
251 listxattr(file, buf, nalloc);
254 return PyErr_SetFromErrno(PyExc_IOError);
257 /* Compute the number of attributes in the list */
258 for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
262 /* Create the tuple which will hold the result */
263 mytuple = PyTuple_New(nattrs);
265 /* Create and insert the attributes as strings in the tuple */
266 for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
267 PyTuple_SET_ITEM(mytuple, nattrs, PyString_FromString(s));
271 /* Free the buffer, now it is no longer needed */
274 /* Return the result */
278 static PyMethodDef xattr_methods[] = {
279 {"getxattr", pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
280 {"setxattr", pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
281 {"removexattr", pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
282 {"listxattr", pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
283 {NULL, NULL, 0, NULL} /* Sentinel */
286 static char __xattr_doc__[] = \
287 "Access extended filesystem attributes\n" \
289 "This module gives access to the extended attributes present\n" \
290 "in some operating systems/filesystems. You can list attributes,\n"\
291 "get, set and remove them.\n"\
292 "The last and optional parameter for all functions is a boolean \n"\
293 "value which enables the 'l-' version of the functions - acting\n"\
294 "on symbolic links and not their destination.\n"\
297 ">>> import xattr\n" \
298 ">>> xattr.listxattr(\"file.txt\")\n" \
299 "('user.mime_type',)\n" \
300 ">>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n" \
302 ">>> xattr.setxattr(\"file.txt\", \"user.comment\", \"Simple text file\")\n"\
303 ">>> xattr.listxattr(\"file.txt\")\n" \
304 "('user.mime_type', 'user.comment')\n" \
305 ">>> xattr.removexattr (\"file.txt\", \"user.comment\")\n" \
312 PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
314 PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
315 PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);