EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_xattr.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2011 Cedric Bail
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #include <math.h>
27
28 #ifdef HAVE_XATTR
29 # include <sys/xattr.h>
30 #endif
31
32 #include "eina_config.h"
33 #include "eina_private.h"
34
35 #include "eina_safety_checks.h"
36 #include "eina_xattr.h"
37 #include "eina_convert.h"
38 #include "eina_stringshare.h"
39
40 /*============================================================================*
41  *                                  Local                                     *
42  *============================================================================*/
43
44 /**
45  * @cond LOCAL
46  */
47
48 typedef struct _Eina_Xattr_Iterator Eina_Xattr_Iterator;
49
50 struct _Eina_Xattr_Iterator
51 {
52    Eina_Iterator iterator;
53
54    const char *file;
55    Eina_Xattr *attr;
56
57    ssize_t length;
58    ssize_t offset;
59
60    int fd;
61
62    char xattr[1];
63 };
64
65 #ifdef HAVE_XATTR
66 static Eina_Bool
67 _eina_xattr_value_ls_fd_iterator_next(Eina_Xattr_Iterator *it, void **data)
68 {
69    char *tmp;
70
71    if (it->offset >= it->length)
72      return EINA_FALSE;
73
74    *data = it->attr;
75    it->attr->name = it->xattr + it->offset;
76
77    it->attr->length = fgetxattr(it->fd, it->attr->name, NULL, 0);
78    if (it->attr->length)
79      {
80         tmp = realloc((void*) it->attr->value, it->attr->length);
81         if (!tmp)
82           {
83              free((void*) it->attr->value);
84              it->attr->value = NULL;
85              it->attr->length = 0;
86           }
87         else
88           {
89              it->attr->length = fgetxattr(it->fd, it->attr->name,
90                                           (void *) it->attr->value,
91                                           it->attr->length);
92           }
93      }
94
95    return EINA_TRUE;
96 }
97
98 static Eina_Bool
99 _eina_xattr_value_ls_iterator_next(Eina_Xattr_Iterator *it, void **data)
100 {
101    char *tmp;
102
103    if (it->offset >= it->length)
104      return EINA_FALSE;
105
106    *data = it->attr;
107    it->attr->name = it->xattr + it->offset;
108
109    it->attr->length = getxattr(it->file, it->attr->name, NULL, 0);
110    if (it->attr->length)
111      {
112         tmp = realloc((void*) it->attr->value, it->attr->length);
113         if (!tmp)
114           {
115              free((void*) it->attr->value);
116              it->attr->value = NULL;
117              it->attr->length = 0;
118           }
119         else
120           {
121              it->attr->length = getxattr(it->file, it->attr->name,
122                                          (void*) it->attr->value,
123                                          it->attr->length);
124           }
125      }
126
127    return EINA_TRUE;
128 }
129
130 static Eina_Bool
131 _eina_xattr_ls_iterator_next(Eina_Xattr_Iterator *it, void **data)
132 {
133    if (it->offset >= it->length)
134      return EINA_FALSE;
135
136    *data = it->xattr + it->offset;
137    it->offset += strlen(it->xattr + it->offset) + 1;
138
139    return EINA_TRUE;
140 }
141
142 static void *
143 _eina_xattr_ls_iterator_container(Eina_Xattr_Iterator *it __UNUSED__)
144 {
145    return NULL;
146 }
147
148 static void
149 _eina_xattr_ls_iterator_free(Eina_Xattr_Iterator *it)
150 {
151    EINA_MAGIC_SET(&it->iterator, 0);
152    if (it->attr) free((void *) it->attr->value);
153    eina_stringshare_del(it->file);
154    free(it->attr);
155    free(it);
156 }
157 #endif
158
159 /**
160  * @endcond
161  */
162
163
164 /*============================================================================*
165  *                                 Global                                     *
166  *============================================================================*/
167
168
169 /*============================================================================*
170  *                                   API                                      *
171  *============================================================================*/
172
173 EAPI Eina_Iterator *
174 eina_xattr_value_fd_ls(int fd)
175 {
176 #ifdef HAVE_XATTR
177    Eina_Xattr_Iterator *it;
178    ssize_t length;
179
180    if (fd < 0) return NULL;
181
182    length = flistxattr(fd, NULL, 0);
183    if (length <= 0) return NULL;
184
185    it = calloc(1, sizeof (Eina_Xattr_Iterator) + length - 1);
186    if (!it) return NULL;
187
188    it->attr = calloc(1, sizeof (Eina_Xattr));
189    if (!it->attr)
190      {
191         free(it);
192         return NULL;
193      }
194
195    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
196
197    it->fd = fd;
198    it->length = flistxattr(fd, it->xattr, length);
199    if (it->length != length)
200      {
201         free(it);
202         return NULL;
203      }
204
205    it->iterator.version = EINA_ITERATOR_VERSION;
206    it->iterator.next = FUNC_ITERATOR_NEXT(_eina_xattr_value_ls_fd_iterator_next);
207    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_xattr_ls_iterator_container);
208    it->iterator.free = FUNC_ITERATOR_FREE(_eina_xattr_ls_iterator_free);
209
210    return &it->iterator;
211 #else
212    return NULL;
213    (void)fd;
214 #endif
215 }
216
217 EAPI Eina_Iterator *
218 eina_xattr_fd_ls(int fd)
219 {
220 #ifdef HAVE_XATTR
221    Eina_Xattr_Iterator *it;
222    ssize_t length;
223
224    if (fd < 0) return NULL;
225
226    length = flistxattr(fd, NULL, 0);
227    if (length <= 0) return NULL;
228
229    it = calloc(1, sizeof (Eina_Xattr_Iterator) + length - 1);
230    if (!it) return NULL;
231
232    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
233
234    it->length = flistxattr(fd, it->xattr, length);
235    if (it->length != length)
236      {
237         free(it);
238         return NULL;
239      }
240
241    it->iterator.version = EINA_ITERATOR_VERSION;
242    it->iterator.next = FUNC_ITERATOR_NEXT(_eina_xattr_ls_iterator_next);
243    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_xattr_ls_iterator_container);
244    it->iterator.free = FUNC_ITERATOR_FREE(_eina_xattr_ls_iterator_free);
245
246    return &it->iterator;
247 #else
248    return NULL;
249    (void)fd;
250 #endif
251 }
252
253 EAPI Eina_Iterator *
254 eina_xattr_ls(const char *file)
255 {
256 #ifdef HAVE_XATTR
257    Eina_Xattr_Iterator *it;
258    ssize_t length;
259
260    EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
261
262    length = listxattr(file, NULL, 0);
263    if (length <= 0) return NULL;
264
265    it = calloc(1, sizeof (Eina_Xattr_Iterator) + length - 1);
266    if (!it) return NULL;
267
268    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
269
270    it->length = listxattr(file, it->xattr, length);
271    if (it->length != length)
272      {
273         free(it);
274         return NULL;
275      }
276
277    it->iterator.version = EINA_ITERATOR_VERSION;
278    it->iterator.next = FUNC_ITERATOR_NEXT(_eina_xattr_ls_iterator_next);
279    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_xattr_ls_iterator_container);
280    it->iterator.free = FUNC_ITERATOR_FREE(_eina_xattr_ls_iterator_free);
281
282    return &it->iterator;
283 #else
284    return NULL;
285    (void)file;
286 #endif
287 }
288
289 EAPI Eina_Iterator *
290 eina_xattr_value_ls(const char *file)
291 {
292 #ifdef HAVE_XATTR
293    Eina_Xattr_Iterator *it;
294    ssize_t length;
295
296    EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
297
298    length = listxattr(file, NULL, 0);
299    if (length <= 0) return NULL;
300
301    it = calloc(1, sizeof (Eina_Xattr_Iterator) + length - 1);
302    if (!it) return NULL;
303
304    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
305
306    it->length = listxattr(file, it->xattr, length);
307    if (it->length != length)
308      {
309         free(it);
310         return NULL;
311      }
312
313    it->file = eina_stringshare_add(file);
314
315    it->iterator.version = EINA_ITERATOR_VERSION;
316    it->iterator.next = FUNC_ITERATOR_NEXT(_eina_xattr_value_ls_iterator_next);
317    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_xattr_ls_iterator_container);
318    it->iterator.free = FUNC_ITERATOR_FREE(_eina_xattr_ls_iterator_free);
319
320    return &it->iterator;
321 #else
322    return NULL;
323    (void)file;
324 #endif
325 }
326
327 EAPI void *
328 eina_xattr_get(const char *file, const char *attribute, ssize_t *size)
329 {
330 #ifdef HAVE_XATTR
331    void *ret = NULL;
332    ssize_t tmp;
333
334    EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
335    EINA_SAFETY_ON_NULL_RETURN_VAL(attribute, NULL);
336    EINA_SAFETY_ON_TRUE_RETURN_VAL(!size, NULL);
337
338    *size = getxattr(file, attribute, NULL, 0);
339    /* Size should be less than 2MB (already huge in my opinion) */
340    if (!(*size > 0 && *size < 2 * 1024 * 1024))
341      goto on_error;
342
343    ret = malloc(*size);
344    if (!ret) return NULL;
345
346    tmp = getxattr(file, attribute, ret, *size);
347    if (tmp != *size)
348      goto on_error;
349
350    return ret;
351
352  on_error:
353    free(ret);
354    *size = 0;
355    return NULL;
356 #else
357    EINA_SAFETY_ON_TRUE_RETURN_VAL(!size, NULL);
358    *size = 0;
359    return NULL;
360    (void)file;
361    (void)attribute;
362 #endif
363 }
364
365 EAPI Eina_Bool
366 eina_xattr_set(const char *file, const char *attribute, const void *data, ssize_t length, Eina_Xattr_Flags flags)
367 {
368 #ifdef HAVE_XATTR
369    int iflags;
370
371    EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
372    EINA_SAFETY_ON_NULL_RETURN_VAL(attribute, EINA_FALSE);
373    EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
374    EINA_SAFETY_ON_TRUE_RETURN_VAL(!(length > 0 && length < 2 * 1024 * 1024), EINA_FALSE);
375
376    switch (flags)
377      {
378      case EINA_XATTR_INSERT: iflags = 0; break;
379      case EINA_XATTR_REPLACE: iflags = XATTR_REPLACE; break;
380      case EINA_XATTR_CREATED: iflags = XATTR_CREATE; break;
381      default:
382        return EINA_FALSE;
383      }
384
385    if (setxattr(file, attribute, data, length, iflags))
386      return EINA_FALSE;
387    return EINA_TRUE;
388 #else
389    return EINA_FALSE;
390    (void)file;
391    (void)attribute;
392    (void)data;
393    (void)length;
394    (void)flags;
395 #endif
396 }
397
398 EAPI Eina_Bool
399 eina_xattr_string_set(const char *file, const char *attribute, const char *data, Eina_Xattr_Flags flags)
400 {
401    EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
402
403    return eina_xattr_set(file, attribute, data, strlen(data) + 1, flags);
404 }
405
406 EAPI char *
407 eina_xattr_string_get(const char *file, const char *attribute)
408 {
409    char *tmp;
410    ssize_t size;
411
412    tmp = eina_xattr_get(file, attribute, &size);
413    if (!tmp) return NULL;
414
415    if (tmp[size - 1] != '\0')
416      {
417         free(tmp);
418         return NULL;
419      }
420
421    return tmp;
422 }
423
424 EAPI Eina_Bool
425 eina_xattr_double_set(const char *file, const char *attribute, double value, Eina_Xattr_Flags flags)
426 {
427    char buffer[128];
428
429    eina_convert_dtoa(value, buffer);
430    return eina_xattr_string_set(file, attribute, buffer, flags);
431 }
432
433 EAPI Eina_Bool
434 eina_xattr_double_get(const char *file, const char *attribute, double *value)
435 {
436    char *tmp;
437    long long int m = 0;
438    long int e = 0;
439
440    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
441
442    tmp = eina_xattr_string_get(file, attribute);
443    if (!tmp) return EINA_FALSE;
444
445    if (!eina_convert_atod(tmp, strlen(tmp), &m, &e))
446      {
447        free(tmp);
448        return EINA_FALSE;
449      }
450
451    *value = ldexp((double)m, e);
452    free(tmp);
453
454    return EINA_TRUE;
455 }
456
457 EAPI Eina_Bool
458 eina_xattr_int_set(const char *file, const char *attribute, int value, Eina_Xattr_Flags flags)
459 {
460    char buffer[10];
461
462    eina_convert_itoa(value, buffer);
463    return eina_xattr_string_set(file, attribute, buffer, flags);
464 }
465
466 EAPI Eina_Bool
467 eina_xattr_int_get(const char *file, const char *attribute, int *value)
468 {
469    char *tmp;
470    char *eos;
471    Eina_Bool result;
472
473    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
474
475    tmp = eina_xattr_string_get(file, attribute);
476    if (!tmp) return EINA_FALSE;
477
478    *value = (int) strtol(tmp, &eos, 10);
479    result = (*eos == '\0');
480    free(tmp);
481
482    return result;
483 }