From 68f36b2d11333507d4ab4f168866e50b5b5cf2ba Mon Sep 17 00:00:00 2001 From: cedric Date: Tue, 3 Jan 2012 14:59:07 +0000 Subject: [PATCH] eina: detect fault during Eina_File mmap memory access and improve Xattr functions. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@66799 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- ChangeLog | 9 ++- NEWS | 5 +- src/include/eina_file.h | 37 +++++++++ src/include/eina_xattr.h | 47 ++++++++++++ src/lib/eina_file.c | 89 ++++++++++++++++++++++ src/lib/eina_mmap.c | 2 + src/lib/eina_private.h | 2 + src/lib/eina_xattr.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 379 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8f0b210..6a1846b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -151,7 +151,7 @@ 2011-12-02 Carsten Haitzler (The Rasterman) 1.1.0 release - + 2011-12-02 Mike Blumenkrantz (discomfitor/zmike) * Add eina_mempool_calloc for returning zeroed memory @@ -181,3 +181,10 @@ 2011-12-30 Cedric Bail * Let eina_hash_free behave like free. + +2012-01-03 Cedric Bail + + * Add eina_xattr_fd_ls, eina_xattr_value_fd_ls and eina_xattr_value_ls. + * Detect fault during access to Eina_File mmap memory, use eina_file_map_faulted + to learn if it happens. + * Add eina_file_xattr_get and eina_file_xattr_value_get. diff --git a/NEWS b/NEWS index 5e042e9..6123cdd 100644 --- a/NEWS +++ b/NEWS @@ -7,7 +7,10 @@ Additions: * eina_mempool_calloc * Eina_Semaphore abstraction API - + * eina_xattr_fd_ls + * Eina_Xattr iterator : eina_xattr_value_fd_ls and eina_xattr_value_ls API + * eina_file_map_faulted API + * Xattr iterator for Eina_File : eina_file_xattr_get and eina_file_xattr_value_get API Eina 1.1.0 diff --git a/src/include/eina_file.h b/src/include/eina_file.h index 295da09..422fb65 100644 --- a/src/include/eina_file.h +++ b/src/include/eina_file.h @@ -348,6 +348,33 @@ EAPI time_t eina_file_mtime_get(Eina_File *file); EAPI const char *eina_file_filename_get(Eina_File *file); /** + * @brief Get the eXtended attribute of an open file. + * + * @param file The file handler to request the eXtended attribute from. + * @return an iterator. + * + * The iterator will list all eXtended attribute name without allocating + * them, so you need to copy them yourself if needed. + * + * @since 1.2 + */ +EAPI Eina_Iterator *eina_file_xattr_get(Eina_File *file); + +/** + * @brief Get the eXtended attribute of an open file. + * + * @param file The file handler to request the eXtended attribute from. + * @return an iterator. + * + * The iterator will list all eXtended attribute without allocating + * them, so you need to copy them yourself if needed. It is returning + * Eina_Xattr structure. + * + * @since 1.2 + */ +EAPI Eina_Iterator *eina_file_xattr_value_get(Eina_File *file); + +/** * @brief Map all the file to a buffer. * * @param file The file handler to map in memory @@ -385,6 +412,16 @@ EAPI void *eina_file_map_new(Eina_File *file, Eina_File_Populate rule, EAPI void eina_file_map_free(Eina_File *file, void *map); /** + * @brief Tell if their was an IO error during the life of a mmaped file + * + * @param file The file handler to the mmaped file. + * @param map Memory map to check if an error occured on it. + * + * @since 1.2 + */ +EAPI Eina_Bool eina_file_map_faulted(Eina_File *file, void *map); + +/** * @} */ diff --git a/src/include/eina_xattr.h b/src/include/eina_xattr.h index 5ab294d..0f89cc3 100644 --- a/src/include/eina_xattr.h +++ b/src/include/eina_xattr.h @@ -39,6 +39,14 @@ typedef enum { EINA_XATTR_CREATED /**< This will only succeed if the extended attribute wasn't previously set */ } Eina_Xattr_Flags; +typedef struct _Eina_Xattr Eina_Xattr; +struct _Eina_Xattr +{ + const char *name; /**< The eXtended attribute name @since 1.2 */ + const char *value; /**< The eXtended attribute value @since 1.2 */ + + size_t length; /**< The length of the eXtended attribute value @since 1.2 */ +}; /** * @brief Get an iterator that list all extended attribute of a file. @@ -54,6 +62,45 @@ typedef enum { EAPI Eina_Iterator *eina_xattr_ls(const char *file); /** + * @brief Get an iterator that list all extended attribute value related to a fd. + * + * @param file The filename to retrieve the extended attribute list from. + * @return an iterator. + * + * The iterator will not allocate any data during the iteration step, so you need to copy them yourself + * if you need. The iterator will provide an Eina_Xattr structure. + * + * @since 1.2 + */ +EAPI Eina_Iterator *eina_xattr_value_ls(const char *file); + +/** + * @brief Get an iterator that list all extended attribute related to a fd. + * + * @param fd The file descriptor to retrieve the extended attribute list from. + * @return an iterator. + * + * The iterator will not allocate any data during the iteration step, so you need to copy them yourself + * if you need. + * + * @since 1.2 + */ +EAPI Eina_Iterator *eina_xattr_fd_ls(int fd); + +/** + * @brief Get an iterator that list all extended attribute value related to a fd. + * + * @param fd The file descriptor to retrieve the extended attribute list from. + * @return an iterator. + * + * The iterator will not allocate any data during the iteration step, so you need to copy them yourself + * if you need. The iterator will provide an Eina_Xattr structure. + * + * @since 1.2 + */ +EAPI Eina_Iterator *eina_xattr_value_fd_ls(int fd); + +/** * @brief Retrieve an extended attribute from a file. * * @param file The file to retrieve the extended attribute from. diff --git a/src/lib/eina_file.c b/src/lib/eina_file.c index c53f674..6f1b0f1 100644 --- a/src/lib/eina_file.c +++ b/src/lib/eina_file.c @@ -138,6 +138,7 @@ struct _Eina_File Eina_Bool shared : 1; Eina_Bool delete_me : 1; + Eina_Bool global_faulty : 1; }; typedef struct _Eina_File_Map Eina_File_Map; @@ -151,6 +152,7 @@ struct _Eina_File_Map int refcount; Eina_Bool hugetlb : 1; + Eina_Bool faulty : 1; }; static Eina_Hash *_eina_file_cache = NULL; @@ -1210,4 +1212,91 @@ eina_file_map_free(Eina_File *file, void *map) eina_lock_release(&file->lock); } +EAPI Eina_Bool +eina_file_map_faulted(Eina_File *file, void *map) +{ + Eina_File_Map *em; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE); + + eina_lock_take(&file->lock); + + if (file->global_map == map) return file->global_faulty; + + em = eina_hash_find(file->rmap, &map); + if (!em) return EINA_FALSE; + + return em->faulty; +} + +EAPI Eina_Iterator * +eina_file_xattr_get(Eina_File *file) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + return eina_xattr_fd_ls(file->fd); +} + +EAPI Eina_Iterator * +eina_file_xattr_value_get(Eina_File *file) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + return eina_xattr_value_fd_ls(file->fd); +} + +void +eina_file_mmap_faulty(void *addr, long page_size) +{ + Eina_File_Map *m; + Eina_File *f; + Eina_Iterator *itf; + Eina_Iterator *itm; + + /* NOTE: I actually don't know if other thread are running, I will try to take the lock. + It may be possible that if other thread are not running and they were in the middle of + accessing an Eina_File this lock are still taken and we will result as a deadlock. */ + eina_lock_take(&_eina_file_lock_cache); + + itf = eina_hash_iterator_data_new(_eina_file_cache); + EINA_ITERATOR_FOREACH(itf, f) + { + Eina_Bool faulty = EINA_FALSE; + + eina_lock_take(&f->lock); + + if (f->global_map) + { + if ((unsigned char *) addr < (((unsigned char *)f->global_map) + f->length) && + (((unsigned char *) addr) + page_size) >= (unsigned char *) f->global_map) + { + f->global_faulty = EINA_TRUE; + faulty = EINA_TRUE; + } + } + + if (!faulty) + { + itm = eina_hash_iterator_data_new(f->map); + EINA_ITERATOR_FOREACH(itm, m) + { + if ((unsigned char *) addr < (((unsigned char *)m->map) + m->length) && + (((unsigned char *) addr) + page_size) >= (unsigned char *) m->map) + { + m->faulty = EINA_TRUE; + faulty = EINA_TRUE; + break; + } + } + eina_iterator_free(itm); + } + + eina_lock_release(&f->lock); + + if (faulty) break; + } + eina_iterator_free(itf); + + eina_lock_release(&_eina_file_lock_cache); +} diff --git a/src/lib/eina_mmap.c b/src/lib/eina_mmap.c index fb27bd7..4589818 100644 --- a/src/lib/eina_mmap.c +++ b/src/lib/eina_mmap.c @@ -110,6 +110,8 @@ _eina_mmap_safe_sigbus(int sig __UNUSED__, errno = perrno; abort(); } + /* Look into mmaped Eina_File if it was one of them, just to remember for later request */ + eina_file_mmap_faulty(addr, _eina_mmap_pagesize); /* restore previous errno */ errno = perrno; } diff --git a/src/lib/eina_private.h b/src/lib/eina_private.h index d390397..6db120c 100644 --- a/src/lib/eina_private.h +++ b/src/lib/eina_private.h @@ -136,5 +136,7 @@ void eina_log_threads_init(void); void eina_log_threads_shutdown(void); #endif +void eina_file_mmap_faulty(void *addr, long page_size); + #endif /* EINA_PRIVATE_H_ */ diff --git a/src/lib/eina_xattr.c b/src/lib/eina_xattr.c index 893456b..7f86f2f 100644 --- a/src/lib/eina_xattr.c +++ b/src/lib/eina_xattr.c @@ -35,6 +35,7 @@ #include "eina_safety_checks.h" #include "eina_xattr.h" #include "eina_convert.h" +#include "eina_stringshare.h" /*============================================================================* * Local * @@ -50,14 +51,83 @@ struct _Eina_Xattr_Iterator { Eina_Iterator iterator; + const char *file; + Eina_Xattr *attr; + ssize_t length; ssize_t offset; + int fd; + char xattr[1]; }; #ifdef HAVE_XATTR static Eina_Bool +_eina_xattr_value_ls_fd_iterator_next(Eina_Xattr_Iterator *it, void **data) +{ + char *tmp; + + if (it->offset >= it->length) + return EINA_FALSE; + + *data = it->attr; + it->attr->name = it->xattr + it->offset; + + it->attr->length = fgetxattr(it->fd, it->attr->name, NULL, 0); + if (it->attr->length) + { + tmp = realloc((void*) it->attr->value, it->attr->length); + if (!tmp) + { + free((void*) it->attr->value); + it->attr->value = NULL; + it->attr->length = 0; + } + else + { + it->attr->length = fgetxattr(it->fd, it->attr->name, + (void *) it->attr->value, + it->attr->length); + } + } + + return EINA_TRUE; +} + +static Eina_Bool +_eina_xattr_value_ls_iterator_next(Eina_Xattr_Iterator *it, void **data) +{ + char *tmp; + + if (it->offset >= it->length) + return EINA_FALSE; + + *data = it->attr; + it->attr->name = it->xattr + it->offset; + + it->attr->length = getxattr(it->file, it->attr->name, NULL, 0); + if (it->attr->length) + { + tmp = realloc((void*) it->attr->value, it->attr->length); + if (!tmp) + { + free((void*) it->attr->value); + it->attr->value = NULL; + it->attr->length = 0; + } + else + { + it->attr->length = getxattr(it->file, it->attr->name, + (void*) it->attr->value, + it->attr->length); + } + } + + return EINA_TRUE; +} + +static Eina_Bool _eina_xattr_ls_iterator_next(Eina_Xattr_Iterator *it, void **data) { if (it->offset >= it->length) @@ -79,6 +149,9 @@ static void _eina_xattr_ls_iterator_free(Eina_Xattr_Iterator *it) { EINA_MAGIC_SET(&it->iterator, 0); + if (it->attr) free((void *) it->attr->value); + eina_stringshare_del(it->file); + free(it->attr); free(it); } #endif @@ -97,6 +170,85 @@ _eina_xattr_ls_iterator_free(Eina_Xattr_Iterator *it) * API * *============================================================================*/ +EAPI Eina_Iterator * +eina_xattr_value_fd_ls(int fd) +{ +#ifdef HAVE_XATTR + Eina_Xattr_Iterator *it; + ssize_t length; + + if (fd < 0) return NULL; + + length = flistxattr(fd, NULL, 0); + if (length <= 0) return NULL; + + it = calloc(1, sizeof (Eina_Xattr_Iterator) + length - 1); + if (!it) return NULL; + + it->attr = calloc(1, sizeof (Eina_Xattr)); + if (!it->attr) + { + free(it); + return NULL; + } + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + + it->fd = fd; + it->length = flistxattr(fd, it->xattr, length); + if (it->length != length) + { + free(it); + return NULL; + } + + it->iterator.version = EINA_ITERATOR_VERSION; + it->iterator.next = FUNC_ITERATOR_NEXT(_eina_xattr_value_ls_fd_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_xattr_ls_iterator_container); + it->iterator.free = FUNC_ITERATOR_FREE(_eina_xattr_ls_iterator_free); + + return &it->iterator; +#else + return NULL; + (void)file; +#endif +} + +EAPI Eina_Iterator * +eina_xattr_fd_ls(int fd) +{ +#ifdef HAVE_XATTR + Eina_Xattr_Iterator *it; + ssize_t length; + + if (fd < 0) return NULL; + + length = flistxattr(fd, NULL, 0); + if (length <= 0) return NULL; + + it = calloc(1, sizeof (Eina_Xattr_Iterator) + length - 1); + if (!it) return NULL; + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + + it->length = flistxattr(fd, it->xattr, length); + if (it->length != length) + { + free(it); + return NULL; + } + + it->iterator.version = EINA_ITERATOR_VERSION; + it->iterator.next = FUNC_ITERATOR_NEXT(_eina_xattr_ls_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_xattr_ls_iterator_container); + it->iterator.free = FUNC_ITERATOR_FREE(_eina_xattr_ls_iterator_free); + + return &it->iterator; +#else + return NULL; + (void)file; +#endif +} EAPI Eina_Iterator * eina_xattr_ls(const char *file) @@ -134,6 +286,44 @@ eina_xattr_ls(const char *file) #endif } +EAPI Eina_Iterator * +eina_xattr_value_ls(const char *file) +{ +#ifdef HAVE_XATTR + Eina_Xattr_Iterator *it; + ssize_t length; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + length = listxattr(file, NULL, 0); + if (length <= 0) return NULL; + + it = calloc(1, sizeof (Eina_Xattr_Iterator) + length - 1); + if (!it) return NULL; + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + + it->length = listxattr(file, it->xattr, length); + if (it->length != length) + { + free(it); + return NULL; + } + + it->file = eina_stringshare_add(file); + + it->iterator.version = EINA_ITERATOR_VERSION; + it->iterator.next = FUNC_ITERATOR_NEXT(_eina_xattr_value_ls_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_xattr_ls_iterator_container); + it->iterator.free = FUNC_ITERATOR_FREE(_eina_xattr_ls_iterator_free); + + return &it->iterator; +#else + return NULL; + (void)file; +#endif +} + EAPI void * eina_xattr_get(const char *file, const char *attribute, ssize_t *size) { -- 2.7.4