File: | xattr.c |
Warning: | line 632, column 20 PyObject ownership leak with reference count of 1 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | xattr - a python module for manipulating filesystem extended attributes | |||
3 | ||||
4 | Copyright (C) 2002, 2003, 2006, 2008, 2012, 2013, 2015 | |||
5 | Iustin Pop <iustin@k1024.org> | |||
6 | ||||
7 | This library is free software; you can redistribute it and/or | |||
8 | modify it under the terms of the GNU Lesser General Public | |||
9 | License as published by the Free Software Foundation; either | |||
10 | version 2.1 of the License, or (at your option) any later version. | |||
11 | ||||
12 | This library is distributed in the hope that it will be useful, | |||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
15 | Lesser General Public License for more details. | |||
16 | ||||
17 | You should have received a copy of the GNU Lesser General Public | |||
18 | License along with this library; if not, write to the Free Software | |||
19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |||
20 | 02110-1301 USA | |||
21 | ||||
22 | */ | |||
23 | ||||
24 | #define PY_SSIZE_T_CLEAN | |||
25 | #include <Python.h> | |||
26 | #if defined(__APPLE__) || defined(__linux__1) | |||
27 | #include <sys/xattr.h> | |||
28 | #endif | |||
29 | #include <stdio.h> | |||
30 | ||||
31 | #define ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" \ | |||
32 | ":param item: a string representing a file-name, a file-like\n" \ | |||
33 | " object, a file descriptor, or (in Python 3.6+) a path-like\n" \ | |||
34 | " object; this represents the file on which to act\n" | |||
35 | ||||
36 | #define NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" \ | |||
37 | ":param nofollow: if true and if\n" \ | |||
38 | " the file name given is a symbolic link, the\n" \ | |||
39 | " function will operate on the symbolic link itself instead\n" \ | |||
40 | " of its target; defaults to false\n" \ | |||
41 | ":type nofollow: boolean, optional\n" \ | |||
42 | ||||
43 | #define NS_DOC":param namespace: if given, the attribute must not contain the\n" " namespace, but instead it will be taken from this parameter\n" ":type namespace: bytes\n" \ | |||
44 | ":param namespace: if given, the attribute must not contain the\n" \ | |||
45 | " namespace, but instead it will be taken from this parameter\n" \ | |||
46 | ":type namespace: bytes\n" | |||
47 | ||||
48 | #define NAME_GET_DOC":param string name: the attribute whose value to retrieve;\n" " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n" \ | |||
49 | ":param string name: the attribute whose value to retrieve;\n" \ | |||
50 | " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n" | |||
51 | ||||
52 | #define NAME_SET_DOC":param string name: the attribute whose value to set;\n" " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n" \ | |||
53 | ":param string name: the attribute whose value to set;\n" \ | |||
54 | " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n" | |||
55 | ||||
56 | #define NAME_REMOVE_DOC":param string name: the attribute to remove;\n" " usually in the form of ``system.posix_acl`` or \n" " ``user.mime_type``\n" \ | |||
57 | ":param string name: the attribute to remove;\n" \ | |||
58 | " usually in the form of ``system.posix_acl`` or \n" \ | |||
59 | " ``user.mime_type``\n" | |||
60 | ||||
61 | #define VALUE_DOC":param string value: possibly with embedded NULLs; note that there\n" " are restrictions regarding the size of the value, for\n" " example, for ext2/ext3, maximum size is the block size\n" \ | |||
62 | ":param string value: possibly with embedded NULLs; note that there\n" \ | |||
63 | " are restrictions regarding the size of the value, for\n" \ | |||
64 | " example, for ext2/ext3, maximum size is the block size\n" \ | |||
65 | ||||
66 | #define FLAGS_DOC":param flags: if 0 or omitted the attribute will be\n" " created or replaced; if :const:`XATTR_CREATE`, the attribute\n" " will be created, giving an error if it already exists;\n" " if :const:`XATTR_REPLACE`, the attribute will be replaced,\n" " giving an error if it doesn't exist;\n" ":type flags: integer\n" \ | |||
67 | ":param flags: if 0 or omitted the attribute will be\n" \ | |||
68 | " created or replaced; if :const:`XATTR_CREATE`, the attribute\n" \ | |||
69 | " will be created, giving an error if it already exists;\n" \ | |||
70 | " if :const:`XATTR_REPLACE`, the attribute will be replaced,\n" \ | |||
71 | " giving an error if it doesn't exist;\n" \ | |||
72 | ":type flags: integer\n" | |||
73 | ||||
74 | #define NS_CHANGED_DOC".. versionchanged:: 0.5.1\n" " The namespace argument, if passed, cannot be None anymore; to\n" " explicitly specify an empty namespace, pass an empty\n" " string (byte string under Python 3)." \ | |||
75 | ".. versionchanged:: 0.5.1\n" \ | |||
76 | " The namespace argument, if passed, cannot be None anymore; to\n" \ | |||
77 | " explicitly specify an empty namespace, pass an empty\n" \ | |||
78 | " string (byte string under Python 3)." | |||
79 | ||||
80 | ||||
81 | /* The initial I/O buffer size for list and get operations; if the | |||
82 | * actual values will be smaller than this, we save a syscall out of | |||
83 | * two and allocate more memory upfront than needed, otherwise we | |||
84 | * incur three syscalls (get with ENORANGE, get with 0 to compute | |||
85 | * actual size, final get). The test suite is marginally faster (5%) | |||
86 | * with this, so it seems worth doing. | |||
87 | */ | |||
88 | #define ESTIMATE_ATTR_SIZE1024 1024 | |||
89 | ||||
90 | typedef enum {T_FD, T_PATH, T_LINK} target_e; | |||
91 | ||||
92 | typedef struct { | |||
93 | target_e type; | |||
94 | union { | |||
95 | const char *name; | |||
96 | int fd; | |||
97 | }; | |||
98 | PyObject *tmp; | |||
99 | } target_t; | |||
100 | ||||
101 | /* Cleans up a tgt structure */ | |||
102 | static void free_tgt(target_t *tgt) { | |||
103 | if (tgt->tmp != NULL((void*)0)) { | |||
104 | Py_DECREF(tgt->tmp)_Py_DECREF(((PyObject*)(tgt->tmp))); | |||
105 | } | |||
106 | } | |||
107 | ||||
108 | /* Used for cpychecker: */ | |||
109 | /* The checker automatically defines this preprocessor name when creating | |||
110 | the custom attribute: */ | |||
111 | #if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE) | |||
112 | #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \ | |||
113 | __attribute__((cpychecker_negative_result_sets_exception)) | |||
114 | #else | |||
115 | #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION | |||
116 | #endif | |||
117 | ||||
118 | static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow) | |||
119 | CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; | |||
120 | ||||
121 | static int merge_ns(const char *ns, const char *name, | |||
122 | const char **result, char **buf) | |||
123 | CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; | |||
124 | ||||
125 | ||||
126 | /** Converts from a string, file or int argument to what we need. | |||
127 | * | |||
128 | * Returns -1 on failure, 0 on success. | |||
129 | */ | |||
130 | static int convert_obj(PyObject *myobj, target_t *tgt, int nofollow) { | |||
131 | int fd; | |||
132 | tgt->tmp = NULL((void*)0); | |||
133 | if((fd = PyObject_AsFileDescriptor(myobj)) != -1) { | |||
134 | tgt->type = T_FD; | |||
135 | tgt->fd = fd; | |||
136 | return 0; | |||
137 | } | |||
138 | // PyObject_AsFileDescriptor sets an error when failing, so clear | |||
139 | // it such that further code works; some method lookups fail if an | |||
140 | // error already occured when called, which breaks at least | |||
141 | // PyOS_FSPath (called by FSConverter). | |||
142 | PyErr_Clear(); | |||
143 | ||||
144 | if(PyUnicode_FSConverter(myobj, &(tgt->tmp))) { | |||
145 | tgt->type = nofollow ? T_LINK : T_PATH; | |||
146 | tgt->name = PyBytes_AS_STRING(tgt->tmp)(((void) (0)), (((PyBytesObject *)(tgt->tmp))->ob_sval) ); | |||
147 | return 0; | |||
148 | } else { | |||
149 | // Don't set our own exception type, since we'd ignore the | |||
150 | // FSConverter-generated one. | |||
151 | tgt->type = T_PATH; | |||
152 | tgt->name = NULL((void*)0); | |||
153 | return -1; | |||
154 | } | |||
155 | } | |||
156 | ||||
157 | /* Combine a namespace string and an attribute name into a | |||
158 | fully-qualified name */ | |||
159 | static int merge_ns(const char *ns, const char *name, | |||
160 | const char **result, char **buf) { | |||
161 | if(ns != NULL((void*)0) && *ns != '\0') { | |||
162 | int cnt; | |||
163 | /* The value of new_size is related to/must be kept in-sync | |||
164 | with the format string below */ | |||
165 | size_t new_size = strlen(ns) + 1 + strlen(name) + 1; | |||
166 | if((*buf = PyMem_Malloc(new_size)) == NULL((void*)0)) { | |||
167 | PyErr_NoMemory(); | |||
168 | return -1; | |||
169 | } | |||
170 | cnt = snprintf(*buf, new_size, "%s.%s", ns, name)__builtin___snprintf_chk (*buf, new_size, 2 - 1, __builtin_object_size (*buf, 2 > 1), "%s.%s", ns, name); | |||
171 | if((size_t) cnt >= new_size || cnt < 0) { | |||
172 | PyErr_SetString(PyExc_ValueError, | |||
173 | "unexpected: can't format the attribute name"); | |||
174 | PyMem_Free(*buf); | |||
175 | return -1; | |||
176 | } | |||
177 | *result = *buf; | |||
178 | } else { | |||
179 | *buf = NULL((void*)0); | |||
180 | *result = name; | |||
181 | } | |||
182 | return 0; | |||
183 | } | |||
184 | ||||
185 | #if defined(__APPLE__) | |||
186 | static inline ssize_t _listxattr(const char *path, char *namebuf, size_t size)listxattr(const char *path, char *namebuf, size_t size) { | |||
187 | return listxattr(path, namebuf, size, 0); | |||
188 | } | |||
189 | static inline ssize_t _llistxattr(const char *path, char *namebuf, size_t size)llistxattr(const char *path, char *namebuf, size_t size) { | |||
190 | return listxattr(path, namebuf, size, XATTR_NOFOLLOW); | |||
191 | } | |||
192 | static inline ssize_t _flistxattr(int fd, char *namebuf, size_t size)flistxattr(int fd, char *namebuf, size_t size) { | |||
193 | return flistxattr(fd, namebuf, size, 0); | |||
194 | } | |||
195 | ||||
196 | static inline ssize_t _getxattr (const char *path, const char *name, void *value, size_t size)getxattr(const char *path, const char *name, void *value, size_t size) { | |||
197 | return getxattr(path, name, value, size, 0, 0); | |||
198 | } | |||
199 | static inline ssize_t _lgetxattr (const char *path, const char *name, void *value, size_t size)lgetxattr(const char *path, const char *name, void *value, size_t size) { | |||
200 | return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW); | |||
201 | } | |||
202 | static inline ssize_t _fgetxattr (int filedes, const char *name, void *value, size_t size)fgetxattr(int filedes, const char *name, void *value, size_t size ) { | |||
203 | return fgetxattr(filedes, name, value, size, 0, 0); | |||
204 | } | |||
205 | ||||
206 | // [fl]setxattr: Both OS X and Linux define XATTR_CREATE and XATTR_REPLACE for the last option. | |||
207 | static inline int _setxattr(const char *path, const char *name, const void *value, size_t size, int flags)setxattr(const char *path, const char *name, const void *value , size_t size, int flags) { | |||
208 | return setxattr(path, name, value, size, 0, flags); | |||
209 | } | |||
210 | static inline int _lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags)lsetxattr(const char *path, const char *name, const void *value , size_t size, int flags) { | |||
211 | return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW); | |||
212 | } | |||
213 | static inline int _fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags)fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags) { | |||
214 | return fsetxattr(filedes, name, value, size, 0, flags); | |||
215 | } | |||
216 | ||||
217 | static inline int _removexattr(const char *path, const char *name)removexattr(const char *path, const char *name) { | |||
218 | return removexattr(path, name, 0); | |||
219 | } | |||
220 | static inline int _lremovexattr(const char *path, const char *name)lremovexattr(const char *path, const char *name) { | |||
221 | return removexattr(path, name, XATTR_NOFOLLOW); | |||
222 | } | |||
223 | static inline int _fremovexattr(int filedes, const char *name)fremovexattr(int filedes, const char *name) { | |||
224 | return fremovexattr(filedes, name, 0); | |||
225 | } | |||
226 | ||||
227 | #elif defined(__linux__1) | |||
228 | #define _listxattr(path, list, size)listxattr(path, list, size) listxattr(path, list, size) | |||
229 | #define _llistxattr(path, list, size)llistxattr(path, list, size) llistxattr(path, list, size) | |||
230 | #define _flistxattr(fd, list, size)flistxattr(fd, list, size) flistxattr(fd, list, size) | |||
231 | ||||
232 | #define _getxattr(path, name, value, size)getxattr(path, name, value, size) getxattr(path, name, value, size) | |||
233 | #define _lgetxattr(path, name, value, size)lgetxattr(path, name, value, size) lgetxattr(path, name, value, size) | |||
234 | #define _fgetxattr(fd, name, value, size)fgetxattr(fd, name, value, size) fgetxattr(fd, name, value, size) | |||
235 | ||||
236 | #define _setxattr(path, name, value, size, flags)setxattr(path, name, value, size, flags) setxattr(path, name, value, size, flags) | |||
237 | #define _lsetxattr(path, name, value, size, flags)lsetxattr(path, name, value, size, flags) lsetxattr(path, name, value, size, flags) | |||
238 | #define _fsetxattr(fd, name, value, size, flags)fsetxattr(fd, name, value, size, flags) fsetxattr(fd, name, value, size, flags) | |||
239 | ||||
240 | #define _removexattr(path, name)removexattr(path, name) removexattr(path, name) | |||
241 | #define _lremovexattr(path, name)lremovexattr(path, name) lremovexattr(path, name) | |||
242 | #define _fremovexattr(fd, name)fremovexattr(fd, name) fremovexattr(fd, name) | |||
243 | ||||
244 | #endif | |||
245 | ||||
246 | typedef ssize_t (*buf_getter)(target_t *tgt, const char *name, | |||
247 | void *output, size_t size); | |||
248 | ||||
249 | static ssize_t _list_obj(target_t *tgt, const char *unused, void *list, | |||
250 | size_t size) { | |||
251 | ssize_t ret; | |||
252 | ||||
253 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread();; | |||
254 | if(tgt->type == T_FD) | |||
255 | ret = _flistxattr(tgt->fd, list, size)flistxattr(tgt->fd, list, size); | |||
256 | else if (tgt->type == T_LINK) | |||
257 | ret = _llistxattr(tgt->name, list, size)llistxattr(tgt->name, list, size); | |||
258 | else | |||
259 | ret = _listxattr(tgt->name, list, size)listxattr(tgt->name, list, size); | |||
260 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); }; | |||
261 | return ret; | |||
262 | } | |||
263 | ||||
264 | static ssize_t _get_obj(target_t *tgt, const char *name, void *value, | |||
265 | size_t size) { | |||
266 | ssize_t ret; | |||
267 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread();; | |||
268 | if(tgt->type == T_FD) | |||
269 | ret = _fgetxattr(tgt->fd, name, value, size)fgetxattr(tgt->fd, name, value, size); | |||
270 | else if (tgt->type == T_LINK) | |||
271 | ret = _lgetxattr(tgt->name, name, value, size)lgetxattr(tgt->name, name, value, size); | |||
272 | else | |||
273 | ret = _getxattr(tgt->name, name, value, size)getxattr(tgt->name, name, value, size); | |||
274 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); }; | |||
275 | return ret; | |||
276 | } | |||
277 | ||||
278 | static int _set_obj(target_t *tgt, const char *name, | |||
279 | const void *value, size_t size, int flags) { | |||
280 | int ret; | |||
281 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread();; | |||
282 | if(tgt->type == T_FD) | |||
283 | ret = _fsetxattr(tgt->fd, name, value, size, flags)fsetxattr(tgt->fd, name, value, size, flags); | |||
284 | else if (tgt->type == T_LINK) | |||
285 | ret = _lsetxattr(tgt->name, name, value, size, flags)lsetxattr(tgt->name, name, value, size, flags); | |||
286 | else | |||
287 | ret = _setxattr(tgt->name, name, value, size, flags)setxattr(tgt->name, name, value, size, flags); | |||
288 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); }; | |||
289 | return ret; | |||
290 | } | |||
291 | ||||
292 | static int _remove_obj(target_t *tgt, const char *name) { | |||
293 | int ret; | |||
294 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread();; | |||
295 | if(tgt->type == T_FD) | |||
296 | ret = _fremovexattr(tgt->fd, name)fremovexattr(tgt->fd, name); | |||
297 | else if (tgt->type == T_LINK) | |||
298 | ret = _lremovexattr(tgt->name, name)lremovexattr(tgt->name, name); | |||
299 | else | |||
300 | ret = _removexattr(tgt->name, name)removexattr(tgt->name, name); | |||
301 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); }; | |||
302 | return ret; | |||
303 | } | |||
304 | ||||
305 | /* Perform a get/list operation with appropriate buffer size, | |||
306 | * determined dynamically. | |||
307 | * | |||
308 | * Arguments: | |||
309 | * - getter: the function that actually does the I/O. | |||
310 | * - tgt, name: passed to the getter. | |||
311 | * - buffer: pointer to either an already allocated memory area (in | |||
312 | * which case size contains its current size), or NULL to | |||
313 | * allocate. In all cases (success or failure), the caller should | |||
314 | * deallocate the buffer, using PyMem_Free(). | |||
315 | * - size: either size of current buffer (if non-NULL), or size for | |||
316 | * initial allocation; zero means use a hardcoded initial buffer | |||
317 | * size (ESTIMATE_ATTR_SIZE). The value will be updated upon return | |||
318 | * with the current buffer size. | |||
319 | * - io_errno: if non-NULL, the actual errno will be recorded here; if | |||
320 | * zero, the call was successful and the output/size/nval are valid. | |||
321 | * | |||
322 | * Return value: if positive or zero, buffer will contain the read | |||
323 | * value. Otherwise, io_errno will contain the I/O errno, or zero | |||
324 | * to signify a Python-level error. In all cases, the Python-level | |||
325 | * error is set to the appropriate value. | |||
326 | */ | |||
327 | static ssize_t _generic_get(buf_getter getter, target_t *tgt, | |||
328 | const char *name, | |||
329 | char **buffer, | |||
330 | size_t *size, | |||
331 | int *io_errno) | |||
332 | CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; | |||
333 | ||||
334 | static ssize_t _generic_get(buf_getter getter, target_t *tgt, | |||
335 | const char *name, | |||
336 | char **buffer, | |||
337 | size_t *size, | |||
338 | int *io_errno) { | |||
339 | ssize_t res; | |||
340 | /* Clear errno for now, will only set it when it fails in I/O. */ | |||
341 | if (io_errno != NULL((void*)0)) { | |||
342 | *io_errno = 0; | |||
343 | } | |||
344 | ||||
345 | #define EXIT_IOERROR() \ | |||
346 | { \ | |||
347 | if (io_errno != NULL((void*)0)) { \ | |||
348 | *io_errno = errno(*__errno_location ()); \ | |||
349 | } \ | |||
350 | PyErr_SetFromErrno(PyExc_IOError); \ | |||
351 | return -1; \ | |||
352 | } | |||
353 | ||||
354 | /* Initialize the buffer, if needed. */ | |||
355 | if (*buffer == NULL((void*)0)) { | |||
356 | if (*size == 0) | |||
357 | *size = ESTIMATE_ATTR_SIZE1024; | |||
358 | if((*buffer = PyMem_Malloc(*size)) == NULL((void*)0)) { | |||
359 | PyErr_NoMemory(); | |||
360 | return -1; | |||
361 | } | |||
362 | } | |||
363 | // Try to get the value, while increasing the buffer if too small. | |||
364 | while((res = getter(tgt, name, *buffer, *size)) == -1) { | |||
365 | if(errno(*__errno_location ()) == ERANGE34) { | |||
366 | ssize_t realloc_size_s = getter(tgt, name, NULL((void*)0), 0); | |||
367 | /* ERANGE + proper size _should_ not fail, but... */ | |||
368 | if(realloc_size_s == -1) { | |||
369 | EXIT_IOERROR(); | |||
370 | } | |||
371 | size_t realloc_size = (size_t) realloc_size_s; | |||
372 | char *tmp_buf; | |||
373 | if((tmp_buf = PyMem_Realloc(*buffer, realloc_size)) == NULL((void*)0)) { | |||
374 | PyErr_NoMemory(); | |||
375 | return -1; | |||
376 | } | |||
377 | *buffer = tmp_buf; | |||
378 | *size = realloc_size; | |||
379 | continue; | |||
380 | } else { | |||
381 | /* else we're dealing with a different error, which we | |||
382 | don't know how to handle nicely, so we return */ | |||
383 | EXIT_IOERROR(); | |||
384 | } | |||
385 | } | |||
386 | return res; | |||
387 | #undef EXIT_IOERROR | |||
388 | } | |||
389 | ||||
390 | /* | |||
391 | Checks if an attribute name matches an optional namespace. | |||
392 | ||||
393 | If the namespace is NULL or an empty string, it will return the | |||
394 | name itself. If the namespace is non-NULL and the name matches, it | |||
395 | will return a pointer to the offset in the name after the namespace | |||
396 | and the separator. If however the name doesn't match the namespace, | |||
397 | it will return NULL. | |||
398 | ||||
399 | */ | |||
400 | const char *matches_ns(const char *ns, const char *name) { | |||
401 | size_t ns_size; | |||
402 | if (ns == NULL((void*)0) || *ns == '\0') | |||
403 | return name; | |||
404 | ns_size = strlen(ns); | |||
405 | ||||
406 | if (strlen(name) > (ns_size+1) && !strncmp(name, ns, ns_size) && | |||
407 | name[ns_size] == '.') | |||
408 | return name + ns_size + 1; | |||
409 | return NULL((void*)0); | |||
410 | } | |||
411 | ||||
412 | /* Wrapper for getxattr */ | |||
413 | static char __pygetxattr_doc__[] = | |||
414 | "getxattr(item, attribute[, nofollow=False])\n" | |||
415 | "Get the value of a given extended attribute (deprecated).\n" | |||
416 | "\n" | |||
417 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
418 | NAME_GET_DOC":param string name: the attribute whose value to retrieve;\n" " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n" | |||
419 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
420 | "\n" | |||
421 | ".. deprecated:: 0.4\n" | |||
422 | " this function has been deprecated\n" | |||
423 | " by the :func:`get` function.\n" | |||
424 | ; | |||
425 | ||||
426 | static PyObject * | |||
427 | pygetxattr(PyObject *self, PyObject *args) | |||
428 | { | |||
429 | PyObject *myarg; | |||
430 | target_t tgt; | |||
431 | int nofollow = 0; | |||
432 | char *attrname = NULL((void*)0); | |||
433 | char *buf = NULL((void*)0); | |||
434 | ssize_t nret; | |||
435 | size_t nalloc = 0; | |||
436 | PyObject *res; | |||
437 | ||||
438 | /* Parse the arguments */ | |||
439 | if (!PyArg_ParseTuple_PyArg_ParseTuple_SizeT(args, "Oet|i", &myarg, NULL((void*)0), &attrname, &nofollow)) | |||
440 | return NULL((void*)0); | |||
441 | if(convert_obj(myarg, &tgt, nofollow) < 0) { | |||
442 | res = NULL((void*)0); | |||
443 | goto free_arg; | |||
444 | } | |||
445 | ||||
446 | nret = _generic_get(_get_obj, &tgt, attrname, &buf, &nalloc, NULL((void*)0)); | |||
447 | if (nret == -1) { | |||
448 | res = NULL((void*)0); | |||
449 | goto free_buf; | |||
450 | } | |||
451 | /* Create the string which will hold the result */ | |||
452 | res = PyBytes_FromStringAndSize(buf, nret); | |||
453 | ||||
454 | free_buf: | |||
455 | /* Free the buffer, now it is no longer needed */ | |||
456 | PyMem_Free(buf); | |||
457 | free_tgt(&tgt); | |||
458 | free_arg: | |||
459 | PyMem_Free(attrname); | |||
460 | ||||
461 | /* Return the result */ | |||
462 | return res; | |||
463 | } | |||
464 | ||||
465 | /* Wrapper for getxattr */ | |||
466 | static char __get_doc__[] = | |||
467 | "get(item, name[, nofollow=False, namespace=None])\n" | |||
468 | "Get the value of a given extended attribute.\n" | |||
469 | "\n" | |||
470 | "Example:\n" | |||
471 | " >>> xattr.get('/path/to/file', 'user.comment')\n" | |||
472 | " 'test'\n" | |||
473 | " >>> xattr.get('/path/to/file', 'comment', namespace=xattr.NS_USER)\n" | |||
474 | " 'test'\n" | |||
475 | "\n" | |||
476 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
477 | NAME_GET_DOC":param string name: the attribute whose value to retrieve;\n" " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n" | |||
478 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
479 | NS_DOC":param namespace: if given, the attribute must not contain the\n" " namespace, but instead it will be taken from this parameter\n" ":type namespace: bytes\n" | |||
480 | ":return: the value of the extended attribute (can contain NULLs)\n" | |||
481 | ":rtype: string\n" | |||
482 | ":raises EnvironmentError: caused by any system errors\n" | |||
483 | "\n" | |||
484 | ".. versionadded:: 0.4\n" | |||
485 | NS_CHANGED_DOC".. versionchanged:: 0.5.1\n" " The namespace argument, if passed, cannot be None anymore; to\n" " explicitly specify an empty namespace, pass an empty\n" " string (byte string under Python 3)." | |||
486 | ; | |||
487 | ||||
488 | static PyObject * | |||
489 | xattr_get(PyObject *self, PyObject *args, PyObject *keywds) | |||
490 | { | |||
491 | PyObject *myarg; | |||
492 | target_t tgt; | |||
493 | int nofollow = 0; | |||
494 | char *attrname = NULL((void*)0), *namebuf; | |||
495 | const char *fullname; | |||
496 | char *buf = NULL((void*)0); | |||
497 | const char *ns = NULL((void*)0); | |||
498 | ssize_t nret; | |||
499 | size_t nalloc = 0; | |||
500 | PyObject *res = NULL((void*)0); | |||
501 | static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL((void*)0)}; | |||
502 | ||||
503 | /* Parse the arguments */ | |||
504 | if (!PyArg_ParseTupleAndKeywords_PyArg_ParseTupleAndKeywords_SizeT(args, keywds, "Oet|iy", kwlist, | |||
505 | &myarg, NULL((void*)0), &attrname, &nofollow, &ns)) | |||
506 | return NULL((void*)0); | |||
507 | res = NULL((void*)0); | |||
508 | if(convert_obj(myarg, &tgt, nofollow) < 0) { | |||
509 | goto free_arg; | |||
510 | } | |||
511 | ||||
512 | if(merge_ns(ns, attrname, &fullname, &namebuf) < 0) { | |||
513 | goto free_tgt; | |||
514 | } | |||
515 | ||||
516 | nret = _generic_get(_get_obj, &tgt, fullname, &buf, &nalloc, NULL((void*)0)); | |||
517 | if(nret == -1) { | |||
518 | goto free_buf; | |||
519 | } | |||
520 | ||||
521 | /* Create the string which will hold the result */ | |||
522 | res = PyBytes_FromStringAndSize(buf, nret); | |||
523 | ||||
524 | /* Free the buffers, they are no longer needed */ | |||
525 | free_buf: | |||
526 | PyMem_Free(buf); | |||
527 | PyMem_Free(namebuf); | |||
528 | free_tgt: | |||
529 | free_tgt(&tgt); | |||
530 | free_arg: | |||
531 | PyMem_Free(attrname); | |||
532 | ||||
533 | /* Return the result */ | |||
534 | return res; | |||
535 | } | |||
536 | ||||
537 | /* Wrapper for getxattr */ | |||
538 | static char __get_all_doc__[] = | |||
539 | "get_all(item[, nofollow=False, namespace=None])\n" | |||
540 | "Get all the extended attributes of an item.\n" | |||
541 | "\n" | |||
542 | "This function performs a bulk-get of all extended attribute names\n" | |||
543 | "and the corresponding value.\n" | |||
544 | "Example:\n" | |||
545 | "\n" | |||
546 | " >>> xattr.get_all('/path/to/file')\n" | |||
547 | " [('user.mime-type', 'plain/text'), ('user.comment', 'test'),\n" | |||
548 | " ('system.posix_acl_access', '\\x02\\x00...')]\n" | |||
549 | " >>> xattr.get_all('/path/to/file', namespace=xattr.NS_USER)\n" | |||
550 | " [('mime-type', 'plain/text'), ('comment', 'test')]\n" | |||
551 | "\n" | |||
552 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
553 | ":keyword namespace: an optional namespace for filtering the\n" | |||
554 | " attributes; for example, querying all user attributes can be\n" | |||
555 | " accomplished by passing namespace=:const:`NS_USER`\n" | |||
556 | ":type namespace: string\n" | |||
557 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
558 | ":return: list of tuples (name, value); note that if a namespace\n" | |||
559 | " argument was passed, it (and the separator) will be stripped from\n" | |||
560 | " the names returned\n" | |||
561 | ":rtype: list\n" | |||
562 | ":raises EnvironmentError: caused by any system errors\n" | |||
563 | "\n" | |||
564 | ".. note:: Since reading the whole attribute list is not an atomic\n" | |||
565 | " operation, it might be possible that attributes are added\n" | |||
566 | " or removed between the initial query and the actual reading\n" | |||
567 | " of the attributes; the returned list will contain only the\n" | |||
568 | " attributes that were present at the initial listing of the\n" | |||
569 | " attribute names and that were still present when the read\n" | |||
570 | " attempt for the value is made.\n" | |||
571 | ".. versionadded:: 0.4\n" | |||
572 | NS_CHANGED_DOC".. versionchanged:: 0.5.1\n" " The namespace argument, if passed, cannot be None anymore; to\n" " explicitly specify an empty namespace, pass an empty\n" " string (byte string under Python 3)." | |||
573 | ; | |||
574 | ||||
575 | static PyObject * | |||
576 | get_all(PyObject *self, PyObject *args, PyObject *keywds) | |||
577 | { | |||
578 | PyObject *myarg, *res; | |||
579 | int nofollow=0; | |||
580 | const char *ns = NULL((void*)0); | |||
581 | char *buf_list = NULL((void*)0), *buf_val = NULL((void*)0); | |||
582 | const char *s; | |||
583 | size_t nalloc = 0; | |||
584 | ssize_t nlist, nval; | |||
585 | PyObject *mylist; | |||
586 | target_t tgt; | |||
587 | static char *kwlist[] = {"item", "nofollow", "namespace", NULL((void*)0)}; | |||
588 | int io_errno; | |||
589 | ||||
590 | /* Parse the arguments */ | |||
591 | if (!PyArg_ParseTupleAndKeywords_PyArg_ParseTupleAndKeywords_SizeT(args, keywds, "O|iy", kwlist, | |||
| ||||
592 | &myarg, &nofollow, &ns)) | |||
593 | return NULL((void*)0); | |||
594 | if(convert_obj(myarg, &tgt, nofollow) < 0) | |||
595 | return NULL((void*)0); | |||
596 | ||||
597 | res = NULL((void*)0); | |||
598 | /* Compute first the list of attributes */ | |||
599 | nlist = _generic_get(_list_obj, &tgt, NULL((void*)0), &buf_list, | |||
600 | &nalloc, &io_errno); | |||
601 | if (nlist == -1) { | |||
602 | /* We can't handle any errors, and the Python error is already | |||
603 | set, just bail out. */ | |||
604 | goto free_tgt; | |||
605 | } | |||
606 | ||||
607 | /* Create the list which will hold the result. */ | |||
608 | mylist = PyList_New(0); | |||
609 | if(mylist == NULL((void*)0)) { | |||
610 | goto free_buf_list; | |||
611 | } | |||
612 | ||||
613 | nalloc = 0; | |||
614 | /* Create and insert the attributes as strings in the list */ | |||
615 | for(s = buf_list; s - buf_list < nlist; s += strlen(s) + 1) { | |||
616 | PyObject *my_tuple; | |||
617 | const char *name; | |||
618 | ||||
619 | if((name = matches_ns(ns, s)) == NULL((void*)0)) | |||
620 | continue; | |||
621 | /* Now retrieve the attribute value */ | |||
622 | nval = _generic_get(_get_obj, &tgt, s, &buf_val, &nalloc, &io_errno); | |||
623 | if (nval == -1) { | |||
624 | if (io_errno == ENODATA61) { | |||
625 | PyErr_Clear(); | |||
626 | continue; | |||
627 | } else { | |||
628 | Py_DECREF(mylist)_Py_DECREF(((PyObject*)(mylist))); | |||
629 | goto free_buf_val; | |||
630 | } | |||
631 | } | |||
632 | my_tuple = Py_BuildValue_Py_BuildValue_SizeT("yy#", name, buf_val, nval); | |||
| ||||
633 | if (my_tuple == NULL((void*)0)) { | |||
634 | Py_DECREF(mylist)_Py_DECREF(((PyObject*)(mylist))); | |||
635 | goto free_buf_val; | |||
636 | } | |||
637 | if(PyList_Append(mylist, my_tuple) < 0) { | |||
638 | Py_DECREF(mylist)_Py_DECREF(((PyObject*)(mylist))); | |||
639 | goto free_buf_val; | |||
640 | } | |||
641 | Py_DECREF(my_tuple)_Py_DECREF(((PyObject*)(my_tuple))); | |||
642 | } | |||
643 | ||||
644 | /* Successful exit */ | |||
645 | res = mylist; | |||
646 | ||||
647 | free_buf_val: | |||
648 | PyMem_Free(buf_val); | |||
649 | ||||
650 | free_buf_list: | |||
651 | PyMem_Free(buf_list); | |||
652 | ||||
653 | free_tgt: | |||
654 | free_tgt(&tgt); | |||
655 | ||||
656 | /* Return the result */ | |||
657 | return res; | |||
658 | } | |||
659 | ||||
660 | ||||
661 | static char __pysetxattr_doc__[] = | |||
662 | "setxattr(item, name, value[, flags=0, nofollow=False])\n" | |||
663 | "Set the value of a given extended attribute (deprecated).\n" | |||
664 | "\n" | |||
665 | "Be careful in case you want to set attributes on symbolic\n" | |||
666 | "links, you have to use all the 5 parameters; use 0 for the \n" | |||
667 | "flags value if you want the default behaviour (create or " | |||
668 | "replace)\n" | |||
669 | "\n" | |||
670 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
671 | NAME_SET_DOC":param string name: the attribute whose value to set;\n" " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n" | |||
672 | VALUE_DOC":param string value: possibly with embedded NULLs; note that there\n" " are restrictions regarding the size of the value, for\n" " example, for ext2/ext3, maximum size is the block size\n" | |||
673 | FLAGS_DOC":param flags: if 0 or omitted the attribute will be\n" " created or replaced; if :const:`XATTR_CREATE`, the attribute\n" " will be created, giving an error if it already exists;\n" " if :const:`XATTR_REPLACE`, the attribute will be replaced,\n" " giving an error if it doesn't exist;\n" ":type flags: integer\n" | |||
674 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
675 | "\n" | |||
676 | ".. deprecated:: 0.4\n" | |||
677 | " this function has been deprecated\n" | |||
678 | " by the :func:`set` function.\n" | |||
679 | ; | |||
680 | ||||
681 | /* Wrapper for setxattr */ | |||
682 | static PyObject * | |||
683 | pysetxattr(PyObject *self, PyObject *args) | |||
684 | { | |||
685 | PyObject *myarg, *res; | |||
686 | int nofollow = 0; | |||
687 | char *attrname = NULL((void*)0); | |||
688 | char *buf = NULL((void*)0); | |||
689 | Py_ssize_t bufsize_s; | |||
690 | size_t bufsize; | |||
691 | int nret; | |||
692 | int flags = 0; | |||
693 | target_t tgt; | |||
694 | ||||
695 | /* Parse the arguments */ | |||
696 | if (!PyArg_ParseTuple_PyArg_ParseTuple_SizeT(args, "Oetet#|ii", &myarg, NULL((void*)0), &attrname, | |||
697 | NULL((void*)0), &buf, &bufsize_s, &flags, &nofollow)) | |||
698 | return NULL((void*)0); | |||
699 | ||||
700 | if (bufsize_s < 0) { | |||
701 | PyErr_SetString(PyExc_ValueError, | |||
702 | "negative value size?!"); | |||
703 | res = NULL((void*)0); | |||
704 | goto free_arg; | |||
705 | } | |||
706 | bufsize = (size_t) bufsize_s; | |||
707 | ||||
708 | if(convert_obj(myarg, &tgt, nofollow) < 0) { | |||
709 | res = NULL((void*)0); | |||
710 | goto free_arg; | |||
711 | } | |||
712 | ||||
713 | /* Set the attribute's value */ | |||
714 | nret = _set_obj(&tgt, attrname, buf, bufsize, flags); | |||
715 | ||||
716 | free_tgt(&tgt); | |||
717 | ||||
718 | if(nret == -1) { | |||
719 | res = PyErr_SetFromErrno(PyExc_IOError); | |||
720 | goto free_arg; | |||
721 | } | |||
722 | ||||
723 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
724 | res = Py_None(&_Py_NoneStruct); | |||
725 | ||||
726 | free_arg: | |||
727 | PyMem_Free(attrname); | |||
728 | PyMem_Free(buf); | |||
729 | ||||
730 | /* Return the result */ | |||
731 | return res; | |||
732 | } | |||
733 | ||||
734 | static char __set_doc__[] = | |||
735 | "set(item, name, value[, flags=0, namespace=None])\n" | |||
736 | "Set the value of a given extended attribute.\n" | |||
737 | "\n" | |||
738 | "Example:\n" | |||
739 | "\n" | |||
740 | " >>> xattr.set('/path/to/file', 'user.comment', 'test')\n" | |||
741 | " >>> xattr.set('/path/to/file', 'comment', 'test'," | |||
742 | " namespace=xattr.NS_USER)\n" | |||
743 | "\n" | |||
744 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
745 | NAME_SET_DOC":param string name: the attribute whose value to set;\n" " usually in the form of ``system.posix_acl`` or ``user.mime_type``\n" | |||
746 | VALUE_DOC":param string value: possibly with embedded NULLs; note that there\n" " are restrictions regarding the size of the value, for\n" " example, for ext2/ext3, maximum size is the block size\n" | |||
747 | FLAGS_DOC":param flags: if 0 or omitted the attribute will be\n" " created or replaced; if :const:`XATTR_CREATE`, the attribute\n" " will be created, giving an error if it already exists;\n" " if :const:`XATTR_REPLACE`, the attribute will be replaced,\n" " giving an error if it doesn't exist;\n" ":type flags: integer\n" | |||
748 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
749 | NS_DOC":param namespace: if given, the attribute must not contain the\n" " namespace, but instead it will be taken from this parameter\n" ":type namespace: bytes\n" | |||
750 | ":returns: None\n" | |||
751 | ":raises EnvironmentError: caused by any system errors\n" | |||
752 | "\n" | |||
753 | ".. versionadded:: 0.4\n" | |||
754 | NS_CHANGED_DOC".. versionchanged:: 0.5.1\n" " The namespace argument, if passed, cannot be None anymore; to\n" " explicitly specify an empty namespace, pass an empty\n" " string (byte string under Python 3)." | |||
755 | ; | |||
756 | ||||
757 | /* Wrapper for setxattr */ | |||
758 | static PyObject * | |||
759 | xattr_set(PyObject *self, PyObject *args, PyObject *keywds) | |||
760 | { | |||
761 | PyObject *myarg, *res; | |||
762 | int nofollow = 0; | |||
763 | char *attrname = NULL((void*)0); | |||
764 | char *buf = NULL((void*)0); | |||
765 | Py_ssize_t bufsize_s; | |||
766 | size_t bufsize; | |||
767 | int nret; | |||
768 | int flags = 0; | |||
769 | target_t tgt; | |||
770 | const char *ns = NULL((void*)0); | |||
771 | char *newname; | |||
772 | const char *full_name; | |||
773 | static char *kwlist[] = {"item", "name", "value", "flags", | |||
774 | "nofollow", "namespace", NULL((void*)0)}; | |||
775 | ||||
776 | /* Parse the arguments */ | |||
777 | if (!PyArg_ParseTupleAndKeywords_PyArg_ParseTupleAndKeywords_SizeT(args, keywds, "Oetet#|iiy", | |||
778 | kwlist, &myarg, NULL((void*)0), &attrname, NULL((void*)0), | |||
779 | &buf, &bufsize_s, &flags, &nofollow, &ns)) | |||
780 | return NULL((void*)0); | |||
781 | ||||
782 | if (bufsize_s < 0) { | |||
783 | PyErr_SetString(PyExc_ValueError, | |||
784 | "negative value size?!"); | |||
785 | res = NULL((void*)0); | |||
786 | goto free_arg; | |||
787 | } | |||
788 | bufsize = (size_t) bufsize_s; | |||
789 | ||||
790 | if(convert_obj(myarg, &tgt, nofollow) < 0) { | |||
791 | res = NULL((void*)0); | |||
792 | goto free_arg; | |||
793 | } | |||
794 | ||||
795 | if(merge_ns(ns, attrname, &full_name, &newname) < 0) { | |||
796 | res = NULL((void*)0); | |||
797 | goto free_arg; | |||
798 | } | |||
799 | ||||
800 | /* Set the attribute's value */ | |||
801 | nret = _set_obj(&tgt, full_name, buf, bufsize, flags); | |||
802 | ||||
803 | PyMem_Free(newname); | |||
804 | ||||
805 | free_tgt(&tgt); | |||
806 | ||||
807 | if(nret == -1) { | |||
808 | res = PyErr_SetFromErrno(PyExc_IOError); | |||
809 | goto free_arg; | |||
810 | } | |||
811 | ||||
812 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
813 | res = Py_None(&_Py_NoneStruct); | |||
814 | ||||
815 | free_arg: | |||
816 | PyMem_Free(attrname); | |||
817 | PyMem_Free(buf); | |||
818 | ||||
819 | /* Return the result */ | |||
820 | return res; | |||
821 | } | |||
822 | ||||
823 | ||||
824 | static char __pyremovexattr_doc__[] = | |||
825 | "removexattr(item, name[, nofollow])\n" | |||
826 | "Remove an attribute from a file (deprecated).\n" | |||
827 | "\n" | |||
828 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
829 | NAME_REMOVE_DOC":param string name: the attribute to remove;\n" " usually in the form of ``system.posix_acl`` or \n" " ``user.mime_type``\n" | |||
830 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
831 | "\n" | |||
832 | ".. deprecated:: 0.4\n" | |||
833 | " this function has been deprecated by the :func:`remove` function.\n" | |||
834 | ; | |||
835 | ||||
836 | /* Wrapper for removexattr */ | |||
837 | static PyObject * | |||
838 | pyremovexattr(PyObject *self, PyObject *args) | |||
839 | { | |||
840 | PyObject *myarg, *res; | |||
841 | int nofollow = 0; | |||
842 | char *attrname = NULL((void*)0); | |||
843 | int nret; | |||
844 | target_t tgt; | |||
845 | ||||
846 | /* Parse the arguments */ | |||
847 | if (!PyArg_ParseTuple_PyArg_ParseTuple_SizeT(args, "Oet|i", &myarg, NULL((void*)0), &attrname, &nofollow)) | |||
848 | return NULL((void*)0); | |||
849 | ||||
850 | if(convert_obj(myarg, &tgt, nofollow) < 0) { | |||
851 | res = NULL((void*)0); | |||
852 | goto free_arg; | |||
853 | } | |||
854 | ||||
855 | /* Remove the attribute */ | |||
856 | nret = _remove_obj(&tgt, attrname); | |||
857 | ||||
858 | free_tgt(&tgt); | |||
859 | ||||
860 | if(nret == -1) { | |||
861 | res = PyErr_SetFromErrno(PyExc_IOError); | |||
862 | goto free_arg; | |||
863 | } | |||
864 | ||||
865 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
866 | res = Py_None(&_Py_NoneStruct); | |||
867 | ||||
868 | free_arg: | |||
869 | PyMem_Free(attrname); | |||
870 | ||||
871 | /* Return the result */ | |||
872 | return res; | |||
873 | } | |||
874 | ||||
875 | static char __remove_doc__[] = | |||
876 | "remove(item, name[, nofollow=False, namespace=None])\n" | |||
877 | "Remove an attribute from a file.\n" | |||
878 | "\n" | |||
879 | "Example:\n" | |||
880 | "\n" | |||
881 | " >>> xattr.remove('/path/to/file', 'user.comment')\n" | |||
882 | "\n" | |||
883 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
884 | NAME_REMOVE_DOC":param string name: the attribute to remove;\n" " usually in the form of ``system.posix_acl`` or \n" " ``user.mime_type``\n" | |||
885 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
886 | NS_DOC":param namespace: if given, the attribute must not contain the\n" " namespace, but instead it will be taken from this parameter\n" ":type namespace: bytes\n" | |||
887 | ":returns: None\n" | |||
888 | ":raises EnvironmentError: caused by any system errors\n" | |||
889 | "\n" | |||
890 | ".. versionadded:: 0.4\n" | |||
891 | NS_CHANGED_DOC".. versionchanged:: 0.5.1\n" " The namespace argument, if passed, cannot be None anymore; to\n" " explicitly specify an empty namespace, pass an empty\n" " string (byte string under Python 3)." | |||
892 | ; | |||
893 | ||||
894 | /* Wrapper for removexattr */ | |||
895 | static PyObject * | |||
896 | xattr_remove(PyObject *self, PyObject *args, PyObject *keywds) | |||
897 | { | |||
898 | PyObject *myarg, *res; | |||
899 | int nofollow = 0; | |||
900 | char *attrname = NULL((void*)0), *name_buf; | |||
901 | const char *ns = NULL((void*)0); | |||
902 | const char *full_name; | |||
903 | int nret; | |||
904 | target_t tgt; | |||
905 | static char *kwlist[] = {"item", "name", "nofollow", "namespace", NULL((void*)0)}; | |||
906 | ||||
907 | /* Parse the arguments */ | |||
908 | if (!PyArg_ParseTupleAndKeywords_PyArg_ParseTupleAndKeywords_SizeT(args, keywds, "Oet|iy", kwlist, | |||
909 | &myarg, NULL((void*)0), &attrname, &nofollow, &ns)) | |||
910 | return NULL((void*)0); | |||
911 | ||||
912 | if(convert_obj(myarg, &tgt, nofollow) < 0) { | |||
913 | res = NULL((void*)0); | |||
914 | goto free_arg; | |||
915 | } | |||
916 | ||||
917 | if(merge_ns(ns, attrname, &full_name, &name_buf) < 0) { | |||
918 | res = NULL((void*)0); | |||
919 | goto free_arg; | |||
920 | } | |||
921 | ||||
922 | /* Remove the attribute */ | |||
923 | nret = _remove_obj(&tgt, full_name); | |||
924 | ||||
925 | PyMem_Free(name_buf); | |||
926 | ||||
927 | free_tgt(&tgt); | |||
928 | ||||
929 | if(nret == -1) { | |||
930 | res = PyErr_SetFromErrno(PyExc_IOError); | |||
931 | goto free_arg; | |||
932 | } | |||
933 | ||||
934 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
935 | res = Py_None(&_Py_NoneStruct); | |||
936 | ||||
937 | free_arg: | |||
938 | PyMem_Free(attrname); | |||
939 | ||||
940 | /* Return the result */ | |||
941 | return res; | |||
942 | } | |||
943 | ||||
944 | static char __pylistxattr_doc__[] = | |||
945 | "listxattr(item[, nofollow=False])\n" | |||
946 | "Return the list of attribute names for a file (deprecated).\n" | |||
947 | "\n" | |||
948 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
949 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
950 | "\n" | |||
951 | ".. deprecated:: 0.4\n" | |||
952 | " this function has been deprecated by the :func:`list` function.\n" | |||
953 | ; | |||
954 | ||||
955 | /* Wrapper for listxattr */ | |||
956 | static PyObject * | |||
957 | pylistxattr(PyObject *self, PyObject *args) | |||
958 | { | |||
959 | char *buf = NULL((void*)0); | |||
960 | int nofollow = 0; | |||
961 | ssize_t nret; | |||
962 | size_t nalloc = 0; | |||
963 | PyObject *myarg; | |||
964 | PyObject *mylist; | |||
965 | Py_ssize_t nattrs; | |||
966 | char *s; | |||
967 | target_t tgt; | |||
968 | ||||
969 | /* Parse the arguments */ | |||
970 | if (!PyArg_ParseTuple_PyArg_ParseTuple_SizeT(args, "O|i", &myarg, &nofollow)) | |||
971 | return NULL((void*)0); | |||
972 | if(convert_obj(myarg, &tgt, nofollow) < 0) | |||
973 | return NULL((void*)0); | |||
974 | ||||
975 | nret = _generic_get(_list_obj, &tgt, NULL((void*)0), &buf, &nalloc, NULL((void*)0)); | |||
976 | if (nret == -1) { | |||
977 | mylist = NULL((void*)0); | |||
978 | goto free_buf; | |||
979 | } | |||
980 | ||||
981 | /* Compute the number of attributes in the list */ | |||
982 | for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) { | |||
983 | nattrs++; | |||
984 | } | |||
985 | ||||
986 | /* Create the list which will hold the result */ | |||
987 | mylist = PyList_New(nattrs); | |||
988 | if(mylist == NULL((void*)0)) { | |||
989 | goto free_buf; | |||
990 | } | |||
991 | ||||
992 | /* Create and insert the attributes as strings in the list */ | |||
993 | for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) { | |||
994 | PyObject *item = PyBytes_FromString(s); | |||
995 | if(item == NULL((void*)0)) { | |||
996 | Py_DECREF(mylist)_Py_DECREF(((PyObject*)(mylist))); | |||
997 | mylist = NULL((void*)0); | |||
998 | goto free_buf; | |||
999 | } | |||
1000 | PyList_SET_ITEM(mylist, nattrs, item)PyList_SetItem(mylist, nattrs, item); | |||
1001 | nattrs++; | |||
1002 | } | |||
1003 | ||||
1004 | free_buf: | |||
1005 | /* Free the buffer, now it is no longer needed */ | |||
1006 | PyMem_Free(buf); | |||
1007 | free_tgt(&tgt); | |||
1008 | ||||
1009 | /* Return the result */ | |||
1010 | return mylist; | |||
1011 | } | |||
1012 | ||||
1013 | static char __list_doc__[] = | |||
1014 | "list(item[, nofollow=False, namespace=None])\n" | |||
1015 | "Return the list of attribute names for a file.\n" | |||
1016 | "\n" | |||
1017 | "Example:\n" | |||
1018 | "\n" | |||
1019 | " >>> xattr.list('/path/to/file')\n" | |||
1020 | " ['user.test', 'user.comment', 'system.posix_acl_access']\n" | |||
1021 | " >>> xattr.list('/path/to/file', namespace=xattr.NS_USER)\n" | |||
1022 | " ['test', 'comment']\n" | |||
1023 | "\n" | |||
1024 | ITEM_DOC":param item: a string representing a file-name, a file-like\n" " object, a file descriptor, or (in Python 3.6+) a path-like\n" " object; this represents the file on which to act\n" | |||
1025 | NOFOLLOW_DOC":param nofollow: if true and if\n" " the file name given is a symbolic link, the\n" " function will operate on the symbolic link itself instead\n" " of its target; defaults to false\n" ":type nofollow: boolean, optional\n" | |||
1026 | NS_DOC":param namespace: if given, the attribute must not contain the\n" " namespace, but instead it will be taken from this parameter\n" ":type namespace: bytes\n" | |||
1027 | ":returns: the list of attributes; note that if a namespace \n" | |||
1028 | " argument was passed, it (and the separator) will be stripped\n" | |||
1029 | " from the names\n" | |||
1030 | " returned\n" | |||
1031 | ":rtype: list\n" | |||
1032 | ":raises EnvironmentError: caused by any system errors\n" | |||
1033 | "\n" | |||
1034 | ".. versionadded:: 0.4\n" | |||
1035 | NS_CHANGED_DOC".. versionchanged:: 0.5.1\n" " The namespace argument, if passed, cannot be None anymore; to\n" " explicitly specify an empty namespace, pass an empty\n" " string (byte string under Python 3)." | |||
1036 | ; | |||
1037 | ||||
1038 | /* Wrapper for listxattr */ | |||
1039 | static PyObject * | |||
1040 | xattr_list(PyObject *self, PyObject *args, PyObject *keywds) | |||
1041 | { | |||
1042 | char *buf = NULL((void*)0); | |||
1043 | int nofollow = 0; | |||
1044 | ssize_t nret; | |||
1045 | size_t nalloc = 0; | |||
1046 | PyObject *myarg; | |||
1047 | PyObject *res; | |||
1048 | const char *ns = NULL((void*)0); | |||
1049 | Py_ssize_t nattrs; | |||
1050 | char *s; | |||
1051 | target_t tgt; | |||
1052 | static char *kwlist[] = {"item", "nofollow", "namespace", NULL((void*)0)}; | |||
1053 | ||||
1054 | /* Parse the arguments */ | |||
1055 | if (!PyArg_ParseTupleAndKeywords_PyArg_ParseTupleAndKeywords_SizeT(args, keywds, "O|iy", kwlist, | |||
1056 | &myarg, &nofollow, &ns)) | |||
1057 | return NULL((void*)0); | |||
1058 | res = NULL((void*)0); | |||
1059 | if(convert_obj(myarg, &tgt, nofollow) < 0) { | |||
1060 | goto free_arg; | |||
1061 | } | |||
1062 | nret = _generic_get(_list_obj, &tgt, NULL((void*)0), &buf, &nalloc, NULL((void*)0)); | |||
1063 | if (nret == -1) { | |||
1064 | goto free_tgt; | |||
1065 | } | |||
1066 | ||||
1067 | /* Compute the number of attributes in the list */ | |||
1068 | for(s = buf, nattrs = 0; (s - buf) < nret; s += strlen(s) + 1) { | |||
1069 | if(matches_ns(ns, s) != NULL((void*)0)) | |||
1070 | nattrs++; | |||
1071 | } | |||
1072 | ||||
1073 | /* Create the list which will hold the result */ | |||
1074 | if((res = PyList_New(nattrs)) == NULL((void*)0)) { | |||
1075 | goto free_buf; | |||
1076 | } | |||
1077 | ||||
1078 | /* Create and insert the attributes as strings in the list */ | |||
1079 | for(s = buf, nattrs = 0; s - buf < nret; s += strlen(s) + 1) { | |||
1080 | const char *name = matches_ns(ns, s); | |||
1081 | if(name != NULL((void*)0)) { | |||
1082 | PyObject *item = PyBytes_FromString(name); | |||
1083 | if(item == NULL((void*)0)) { | |||
1084 | Py_DECREF(res)_Py_DECREF(((PyObject*)(res))); | |||
1085 | res = NULL((void*)0); | |||
1086 | goto free_buf; | |||
1087 | } | |||
1088 | PyList_SET_ITEM(res, nattrs, item)PyList_SetItem(res, nattrs, item); | |||
1089 | nattrs++; | |||
1090 | } | |||
1091 | } | |||
1092 | ||||
1093 | free_buf: | |||
1094 | /* Free the buffer, now it is no longer needed */ | |||
1095 | PyMem_Free(buf); | |||
1096 | ||||
1097 | free_tgt: | |||
1098 | free_tgt(&tgt); | |||
1099 | free_arg: | |||
1100 | ||||
1101 | /* Return the result */ | |||
1102 | return res; | |||
1103 | } | |||
1104 | ||||
1105 | static PyMethodDef xattr_methods[] = { | |||
1106 | {"getxattr", pygetxattr, METH_VARARGS0x0001, __pygetxattr_doc__ }, | |||
1107 | {"get", (PyCFunction) xattr_get, METH_VARARGS0x0001 | METH_KEYWORDS0x0002, | |||
1108 | __get_doc__ }, | |||
1109 | {"get_all", (PyCFunction) get_all, METH_VARARGS0x0001 | METH_KEYWORDS0x0002, | |||
1110 | __get_all_doc__ }, | |||
1111 | {"setxattr", pysetxattr, METH_VARARGS0x0001, __pysetxattr_doc__ }, | |||
1112 | {"set", (PyCFunction) xattr_set, METH_VARARGS0x0001 | METH_KEYWORDS0x0002, | |||
1113 | __set_doc__ }, | |||
1114 | {"removexattr", pyremovexattr, METH_VARARGS0x0001, __pyremovexattr_doc__ }, | |||
1115 | {"remove", (PyCFunction) xattr_remove, METH_VARARGS0x0001 | METH_KEYWORDS0x0002, | |||
1116 | __remove_doc__ }, | |||
1117 | {"listxattr", pylistxattr, METH_VARARGS0x0001, __pylistxattr_doc__ }, | |||
1118 | {"list", (PyCFunction) xattr_list, METH_VARARGS0x0001 | METH_KEYWORDS0x0002, | |||
1119 | __list_doc__ }, | |||
1120 | {NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)} /* Sentinel */ | |||
1121 | }; | |||
1122 | ||||
1123 | static char __xattr_doc__[] = \ | |||
1124 | "This module gives access to the extended attributes present\n" | |||
1125 | "in some operating systems/filesystems. You can list attributes,\n" | |||
1126 | "get, set and remove them.\n" | |||
1127 | "\n" | |||
1128 | "The module exposes two sets of functions:\n" | |||
1129 | " - the 'old' :func:`listxattr`, :func:`getxattr`, :func:`setxattr`,\n" | |||
1130 | " :func:`removexattr`\n" | |||
1131 | " functions which are deprecated since version 0.4\n" | |||
1132 | " - the new :func:`list`, :func:`get`, :func:`get_all`, :func:`set`,\n" | |||
1133 | " :func:`remove` functions\n" | |||
1134 | " which expose a namespace-aware API and simplify a bit the calling\n" | |||
1135 | " model by using keyword arguments\n" | |||
1136 | "\n" | |||
1137 | "Example: \n\n" | |||
1138 | " >>> import xattr\n" | |||
1139 | " >>> xattr.listxattr(\"file.txt\")\n" | |||
1140 | " ['user.mime_type']\n" | |||
1141 | " >>> xattr.getxattr(\"file.txt\", \"user.mime_type\")\n" | |||
1142 | " 'text/plain'\n" | |||
1143 | " >>> xattr.setxattr(\"file.txt\", \"user.comment\", " | |||
1144 | "\"Simple text file\")\n" | |||
1145 | " >>> xattr.listxattr(\"file.txt\")\n" | |||
1146 | " ['user.mime_type', 'user.comment']\n" | |||
1147 | " >>> xattr.removexattr (\"file.txt\", \"user.comment\")\n" | |||
1148 | "\n" | |||
1149 | ".. note:: Most or all errors reported by the system while using\n" | |||
1150 | " the ``xattr`` library will be reported by raising\n" | |||
1151 | " a :exc:`EnvironmentError`; under\n" | |||
1152 | " Linux, the following ``errno`` values are used:\n" | |||
1153 | "\n" | |||
1154 | " - ``ENODATA`` means that the attribute name is invalid\n" | |||
1155 | " - ``ENOTSUP`` and ``EOPNOTSUPP`` mean that the filesystem does not\n" | |||
1156 | " support extended attributes, or that the namespace is invalid\n" | |||
1157 | " - ``E2BIG`` mean that the attribute value is too big\n" | |||
1158 | " - ``ERANGE`` mean that the attribute name is too big (it might also\n" | |||
1159 | " mean an error in the xattr module itself)\n" | |||
1160 | " - ``ENOSPC`` and ``EDQUOT`` are documented as meaning out of disk\n" | |||
1161 | " space or out of disk space because of quota limits\n" | |||
1162 | ".. note:: Under Python 3, the namespace argument is a byte string,\n" | |||
1163 | " not a unicode string.\n" | |||
1164 | "\n" | |||
1165 | ; | |||
1166 | ||||
1167 | static struct PyModuleDef xattrmodule = { | |||
1168 | PyModuleDef_HEAD_INIT{ { 1, ((void*)0) }, ((void*)0), 0, ((void*)0), }, | |||
1169 | "xattr", | |||
1170 | __xattr_doc__, | |||
1171 | 0, | |||
1172 | xattr_methods, | |||
1173 | }; | |||
1174 | ||||
1175 | #define INITERRORreturn ((void*)0) return NULL((void*)0) | |||
1176 | ||||
1177 | PyMODINIT_FUNCPyObject* | |||
1178 | PyInit_xattr(void) | |||
1179 | ||||
1180 | { | |||
1181 | PyObject *ns_security = NULL((void*)0); | |||
1182 | PyObject *ns_system = NULL((void*)0); | |||
1183 | PyObject *ns_trusted = NULL((void*)0); | |||
1184 | PyObject *ns_user = NULL((void*)0); | |||
1185 | PyObject *m = PyModule_Create(&xattrmodule)PyModule_Create2(&xattrmodule, 1013); | |||
1186 | if (m==NULL((void*)0)) | |||
1187 | return NULL((void*)0); | |||
1188 | ||||
1189 | PyModule_AddStringConstant(m, "__author__", _XATTR_AUTHOR"Iustin Pop"); | |||
1190 | PyModule_AddStringConstant(m, "__contact__", _XATTR_EMAIL"iustin@k1024.org"); | |||
1191 | PyModule_AddStringConstant(m, "__version__", _XATTR_VERSION"0.7.2"); | |||
1192 | PyModule_AddStringConstant(m, "__license__", | |||
1193 | "GNU Lesser General Public License (LGPL)"); | |||
1194 | PyModule_AddStringConstant(m, "__docformat__", "restructuredtext en"); | |||
1195 | ||||
1196 | PyModule_AddIntConstant(m, "XATTR_CREATE", XATTR_CREATEXATTR_CREATE); | |||
1197 | PyModule_AddIntConstant(m, "XATTR_REPLACE", XATTR_REPLACEXATTR_REPLACE); | |||
1198 | ||||
1199 | /* namespace constants */ | |||
1200 | if((ns_security = PyBytes_FromString("security")) == NULL((void*)0)) | |||
1201 | goto err_out; | |||
1202 | if((ns_system = PyBytes_FromString("system")) == NULL((void*)0)) | |||
1203 | goto err_out; | |||
1204 | if((ns_trusted = PyBytes_FromString("trusted")) == NULL((void*)0)) | |||
1205 | goto err_out; | |||
1206 | if((ns_user = PyBytes_FromString("user")) == NULL((void*)0)) | |||
1207 | goto err_out; | |||
1208 | if(PyModule_AddObject(m, "NS_SECURITY", ns_security) < 0) | |||
1209 | goto err_out; | |||
1210 | ns_security = NULL((void*)0); | |||
1211 | if(PyModule_AddObject(m, "NS_SYSTEM", ns_system) < 0) | |||
1212 | goto err_out; | |||
1213 | ns_system = NULL((void*)0); | |||
1214 | if(PyModule_AddObject(m, "NS_TRUSTED", ns_trusted) < 0) | |||
1215 | goto err_out; | |||
1216 | ns_trusted = NULL((void*)0); | |||
1217 | if(PyModule_AddObject(m, "NS_USER", ns_user) < 0) | |||
1218 | goto err_out; | |||
1219 | ns_user = NULL((void*)0); | |||
1220 | ||||
1221 | return m; | |||
1222 | ||||
1223 | err_out: | |||
1224 | Py_XDECREF(ns_user)_Py_XDECREF(((PyObject*)(ns_user))); | |||
1225 | Py_XDECREF(ns_trusted)_Py_XDECREF(((PyObject*)(ns_trusted))); | |||
1226 | Py_XDECREF(ns_system)_Py_XDECREF(((PyObject*)(ns_system))); | |||
1227 | Py_XDECREF(ns_security)_Py_XDECREF(((PyObject*)(ns_security))); | |||
1228 | INITERRORreturn ((void*)0); | |||
1229 | } |
1 | #ifndef _Py_BuildValue_SizeT |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* _Py_BuildValue_SizeT(const char *format, ...) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API _Py_BuildValue_SizeT is defined as a macro." |
10 | #endif |