]> git.k1024.org Git - debian-pyxattr.git/blob - xattr.c
Update changelog
[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, char **filename) {
6     if(PyString_Check(myobj)) {
7         *ishandle = 0;
8         *filename = PyString_AS_STRING(myobj);
9     } else if((*filehandle = PyObject_AsFileDescriptor(myobj)) != -1) {
10         *ishandle = 1;
11     } else {
12         PyErr_SetString(PyExc_TypeError, "argument 1 must be string or int");
13         return 0;
14     }
15     return 1;
16 }
17
18 /* Wrapper for getxattr */
19 static char __pygetxattr_doc__[] = \
20 "Get the value of a given extended attribute.\n" \
21 "\n" \
22 "Parameters:\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" \
25 "\t      which to act\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" \
31 "\t      of its target;" \
32 ;
33
34 static PyObject *
35 pygetxattr(PyObject *self, PyObject *args)
36 {
37     PyObject *myarg;
38     char *file = NULL;
39     int filedes = -1, ishandle, dolink=0;
40     char *attrname;
41     char *buf;
42     int nalloc, nret;
43     PyObject *res;
44
45     /* Parse the arguments */
46     if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
47         return NULL;
48     if(!convertObj(myarg, &ishandle, &filedes, &file))
49         return NULL;
50
51     /* Find out the needed size of the buffer */
52     nalloc = ishandle ?
53         fgetxattr(filedes, attrname, NULL, 0) :
54         dolink ?
55         lgetxattr(file, attrname, NULL, 0) :
56         getxattr(file, attrname, NULL, 0);
57     if(nalloc == -1) {
58         return PyErr_SetFromErrno(PyExc_IOError);
59     }
60
61     /* Try to allocate the memory, using Python's allocator */
62     if((buf = PyMem_Malloc(nalloc)) == NULL) {
63         PyErr_NoMemory();
64         return NULL;
65     }
66
67     /* Now retrieve the attribute value */
68     nret = ishandle ?
69         fgetxattr(filedes, attrname, buf, nalloc) :
70         dolink ?
71         lgetxattr(file, attrname, buf, nalloc) :
72         getxattr(file, attrname, buf, nalloc);
73     if(nret == -1) {
74         PyMem_Free(buf);
75         return PyErr_SetFromErrno(PyExc_IOError);
76     }
77
78     /* Create the string which will hold the result */
79     res = PyString_FromStringAndSize(buf, nret);
80
81     /* Free the buffer, now it is no longer needed */
82     PyMem_Free(buf);
83
84     /* Return the result */
85     return res;
86 }
87
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 " \
93 "replace)\n" \
94 "\n" \
95 "Parameters:\n" \
96 "\t- a string representing filename, or a file-like object,\n" \
97 "\t      or a file descriptor; this represents the file on \n" \
98 "\t      which to act\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;" \
113 ;
114
115 /* Wrapper for setxattr */
116 static PyObject *
117 pysetxattr(PyObject *self, PyObject *args)
118 {
119     PyObject *myarg;
120     char *file;
121     int ishandle, filedes, dolink=0;
122     char *attrname;
123     char *buf;
124     int bufsize, nret;
125     int flags = 0;
126
127     /* Parse the arguments */
128     if (!PyArg_ParseTuple(args, "Oss#|bi", &myarg, &attrname, &buf, &bufsize, &flags, &dolink))
129         return NULL;
130     if(!convertObj(myarg, &ishandle, &filedes, &file))
131         return NULL;
132
133     /* Set the attribute's value */
134     nret = ishandle ?
135         fsetxattr(filedes, attrname, buf, bufsize, flags) :
136         dolink ?
137         lsetxattr(file, attrname, buf, bufsize, flags) :
138         setxattr(file, attrname, buf, bufsize, flags);
139
140     if(nret == -1) {
141         return PyErr_SetFromErrno(PyExc_IOError);
142     }
143
144     /* Return the result */
145     Py_INCREF(Py_None);
146     return Py_None;
147 }
148
149 static char __pyremovexattr_doc__[] = \
150 "Remove an attribute from a file\n" \
151 "\n" \
152 "Parameters:\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;" \
162 ;
163
164 /* Wrapper for removexattr */
165 static PyObject *
166 pyremovexattr(PyObject *self, PyObject *args)
167 {
168     PyObject *myarg;
169     char *file;
170     int ishandle, filedes, dolink=0;
171     char *attrname;
172     int nret;
173
174     /* Parse the arguments */
175     if (!PyArg_ParseTuple(args, "Os|i", &myarg, &attrname, &dolink))
176         return NULL;
177
178     if(!convertObj(myarg, &ishandle, &filedes, &file))
179         return NULL;
180
181     /* Remove the attribute */
182     nret = ishandle ?
183         fremovexattr(filedes, attrname) :
184         dolink ?
185         lremovexattr(file, attrname) :
186         removexattr(file, attrname);
187
188     if(nret == -1)
189         return PyErr_SetFromErrno(PyExc_IOError);
190
191     /* Return the result */
192     Py_INCREF(Py_None);
193     return Py_None;
194 }
195
196 static char __pylistxattr_doc__[] = \
197 "Return the tuple of attribute names from a file\n" \
198 "\n" \
199 "Parameters:\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" \
202 "\t      be queried\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;" \
207 ;
208
209 /* Wrapper for listxattr */
210 static PyObject *
211 pylistxattr(PyObject *self, PyObject *args)
212 {
213     char *file = NULL;
214     int filedes = -1;
215     char *buf;
216     int ishandle, dolink=0;
217     int nalloc, nret;
218     PyObject *myarg;
219     PyObject *mytuple;
220     int nattrs;
221     char *s;
222
223     /* Parse the arguments */
224     if (!PyArg_ParseTuple(args, "O|i", &myarg, &dolink))
225         return NULL;
226     if(!convertObj(myarg, &ishandle, &filedes, &file))
227         return NULL;
228
229     /* Find out the needed size of the buffer */
230     nalloc = ishandle ?
231         flistxattr(filedes, NULL, 0) :
232         dolink ?
233         llistxattr(file, NULL, 0) :
234         listxattr(file, NULL, 0);
235
236     if(nalloc == -1) {
237         return PyErr_SetFromErrno(PyExc_IOError);
238     }
239
240     /* Try to allocate the memory, using Python's allocator */
241     if((buf = PyMem_Malloc(nalloc)) == NULL) {
242         PyErr_NoMemory();
243         return NULL;
244     }
245
246     /* Now retrieve the list of attributes */
247     nret = ishandle ?
248         flistxattr(filedes, buf, nalloc) :
249         dolink ?
250         llistxattr(file, buf, nalloc) :
251         listxattr(file, buf, nalloc);
252
253     if(nret == -1) {
254         return PyErr_SetFromErrno(PyExc_IOError);
255     }
256
257     /* Compute the number of attributes in the list */
258     for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
259         nattrs++;
260     }
261
262     /* Create the tuple which will hold the result */
263     mytuple = PyTuple_New(nattrs);
264
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));
268         nattrs++;
269     }
270
271     /* Free the buffer, now it is no longer needed */
272     PyMem_Free(buf);
273
274     /* Return the result */
275     return mytuple;
276 }
277
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 */
284 };
285
286 static char __xattr_doc__[] = \
287 "Access extended filesystem attributes\n" \
288 "\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"\
295 "\n" \
296 "Example: \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" \
301 "'text/plain'\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" \
306 "" \
307 ;
308
309 void
310 initxattr(void)
311 {
312     PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
313
314     PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
315     PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
316
317 }