1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-30 22:19:17 +02:00
Stephen Fewer a635b67ada Add a list_shift() function to the common linked list code.
git-svn-id: file:///home/svn/framework3/trunk@10052 4d416f70-5f16-0410-b530-b9f4589650da
2010-08-19 11:25:11 +00:00

336 lines
5.8 KiB
C

#include "common.h"
/*
* An implementation of a simple thread safe double linked list structure. Can be used as either
* a stack (via pop/push), a queue (via push/shift) or an array (via get/add/insert/remove). If
* performing a group of actions on a list based on results from list actions, acquire the list
* lock before the group of actions and release lock when done.
*/
/*
* Create a thread safe double linked list.
*/
LIST * list_create( VOID )
{
LIST * list = (LIST *)malloc( sizeof(LIST) );
if( list != NULL )
{
list->start = NULL;
list->end = NULL;
list->count = 0;
list->lock = lock_create();
if( list->lock == NULL )
{
list_destroy( list );
return NULL;
}
}
return list;
}
/*
* Destroy an existing linked list. This destroys all nodes and the list itself
* but not the data held in the linked list. This is the responsibility of the
* caller to destroy.
*/
VOID list_destroy( LIST * list )
{
NODE * current_node;
NODE * next_node;
if( list != NULL )
{
lock_acquire( list->lock );
current_node = list->start;
while( current_node != NULL )
{
next_node = current_node->next;
current_node->next = NULL;
current_node->prev = NULL;
free( current_node );
current_node = next_node;
}
list->count = 0;
lock_release( list->lock );
lock_destroy( list->lock );
free( list );
}
}
/*
* Return the number of items in the list. If using this coung value to itterate through the list
* with list_get, acquire the lists lock before the list_count/list_get block and release it afterwards.
*/
DWORD list_count( LIST * list )
{
DWORD count = 0;
if( list != NULL )
{
lock_acquire( list->lock );
count = list->count;
lock_release( list->lock );
}
return count;
}
/*
* Get the data value held in the list and a specified index. This will perform a linear search from
* the begining of the list returning the data value if found or NULL if not found.
*/
LPVOID list_get( LIST * list, DWORD index )
{
LPVOID data = NULL;
NODE * current_node = NULL;
if( list == NULL )
return NULL;
lock_acquire( list->lock );
if( list->count <= index )
{
lock_release( list->lock );
return NULL;
}
current_node = list->start;
while( current_node != NULL )
{
if( index == 0 )
break;
current_node = current_node->next;
index--;
}
if( current_node != NULL )
data = current_node->data;
lock_release( list->lock );
return data;
}
/*
* Adds a data item onto the end of the list.
*/
BOOL list_add( LIST * list, LPVOID data )
{
return list_push( list, data );
}
/*
* Internal function to remove a node from a list. Assumes caller has aquired the appropriate lock first.
*/
BOOL list_remove_node( LIST * list, NODE * node )
{
if( list == NULL || node == NULL)
return FALSE;
if( list->count - 1 == 0 )
{
list->start = NULL;
list->end = NULL;
}
else
{
if( list->start == node )
{
list->start = list->start->next;
list->start->prev = NULL;
}
else if( list->end == node )
{
list->end = list->end->prev;
list->end->next = NULL;
}
else
{
node->next->prev = node->prev;
node->prev->next = node->next;
}
}
list->count -= 1;
node->next = NULL;
node->prev = NULL;
free( node );
return TRUE;
}
/*
* Remove a given data item from the list. Assumes data items are unqique as only the first occurrence is removed.
*/
BOOL list_remove( LIST * list, LPVOID data )
{
BOOL result = FALSE;
NODE * current_node = NULL;
if( list == NULL || data == NULL )
return FALSE;
lock_acquire( list->lock );
current_node = list->start;
while( current_node != NULL )
{
if( current_node->data == data )
break;
current_node = current_node->next;
}
result = list_remove_node( list, current_node );
lock_release( list->lock );
return result;
}
/*
* Remove a list item at the specified index.
*/
BOOL list_delete( LIST * list, DWORD index )
{
BOOL result = FALSE;
LPVOID data = NULL;
NODE * current_node = NULL;
if( list == NULL )
return FALSE;
lock_acquire( list->lock );
if( list->count > index )
{
current_node = list->start;
while( current_node != NULL )
{
if( index == 0 )
{
result = list_remove_node( list, current_node );
break;
}
current_node = current_node->next;
index--;
}
}
lock_release( list->lock );
return result;
}
/*
* Push a data item onto the end of the list.
*/
BOOL list_push( LIST * list, LPVOID data )
{
NODE * node = NULL;
if( list == NULL )
return FALSE;
node = (NODE *)malloc( sizeof(NODE) );
if( node == NULL )
return FALSE;
node->data = data;
node->next = NULL;
node->prev = NULL;
lock_acquire( list->lock );
if ( list->end != NULL )
{
list->end->next = node;
node->prev = list->end;
list->end = node;
}
else
{
list->start = node;
list->end = node;
}
list->count += 1;
lock_release( list->lock );
return TRUE;
}
/*
* Pop a data value off the end of the list.
*/
LPVOID list_pop( LIST * list )
{
LPVOID data = NULL;
if( list == NULL )
return NULL;
lock_acquire( list->lock );
if( list->end != NULL )
{
data = list->end->data;
list_remove_node( list, list->end );
}
lock_release( list->lock );
return data;
}
/*
* Pop a data value off the start of the list.
*/
LPVOID list_shift( LIST * list )
{
LPVOID data = NULL;
if( list == NULL )
return NULL;
lock_acquire( list->lock );
if( list->start != NULL )
{
data = list->start->data;
list_remove_node( list, list->start );
}
lock_release( list->lock );
return data;
}