#include <sys/types.h>
#include <sys/syslog.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <c.h>
#include <errno.h>
#include "webdavd.h"
#include "webdav_inode.h"
#include "../webdav_fs.kextproj/webdav_fs.kmodproj/webdav.h"
static int hashuri(const char *string, unsigned int length)
{
int i, hash_val = 0;
const char *start;
int numchars = MIN(length, WEBDAV_UNIQUE_HASH_CHARS);
start = string + length - numchars;
hash_val = 0;
for (i = 1; *start != 0 && i <= numchars; i++, start++)
{
hash_val += (unsigned char)*start * i;
}
hash_val = (hash_val << 8) + length%256;
return (hash_val);
}
int webdav_inode_init(char *uri, unsigned int urilen)
{
int error;
pthread_mutexattr_t mutexattr;
webdav_file_record_t * filerec_ptr;
bzero(&ginode_hashtbl, sizeof(ginode_hashtbl));
error = pthread_mutexattr_init(&mutexattr);
if (error)
{
syslog(LOG_ERR, "webdav_inode_init: pthread_mutexattr_init() failed: %s", strerror(error));
return (error);
}
error = pthread_mutex_init(&ginode_lock, &mutexattr);
if (error)
{
syslog(LOG_ERR, "webdav_inode_init: pthread_mutex_init() failed: %s", strerror(error));
return (error);
}
filerec_ptr = malloc(sizeof(webdav_file_record_t));
if (!filerec_ptr)
{
syslog(LOG_ERR, "webdav_inode_init: filerec_ptr could not be allocated: %s", strerror(errno));
return (ENOMEM);
}
filerec_ptr->uri = malloc(urilen + 1);
if (!filerec_ptr->uri)
{
syslog(LOG_ERR, "webdav_inode_init: uri could not be allocated: %s", strerror(errno));
free(filerec_ptr);
return (ENOMEM);
}
bcopy(uri, filerec_ptr->uri, urilen);
filerec_ptr->uri[urilen] = '\0';
filerec_ptr->uri_length = urilen;
filerec_ptr->next = 0;
filerec_ptr->inode = WEBDAV_ROOTFILEID;
filerec_ptr->file_handle = -1;
ginode_hashtbl[hashuri((const char *)uri, urilen) % WEBDAV_FILE_RECORD_HASH_BUCKETS] = filerec_ptr;
return (0);
}
int webdav_get_inode(const char *uri, unsigned int length, int make_entry, int *inode)
{
int hash_num, error = 0, error2 = 0, found = 0;
webdav_file_record_t * filerec_ptr, *head_ptr;
error = pthread_mutex_lock(&ginode_lock);
if (error)
{
syslog(LOG_ERR, "webdav_get_inode: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
return (error);
}
hash_num = hashuri(uri, length);
filerec_ptr = head_ptr = ginode_hashtbl[hash_num%WEBDAV_FILE_RECORD_HASH_BUCKETS];
while (filerec_ptr && !found)
{
if ((filerec_ptr->uri_length == length) && !memcmp(uri, filerec_ptr->uri, length))
{
*inode = filerec_ptr->inode;
goto unlock;
}
else
{
filerec_ptr = filerec_ptr->next;
}
}
if (make_entry)
{
filerec_ptr = malloc(sizeof(webdav_file_record_t));
if (!filerec_ptr)
{
syslog(LOG_ERR, "webdav_get_inode: could not allocate filerec_ptr");
webdav_kill(-1);
error = ENOMEM;
goto unlock;
}
filerec_ptr->uri = malloc(length + 1);
if (!filerec_ptr->uri)
{
syslog(LOG_ERR, "webdav_get_inode: could not allocate filerec_ptr->uri");
webdav_kill(-1);
free(filerec_ptr);
error = ENOMEM;
goto unlock;
}
bcopy(uri, filerec_ptr->uri, length);
filerec_ptr->uri[length] = '\0';
filerec_ptr->uri_length = length;
filerec_ptr->inode = ginode_cntr++;
filerec_ptr->file_handle = -1;
filerec_ptr->next = head_ptr;
ginode_hashtbl[hash_num%WEBDAV_FILE_RECORD_HASH_BUCKETS] = filerec_ptr;
*inode = filerec_ptr->inode;
}
else
{
*inode = 0;
}
unlock:
error2 = pthread_mutex_unlock(&ginode_lock);
if ( error2 )
{
syslog(LOG_ERR, "webdav_get_inode: pthread_mutex_unlock(): %s", strerror(error2));
webdav_kill(-1);
if (!error)
{
error = error2;
}
}
return (error);
}
int webdav_set_inode(const char *uri, unsigned int length, int inode)
{
int hash_num, error = 0, error2 = 0;
webdav_file_record_t * filerec_ptr, *head_ptr;
error = pthread_mutex_lock(&ginode_lock);
if (error)
{
syslog(LOG_ERR, "webdav_set_inode: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
return (error);
}
hash_num = hashuri(uri, length);
filerec_ptr = head_ptr = ginode_hashtbl[hash_num%WEBDAV_FILE_RECORD_HASH_BUCKETS];
while (filerec_ptr)
{
if ((filerec_ptr->uri_length == length) && !memcmp(uri, filerec_ptr->uri, length))
{
filerec_ptr->inode = inode;
goto unlock;
}
else
{
filerec_ptr = filerec_ptr->next;
}
}
filerec_ptr = malloc(sizeof(webdav_file_record_t));
if (!filerec_ptr)
{
syslog(LOG_ERR, "webdav_set_inode: could not allocate filerec_ptr");
webdav_kill(-1);
error = ENOMEM;
goto unlock;
}
filerec_ptr->uri = malloc(length + 1);
if (!filerec_ptr->uri)
{
syslog(LOG_ERR, "webdav_set_inode: could not allocate filerec_ptr->uri");
webdav_kill(-1);
free(filerec_ptr);
error = ENOMEM;
goto unlock;
}
bcopy(uri, filerec_ptr->uri, length);
filerec_ptr->uri[length] = '\0';
filerec_ptr->uri_length = length;
filerec_ptr->inode = inode;
filerec_ptr->next = head_ptr;
filerec_ptr->file_handle = -1;
ginode_hashtbl[hash_num%WEBDAV_FILE_RECORD_HASH_BUCKETS] = filerec_ptr;
unlock:
error2 = pthread_mutex_unlock(&ginode_lock);
if ( error2 )
{
syslog(LOG_ERR, "webdav_set_inode: pthread_mutex_unlock(): %s", strerror(error2));
webdav_kill(-1);
if (!error)
{
error = error2;
}
}
return (error);
}
int webdav_remove_inode(const char *uri, unsigned int length)
{
int hash_num, error = 0, error2 = 0;
webdav_file_record_t * filerec_ptr, *prev_ptr;
error = pthread_mutex_lock(&ginode_lock);
if (error)
{
syslog(LOG_ERR, "webdav_remove_inode: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
return (error);
}
hash_num = hashuri(uri, length);
filerec_ptr = prev_ptr = ginode_hashtbl[hash_num%WEBDAV_FILE_RECORD_HASH_BUCKETS];
if (filerec_ptr)
{
if ((filerec_ptr->uri_length == length) && !memcmp(uri, filerec_ptr->uri, length))
{
ginode_hashtbl[hash_num%WEBDAV_FILE_RECORD_HASH_BUCKETS] = filerec_ptr->next;
free(filerec_ptr->uri);
free(filerec_ptr);
goto unlock;
}
else
{
filerec_ptr = filerec_ptr->next;
}
}
else
{
goto unlock;
}
while (filerec_ptr)
{
if ((filerec_ptr->uri_length == length) && !memcmp(uri, filerec_ptr->uri, length))
{
prev_ptr->next = filerec_ptr->next;
free(filerec_ptr->uri);
free(filerec_ptr);
goto unlock;
}
else
{
prev_ptr = filerec_ptr;
filerec_ptr = filerec_ptr->next;
}
}
unlock:
error2 = pthread_mutex_unlock(&ginode_lock);
if ( error2 )
{
syslog(LOG_ERR, "webdav_remove_inode: pthread_mutex_unlock(): %s", strerror(error2));
webdav_kill(-1);
if (!error)
{
error = error2;
}
}
return (error);
}
int webdav_get_file_handle(const char *uri, unsigned int length, webdav_filehandle_t *a_file_handle)
{
int hash_num, error = 0, error2 = 0, found = 0;
webdav_file_record_t * filerec_ptr, *head_ptr;
error = pthread_mutex_lock(&ginode_lock);
if (error)
{
syslog(LOG_ERR, "webdav_get_file_handle: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
return (error);
}
*a_file_handle = -1;
hash_num = hashuri(uri, length);
filerec_ptr = head_ptr = ginode_hashtbl[hash_num%WEBDAV_FILE_RECORD_HASH_BUCKETS];
while (filerec_ptr && !found)
{
if ((filerec_ptr->uri_length == length) && !memcmp(uri, filerec_ptr->uri, length))
{
*a_file_handle = filerec_ptr->file_handle;
goto unlock;
}
else
{
filerec_ptr = filerec_ptr->next;
}
}
unlock:
error2 = pthread_mutex_unlock(&ginode_lock);
if ( error2 )
{
syslog(LOG_ERR, "webdav_get_file_handle: pthread_mutex_unlock(): %s", strerror(error2));
webdav_kill(-1);
if (!error)
{
error = error2;
}
}
return (error);
}
int webdav_set_file_handle(const char *uri, unsigned int length, webdav_filehandle_t file_handle)
{
int hash_num, error = 0, error2 = 0, found = 0;
webdav_file_record_t * filerec_ptr, *head_ptr;
error = pthread_mutex_lock(&ginode_lock);
if (error)
{
syslog(LOG_ERR, "webdav_set_file_handle: pthread_mutex_lock(): %s", strerror(error));
webdav_kill(-1);
return (error);
}
hash_num = hashuri(uri, length);
filerec_ptr = head_ptr = ginode_hashtbl[hash_num%WEBDAV_FILE_RECORD_HASH_BUCKETS];
while (filerec_ptr && !found)
{
if ((filerec_ptr->uri_length == length) && !memcmp(uri, filerec_ptr->uri, length))
{
filerec_ptr->file_handle = file_handle;
goto unlock;
}
else
{
filerec_ptr = filerec_ptr->next;
}
}
error = ENOENT;
unlock:
error2 = pthread_mutex_unlock(&ginode_lock);
if ( error2 )
{
syslog(LOG_ERR, "webdav_set_file_handle: pthread_mutex_unlock(): %s", strerror(error2));
webdav_kill(-1);
if (!error)
{
error = error2;
}
}
return (error);
}