Add native Windows thread support instead of using pthread
[framework/uifw/eet.git] / src / lib / eet_lib.c
index 8fed189..601aa22 100644 (file)
@@ -6,10 +6,6 @@
 # include <config.h>
 #endif
 
-#if defined(_WIN32) && ! defined(__CEGCC__)
-# include <winsock2.h>
-#endif
-
 #ifdef HAVE_ALLOCA_H
 # include <alloca.h>
 #elif defined __GNUC__
@@ -27,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>
@@ -60,7 +60,7 @@ void *alloca (size_t);
 # include <openssl/evp.h>
 #endif
 
-#ifdef EFL_HAVE_PTHREAD
+#ifdef EFL_HAVE_POSIX_THREADS
 # include <pthread.h>
 #endif
 
@@ -69,6 +69,9 @@ 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
 #endif
@@ -85,7 +88,6 @@ typedef struct _Eet_File_Directory      Eet_File_Directory;
 struct _Eet_File
 {
    char                 *path;
-   FILE                 *fp;
    FILE                        *readfp;
    Eet_File_Header      *header;
    Eet_Dictionary       *ed;
@@ -107,8 +109,12 @@ struct _Eet_File
 
    time_t                mtime;
 
-#ifdef EFL_HAVE_PTHREAD
+#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;
@@ -144,6 +150,7 @@ struct _Eet_File_Node
    unsigned char         free_name : 1;
    unsigned char         compression : 1;
    unsigned char         ciphered : 1;
+   unsigned char         alias : 1;
 };
 
 #if 0
@@ -179,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
 {
@@ -220,28 +231,45 @@ static int                read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int
 
 static Eet_Error        eet_internal_close(Eet_File *ef, Eina_Bool locked);
 
-#ifdef EFL_HAVE_PTHREAD
+#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 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) 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);
+#  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 ;
-#define UNLOCK_CACHE ;
+# define LOCK_CACHE do {} while (0)
+# define UNLOCK_CACHE do {} while (0)
 
-#define INIT_FILE(File) ;
-#define LOCK_FILE(File) ;
-#define UNLOCK_FILE(File) ;
-#define DESTROY_FILE(File) ;
+# 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
+#endif /* EFL_HAVE_THREADS */
 
 /* cache. i don't expect this to ever be large, so arrays will do */
 static int        eet_writers_num     = 0;
@@ -280,7 +308,7 @@ eet_test_close(int test, Eet_File *ef)
    if (test)
      {
        ef->delete_me_now = 1;
-        eet_internal_close(ef, 0);
+        eet_internal_close(ef, EINA_TRUE);
      }
    return test;
 }
@@ -307,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)
 {
@@ -333,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_internal_close(ef, 1);
+             eet_internal_close(del_ef, EINA_TRUE);
          }
      }
 
@@ -358,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)
 {
@@ -421,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);
@@ -501,8 +535,8 @@ 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 */
@@ -513,7 +547,7 @@ eet_flush2(Eet_File *ef)
             unsigned int flag;
              int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
 
-            flag = (efn->ciphered << 1) | efn->compression;
+            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);
@@ -522,7 +556,7 @@ eet_flush2(Eet_File *ef)
              ibuf[4] = (int) htonl ((unsigned int) efn->name_size);
              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;
           }
      }
@@ -544,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;
           }
      }
@@ -554,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;
           }
      }
@@ -566,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;
               }
          }
@@ -582,13 +616,13 @@ 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
@@ -596,12 +630,12 @@ eet_flush2(Eet_File *ef)
 // 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(ef->fp));
+//   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;
      }
@@ -609,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)
          {
@@ -624,137 +660,10 @@ 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)
-{
-   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++;
-         }
-     }
-
-   /* calculate offsets per entry */
-   offset = 0;
-   for (i = 0; i < num; i++)
-     {
-       for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
-         {
-            efn->offset = 12 + size + offset;
-            offset += efn->size;
-         }
-     }
-
-   /* 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++)
-     {
-       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;
-         }
-     }
-
-   /* write data */
-   for (i = 0; i < num; i++)
-     {
-       for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
-         {
-            if (fwrite(efn->data, efn->size, 1, ef->fp) != 1)
-              goto write_error;
-         }
-     }
-
-   /* no more writes pending */
-   ef->writes_pending = 0;
-
-   return EET_ERROR_NONE;
-
-   write_error:
-   if (ferror(ef->fp))
-     {
-       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;
-         }
-     }
-   sign_error:
-   if (ef->fp) fclose(ef->fp);
-   ef->fp = NULL;
-   return EET_ERROR_WRITE_ERROR;
-}
-#endif
-
 EAPI int
 eet_init(void)
 {
@@ -839,6 +748,29 @@ eet_shutdown(void)
    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
 eet_clearcache(void)
 {
@@ -849,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++;
@@ -887,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 */
@@ -981,6 +915,7 @@ eet_internal_read2(Eet_File *ef)
 
        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))           \
@@ -1212,6 +1147,7 @@ eet_internal_read1(Eet_File *ef)
 
         efn->name_size = name_size;
        efn->ciphered = 0;
+       efn->alias = 0;
 
        /* invalid size */
        if (eet_test_close(efn->size <= 0, ef))
@@ -1281,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)
 {
@@ -1302,7 +1244,7 @@ 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;
      }
 
@@ -1317,10 +1259,13 @@ eet_internal_close(Eet_File *ef, Eina_Bool locked)
    /* 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) return EET_ERROR_NONE;
+   if (ef->references > 0) goto on_error;
    /* flush any writes */
    err = eet_flush2(ef);
 
@@ -1329,21 +1274,16 @@ eet_internal_close(Eet_File *ef, Eina_Bool locked)
 
    /* 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;
+     goto on_error;
 
    /* remove from cache */
-   if (!locked)
-     {
-        LOCK_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);
-   if (!locked)
-     {
-        UNLOCK_CACHE;
-     }
+
+   /* we can unlock the cache now */
+   if (!locked) UNLOCK_CACHE;
 
    DESTROY_FILE(ef);
 
@@ -1385,7 +1325,6 @@ eet_internal_close(Eet_File *ef, Eina_Bool locked)
 
    if (ef->sha1) free(ef->sha1);
    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 */
@@ -1394,6 +1333,10 @@ eet_internal_close(Eet_File *ef, Eina_Bool locked)
    /* free it */
    free(ef);
    return err;
+
+ on_error:
+   if (!locked) UNLOCK_CACHE;
+   return EET_ERROR_NONE;
 }
 
 EAPI Eet_File *
@@ -1418,14 +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 *
@@ -1447,10 +1393,10 @@ eet_open(const char *file, Eet_File_Mode mode)
        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_internal_close(ef, 1);
+             eet_internal_close(ef, EINA_TRUE);
          }
        ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
      }
@@ -1462,48 +1408,42 @@ eet_open(const char *file, Eet_File_Mode mode)
          {
             ef->delete_me_now = 1;
             ef->references++;
-             eet_internal_close(ef, 1);
+             eet_internal_close(ef, EINA_TRUE);
          }
        ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
      }
-   UNLOCK_CACHE;
-   
-    /* 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 */
@@ -1511,7 +1451,7 @@ eet_open(const char *file, Eet_File_Mode mode)
      {
        ef->delete_me_now = 1;
        ef->references++;
-        eet_internal_close(ef, 0);
+        eet_internal_close(ef, EINA_TRUE);
        ef = NULL;
      }
 
@@ -1520,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;
      }
 
@@ -1528,13 +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 */
    INIT_FILE(ef);
-   ef->fp = fp;
    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;
@@ -1550,50 +1490,48 @@ eet_open(const char *file, Eet_File_Mode mode)
    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)
      {
-       LOCK_CACHE;
        if (ef->mode == EET_FILE_MODE_READ)
          eet_cache_add(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_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
-       UNLOCK_CACHE;
      }
 
+   UNLOCK_CACHE;
    return ef;
+
+on_error:
+   UNLOCK_CACHE;
+   return NULL;
 }
 
 EAPI Eet_File_Mode
@@ -1654,15 +1592,15 @@ eet_identity_set(Eet_File *ef, Eet_Key *key)
 EAPI Eet_Error
 eet_close(Eet_File *ef)
 {
-   return eet_internal_close(ef, 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)
 {
-   void                        *data = NULL;
-   int                 size = 0;
-   Eet_File_Node       *efn;
+   Eet_File_Node *efn;
+   char *data = NULL;
+   int size = 0;
 
    if (size_ret)
      *size_ret = 0;
@@ -1699,6 +1637,7 @@ eet_read_cipher(Eet_File *ef, const char *name, int *size_ret, const char *ciphe
         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
@@ -1767,12 +1706,27 @@ eet_read_cipher(Eet_File *ef, const char *name, int *size_ret, const char *ciphe
          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:
@@ -1790,9 +1744,9 @@ eet_read(Eet_File *ef, const char *name, int *size_ret)
 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;
@@ -1822,13 +1776,42 @@ eet_read_direct(Eet_File *ef, const char *name, int *size_ret)
    /* get size (uncompressed, if compressed at all) */
    size = efn->data_size;
 
-   /* uncompressed data */
-   if (efn->compression == 0
-       && efn->ciphered == 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)
@@ -1843,6 +1826,150 @@ eet_read_direct(Eet_File *ef, const char *name, int *size_ret)
    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_cipher(Eet_File *ef, const char *name, const void *data, int size, int comp, const char *cipher_key)
 {
@@ -1914,7 +2041,7 @@ eet_write_cipher(Eet_File *ef, const char *name, const void *data, int size, int
                           (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
          {
             free(data2);
-            return 0;
+            goto on_error;
          }
        /* record compressed chunk size */
        data_size = (int)buflen;
@@ -1964,6 +2091,7 @@ eet_write_cipher(Eet_File *ef, const char *name, const void *data, int size, int
        if ((efn->name) && (eet_string_match(efn->name, name)))
          {
             free(efn->data);
+            efn->alias = 0;
             efn->ciphered = cipher_key ? 1 : 0;
             efn->compression = !!comp;
             efn->size = data_size;
@@ -1989,6 +2117,7 @@ eet_write_cipher(Eet_File *ef, const char *name, const void *data, int size, int
        efn->next = ef->header->directory->nodes[hash];
        ef->header->directory->nodes[hash] = efn;
        efn->offset = -1;
+       efn->alias = 0;
        efn->ciphered = cipher_key ? 1 : 0;
        efn->compression = !!comp;
        efn->size = data_size;
@@ -2215,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;
 }