# include <config.h>
#endif
-#if defined(_WIN32) && ! defined(__CEGCC__)
-# include <winsock2.h>
-#endif
-
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#elif defined __GNUC__
void *alloca (size_t);
#endif
+#ifdef _WIN32
+# include <winsock2.h>
+#endif
+
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
# include <openssl/evp.h>
#endif
-#ifdef EFL_HAVE_PTHREAD
+#ifdef EFL_HAVE_POSIX_THREADS
# include <pthread.h>
#endif
#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
struct _Eet_File
{
char *path;
- FILE *fp;
FILE *readfp;
Eet_File_Header *header;
Eet_Dictionary *ed;
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;
unsigned char free_name : 1;
unsigned char compression : 1;
unsigned char ciphered : 1;
+ unsigned char alias : 1;
};
#if 0
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
{
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;
if (test)
{
ef->delete_me_now = 1;
- eet_internal_close(ef, 0);
+ eet_internal_close(ef, EINA_TRUE);
}
return test;
}
}
/* 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)
{
if (del_ef)
{
del_ef->delete_me_now = 1;
- eet_internal_close(ef, 1);
+ eet_internal_close(del_ef, EINA_TRUE);
}
}
}
/* 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)
{
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);
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 */
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);
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;
}
}
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;
}
}
{
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;
}
}
{
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;
}
}
{
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
// 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;
}
/* 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)
{
}
}
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)
{
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)
{
* 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++;
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 */
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)) \
efn->name_size = name_size;
efn->ciphered = 0;
+ efn->alias = 0;
/* invalid size */
if (eet_test_close(efn->size <= 0, 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)
{
return eet_internal_read2(ef);
default:
ef->delete_me_now = 1;
- eet_close(ef);
+ eet_internal_close(ef, EINA_TRUE);
break;
}
/* 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);
/* 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);
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 */
/* free it */
free(ef);
return err;
+
+ on_error:
+ if (!locked) UNLOCK_CACHE;
+ return EET_ERROR_NONE;
}
EAPI Eet_File *
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 *
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);
}
{
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 */
{
ef->delete_me_now = 1;
ef->references++;
- eet_internal_close(ef, 0);
+ eet_internal_close(ef, EINA_TRUE);
ef = NULL;
}
/* reference it up and return it */
if (fp != NULL) fclose(fp);
ef->references++;
+ UNLOCK_CACHE;
return ef;
}
/* 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;
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
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;
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
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:
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;
/* 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)
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)
{
(uLong)size, Z_BEST_COMPRESSION) != Z_OK)
{
free(data2);
- return 0;
+ goto on_error;
}
/* record compressed chunk size */
data_size = (int)buflen;
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;
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;
}
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;
}