]> git.k1024.org Git - pyxattr.git/blob - xattr.c
Initial revision
[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(PyInt_Check(myobj)) {
10         *ishandle = 1;
11         *filehandle = PyInt_AS_LONG(myobj);
12     } else if(PyFile_Check(myobj)) {
13         *ishandle = 1;
14         *filehandle = fileno(PyFile_AsFile(myobj));
15         if(*filehandle == -1) {
16             PyErr_SetFromErrno(PyExc_IOError);
17             return 0;
18         }
19     } else {
20         PyErr_SetString(PyExc_TypeError, "argument 1 must be string or int");
21         return 0;
22     }
23     return 1;
24 }
25
26 /* Wrapper for getxattr */
27 static PyObject *
28 pygetxattr(PyObject *self, PyObject *args)
29 {
30     PyObject *myarg;
31     char *file;
32     int filedes, ishandle;
33     char *attrname;
34     char *buf;
35     int nalloc, nret;
36     PyObject *res;
37     
38     /* Parse the arguments */
39     if (!PyArg_ParseTuple(args, "Os", &myarg, &attrname))
40         return NULL;
41     if(!convertObj(myarg, &ishandle, &filedes, &file))
42         return NULL;
43
44     /* Find out the needed size of the buffer */
45     nalloc = ishandle ? 
46         fgetxattr(filedes, attrname, NULL, 0) : 
47         getxattr(file, attrname, NULL, 0);
48     if(nalloc == -1) {
49         return PyErr_SetFromErrno(PyExc_IOError);
50     }
51
52     /* Try to allocate the memory, using Python's allocator */
53     if((buf = PyMem_Malloc(nalloc)) == NULL) {
54         PyErr_NoMemory();
55         return NULL;
56     }
57
58     /* Now retrieve the attribute value */
59     nret = ishandle ? 
60         fgetxattr(filedes, attrname, buf, nalloc) :
61         getxattr(file, attrname, buf, nalloc);
62     if(nret == -1) {
63         return PyErr_SetFromErrno(PyExc_IOError);
64     }
65
66     /* Create the string which will hold the result */
67     res = PyString_FromStringAndSize(buf, nret);
68
69     /* Free the buffer, now it is no longer needed */
70     PyMem_Free(buf);
71
72     /* Return the result */
73     return res;
74 }
75
76 /* Wrapper for setxattr */
77 static PyObject *
78 pysetxattr(PyObject *self, PyObject *args)
79 {
80     PyObject *myarg;
81     char *file;
82     int ishandle, filedes;
83     char *attrname;
84     char *buf;
85     char mode = 0;
86     int bufsize, nret;
87     int flags;
88     
89     /* Parse the arguments */
90     if (!PyArg_ParseTuple(args, "Oss#|b", &myarg, &attrname, &buf, &bufsize, &mode))
91         return NULL;
92     if(!convertObj(myarg, &ishandle, &filedes, &file))
93         return NULL;
94
95     /* Check the flags and convert them to libattr values */
96     flags = mode == 1 ? XATTR_CREATE : mode == 2 ? XATTR_REPLACE : 0;
97
98     /* Set the attribute's value */
99     nret = ishandle ?
100         fsetxattr(filedes, attrname, buf, bufsize, flags) :
101         setxattr(file, attrname, buf, bufsize, flags);
102
103     if(nret == -1) {
104         return PyErr_SetFromErrno(PyExc_IOError);
105     }
106
107     /* Return the result */
108     Py_INCREF(Py_None);
109     return Py_None;
110 }
111
112 /* Wrapper for removexattr */
113 static PyObject *
114 pyremovexattr(PyObject *self, PyObject *args)
115 {
116     PyObject *myarg;
117     char *file;
118     int ishandle, filedes;
119     char *attrname;
120     int nret;
121     
122     /* Parse the arguments */
123     if (!PyArg_ParseTuple(args, "Os", &myarg, &attrname))
124         return NULL;
125
126     if(!convertObj(myarg, &ishandle, &filedes, &file))
127         return NULL;
128
129     /* Remove the attribute */
130     nret = ishandle ?
131         fremovexattr(filedes, attrname) :
132         removexattr(file, attrname);
133
134     if(nret == -1)
135         return PyErr_SetFromErrno(PyExc_IOError);
136
137     /* Return the result */
138     Py_INCREF(Py_None);
139     return Py_None;
140 }
141
142 /* Wrapper for listxattr */
143 static PyObject *
144 pylistxattr(PyObject *self, PyObject *args)
145 {
146     char *file = NULL;
147     int filedes = -1;
148     char *buf;
149     int ishandle;
150     int nalloc, nret;
151     PyObject *myarg;
152     PyObject *mytuple;
153     int nattrs;
154     char *s;
155     
156     /* Parse the arguments */
157     if (!PyArg_ParseTuple(args, "O", &myarg))
158         return NULL;
159     if(!convertObj(myarg, &ishandle, &filedes, &file))
160         return NULL;
161
162     /* Find out the needed size of the buffer */
163     nalloc = ishandle ?
164         flistxattr(filedes, NULL, 0) :
165         listxattr(file, NULL, 0);
166
167     if(nalloc == -1) {
168         return PyErr_SetFromErrno(PyExc_IOError);
169     }
170
171     /* Try to allocate the memory, using Python's allocator */
172     if((buf = PyMem_Malloc(nalloc)) == NULL) {
173         PyErr_NoMemory();
174         return NULL;
175     }
176
177     /* Now retrieve the list of attributes */
178     nret = ishandle ? 
179         flistxattr(filedes, buf, nalloc) : 
180         listxattr(file, buf, nalloc);
181     if(nret == -1) {
182         return PyErr_SetFromErrno(PyExc_IOError);
183     }
184
185     /* Compute the number of attributes in the list */
186     for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) {
187         nattrs++;
188     }
189
190     /* Create the tuple which will hold the result */
191     mytuple = PyTuple_New(nattrs);
192
193     /* Create and insert the attributes as strings in the tuple */
194     for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) {
195         PyTuple_SET_ITEM(mytuple, nattrs, PyString_FromString(s));
196         nattrs++;
197     }
198
199     /* Free the buffer, now it is no longer needed */
200     PyMem_Free(buf);
201
202     /* Return the result */
203     return mytuple;
204 }
205
206 static PyMethodDef AclMethods[] = {
207     {"getxattr",  pygetxattr, METH_VARARGS,
208      "Get the value of a given extended attribute."},
209     {"setxattr",  pysetxattr, METH_VARARGS,
210      "Set the value of a given extended attribute."},
211     {"removexattr",  pyremovexattr, METH_VARARGS,
212      "Remove the a given extended attribute."},
213     {"listxattr",  pylistxattr, METH_VARARGS,
214      "Retrieve the list of extened attributes."},
215     {NULL, NULL, 0, NULL}        /* Sentinel */
216 };
217
218 void
219 initaclmodule(void)
220 {
221     (void) Py_InitModule3("aclmodule", AclMethods, "Wrapper module for libattr");
222 }