eina: detect fault during Eina_File mmap memory access and improve Xattr functions.
authorCedric BAIL <cedric.bail@free.fr>
Tue, 3 Jan 2012 14:59:07 +0000 (14:59 +0000)
committerCedric BAIL <cedric.bail@free.fr>
Tue, 3 Jan 2012 14:59:07 +0000 (14:59 +0000)
SVN revision: 66799

legacy/eina/ChangeLog
legacy/eina/NEWS
legacy/eina/src/include/eina_file.h
legacy/eina/src/include/eina_xattr.h
legacy/eina/src/lib/eina_file.c
legacy/eina/src/lib/eina_mmap.c
legacy/eina/src/lib/eina_private.h
legacy/eina/src/lib/eina_xattr.c

index 8f0b210..6a1846b 100644 (file)
 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
 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.
index 5e042e9..6123cdd 100644 (file)
@@ -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
 
index 295da09..422fb65 100644 (file)
@@ -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);
+
+/**
  * @}
  */
 
index 5ab294d..0f89cc3 100644 (file)
@@ -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.
index c53f674..6f1b0f1 100644 (file)
@@ -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);
+}
 
index fb27bd7..4589818 100644 (file)
@@ -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;
 }
index d390397..6db120c 100644 (file)
@@ -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_ */
 
index 893456b..7f86f2f 100644 (file)
@@ -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)
 {