Add native Windows thread support instead of using pthread
[framework/uifw/eet.git] / src / lib / eet_lib.c
index cb3c535..601aa22 100644 (file)
@@ -23,6 +23,10 @@ extern "C"
 void *alloca (size_t);
 #endif
 
+#ifdef _WIN32
+# include <winsock2.h>
+#endif
+
 #include <stdio.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -32,23 +36,32 @@ void *alloca (size_t);
 #include <string.h>
 #include <fnmatch.h>
 #include <fcntl.h>
-#include <unistd.h>
 #include <zlib.h>
 
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
+#ifndef _MSC_VER
+# include <unistd.h>
 #endif
 
-#if defined(_WIN32) && ! defined(__CEGCC__)
-# include <winsock2.h>
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
 #endif
 
 #ifdef HAVE_EVIL
 # include <Evil.h>
 #endif
 
+#ifdef HAVE_GNUTLS
+# include <gnutls/gnutls.h>
+# include <gcrypt.h>
+#endif
+
 #ifdef HAVE_OPENSSL
 # include <openssl/err.h>
+# include <openssl/evp.h>
+#endif
+
+#ifdef EFL_HAVE_POSIX_THREADS
+# include <pthread.h>
 #endif
 
 #include <Eina.h>
@@ -56,8 +69,11 @@ void *alloca (size_t);
 #include "Eet.h"
 #include "Eet_private.h"
 
+static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV };
+EAPI Eet_Version *eet_version = &_version;
+
 #ifdef HAVE_REALPATH
-#undef HAVE_REALPATH
+# undef HAVE_REALPATH
 #endif
 
 #define EET_MAGIC_FILE                  0x1ee7ff00
@@ -72,22 +88,35 @@ typedef struct _Eet_File_Directory      Eet_File_Directory;
 struct _Eet_File
 {
    char                 *path;
-   FILE                 *fp;
    FILE                        *readfp;
    Eet_File_Header      *header;
    Eet_Dictionary       *ed;
    Eet_Key             *key;
    const unsigned char  *data;
    const void           *x509_der;
+   const void           *signature;
+   void                 *sha1;
+
+   Eet_File_Mode         mode;
 
    int                   magic;
    int                   references;
 
-   Eet_File_Mode         mode;
    int                   data_size;
    int                   x509_length;
+   unsigned int          signature_length;
+   int                   sha1_length;
+
    time_t                mtime;
 
+#ifdef EFL_HAVE_THREADS
+# ifdef EFL_HAVE_POSIX_THREADS
+   pthread_mutex_t      file_lock;
+# else
+   HANDLE                file_lock;
+# endif
+#endif
+
    unsigned char         writes_pending : 1;
    unsigned char         delete_me_now : 1;
 };
@@ -120,6 +149,8 @@ struct _Eet_File_Node
 
    unsigned char         free_name : 1;
    unsigned char         compression : 1;
+   unsigned char         ciphered : 1;
+   unsigned char         alias : 1;
 };
 
 #if 0
@@ -132,7 +163,7 @@ int bytes_directory_entries; /* bytes of directory entries to follow */
 struct
 {
    int offset; /* bytes offset into file for data chunk */
-   int flags; /* flags - for now 0 = uncompressed, 1 = compressed */
+   int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
    int size; /* size of the data chunk */
    int data_size; /* size of the (uncompressed) data chunk */
    int name_size; /* length in bytes of the name field */
@@ -155,7 +186,11 @@ struct
   int data_size; /* size of the (uncompressed) data chunk */
   int name_offset; /* bytes offset into file for name string */
   int name_size; /* length in bytes of the name field */
-  int flags; /* flags - for now 0 = uncompressed, 1 = compressed */
+  int flags; /* bit flags - for now:
+               bit 0 => compresion on/off
+               bit 1 => ciphered on/off
+               bit 2 => alias
+             */
 } directory[num_directory_entries];
 struct
 {
@@ -194,6 +229,48 @@ static Eet_Error   eet_flush2(Eet_File *ef);
 static Eet_File_Node   *find_node_by_name(Eet_File *ef, const char *name);
 static int             read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len);
 
+static Eet_Error        eet_internal_close(Eet_File *ef, Eina_Bool locked);
+
+#ifdef EFL_HAVE_THREADS
+
+# ifdef EFL_HAVE_POSIX_THREADS
+
+static pthread_mutex_t eet_cache_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#  define LOCK_CACHE pthread_mutex_lock(&eet_cache_lock)
+#  define UNLOCK_CACHE pthread_mutex_unlock(&eet_cache_lock)
+
+#  define INIT_FILE(File) pthread_mutex_init(&File->file_lock, NULL)
+#  define LOCK_FILE(File) pthread_mutex_lock(&File->file_lock)
+#  define UNLOCK_FILE(File) pthread_mutex_unlock(&File->file_lock)
+#  define DESTROY_FILE(File) pthread_mutex_destroy(&File->file_lock)
+
+# else /* EFL_HAVE_WIN32_THREADS */
+
+static HANDLE eet_cache_lock = NULL;
+
+#  define LOCK_CACHE WaitForSingleObject(eet_cache_lock, INFINITE)
+#  define UNLOCK_CACHE ReleaseMutex(eet_cache_lock)
+
+#  define INIT_FILE(File) File->file_lock = CreateMutex(NULL, FALSE, NULL)
+#  define LOCK_FILE(File) WaitForSingleObject(File->file_lock, INFINITE)
+#  define UNLOCK_FILE(File) ReleaseMutex(File->file_lock)
+#  define DESTROY_FILE(File) CloseHandle(File->file_lock)
+
+# endif /* EFL_HAVE_WIN32_THREADS */
+
+#else
+
+# define LOCK_CACHE do {} while (0)
+# define UNLOCK_CACHE do {} while (0)
+
+# define INIT_FILE(File) do {} while (0)
+# define LOCK_FILE(File) do {} while (0)
+# define UNLOCK_FILE(File) do {} while (0)
+# define DESTROY_FILE(File) do {} while (0)
+
+#endif /* EFL_HAVE_THREADS */
+
 /* cache. i don't expect this to ever be large, so arrays will do */
 static int        eet_writers_num     = 0;
 static int        eet_writers_alloc   = 0;
@@ -201,7 +278,10 @@ static Eet_File **eet_writers         = NULL;
 static int        eet_readers_num     = 0;
 static int        eet_readers_alloc   = 0;
 static Eet_File **eet_readers         = NULL;
-static int        eet_initcount       = 0;
+static int        eet_init_count       = 0;
+
+/* log domain variable */
+int _eet_log_dom_global = -1;
 
 /* Check to see its' an eet file pointer */
 static inline int
@@ -228,7 +308,7 @@ eet_test_close(int test, Eet_File *ef)
    if (test)
      {
        ef->delete_me_now = 1;
-       eet_close(ef);
+        eet_internal_close(ef, EINA_TRUE);
      }
    return test;
 }
@@ -255,6 +335,7 @@ eet_cache_find(const char *path, Eet_File **cache, int cache_num)
 }
 
 /* add to end of cache */
+/* this should only be called when the cache lock is already held */
 static void
 eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
 {
@@ -281,7 +362,7 @@ eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
        if (del_ef)
          {
             del_ef->delete_me_now = 1;
-            eet_close(del_ef);
+             eet_internal_close(del_ef, EINA_TRUE);
          }
      }
 
@@ -295,7 +376,7 @@ eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
        new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
        if (!new_cache)
          {
-            fprintf(stderr, "BAD ERROR! Eet realloc of cache list failed. Abort\n");
+            CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
             abort();
          }
      }
@@ -306,6 +387,7 @@ eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
 }
 
 /* delete from cache */
+/* this should only be called when the cache lock is already held */
 static void
 eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
 {
@@ -340,7 +422,7 @@ eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
             new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
             if (!new_cache)
               {
-                 fprintf(stderr, "BAD ERROR! Eet realloc of cache list failed. Abort\n");
+                 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
                  abort();
               }
          }
@@ -369,38 +451,42 @@ eet_string_match(const char *s1, const char *s2)
 static Eet_Error
 eet_flush2(Eet_File *ef)
 {
-   Eet_File_Node        *efn;
-   Eet_Error             error = EET_ERROR_NONE;
-   int                   head[EET_FILE2_HEADER_COUNT];
-   int                   num_directory_entries = 0;
-   int                   num_dictionary_entries = 0;
-   int                   bytes_directory_entries = 0;
-   int                   bytes_dictionary_entries = 0;
-   int                   bytes_strings = 0;
-   int                   data_offset = 0;
-   int                   strings_offset = 0;
-   int                   num;
-   int                   i;
-   int                   j;
+   Eet_File_Node *efn;
+   FILE *fp;
+   Eet_Error error = EET_ERROR_NONE;
+   int head[EET_FILE2_HEADER_COUNT];
+   int num_directory_entries = 0;
+   int num_dictionary_entries = 0;
+   int bytes_directory_entries = 0;
+   int bytes_dictionary_entries = 0;
+   int bytes_strings = 0;
+   int data_offset = 0;
+   int strings_offset = 0;
+   int num;
+   int i;
+   int j;
 
    if (eet_check_pointer(ef))
      return EET_ERROR_BAD_OBJECT;
    if (eet_check_header(ef))
      return EET_ERROR_EMPTY;
-   if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE))
-     return EET_ERROR_NOT_WRITABLE;
    if (!ef->writes_pending)
      return EET_ERROR_NONE;
-   if (ef->mode == EET_FILE_MODE_READ_WRITE && ef->fp == NULL)
+
+   if ((ef->mode == EET_FILE_MODE_READ_WRITE)
+       || (ef->mode == EET_FILE_MODE_WRITE))
      {
        int fd;
 
+       /* opening for write - delete old copy of file right away */
        unlink(ef->path);
        fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
-       ef->fp = fdopen(fd, "wb");
-       if (!ef->fp) return EET_ERROR_NOT_WRITABLE;
-       fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC);
+       fp = fdopen(fd, "wb");
+       if (!fp) return EET_ERROR_NOT_WRITABLE;
+       fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
      }
+   else
+     return EET_ERROR_NOT_WRITABLE;
 
    /* calculate string base offset and data base offset */
    num = (1 << ef->header->directory->size);
@@ -449,26 +535,28 @@ eet_flush2(Eet_File *ef)
    head[1] = (int) htonl ((unsigned int) num_directory_entries);
    head[2] = (int) htonl ((unsigned int) num_dictionary_entries);
 
-   fseek(ef->fp, 0, SEEK_SET);
-   if (fwrite(head, sizeof (head), 1, ef->fp) != 1)
+   fseek(fp, 0, SEEK_SET);
+   if (fwrite(head, sizeof (head), 1, fp) != 1)
      goto write_error;
 
    /* write directories entry */
-   j = 0;
    for (i = 0; i < num; i++)
      {
         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
           {
-             int        ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
+            unsigned int flag;
+             int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
+
+            flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
 
              ibuf[0] = (int) htonl ((unsigned int) efn->offset);
              ibuf[1] = (int) htonl ((unsigned int) efn->size);
              ibuf[2] = (int) htonl ((unsigned int) efn->data_size);
              ibuf[3] = (int) htonl ((unsigned int) efn->name_offset);
              ibuf[4] = (int) htonl ((unsigned int) efn->name_size);
-             ibuf[5] = (int) htonl ((unsigned int) efn->compression);
+             ibuf[5] = (int) htonl ((unsigned int) flag);
 
-             if (fwrite(ibuf, sizeof(ibuf), 1, ef->fp) != 1)
+             if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
                goto write_error;
           }
      }
@@ -490,7 +578,7 @@ eet_flush2(Eet_File *ef)
 
              offset += ef->ed->all[j].len;
 
-             if (fwrite(sbuf, sizeof (sbuf), 1, ef->fp) != 1)
+             if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
                goto write_error;
           }
      }
@@ -500,7 +588,7 @@ eet_flush2(Eet_File *ef)
      {
         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
           {
-             if (fwrite(efn->name, efn->name_size, 1, ef->fp) != 1)
+             if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
                goto write_error;
           }
      }
@@ -512,12 +600,12 @@ eet_flush2(Eet_File *ef)
          {
             if (ef->ed->all[j].str)
               {
-                 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, ef->fp) != 1)
+                 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
                    goto write_error;
               }
             else
               {
-                 if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, ef->fp) != 1)
+                 if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, fp) != 1)
                    goto write_error;
               }
          }
@@ -528,18 +616,26 @@ eet_flush2(Eet_File *ef)
      {
         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
           {
-             if (fwrite(efn->data, efn->size, 1, ef->fp) != 1)
+             if (fwrite(efn->data, efn->size, 1, fp) != 1)
                goto write_error;
           }
      }
 
    /* flush all write to the file. */
-   fflush(ef->fp);
+   fflush(fp);
+// this is going to really cause trouble. if ANYTHING this needs to go into a
+// thread spawned off - but even then...
+// in this case... ext4 is "wrong". (yes we can jump up and down and point posix
+// manual pages at eachother, but ext4 broke behavior that has been in place
+// for decades and that 1000's of apps rely on daily - that is that one operation
+// to disk is committed to disk BEFORE following operations, so the fs retains
+// a consistent state
+//   fsync(fileno(fp));
 
    /* append signature if required */
    if (ef->key)
      {
-       error = eet_identity_sign(ef->fp, ef->key);
+       error = eet_identity_sign(fp, ef->key);
        if (error != EET_ERROR_NONE)
          goto sign_error;
      }
@@ -547,10 +643,12 @@ eet_flush2(Eet_File *ef)
    /* no more writes pending */
    ef->writes_pending = 0;
 
+   fclose(fp);
+
    return EET_ERROR_NONE;
 
    write_error:
-   if (ferror(ef->fp))
+   if (ferror(fp))
      {
        switch (errno)
          {
@@ -562,168 +660,115 @@ eet_flush2(Eet_File *ef)
          }
      }
    sign_error:
-   if (ef->fp) fclose(ef->fp);
-   ef->fp = NULL;
+   fclose(fp);
    return error;
 }
 
-#if 0 /* Unused */
-/* flush out writes to an eet file */
-static Eet_Error
-eet_flush(Eet_File *ef)
+EAPI int
+eet_init(void)
 {
-   Eet_File_Node       *efn;
-   int                 head[3];
-   int                 count = 0;
-   int                 size = 0;
-   int                 offset = 0;
-   int                 i;
-   int                 num;
-
-   /* check to see its' an eet file pointer */
-   if (eet_check_pointer(ef))
-     return EET_ERROR_BAD_OBJECT;
-   if (eet_check_header(ef))
-     return EET_ERROR_EMPTY;
-   if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE))
-     return EET_ERROR_NOT_WRITABLE;
-   if (!ef->writes_pending)
-     return EET_ERROR_NONE;
-
-   /* calculate total size in bytes of directory block */
-   num = (1 << ef->header->directory->size);
-   for (i = 0; i < num; i++)
-     {
-       for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
-         {
-            size += 20 + strlen(efn->name) + 1;
-            count++;
-         }
-     }
+   if (++eet_init_count != 1)
+     return eet_init_count;
 
-   /* calculate offsets per entry */
-   offset = 0;
-   for (i = 0; i < num; i++)
+   if (!eina_init())
      {
-       for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
-         {
-            efn->offset = 12 + size + offset;
-            offset += efn->size;
-         }
+       fprintf(stderr, "Eet: Eina init failed");
+       return --eet_init_count;
      }
-
-   /* go thru and write the header */
-   head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE);
-   head[1] = (int) htonl ((unsigned int) count);
-   head[2] = (int) htonl ((unsigned int) size);
-
-   fseek(ef->fp, 0, SEEK_SET);
-   if (fwrite(head, 12, 1, ef->fp) != 1)
-     goto write_error;
-
-   for (i = 0; i < num; i++)
+   _eet_log_dom_global = eina_log_domain_register("Eet", EET_DEFAULT_LOG_COLOR);
+   if (_eet_log_dom_global < 0)
      {
-       for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
-         {
-            unsigned int       ibuf[5];
-            int                name_size;
-
-            name_size = strlen(efn->name) + 1;
-
-            ibuf[0] = (int) htonl ((unsigned int) efn->offset);
-            ibuf[1] = (int) htonl ((unsigned int) efn->compression);
-            ibuf[2] = (int) htonl ((unsigned int) efn->size);
-            ibuf[3] = (int) htonl ((unsigned int) efn->data_size);
-            ibuf[4] = (int) htonl ((unsigned int) name_size);
-
-
-            if (fwrite(ibuf, sizeof(ibuf), 1, ef->fp) != 1)
-              goto write_error;
-            if (fwrite(efn->name, name_size, 1, ef->fp) != 1)
-              goto write_error;
-         }
+       EINA_LOG_ERR("Eet Can not create a general log domain.");
+       goto shutdown_eina;
      }
 
-   /* write data */
-   for (i = 0; i < num; i++)
+   if (!eet_node_init())
      {
-       for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
-         {
-            if (fwrite(efn->data, efn->size, 1, ef->fp) != 1)
-              goto write_error;
-         }
+       EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
+       goto unregister_log_domain;
      }
 
-   /* no more writes pending */
-   ef->writes_pending = 0;
-
-   return EET_ERROR_NONE;
-
-   write_error:
-   if (ferror(ef->fp))
+#ifdef HAVE_GNUTLS
+   /* Before the library can be used, it must initialize itself if needed. */
+   if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P) == 0)
      {
-       switch (errno)
-         {
-          case EFBIG:
-             fclose(ef->fp);
-             ef->fp = NULL;
-             return EET_ERROR_WRITE_ERROR_FILE_TOO_BIG;
-          case EIO:
-             fclose(ef->fp);
-             ef->fp = NULL;
-             return EET_ERROR_WRITE_ERROR_IO_ERROR;
-          case ENOSPC:
-             fclose(ef->fp);
-             ef->fp = NULL;
-             return EET_ERROR_WRITE_ERROR_OUT_OF_SPACE;
-          case EPIPE:
-             fclose(ef->fp);
-             ef->fp = NULL;
-             return EET_ERROR_WRITE_ERROR_FILE_CLOSED;
-          default:
-             fclose(ef->fp);
-             ef->fp = NULL;
-             return EET_ERROR_WRITE_ERROR;
-         }
+       gcry_check_version(NULL);
+       /* Disable warning messages about problems with the secure memory subsystem.
+          This command should be run right after gcry_check_version. */
+       if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
+         goto shutdown_eet;
+       /* This command is used to allocate a pool of secure memory and thus
+          enabling the use of secure memory. It also drops all extra privileges the
+          process has (i.e. if it is run as setuid (root)). If the argument nbytes
+          is 0, secure memory will be disabled. The minimum amount of secure memory
+          allocated is currently 16384 bytes; you may thus use a value of 1 to
+          request that default size. */
+       if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
+         WRN("BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
      }
-   sign_error:
-   if (ef->fp) fclose(ef->fp);
-   ef->fp = NULL;
-   return EET_ERROR_WRITE_ERROR;
-}
+   if (gnutls_global_init())
+     goto shutdown_eet;
 #endif
-
-EAPI int
-eet_init(void)
-{
-   eet_initcount++;
-
-   if (eet_initcount > 1) return eet_initcount;
-
 #ifdef HAVE_OPENSSL
    ERR_load_crypto_strings();
+   OpenSSL_add_all_algorithms();
 #endif
 
-   eina_init();
+   return eet_init_count;
 
-   return eet_initcount;
+ shutdown_eet:
+   eet_node_shutdown();
+ unregister_log_domain:
+   eina_log_domain_unregister(_eet_log_dom_global);
+   _eet_log_dom_global = -1;
+ shutdown_eina:
+   eina_shutdown();
+   return --eet_init_count;
 }
 
 EAPI int
 eet_shutdown(void)
 {
-   eet_initcount--;
-
-   if (eet_initcount > 0) return eet_initcount;
+   if (--eet_init_count != 0)
+     return eet_init_count;
 
    eet_clearcache();
+   eet_node_shutdown();
+#ifdef HAVE_GNUTLS
+   gnutls_global_deinit();
+#endif
 #ifdef HAVE_OPENSSL
+   EVP_cleanup();
    ERR_free_strings();
 #endif
-
+   eina_log_domain_unregister(_eet_log_dom_global);
+   _eet_log_dom_global = -1;
    eina_shutdown();
 
-   return eet_initcount;
+   return eet_init_count;
+}
+
+EAPI Eet_Error
+eet_sync(Eet_File *ef)
+{
+   Eet_Error ret;
+
+   if (eet_check_pointer(ef))
+     return EET_ERROR_BAD_OBJECT;
+
+   if ((ef->mode != EET_FILE_MODE_WRITE) &&
+       (ef->mode != EET_FILE_MODE_READ_WRITE))
+     return EET_ERROR_NOT_WRITABLE;
+
+   if (!ef->writes_pending)
+     return EET_ERROR_NONE;
+
+   LOCK_FILE(ef);
+
+   ret = eet_flush2(ef);
+
+   UNLOCK_FILE(ef);
+   return ret;
 }
 
 EAPI void
@@ -736,6 +781,7 @@ eet_clearcache(void)
     * We need to compute the list of eet file to close separately from the cache,
     * due to eet_close removing them from the cache after each call.
     */
+   LOCK_CACHE;
    for (i = 0; i < eet_writers_num; i++)
      {
        if (eet_writers[i]->references <= 0) num++;
@@ -774,9 +820,10 @@ eet_clearcache(void)
 
        for (i = 0; i < num; i++)
          {
-            eet_close(closelist[i]);
+            eet_internal_close(closelist[i], EINA_TRUE);
          }
      }
+   UNLOCK_CACHE;
 }
 
 /* FIXME: MMAP race condition in READ_WRITE_MODE */
@@ -785,7 +832,7 @@ eet_internal_read2(Eet_File *ef)
 {
    const int    *data = (const int*) ef->data;
    const char   *start = (const char*) ef->data;
-   int           index = 0;
+   int           idx = 0;
    int           num_directory_entries;
    int           bytes_directory_entries;
    int           num_dictionary_entries;
@@ -793,7 +840,7 @@ eet_internal_read2(Eet_File *ef)
    int           signature_base_offset;
    int           i;
 
-   index += sizeof(int);
+   idx += sizeof(int);
    if (eet_test_close((int) ntohl(*data) != EET_MAGIC_FILE2, ef))
      return NULL;
    data++;
@@ -806,9 +853,9 @@ eet_internal_read2(Eet_File *ef)
    }
 
    /* get entries count and byte count */
-   GET_INT(num_directory_entries, data, index);
+   GET_INT(num_directory_entries, data, idx);
    /* get dictionary count and byte count */
-   GET_INT(num_dictionary_entries, data, index);
+   GET_INT(num_dictionary_entries, data, idx);
 
    bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
    bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
@@ -850,6 +897,7 @@ eet_internal_read2(Eet_File *ef)
         int              name_offset;
         int              name_size;
         int              hash;
+       int              flag;
 
         /* out directory block is inconsistent - we have oveerun our */
         /* dynamic block buffer before we finished scanning dir entries */
@@ -858,12 +906,16 @@ eet_internal_read2(Eet_File *ef)
           return NULL;
 
         /* get entrie header */
-        GET_INT(efn->offset, data, index);
-        GET_INT(efn->size, data, index);
-        GET_INT(efn->data_size, data, index);
-        GET_INT(name_offset, data, index);
-        GET_INT(name_size, data, index);
-        GET_INT(efn->compression, data, index);
+        GET_INT(efn->offset, data, idx);
+        GET_INT(efn->size, data, idx);
+        GET_INT(efn->data_size, data, idx);
+        GET_INT(name_offset, data, idx);
+        GET_INT(name_size, data, idx);
+        GET_INT(flag, data, idx);
+
+       efn->compression = flag & 0x1 ? 1 : 0;
+       efn->ciphered = flag & 0x2 ? 1 : 0;
+       efn->alias = flag & 0x4 ? 1 : 0;
 
 #define EFN_TEST(Test, Ef, Efn)                 \
         if (eet_test_close(Test, Ef))           \
@@ -918,7 +970,7 @@ eet_internal_read2(Eet_File *ef)
         const int       *dico = (const int*) ef->data + EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries + EET_FILE2_HEADER_COUNT;
         int              j;
 
-        if (eet_test_close((num_dictionary_entries * (int) EET_FILE2_DICTIONARY_ENTRY_SIZE + index) > (bytes_dictionary_entries + bytes_directory_entries), ef))
+        if (eet_test_close((num_dictionary_entries * (int) EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) > (bytes_dictionary_entries + bytes_directory_entries), ef))
             return NULL;
 
         ef->ed = calloc(1, sizeof (Eet_Dictionary));
@@ -937,11 +989,11 @@ eet_internal_read2(Eet_File *ef)
              int   hash;
              int   offset;
 
-             GET_INT(hash, dico, index);
-             GET_INT(offset, dico, index);
-             GET_INT(ef->ed->all[j].len, dico, index);
-             GET_INT(ef->ed->all[j].prev, dico, index);
-             GET_INT(ef->ed->all[j].next, dico, index);
+             GET_INT(hash, dico, idx);
+             GET_INT(offset, dico, idx);
+             GET_INT(ef->ed->all[j].len, dico, idx);
+             GET_INT(ef->ed->all[j].prev, dico, idx);
+             GET_INT(ef->ed->all[j].next, dico, idx);
 
              /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
                 So stick to int and check the value. */
@@ -975,17 +1027,22 @@ eet_internal_read2(Eet_File *ef)
    /* Check if the file is signed */
    ef->x509_der = NULL;
    ef->x509_length = 0;
+   ef->signature = NULL;
+   ef->signature_length = 0;
+
    if (signature_base_offset < ef->data_size)
      {
 #ifdef HAVE_SIGNATURE
        const unsigned char *buffer = ((const unsigned char*) ef->data) + signature_base_offset;
        ef->x509_der = eet_identity_check(ef->data, signature_base_offset,
+                                         &ef->sha1, &ef->sha1_length,
                                          buffer, ef->data_size - signature_base_offset,
+                                         &ef->signature, &ef->signature_length,
                                          &ef->x509_length);
 
        if (eet_test_close(ef->x509_der == NULL, ef)) return NULL;
 #else
-       fprintf(stderr, "This file could be signed but you didn't compile the necessary code to check the signature.\n");
+       ERR("This file could be signed but you didn't compile the necessary code to check the signature.");
 #endif
      }
 
@@ -998,16 +1055,16 @@ eet_internal_read1(Eet_File *ef)
 {
    const unsigned char *dyn_buf = NULL;
    const unsigned char *p = NULL;
-   int                  index = 0;
+   int                  idx = 0;
    int                  num_entries;
    int                  byte_entries;
    int                  i;
 
-   fprintf(stderr, "EET file format of '%s' is deprecated. You should just open it one time with mode == EET_FILE_MODE_READ_WRITE to solve this issue.\n", ef->path);
+   WRN("EET file format of '%s' is deprecated. You should just open it one time with mode == EET_FILE_MODE_READ_WRITE to solve this issue.", ef->path);
 
    /* build header table if read mode */
    /* geat header */
-   index += sizeof(int);
+   idx += sizeof(int);
    if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
      return NULL;
 
@@ -1020,8 +1077,8 @@ eet_internal_read1(Eet_File *ef)
         }
 
    /* get entries count and byte count */
-   EXTRACT_INT(num_entries, ef->data, index);
-   EXTRACT_INT(byte_entries, ef->data, index);
+   EXTRACT_INT(num_entries, ef->data, idx);
+   EXTRACT_INT(byte_entries, ef->data, idx);
 
    /* we cant have <= 0 values here - invalid */
    if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
@@ -1055,7 +1112,7 @@ eet_internal_read1(Eet_File *ef)
      return NULL;
 
    /* actually read the directory block - all of it, into ram */
-   dyn_buf = ef->data + index;
+   dyn_buf = ef->data + idx;
 
    /* parse directory block */
    p = dyn_buf;
@@ -1089,6 +1146,8 @@ eet_internal_read1(Eet_File *ef)
        EXTRACT_INT(name_size, p, indexn);
 
         efn->name_size = name_size;
+       efn->ciphered = 0;
+       efn->alias = 0;
 
        /* invalid size */
        if (eet_test_close(efn->size <= 0, ef))
@@ -1122,14 +1181,14 @@ eet_internal_read1(Eet_File *ef)
             efn->name = malloc(sizeof(char) * name_size + 1);
             if (eet_test_close(efn->name == NULL, ef))
               {
-                 free (efn);
+                 free(efn);
                  return NULL;
               }
 
             strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
             efn->name[name_size] = 0;
 
-            printf("File: %s is not up to date for key \"%s\" - needs rebuilding sometime\n", ef->path, efn->name);
+            WRN("File: %s is not up to date for key \"%s\" - needs rebuilding sometime", ef->path, efn->name);
          }
        else
          /* The only really usefull peace of code for efn->name (no backward compatibility) */
@@ -1158,6 +1217,12 @@ eet_internal_read1(Eet_File *ef)
 }
 #endif
 
+/*
+ * this should only be called when the cache lock is already held
+ * (We could drop this restriction if we add a parameter to eet_test_close
+ * that indicates if the lock is held or not.  For now it is easiest
+ * to just require that it is always held.)
+ */
 static Eet_File *
 eet_internal_read(Eet_File *ef)
 {
@@ -1179,13 +1244,101 @@ eet_internal_read(Eet_File *ef)
        return eet_internal_read2(ef);
       default:
        ef->delete_me_now = 1;
-       eet_close(ef);
+       eet_internal_close(ef, EINA_TRUE);
        break;
      }
 
    return NULL;
 }
 
+static Eet_Error
+eet_internal_close(Eet_File *ef, Eina_Bool locked)
+{
+   Eet_Error err;
+
+   /* check to see its' an eet file pointer */
+   if (eet_check_pointer(ef))
+     return EET_ERROR_BAD_OBJECT;
+
+   if (!locked) LOCK_CACHE;
+
+   /* deref */
+   ef->references--;
+   /* if its still referenced - dont go any further */
+   if (ef->references > 0) goto on_error;
+   /* flush any writes */
+   err = eet_flush2(ef);
+
+   eet_identity_unref(ef->key);
+   ef->key = NULL;
+
+   /* if not urgent to delete it - dont free it - leave it in cache */
+   if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
+     goto on_error;
+
+   /* remove from cache */
+   if (ef->mode == EET_FILE_MODE_READ)
+     eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
+   else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
+     eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
+
+   /* we can unlock the cache now */
+   if (!locked) UNLOCK_CACHE;
+
+   DESTROY_FILE(ef);
+
+   /* free up data */
+   if (ef->header)
+     {
+       if (ef->header->directory)
+         {
+            if (ef->header->directory->nodes)
+              {
+                 int i, num;
+
+                 num = (1 << ef->header->directory->size);
+                 for (i = 0; i < num; i++)
+                   {
+                      Eet_File_Node *efn;
+
+                      while ((efn = ef->header->directory->nodes[i]))
+                        {
+                           if (efn->data)
+                             free(efn->data);
+
+                           ef->header->directory->nodes[i] = efn->next;
+
+                           if (efn->free_name)
+                             free(efn->name);
+
+                           free(efn);
+                        }
+                   }
+                 free(ef->header->directory->nodes);
+              }
+            free(ef->header->directory);
+         }
+       free(ef->header);
+     }
+
+   eet_dictionary_free(ef->ed);
+
+   if (ef->sha1) free(ef->sha1);
+   if (ef->data) munmap((void*)ef->data, ef->data_size);
+   if (ef->readfp) fclose(ef->readfp);
+
+   /* zero out ram for struct - caution tactic against stale memory use */
+   memset(ef, 0, sizeof(Eet_File));
+
+   /* free it */
+   free(ef);
+   return err;
+
+ on_error:
+   if (!locked) UNLOCK_CACHE;
+   return EET_ERROR_NONE;
+}
+
 EAPI Eet_File *
 eet_memopen_read(const void *data, size_t size)
 {
@@ -1198,6 +1351,7 @@ eet_memopen_read(const void *data, size_t size)
    if (!ef)
      return NULL;
 
+   INIT_FILE(ef);
    ef->ed = NULL;
    ef->path = NULL;
    ef->key = NULL;
@@ -1207,12 +1361,17 @@ eet_memopen_read(const void *data, size_t size)
    ef->header = NULL;
    ef->mtime = 0;
    ef->delete_me_now = 1;
-   ef->fp = NULL;
    ef->readfp = NULL;
    ef->data = data;
    ef->data_size = size;
+   ef->sha1 = NULL;
+   ef->sha1_length = 0;
 
-   return eet_internal_read(ef);
+   /* eet_internal_read expects the cache lock to be held when it is called */
+   LOCK_CACHE;
+   ef = eet_internal_read(ef);
+   UNLOCK_CACHE;
+   return ef;
 }
 
 EAPI Eet_File *
@@ -1228,15 +1387,16 @@ eet_open(const char *file, Eet_File_Mode mode)
 
    /* find the current file handle in cache*/
    ef = NULL;
+   LOCK_CACHE;
    if (mode == EET_FILE_MODE_READ)
      {
        ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
        if (ef)
          {
-            eet_flush2(ef);
+            eet_sync(ef);
             ef->references++;
             ef->delete_me_now = 1;
-            eet_close(ef);
+             eet_internal_close(ef, EINA_TRUE);
          }
        ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
      }
@@ -1248,44 +1408,42 @@ eet_open(const char *file, Eet_File_Mode mode)
          {
             ef->delete_me_now = 1;
             ef->references++;
-            eet_close(ef);
+             eet_internal_close(ef, EINA_TRUE);
          }
        ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
      }
 
-    /* try open the file based on mode */
+   /* try open the file based on mode */
    if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
      {
+       /* Prevent garbage in futur comparison. */
+       file_stat.st_mtime = 0;
+
        fp = fopen(file, "rb");
-       if (!fp) goto on_error;
+       if (!fp) goto open_error;
        if (fstat(fileno(fp), &file_stat))
          {
             fclose(fp);
             fp = NULL;
-            goto on_error;
+            goto open_error;
          }
        if ((mode == EET_FILE_MODE_READ) &&
            (file_stat.st_size < ((int) sizeof(int) * 3)))
          {
             fclose(fp);
             fp = NULL;
-            goto on_error;
+            goto open_error;
          }
 
-     on_error:
-       if (fp == NULL && mode == EET_FILE_MODE_READ) return NULL;
+     open_error:
+       if (fp == NULL && mode == EET_FILE_MODE_READ) goto on_error;
      }
    else
      {
-       int fd;
-
        if (mode != EET_FILE_MODE_WRITE) return NULL;
        memset(&file_stat, 0, sizeof(file_stat));
-       /* opening for write - delete old copy of file right away */
-       unlink(file);
-       fd = open(file, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
-       fp = fdopen(fd, "wb");
-       if (!fp) return NULL;
+
+       fp = NULL;
      }
 
    /* We found one */
@@ -1293,7 +1451,7 @@ eet_open(const char *file, Eet_File_Mode mode)
      {
        ef->delete_me_now = 1;
        ef->references++;
-       eet_close(ef);
+        eet_internal_close(ef, EINA_TRUE);
        ef = NULL;
      }
 
@@ -1302,6 +1460,7 @@ eet_open(const char *file, Eet_File_Mode mode)
        /* reference it up and return it */
        if (fp != NULL) fclose(fp);
        ef->references++;
+       UNLOCK_CACHE;
        return ef;
      }
 
@@ -1310,12 +1469,12 @@ eet_open(const char *file, Eet_File_Mode mode)
    /* Allocate struct for eet file and have it zero'd out */
    ef = malloc(sizeof(Eet_File) + file_len);
    if (!ef)
-     return NULL;
+     goto on_error;
 
    /* fill some of the members */
-   ef->fp = fp;
+   INIT_FILE(ef);
    ef->key = NULL;
-   ef->readfp = NULL;
+   ef->readfp = fp;
    ef->path = ((char *)ef) + sizeof(Eet_File);
    memcpy(ef->path, file, file_len);
    ef->magic = EET_MAGIC_FILE;
@@ -1327,39 +1486,36 @@ eet_open(const char *file, Eet_File_Mode mode)
    ef->delete_me_now = 0;
    ef->data = NULL;
    ef->data_size = 0;
+   ef->sha1 = NULL;
+   ef->sha1_length = 0;
 
    ef->ed = (mode == EET_FILE_MODE_WRITE)
-     || (ef->fp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
+     || (ef->readfp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
      eet_dictionary_add() : NULL;
 
-   if (ef->fp == NULL && mode == EET_FILE_MODE_READ_WRITE) goto empty_file;
+   if (ef->readfp == NULL &&
+       (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
+     goto empty_file;
 
    /* if we can't open - bail out */
-   if (eet_test_close(!ef->fp, ef))
-     return NULL;
+   if (eet_test_close(!ef->readfp, ef))
+     goto on_error;
 
-   fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC);
+   fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
    /* if we opened for read or read-write */
    if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
      {
        ef->data_size = file_stat.st_size;
        ef->data = mmap(NULL, ef->data_size, PROT_READ,
-                       MAP_SHARED, fileno(ef->fp), 0);
+                       MAP_SHARED, fileno(ef->readfp), 0);
        if (eet_test_close((ef->data == MAP_FAILED), ef))
-         return NULL;
+         goto on_error;
        ef = eet_internal_read(ef);
        if (!ef)
-         return NULL;
+         goto on_error;
      }
 
  empty_file:
-   /* we need to delete the original file in read-write mode and re-open for writing */
-   if (ef->mode == EET_FILE_MODE_READ_WRITE)
-     {
-       ef->readfp = ef->fp;
-       ef->fp = NULL;
-     }
-
    /* add to cache */
    if (ef->references == 1)
      {
@@ -1370,7 +1526,12 @@ eet_open(const char *file, Eet_File_Mode mode)
            eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
      }
 
+   UNLOCK_CACHE;
    return ef;
+
+on_error:
+   UNLOCK_CACHE;
+   return NULL;
 }
 
 EAPI Eet_File_Mode
@@ -1392,6 +1553,25 @@ eet_identity_x509(Eet_File *ef, int *der_length)
    return ef->x509_der;
 }
 
+EAPI const void *
+eet_identity_signature(Eet_File *ef, int *signature_length)
+{
+   if (!ef->signature) return NULL;
+
+   if (signature_length) *signature_length = ef->signature_length;
+   return ef->signature;
+}
+
+EAPI const void *
+eet_identity_sha1(Eet_File *ef, int *sha1_length)
+{
+   if (!ef->sha1)
+     ef->sha1 = eet_identity_compute_sha1(ef->data, ef->data_size, &ef->sha1_length);
+
+   if (sha1_length) *sha1_length = ef->sha1_length;
+   return ef->sha1;
+}
+
 EAPI Eet_Error
 eet_identity_set(Eet_File *ef, Eet_Key *key)
 {
@@ -1412,88 +1592,18 @@ eet_identity_set(Eet_File *ef, Eet_Key *key)
 EAPI Eet_Error
 eet_close(Eet_File *ef)
 {
-   Eet_Error err;
-
-   /* check to see its' an eet file pointer */
-   if (eet_check_pointer(ef))
-     return EET_ERROR_BAD_OBJECT;
-   /* deref */
-   ef->references--;
-   /* if its still referenced - dont go any further */
-   if (ef->references > 0) return EET_ERROR_NONE;
-   /* flush any writes */
-   err = eet_flush2(ef);
-
-   eet_identity_unref(ef->key);
-   ef->key = NULL;
-
-   /* if not urgent to delete it - dont free it - leave it in cache */
-   if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
-     return EET_ERROR_NONE;
-
-   /* remove from cache */
-   if (ef->mode == EET_FILE_MODE_READ)
-     eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
-   else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
-     eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
-
-   /* free up data */
-   if (ef->header)
-     {
-       if (ef->header->directory)
-         {
-            if (ef->header->directory->nodes)
-              {
-                 int i, num;
-
-                 num = (1 << ef->header->directory->size);
-                 for (i = 0; i < num; i++)
-                   {
-                      Eet_File_Node *efn;
-
-                      while ((efn = ef->header->directory->nodes[i]))
-                        {
-                           if (efn->data)
-                             free(efn->data);
-
-                           ef->header->directory->nodes[i] = efn->next;
-
-                           if (efn->free_name)
-                             free(efn->name);
-
-                           free(efn);
-                        }
-                   }
-                 free(ef->header->directory->nodes);
-              }
-            free(ef->header->directory);
-         }
-       free(ef->header);
-     }
-
-   eet_dictionary_free(ef->ed);
-
-   if (ef->data) munmap((void*)ef->data, ef->data_size);
-   if (ef->fp) fclose(ef->fp);
-   if (ef->readfp) fclose(ef->readfp);
-
-   /* zero out ram for struct - caution tactic against stale memory use */
-   memset(ef, 0, sizeof(Eet_File));
-
-   /* free it */
-   free(ef);
-   return err;
-}
-
-EAPI void *
-eet_read(Eet_File *ef, const char *name, int *size_ret)
-{
-   void                        *data = NULL;
-   int                 size = 0;
-   Eet_File_Node       *efn;
-
-   if (size_ret)
-     *size_ret = 0;
+   return eet_internal_close(ef, EINA_FALSE);
+}
+
+EAPI void *
+eet_read_cipher(Eet_File *ef, const char *name, int *size_ret, const char *cipher_key)
+{
+   Eet_File_Node *efn;
+   char *data = NULL;
+   int size = 0;
+
+   if (size_ret)
+     *size_ret = 0;
 
    /* check to see its' an eet file pointer */
    if (eet_check_pointer(ef))
@@ -1508,36 +1618,49 @@ eet_read(Eet_File *ef, const char *name, int *size_ret)
    if (eet_check_header(ef))
      return NULL;
 
+   LOCK_FILE(ef);
+
    /* hunt hash bucket */
    efn = find_node_by_name(ef, name);
-   if (!efn)
-     return NULL;
+   if (!efn) goto on_error;
 
    /* get size (uncompressed, if compressed at all) */
    size = efn->data_size;
 
    /* allocate data */
    data = malloc(size);
-   if (!data)
-     return NULL;
+   if (!data) goto on_error;
 
    /* uncompressed data */
    if (efn->compression == 0)
      {
+        void *data_deciphered = NULL;
+       unsigned int data_deciphered_sz = 0;
        /* if we alreayd have the data in ram... copy that */
+
        if (efn->data)
          memcpy(data, efn->data, efn->size);
        else
          if (!read_data_from_disk(ef, efn, data, size))
-           {
-              free(data);
-              return NULL;
-           }
+           goto on_error;
+        if (efn->ciphered && cipher_key)
+         {
+           if (eet_decipher(data, size, cipher_key, strlen(cipher_key), &data_deciphered, &data_deciphered_sz))
+             {
+               if (data_deciphered) free(data_deciphered);
+               goto on_error;
+             }
+           free(data);
+           data = data_deciphered;
+           size = data_deciphered_sz;
+         }
      }
    /* compressed data */
    else
      {
        void    *tmp_data;
+       void    *data_deciphered = NULL;
+       unsigned int data_deciphered_sz = 0;
        int     free_tmp = 0;
        int     compr_size = efn->size;
        uLongf  dlen;
@@ -1549,47 +1672,81 @@ eet_read(Eet_File *ef, const char *name, int *size_ret)
          {
             tmp_data = malloc(compr_size);
             if (!tmp_data)
-              {
-                 free(data);
-                 return NULL;
-              }
+              goto on_error;
 
             free_tmp = 1;
 
             if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
               {
                  free(tmp_data);
-                 free(data);
-                 return NULL;
+                 goto on_error;
               }
          }
 
+       if (efn->ciphered && cipher_key)
+         {
+           if (eet_decipher(tmp_data, compr_size, cipher_key, strlen(cipher_key), &data_deciphered, &data_deciphered_sz))
+             {
+               if (free_tmp) free(tmp_data);
+               if (data_deciphered) free(data_deciphered);
+               goto on_error;
+             }
+           free(tmp_data);
+           tmp_data = data_deciphered;
+           compr_size = data_deciphered_sz;
+         }
+
        /* decompress it */
        dlen = size;
        if (uncompress((Bytef *)data, &dlen,
                 tmp_data, (uLongf)compr_size))
-         {
-            free(data);
-            return NULL;
-         }
+         goto on_error;
 
        if (free_tmp)
          free(tmp_data);
      }
 
-   /* fill in return values */
-   if (size_ret)
-     *size_ret = size;
+   UNLOCK_FILE(ef);
+
+   /* handle alias */
+   if (efn->alias)
+     {
+       void *tmp;
+
+       if (data[size - 1] != '\0')
+         goto on_error;
+
+       tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
+
+       free(data);
+
+       data = tmp;
+     }
+   else
+     /* fill in return values */
+     if (size_ret)
+       *size_ret = size;
 
    return data;
+
+ on_error:
+   UNLOCK_FILE(ef);
+   free(data);
+   return NULL;
+}
+
+EAPI void *
+eet_read(Eet_File *ef, const char *name, int *size_ret)
+{
+   return eet_read_cipher(ef, name, size_ret, NULL);
 }
 
 EAPI const void *
 eet_read_direct(Eet_File *ef, const char *name, int *size_ret)
 {
-   const void  *data = NULL;
-   int          size = 0;
    Eet_File_Node *efn;
+   const char *data = NULL;
+   int size = 0;
 
    if (size_ret)
      *size_ret = 0;
@@ -1607,36 +1764,217 @@ eet_read_direct(Eet_File *ef, const char *name, int *size_ret)
    if (eet_check_header(ef))
      return NULL;
 
+   LOCK_FILE(ef);
+
    /* hunt hash bucket */
    efn = find_node_by_name(ef, name);
-   if (!efn)
-     return NULL;
+   if (!efn) goto on_error;
 
    if (efn->offset < 0 && efn->data == NULL)
-     return NULL;
+     goto on_error;
 
    /* get size (uncompressed, if compressed at all) */
    size = efn->data_size;
 
-   /* uncompressed data */
-   if (efn->compression == 0)
-     data = efn->data ? efn->data : ef->data + efn->offset;
-   /* compressed data */
+   if (efn->alias)
+     {
+       data = efn->data ? efn->data : ef->data + efn->offset;
+
+       /* handle alias case */
+       if (efn->compression)
+         {
+            char *tmp;
+            int compr_size = efn->size;
+            uLongf dlen;
+
+            tmp = alloca(sizeof (compr_size));
+            dlen = size;
+
+            if (uncompress((Bytef *)tmp, &dlen, (Bytef *) data, (uLongf)compr_size))
+              goto on_error;
+
+            if (tmp[compr_size - 1] != '\0')
+              goto on_error;
+
+            return eet_read_direct(ef, tmp, size_ret);
+         }
+
+       if (!data) goto on_error;
+       if (data[size - 1] != '\0') goto on_error;
+
+       return eet_read_direct(ef, data, size_ret);
+     }
    else
-     data = NULL;
+     /* uncompressed data */
+     if (efn->compression == 0
+        && efn->ciphered == 0)
+       data = efn->data ? efn->data : ef->data + efn->offset;
+   /* compressed data */
+     else
+       data = NULL;
 
    /* fill in return values */
    if (size_ret)
      *size_ret = size;
 
+   UNLOCK_FILE(ef);
+
    return data;
+
+ on_error:
+   UNLOCK_FILE(ef);
+   return NULL;
+}
+
+EAPI Eina_Bool
+eet_alias(Eet_File *ef, const char *name, const char *destination, int comp)
+{
+   Eet_File_Node *efn;
+   void *data2;
+   Eina_Bool exists_already = EINA_FALSE;
+   int data_size;
+   int hash;
+
+   /* check to see its' an eet file pointer */
+   if (eet_check_pointer(ef))
+     return EINA_FALSE;
+   if ((!name) || (!destination))
+     return EINA_FALSE;
+   if ((ef->mode != EET_FILE_MODE_WRITE) &&
+       (ef->mode != EET_FILE_MODE_READ_WRITE))
+     return EINA_FALSE;
+
+   LOCK_FILE(ef);
+
+   if (!ef->header)
+     {
+       /* allocate header */
+       ef->header = calloc(1, sizeof(Eet_File_Header));
+       if (!ef->header)
+         goto on_error;
+
+       ef->header->magic = EET_MAGIC_FILE_HEADER;
+       /* allocate directory block in ram */
+       ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
+       if (!ef->header->directory)
+         {
+            free(ef->header);
+            ef->header = NULL;
+            goto on_error;
+         }
+
+       /* 8 bit hash table (256 buckets) */
+       ef->header->directory->size = 8;
+       /* allocate base hash table */
+       ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
+       if (!ef->header->directory->nodes)
+         {
+            free(ef->header->directory);
+            ef->header = NULL;
+            goto on_error;
+         }
+     }
+
+   /* figure hash bucket */
+   hash = _eet_hash_gen(name, ef->header->directory->size);
+
+   data_size = comp ?
+     12 + (((strlen(destination) + 1) * 101) / 100)
+     : strlen(destination) + 1;
+
+   data2 = malloc(data_size);
+   if (!data2) goto on_error;
+
+   /* if we want to compress */
+   if (comp)
+     {
+       uLongf buflen;
+
+       /* compress the data with max compression */
+       buflen = (uLongf)data_size;
+       if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
+                     (uLong)strlen(destination) + 1, Z_BEST_COMPRESSION) != Z_OK)
+         {
+            free(data2);
+            goto on_error;
+         }
+       /* record compressed chunk size */
+       data_size = (int)buflen;
+       if (data_size < 0 || data_size >= (int) (strlen(destination) + 1))
+         {
+            comp = 0;
+            data_size = strlen(destination) + 1;
+         }
+       else
+         {
+            void *data3;
+
+            data3 = realloc(data2, data_size);
+            if (data3)
+              data2 = data3;
+         }
+     }
+
+   if (!comp)
+     memcpy(data2, destination, data_size);
+
+   /* Does this node already exist? */
+   for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
+     {
+       /* if it matches */
+       if ((efn->name) && (eet_string_match(efn->name, name)))
+         {
+            free(efn->data);
+            efn->alias = 1;
+            efn->ciphered = 0;
+            efn->compression = !!comp;
+            efn->size = data_size;
+            efn->data_size = strlen(destination) + 1;
+            efn->data = data2;
+            efn->offset = -1;
+            exists_already = EINA_TRUE;
+            break;
+         }
+     }
+   if (!exists_already)
+     {
+       efn = malloc(sizeof(Eet_File_Node));
+       if (!efn)
+         {
+            free(data2);
+            goto on_error;
+         }
+       efn->name = strdup(name);
+        efn->name_size = strlen(efn->name) + 1;
+        efn->free_name = 1;
+
+       efn->next = ef->header->directory->nodes[hash];
+       ef->header->directory->nodes[hash] = efn;
+       efn->offset = -1;
+       efn->alias = 1;
+       efn->ciphered = 0;
+       efn->compression = !!comp;
+       efn->size = data_size;
+       efn->data_size = strlen(destination) + 1;
+       efn->data = data2;
+     }
+
+   /* flags that writes are pending */
+   ef->writes_pending = 1;
+
+   UNLOCK_FILE(ef);
+   return EINA_TRUE;
+
+ on_error:
+   UNLOCK_FILE(ef);
+   return EINA_FALSE;
 }
 
 EAPI int
-eet_write(Eet_File *ef, const char *name, const void *data, int size, int compress)
+eet_write_cipher(Eet_File *ef, const char *name, const void *data, int size, int comp, const char *cipher_key)
 {
    Eet_File_Node       *efn;
-   void                        *data2;
+   void                        *data2 = NULL;
    int                 exists_already = 0;
    int                 data_size;
    int                 hash;
@@ -1650,38 +1988,50 @@ eet_write(Eet_File *ef, const char *name, const void *data, int size, int compre
        (ef->mode != EET_FILE_MODE_READ_WRITE))
      return 0;
 
+   LOCK_FILE(ef);
+
    if (!ef->header)
      {
        /* allocate header */
        ef->header = calloc(1, sizeof(Eet_File_Header));
        if (!ef->header)
-         return 0;
+         goto on_error;
 
        ef->header->magic = EET_MAGIC_FILE_HEADER;
        /* allocate directory block in ram */
        ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
        if (!ef->header->directory)
-         return 0;
+         {
+            free(ef->header);
+            ef->header = NULL;
+            goto on_error;
+         }
 
        /* 8 bit hash table (256 buckets) */
        ef->header->directory->size = 8;
        /* allocate base hash table */
        ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
        if (!ef->header->directory->nodes)
-         return 0;
+         {
+            free(ef->header->directory);
+            ef->header = NULL;
+            goto on_error;
+         }
      }
 
    /* figure hash bucket */
    hash = _eet_hash_gen(name, ef->header->directory->size);
 
-   data_size = compress ? 12 + ((size * 101) / 100) : size;
+   data_size = comp ? 12 + ((size * 101) / 100) : size;
 
-   data2 = malloc(data_size);
-   if (!data2)
-     return 0;
+   if (comp || !cipher_key)
+     {
+       data2 = malloc(data_size);
+       if (!data2) goto on_error;
+     }
 
    /* if we want to compress */
-   if (compress)
+   if (comp)
      {
        uLongf buflen;
 
@@ -1691,13 +2041,13 @@ eet_write(Eet_File *ef, const char *name, const void *data, int size, int compre
                           (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
          {
             free(data2);
-            return 0;
+            goto on_error;
          }
        /* record compressed chunk size */
        data_size = (int)buflen;
        if (data_size < 0 || data_size >= size)
          {
-            compress = 0;
+            comp = 0;
             data_size = size;
          }
        else
@@ -1709,8 +2059,30 @@ eet_write(Eet_File *ef, const char *name, const void *data, int size, int compre
               data2 = data3;
          }
      }
-   if (!compress)
-     memcpy(data2, data, size);
+
+   if (cipher_key)
+     {
+       void *data_ciphered = NULL;
+       unsigned int data_ciphered_sz = 0;
+       const void *tmp;
+
+       tmp = data2 ? data2 : data;
+       if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key), &data_ciphered, &data_ciphered_sz))
+        {
+          if (data2) free(data2);
+          data2 = data_ciphered;
+          data_size = data_ciphered_sz;
+          size = (data_size > size) ? data_size : size;
+        }
+       else
+        {
+          if (data_ciphered) free(data_ciphered);
+          cipher_key = NULL;
+        }
+     }
+   else
+     if (!comp)
+       memcpy(data2, data, size);
 
    /* Does this node already exist? */
    for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
@@ -1719,7 +2091,9 @@ eet_write(Eet_File *ef, const char *name, const void *data, int size, int compre
        if ((efn->name) && (eet_string_match(efn->name, name)))
          {
             free(efn->data);
-            efn->compression = !!compress;
+            efn->alias = 0;
+            efn->ciphered = cipher_key ? 1 : 0;
+            efn->compression = !!comp;
             efn->size = data_size;
             efn->data_size = size;
             efn->data = data2;
@@ -1734,7 +2108,7 @@ eet_write(Eet_File *ef, const char *name, const void *data, int size, int compre
        if (!efn)
          {
             free(data2);
-            return 0;
+            goto on_error;
          }
        efn->name = strdup(name);
         efn->name_size = strlen(efn->name) + 1;
@@ -1743,7 +2117,9 @@ eet_write(Eet_File *ef, const char *name, const void *data, int size, int compre
        efn->next = ef->header->directory->nodes[hash];
        ef->header->directory->nodes[hash] = efn;
        efn->offset = -1;
-       efn->compression = !!compress;
+       efn->alias = 0;
+       efn->ciphered = cipher_key ? 1 : 0;
+       efn->compression = !!comp;
        efn->size = data_size;
        efn->data_size = size;
        efn->data = data2;
@@ -1751,7 +2127,18 @@ eet_write(Eet_File *ef, const char *name, const void *data, int size, int compre
 
    /* flags that writes are pending */
    ef->writes_pending = 1;
+   UNLOCK_FILE(ef);
    return data_size;
+
+ on_error:
+   UNLOCK_FILE(ef);
+   return 0;
+}
+
+EAPI int
+eet_write(Eet_File *ef, const char *name, const void *data, int size, int comp)
+{
+   return eet_write_cipher(ef, name, data, size, comp, NULL);
 }
 
 EAPI int
@@ -1775,6 +2162,8 @@ eet_delete(Eet_File *ef, const char *name)
    if (eet_check_header(ef))
      return 0;
 
+   LOCK_FILE(ef);
+
    /* figure hash bucket */
    hash = _eet_hash_gen(name, ef->header->directory->size);
 
@@ -1789,7 +2178,7 @@ eet_delete(Eet_File *ef, const char *name)
             if (efn->data)
               free(efn->data);
 
-            if (efn == ef->header->directory->nodes[hash])
+            if (pefn == NULL)
               ef->header->directory->nodes[hash] = efn->next;
             else
               pefn->next = efn->next;
@@ -1804,6 +2193,8 @@ eet_delete(Eet_File *ef, const char *name)
    if (exists_already)
      ef->writes_pending = 1;
 
+   UNLOCK_FILE(ef);
+
    /* update access time */
    return exists_already;
 }
@@ -1838,6 +2229,10 @@ eet_list(Eet_File *ef, const char *glob, int *count_ret)
        return NULL;
      }
 
+   if (!strcmp(glob, "*")) glob = NULL;
+
+   LOCK_FILE(ef);
+
    /* loop through all entries */
    num = (1 << ef->header->directory->size);
    for (i = 0; i < num; i++)
@@ -1848,7 +2243,7 @@ eet_list(Eet_File *ef, const char *glob, int *count_ret)
              * check for * explicitly, because on some systems, * isn't well
              * supported
              */
-            if ((!strcmp (glob, "*")) || !fnmatch(glob, efn->name, 0))
+            if ((!glob) || !fnmatch(glob, efn->name, 0))
               {
                  /* add it to our list */
                  list_count++;
@@ -1864,10 +2259,7 @@ eet_list(Eet_File *ef, const char *glob, int *count_ret)
                         {
                            free(list_ret);
 
-                           if (count_ret)
-                             *count_ret = 0;
-
-                           return NULL;
+                           goto on_error;
                         }
                       list_ret = new_list;
                    }
@@ -1878,11 +2270,21 @@ eet_list(Eet_File *ef, const char *glob, int *count_ret)
          }
      }
 
+   UNLOCK_FILE(ef);
+
    /* return count and list */
    if (count_ret)
      *count_ret = list_count;
 
    return list_ret;
+
+ on_error:
+   UNLOCK_FILE(ef);
+
+   if (count_ret)
+     *count_ret = 0;
+
+   return NULL;
 }
 
 EAPI int
@@ -1897,6 +2299,8 @@ eet_num_entries(Eet_File *ef)
         (ef->mode != EET_FILE_MODE_READ_WRITE)))
      return -1;
 
+   LOCK_FILE(ef);
+
    /* loop through all entries */
    num = (1 << ef->header->directory->size);
    for (i = 0; i < num; i++)
@@ -1905,6 +2309,8 @@ eet_num_entries(Eet_File *ef)
          ret++;
      }
 
+   UNLOCK_FILE(ef);
+
    return ret;
 }
 
@@ -1938,12 +2344,15 @@ read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len)
      }
    else
      {
+       if (!ef->readfp)
+         return 0;
+
        /* seek to data location */
-       if (fseek(ef->fp, efn->offset, SEEK_SET) < 0)
+       if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
          return 0;
 
        /* read it */
-       len = fread(buf, len, 1, ef->fp);
+       len = fread(buf, len, 1, ef->readfp);
      }
    return len;
 }