]> git.k1024.org Git - pyxattr.git/blob - xattr.c
Improved documentation and added some constants (XATTR_*)
[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" \
28 ;
29
30 static PyObject *
31 pygetxattr(PyObject *self, PyObject *args)
32 {
33     PyObject *myarg;
34     char *file;
35     int filedes, ishandle;
36     char *attrname;
37     char *buf;
38     int nalloc, nret;
39     PyObject *res;
40     
41     /* Parse the arguments */
42     if (!PyArg_ParseTuple(args, "Os", &myarg, &attrname))
43         return NULL;
44     if(!convertObj(myarg, &ishandle, &filedes, &file))
45         return NULL;
46
47     /* Find out the needed size of the buffer */
48     nalloc = ishandle ? 
49         fgetxattr(filedes, attrname, NULL, 0) : 
50         getxattr(file, attrname, NULL, 0);
51     if(nalloc == -1) {
52         return PyErr_SetFromErrno(PyExc_IOError);
53     }
54
55     /* Try to allocate the memory, using Python's allocator */
56     if((buf = PyMem_Malloc(nalloc)) == NULL) {
57         PyErr_NoMemory();
58         return NULL;
59     }
60
61     /* Now retrieve the attribute value */
62     nret = ishandle ? 
63         fgetxattr(filedes, attrname, buf, nalloc) :
64         getxattr(file, attrname, buf, nalloc);
65     if(nret == -1) {
66         return PyErr_SetFromErrno(PyExc_IOError);
67     }
68
69     /* Create the string which will hold the result */
70     res = PyString_FromStringAndSize(buf, nret);
71
72     /* Free the buffer, now it is no longer needed */
73     PyMem_Free(buf);
74
75     /* Return the result */
76     return res;
77 }
78
79 static char __pysetxattr_doc__[] = \
80 "Set the value of a given extended attribute.\n" \
81 "\n" \
82 "Parameters:\n" \
83 "\t- a string representing filename, or a file-like object,\n" \
84 "\t      or a file descriptor; this represents the file on \n" \
85 "\t      which to act\n" \
86 "\t- a string, representing the attribute whose value to set;\n" \
87 "\t      usually in form of system.posix_acl or user.mime_type\n" \
88 "\t- a string, possibly with embedded NULLs; note that there\n" \
89 "\t      are restrictions regarding the size of the value, for\n" \
90 "\t      example, for ext2/ext3, maximum size is the block size\n" \
91 "\t- a small integer; if ommited the attribute will be created\n" \
92 "\t      or replaced; if XATTR_CREATE, the attribute will be \n" \
93 "\t      created, giving an error if it already exists; if \n" \
94 "\t      XATTR_REPLACE, the attribute will be replaced, giving \n" \
95 "\t      an error if it doesn't exists." \
96 ;
97
98 /* Wrapper for setxattr */
99 static PyObject *
100 pysetxattr(PyObject *self, PyObject *args)
101 {
102     PyObject *myarg;
103     char *file;
104     int ishandle, filedes;
105     char *attrname;
106     char *buf;
107     int bufsize, nret;
108     int flags = 0;
109     
110     /* Parse the arguments */
111     if (!PyArg_ParseTuple(args, "Oss#|b", &myarg, &attrname, &buf, &bufsize, &flags))
112         return NULL;
113     if(!convertObj(myarg, &ishandle, &filedes, &file))
114         return NULL;
115
116     /* Set the attribute's value */
117     nret = ishandle ?
118         fsetxattr(filedes, attrname, buf, bufsize, flags) :
119         setxattr(file, attrname, buf, bufsize, flags);
120
121     if(nret == -1) {
122         return PyErr_SetFromErrno(PyExc_IOError);
123     }
124
125     /* Return the result */
126     Py_INCREF(Py_None);
127     return Py_None;
128 }
129
130 static char __pyremovexattr_doc__[] = \
131 "Remove an attribute from a file\n" \
132 "\n" \
133 "Parameters:\n" \
134 "\t- a string representing filename, or a file-like object,\n" \
135 "\t      or a file descriptor; this represents the file on \n" \
136 "\t      which to act\n" \
137 "\t- a string, representing the attribute to be removed;\n" \
138 "\t      usually in form of system.posix_acl or user.mime_type" \
139 ;
140
141 /* Wrapper for removexattr */
142 static PyObject *
143 pyremovexattr(PyObject *self, PyObject *args)
144 {
145     PyObject *myarg;
146     char *file;
147     int ishandle, filedes;
148     char *attrname;
149     int nret;
150     
151     /* Parse the arguments */
152     if (!PyArg_ParseTuple(args, "Os", &myarg, &attrname))
153         return NULL;
154
155     if(!convertObj(myarg, &ishandle, &filedes, &file))
156         return NULL;
157
158     /* Remove the attribute */
159     nret = ishandle ?
160         fremovexattr(filedes, attrname) :
161         removexattr(file, attrname);
162
163     if(nret == -1)
164         return PyErr_SetFromErrno(PyExc_IOError);
165
166     /* Return the result */
167     Py_INCREF(Py_None);
168     return Py_None;
169 }
170
171 static char __pylistxattr_doc__[] = \
172 "Return the list of attribute names from a file\n" \
173 "\n" \
174 "Parameters:\n" \
175 "\t- a string representing filename, or a file-like object,\n" \
176 "\t      or a file descriptor; this represents the file to \n" \
177 "\t      be queried\n" \
178 ;
179
180 /* Wrapper for listxattr */
181 static PyObject *
182 pylistxattr(PyObject *self, PyObject *args)
183 {
184     char *file = NULL;
185     int filedes = -1;
186     char *buf;
187     int ishandle;
188     int nalloc, nret;
189     PyObject *myarg;
190     PyObject *mytuple;
191     int nattrs;
192     char *s;
193     
194     /* Parse the arguments */
195     if (!PyArg_ParseTuple(args, "O", &myarg))
196         return NULL;
197     if(!convertObj(myarg, &ishandle, &filedes, &file))
198         return NULL;
199
200     /* Find out the needed size of the buffer */
201     nalloc = ishandle ?
202         flistxattr(filedes, NULL, 0) :
203         listxattr(file, NULL, 0);
204
205     if(nalloc == -1) {
206         return PyErr_SetFromErrno(PyExc_IOError);
207     }
208
209     /* Try to allocate the memory, using Python's allocator */
210     if((buf = PyMem_Malloc(nalloc)) == NULL) {
211         PyErr_NoMemory();
212         return NULL;
213     }
214
215     /* Now retrieve the list of attributes */
216     nret = ishandle ? 
217         flistxattr(filedes, buf, nalloc) : 
218         listxattr(file, buf, nalloc);
219     if(nret == -1) {
220         return PyErr_SetFromErrno(PyExc_IOError);
221     }
222
223     /* Compute the number of attributes in the list */
224     for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
225         nattrs++;
226     }
227
228     /* Create the tuple which will hold the result */
229     mytuple = PyTuple_New(nattrs);
230
231     /* Create and insert the attributes as strings in the tuple */
232     for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
233         PyTuple_SET_ITEM(mytuple, nattrs, PyString_FromString(s));
234         nattrs++;
235     }
236
237     /* Free the buffer, now it is no longer needed */
238     PyMem_Free(buf);
239
240     /* Return the result */
241     return mytuple;
242 }
243
244 static PyMethodDef xattr_methods[] = {
245     {"getxattr",  pygetxattr, METH_VARARGS, __pygetxattr_doc__ },
246     {"setxattr",  pysetxattr, METH_VARARGS, __pysetxattr_doc__ },
247     {"removexattr",  pyremovexattr, METH_VARARGS, __pyremovexattr_doc__ },
248     {"listxattr",  pylistxattr, METH_VARARGS, __pylistxattr_doc__ },
249     {NULL, NULL, 0, NULL}        /* Sentinel */
250 };
251
252 static char __xattr_doc__[] = \
253 "Access extended filesystem attributes\n" \
254 "\n" \
255 "This module gives access to the extended attributes present\n" \
256 "in some operating systems/filesystems. You can list attributes,\n"\
257 "get, set and remove them.\n"\
258 ;
259
260 void
261 initxattr(void)
262 {
263     PyObject *m = Py_InitModule3("xattr", xattr_methods, __xattr_doc__);
264     
265     PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATE);
266     PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACE);
267
268 }