1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-04-18 07:11:12 +02:00
2013-11-06 11:38:22 +10:00

391 lines
7.5 KiB
C

/*!
* @file list.c
* @brief Definitions for functions that operate on lists.
* @details 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.
*/
#include "common.h"
/*!
* @brief Create a thread-safe double linked list.
* @returns A new instance of a linked list.
* @retval NULL Indicates a memory allocation failure.
*/
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;
}
/*!
* @brief Destroy an existing linked list.
* @details 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.
* @param list The \c LIST instance 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);
}
}
/*!
* @brief Get the number of items in the list.
* @param list The \c LIST to get a count of.
* @returns The number of elements in the list.
* @remark 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;
}
/*!
* @brief Get the data value held in the list and a specified index.
* @param list Pointer to the \c LIST to get the element from.
* @param index Index of the element to get;
* @returns Pointer to the item in the list.
* @retval NULL Indicates the element doesn't exist in the list.
* @remark This will perform a linear search from the beginning of the list.
*/
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;
}
/*!
* @brief Add a data item onto the end of the list.
* @param list Pointer to the \c LIST to add the item to.
* @param data The data that is to be added to the list.
* @returns Indication of success or failure.
* @sa list_push
*/
BOOL list_add(LIST * list, LPVOID data)
{
return list_push(list, data);
}
/*!
* @brief Internal function to remove a node from a list.
* @param list Pointer to the \c LIST containing \c node.
* @param node Pointer to the \c NOTE to remove.
* @returns Indication of success or failure.
* @remark 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;
}
/*!
* @brief Remove a given data item from the list.
* @param list Pointer to the \c LIST to remove the item from.
* @param data The data that is to be removed from the list.
* @remark Assumes data items are unqique as only the first occurrence is removed.
* @returns Indication of success or failure.
* @sa list_remove_node
*/
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;
}
/*!
* @brief Remove a list item at the specified index.
* @param list Pointer to the \c LIST to remove the item from.
* @param index Index of the item to remove.
* @returns Indication of success or failure.
*/
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;
}
/*!
* @brief Push a data item onto the end of the list.
* @param list Pointer to the \c LIST to append the data to.
* @param data Pointer to the data to append.
* @returns Indication of success or failure.
*/
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;
}
/*!
* @brief Pop a data value off the end of the list.
* @param list Pointer to the \c LIST to pop the value from.
* @returns The popped value.
* @retval NULL Indicates no data in 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;
}
/*!
* @brief Pop a data value off the start of the list.
* @param list Pointer to the \c LIST to shift the value from.
* @returns The shifted value.
* @retval NULL Indicates no data in 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;
}