#include <sys/types.h>
#include <sys/syslog.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include "webdavd.h"
#include "webdav_memcache.h"
static
void webdav_free_remaining(webdav_memcache_element_t *current_item);
static
int create_webdav_memcache_element(const char *uri, int uri_length, struct vattr *vap,
char *appledoubleheader, time_t now, webdav_memcache_element_t **element);
static
void webdav_free_remaining(current_item)
webdav_memcache_element_t *current_item;
{
webdav_memcache_element_t * next_item;
next_item = current_item->next;
while (current_item)
{
free(current_item->uri);
if (current_item->appledoubleheader)
{
free(current_item->appledoubleheader);
}
free(current_item);
current_item = next_item;
if (current_item)
{
next_item = current_item->next;
}
}
}
int webdav_memcache_init(cache_header)
webdav_memcache_header_t *cache_header;
{
int i, error = 0;
pthread_mutexattr_t mutexattr;
bzero(cache_header, sizeof(*cache_header));
cache_header->open_uids = WEBDAV_NUMCACHEDUIDS;
cache_header->last_uid = 0;
error = pthread_mutexattr_init(&mutexattr);
if (error)
{
syslog(LOG_ERR, "webdav_memcache_init: pthread_mutexattr_init() failed: %s", strerror(error));
return (error);
}
error = pthread_mutex_init(&(cache_header->lock), &mutexattr);
if (error)
{
syslog(LOG_ERR, "webdav_memcache_init: pthread_mutex_init() failed: %s", strerror(error));
return (error);
}
for (i = 0; i < WEBDAV_NUMCACHEDUIDS; i++)
{
(cache_header->uid_array)[i].uid = (uid_t)-1;
}
return (error);
}
static
int create_webdav_memcache_element(const char *uri, int uri_length, struct vattr *vap,
char *appledoubleheader, time_t now, webdav_memcache_element_t **element)
{
int error;
webdav_memcache_element_t *new_item;
new_item = malloc(sizeof(webdav_memcache_element_t));
if (!new_item)
{
#ifdef DEBUG
syslog(LOG_INFO, "create_webdav_memcache_element: could not allocate new_item");
#endif
error = ENOMEM;
goto exit;
}
new_item->uri = malloc((size_t)(uri_length + 1));
if (!(new_item->uri))
{
#ifdef DEBUG
syslog(LOG_INFO, "create_webdav_memcache_element: could not allocate new_item->uri");
#endif
error = ENOMEM;
goto free_element;
}
new_item->uri_length = uri_length;
strcpy(new_item->uri, uri);
bcopy(vap, &(new_item->vap), sizeof(struct vattr));
if (appledoubleheader)
{
new_item->appledoubleheader = malloc(APPLEDOUBLEHEADER_LENGTH);
if (!(new_item->appledoubleheader))
{
#ifdef DEBUG
syslog(LOG_INFO, "create_webdav_memcache_element: could not allocate new_item->vap");
#endif
error = ENOMEM;
goto free_all;
}
bcopy(appledoubleheader, new_item->appledoubleheader, APPLEDOUBLEHEADER_LENGTH);
}
else
{
new_item->appledoubleheader = NULL;
}
new_item->next = 0;
new_item->time_received = now;
error = 0;
goto exit;
free_all:
if (new_item->uri)
{
free(new_item->uri);
}
free_element:
free(new_item);
new_item = NULL;
exit:
*element = new_item;
return (error);
}
int webdav_memcache_insert(uid_t uid, const char *uri, webdav_memcache_header_t *cache_header,
struct vattr *vap, char *appledoubleheader)
{
webdav_memcache_element_t * new_item;
webdav_memcache_element_t * current_item;
webdav_memcache_element_t * previous_item;
int error = 0, error2 = 0;
int i = 0;
int uidslot = 0;
int uri_length;
time_t now;
now = time(0);
if ( now == -1 )
{
#ifdef DEBUG
syslog(LOG_INFO, "webdav_memcache_insert: time(): %s", strerror(errno));
#endif
return (errno);
}
uri_length = strlen(uri);
error = pthread_mutex_lock(&(cache_header->lock));
if (error)
{
syslog(LOG_ERR, "webdav_memcache_insert: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
return (error);
}
for (i = 0; i < WEBDAV_NUMCACHEDUIDS; ++i)
{
if (cache_header->uid_array[i].uid == uid)
{
uidslot = i;
break;
}
}
if (i == WEBDAV_NUMCACHEDUIDS)
{
error = create_webdav_memcache_element(uri, uri_length, vap, appledoubleheader,
now, &new_item);
if (error)
{
goto unlock;
}
uidslot = cache_header->last_uid;
if (cache_header->open_uids == 0)
{
cache_header->uid_array[uidslot].uid = uid;
current_item = cache_header->uid_array[uidslot].item_head;
if (current_item)
{
webdav_free_remaining(current_item);
}
}
else
{
--cache_header->open_uids;
cache_header->uid_array[uidslot].uid = uid;
}
cache_header->uid_array[uidslot].item_head = new_item;
cache_header->uid_array[uidslot].item_tail = new_item;
++cache_header->last_uid;
if (cache_header->last_uid == WEBDAV_NUMCACHEDUIDS)
{
cache_header->last_uid = 0;
}
}
else
{
current_item = cache_header->uid_array[uidslot].item_head;
previous_item = NULL;
while (current_item)
{
if ( now > (current_item->time_received + WEBDAV_MEMCACHE_TIMEOUT))
{
if (!previous_item)
{
cache_header->uid_array[i].item_head = NULL;
}
else
{
previous_item->next = NULL;
}
cache_header->uid_array[i].item_tail = previous_item;
webdav_free_remaining(current_item);
break;
}
else
{
if ((uri_length == current_item->uri_length) &&
(!memcmp(uri, current_item->uri, (size_t)uri_length)))
{
if (!previous_item)
{
cache_header->uid_array[uidslot].item_head = current_item->next;
}
else
{
previous_item->next = current_item->next;
}
if (cache_header->uid_array[i].item_tail == current_item)
{
cache_header->uid_array[i].item_tail = previous_item;
}
current_item->next = NULL;
webdav_free_remaining(current_item);
break;
}
else
{
previous_item = current_item;
current_item = previous_item->next;
}
}
}
error = create_webdav_memcache_element(uri, uri_length, vap, appledoubleheader,
now, &new_item);
if (error)
{
goto unlock;
}
new_item->next = cache_header->uid_array[uidslot].item_head;
cache_header->uid_array[uidslot].item_head = new_item;
if (!cache_header->uid_array[i].item_tail)
{
cache_header->uid_array[i].item_tail = new_item;
}
}
unlock:
error2 = pthread_mutex_unlock(&(cache_header->lock));
if (error2)
{
syslog(LOG_ERR, "webdav_memcache_insert: pthread_mutex_unlock(): %s", strerror(error2));
webdav_kill(-1);
if ( !error )
{
error = error2;
}
}
return (error);
}
int webdav_memcache_retrieve(uid_t uid, char *uri,
webdav_memcache_header_t *cache_header, struct vattr *vap, char *appledoubleheader,
int32_t *lastvalidtime)
{
webdav_memcache_element_t * current_item = 0;
webdav_memcache_element_t * previous_item = 0;
int length = strlen(uri);
time_t now = time(0);
int i = 0;
int error = 0;
int result = FALSE;
error = pthread_mutex_lock(&(cache_header->lock));
if (error)
{
syslog(LOG_ERR, "webdav_memcache_retrieve: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
return (result);
}
for (i = 0; i < WEBDAV_NUMCACHEDUIDS; ++i)
{
if (cache_header->uid_array[i].uid == uid)
{
current_item = cache_header->uid_array[i].item_head;
break;
}
}
previous_item = 0;
while (current_item)
{
if (now > (current_item->time_received + WEBDAV_MEMCACHE_TIMEOUT))
{
if (!previous_item)
{
cache_header->uid_array[i].item_head = 0;
}
else
{
previous_item->next = 0;
}
cache_header->uid_array[i].item_tail = previous_item;
webdav_free_remaining(current_item);
goto done;
}
else
{
if ((length == current_item->uri_length) &&
(!memcmp(uri, current_item->uri, (size_t)length)))
{
bcopy(&(current_item->vap), vap, sizeof(struct vattr));
if (lastvalidtime)
{
*lastvalidtime = current_item->time_received;
}
if (appledoubleheader)
{
if (current_item->appledoubleheader)
{
bcopy(current_item->appledoubleheader, appledoubleheader, APPLEDOUBLEHEADER_LENGTH);
result = TRUE;
goto done;
}
else
{
previous_item = current_item;
current_item = previous_item->next;
}
}
else
{
result = TRUE;
goto done;
}
}
else
{
previous_item = current_item;
current_item = previous_item->next;
}
}
}
done:
error = pthread_mutex_unlock(&(cache_header->lock));
if ( error )
{
syslog(LOG_ERR, "webdav_memcache_retrieve: pthread_mutex_unlock(): %s", strerror(error));
webdav_kill(-1);
}
return (result);
}
int webdav_memcache_remove(uid, uri, cache_header)
uid_t uid;
char *uri;
webdav_memcache_header_t *cache_header;
{
#pragma unused(uid)
webdav_memcache_element_t * current_item = 0;
webdav_memcache_element_t * previous_item = 0;
int length = strlen(uri);
time_t now = time(0);
int i = 0;
int error = 0;
error = pthread_mutex_lock(&(cache_header->lock));
if (error)
{
syslog(LOG_ERR, "webdav_memcache_remove: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
return (error);
}
for (i = 0; i < WEBDAV_NUMCACHEDUIDS; ++i)
{
if (cache_header->uid_array[i].uid == (uid_t)-1)
{
continue;
}
current_item = cache_header->uid_array[i].item_head;
previous_item = 0;
while (current_item)
{
if (now > (current_item->time_received + WEBDAV_MEMCACHE_TIMEOUT))
{
if (!previous_item)
{
cache_header->uid_array[i].item_head = 0;
}
else
{
previous_item->next = 0;
}
cache_header->uid_array[i].item_tail = previous_item;
webdav_free_remaining(current_item);
current_item = 0;
}
else
{
if ((length == current_item->uri_length) &&
(!memcmp(uri, current_item->uri, (size_t)length)))
{
free(current_item->uri);
if (current_item->appledoubleheader)
{
free(current_item->appledoubleheader);
}
if (!previous_item)
{
cache_header->uid_array[i].item_head = current_item->next;
free(current_item);
current_item = cache_header->uid_array[i].item_head;
}
else
{
previous_item->next = current_item->next;
free(current_item);
current_item = previous_item->next;
}
}
else
{
previous_item = current_item;
current_item = previous_item->next;
}
}
}
}
error = pthread_mutex_unlock(&(cache_header->lock));
if ( error )
{
syslog(LOG_ERR, "webdav_memcache_remove: pthread_mutex_unlock(): %s", strerror(error));
webdav_kill(-1);
}
return (error);
}
int webdav_memcache_invalidate(webdav_memcache_header_t *cache_header)
{
int error;
int index;
error = pthread_mutex_lock(&(cache_header->lock));
if (error)
{
syslog(LOG_ERR, "webdav_memcache_invalidate: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
goto done;
}
for (index = 0; index < WEBDAV_NUMCACHEDUIDS; ++index)
{
if (cache_header->uid_array[index].uid != (uid_t)-1)
{
if (cache_header->uid_array[index].item_head != NULL)
{
webdav_free_remaining(cache_header->uid_array[index].item_head);
cache_header->uid_array[index].item_head = cache_header->uid_array[index].item_tail = NULL;
}
}
}
error = pthread_mutex_unlock(&(cache_header->lock));
if ( error )
{
syslog(LOG_ERR, "webdav_memcache_invalidate: pthread_mutex_unlock(): %s", strerror(error));
webdav_kill(-1);
}
done:
return (error);
}