2005-07-22 07:46:58 +00:00
|
|
|
/* emem.c
|
2006-05-28 19:49:07 +00:00
|
|
|
* Wireshark memory management and garbage collection functions
|
2005-07-22 07:46:58 +00:00
|
|
|
* Ronnie Sahlberg 2005
|
|
|
|
*
|
2005-07-22 17:55:47 +00:00
|
|
|
* $Id$
|
2005-07-22 07:46:58 +00:00
|
|
|
*
|
2006-05-21 05:12:17 +00:00
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
2005-07-22 07:46:58 +00:00
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
2005-07-24 01:21:38 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
2005-07-22 07:46:58 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
2005-07-22 23:38:51 +00:00
|
|
|
#include <stdlib.h>
|
2005-07-24 00:29:57 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
2007-12-04 03:26:50 +00:00
|
|
|
#include <ctype.h>
|
2006-01-09 23:11:40 +00:00
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
#include <glib.h>
|
2008-08-05 02:23:35 +00:00
|
|
|
|
2009-09-04 11:48:04 +00:00
|
|
|
#include "proto.h"
|
2005-07-22 07:46:58 +00:00
|
|
|
#include "emem.h"
|
|
|
|
|
2007-04-04 12:18:10 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h> /* VirtualAlloc, VirtualProtect */
|
|
|
|
#include <process.h> /* getpid */
|
|
|
|
#endif
|
|
|
|
|
2006-03-10 05:15:52 +00:00
|
|
|
/*
|
|
|
|
* Tools like Valgrind and ElectricFence don't work well with memchunks.
|
2009-08-11 09:24:56 +00:00
|
|
|
* Export the following environment variables to make {ep|se}_alloc() allocate each
|
2006-03-10 05:15:52 +00:00
|
|
|
* object individually.
|
2009-08-11 09:24:56 +00:00
|
|
|
*
|
|
|
|
* WIRESHARK_DEBUG_EP_NO_CHUNKS
|
|
|
|
* WIRESHARK_DEBUG_SE_NO_CHUNKS
|
2006-03-10 05:15:52 +00:00
|
|
|
*/
|
2009-08-11 09:24:56 +00:00
|
|
|
static gboolean ep_debug_use_chunks;
|
|
|
|
static gboolean se_debug_use_chunks;
|
2006-03-10 05:15:52 +00:00
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
/* Do we want to use canaries?
|
|
|
|
* Export the following environment variables to disable canaries
|
|
|
|
*
|
|
|
|
* WIRESHARK_DEBUG_EP_NO_CANARY
|
|
|
|
* WIRESHARK_DEBUG_SE_NO_CANARY
|
|
|
|
*/
|
|
|
|
static gboolean ep_debug_use_canary;
|
|
|
|
static gboolean se_debug_use_canary;
|
2009-08-10 16:36:44 +00:00
|
|
|
|
|
|
|
/* Do we want to use guardpages? if available */
|
|
|
|
#define WANT_GUARD_PAGES 1
|
2006-03-10 05:39:57 +00:00
|
|
|
|
2006-03-10 05:15:52 +00:00
|
|
|
#ifdef WANT_GUARD_PAGES
|
2006-02-27 20:51:53 +00:00
|
|
|
/* Add guard pages at each end of our allocated memory */
|
2006-03-03 20:44:53 +00:00
|
|
|
#if defined(HAVE_SYSCONF) && defined(HAVE_MMAP) && defined(HAVE_MPROTECT) && defined(HAVE_STDINT_H)
|
|
|
|
#include <stdint.h>
|
2006-02-27 20:51:53 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
2006-06-17 02:31:56 +00:00
|
|
|
#if defined(MAP_ANONYMOUS)
|
|
|
|
#define ANON_PAGE_MODE (MAP_ANONYMOUS|MAP_PRIVATE)
|
|
|
|
#elif defined(MAP_ANON)
|
|
|
|
#define ANON_PAGE_MODE (MAP_ANON|MAP_PRIVATE)
|
|
|
|
#else
|
|
|
|
#define ANON_PAGE_MODE (MAP_PRIVATE) /* have to map /dev/zero */
|
|
|
|
#define NEED_DEV_ZERO
|
|
|
|
#endif
|
|
|
|
#ifdef NEED_DEV_ZERO
|
|
|
|
#include <fcntl.h>
|
|
|
|
static int dev_zero_fd;
|
|
|
|
#define ANON_FD dev_zero_fd
|
|
|
|
#else
|
|
|
|
#define ANON_FD -1
|
|
|
|
#endif
|
2006-02-27 20:51:53 +00:00
|
|
|
#define USE_GUARD_PAGES 1
|
|
|
|
#endif
|
2006-03-10 05:15:52 +00:00
|
|
|
#endif
|
2006-02-27 20:51:53 +00:00
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
/* When required, allocate more memory from the OS in this size chunks */
|
|
|
|
#define EMEM_PACKET_CHUNK_SIZE 10485760
|
|
|
|
|
2006-01-09 23:11:40 +00:00
|
|
|
/* The maximum number of allocations per chunk */
|
|
|
|
#define EMEM_ALLOCS_PER_CHUNK (EMEM_PACKET_CHUNK_SIZE / 512)
|
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
#define EMEM_CANARY_SIZE 8
|
|
|
|
#define EMEM_CANARY_DATA_SIZE (EMEM_CANARY_SIZE * 2 - 1)
|
2008-08-05 02:23:35 +00:00
|
|
|
|
|
|
|
/* this should be static, but if it were gdb would had problems finding it */
|
2009-08-11 09:24:56 +00:00
|
|
|
guint8 ep_canary[EMEM_CANARY_DATA_SIZE];
|
|
|
|
guint8 se_canary[EMEM_CANARY_DATA_SIZE];
|
|
|
|
|
|
|
|
typedef struct _emem_no_chunk_t {
|
|
|
|
unsigned int c_count;
|
|
|
|
void *canary[EMEM_ALLOCS_PER_CHUNK];
|
|
|
|
guint8 cmp_len[EMEM_ALLOCS_PER_CHUNK];
|
|
|
|
} emem_canary_t;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
typedef struct _emem_chunk_t {
|
|
|
|
struct _emem_chunk_t *next;
|
2009-08-11 09:24:56 +00:00
|
|
|
char *buf;
|
2006-02-27 20:51:53 +00:00
|
|
|
unsigned int amount_free_init;
|
2005-07-22 07:46:58 +00:00
|
|
|
unsigned int amount_free;
|
2006-02-27 20:51:53 +00:00
|
|
|
unsigned int free_offset_init;
|
2005-07-22 07:46:58 +00:00
|
|
|
unsigned int free_offset;
|
2009-08-11 09:24:56 +00:00
|
|
|
emem_canary_t *canary_info;
|
2005-07-22 07:46:58 +00:00
|
|
|
} emem_chunk_t;
|
|
|
|
|
|
|
|
typedef struct _emem_header_t {
|
2009-04-14 14:08:19 +00:00
|
|
|
emem_chunk_t *free_list;
|
|
|
|
emem_chunk_t *used_list;
|
2005-07-22 07:46:58 +00:00
|
|
|
} emem_header_t;
|
|
|
|
|
2008-04-21 08:58:50 +00:00
|
|
|
static emem_header_t ep_packet_mem;
|
|
|
|
static emem_header_t se_packet_mem;
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2006-04-28 16:40:39 +00:00
|
|
|
#if defined (_WIN32)
|
|
|
|
static SYSTEM_INFO sysinfo;
|
|
|
|
static OSVERSIONINFO versinfo;
|
|
|
|
static int pagesize;
|
|
|
|
#elif defined(USE_GUARD_PAGES)
|
|
|
|
static intptr_t pagesize;
|
|
|
|
#endif /* _WIN32 / USE_GUARD_PAGES */
|
2006-03-10 05:39:57 +00:00
|
|
|
|
2006-01-09 23:11:40 +00:00
|
|
|
/*
|
|
|
|
* Set a canary value to be placed between memchunks.
|
|
|
|
*/
|
2006-01-10 21:12:48 +00:00
|
|
|
void
|
|
|
|
emem_canary(guint8 *canary) {
|
|
|
|
int i;
|
2006-03-10 05:15:52 +00:00
|
|
|
static GRand *rand_state = NULL;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
|
|
|
if (rand_state == NULL) {
|
|
|
|
rand_state = g_rand_new();
|
|
|
|
}
|
2006-01-10 21:12:48 +00:00
|
|
|
for (i = 0; i < EMEM_CANARY_DATA_SIZE; i ++) {
|
|
|
|
canary[i] = (guint8) g_rand_int(rand_state);
|
|
|
|
}
|
|
|
|
return;
|
2006-01-09 23:11:40 +00:00
|
|
|
}
|
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
/*
|
|
|
|
* Given an allocation size, return the amount of padding needed for
|
|
|
|
* the canary value.
|
|
|
|
*/
|
2006-01-11 02:05:05 +00:00
|
|
|
static guint8
|
2006-01-10 21:12:48 +00:00
|
|
|
emem_canary_pad (size_t allocation) {
|
|
|
|
guint8 pad;
|
|
|
|
|
|
|
|
pad = EMEM_CANARY_SIZE - (allocation % EMEM_CANARY_SIZE);
|
|
|
|
if (pad < EMEM_CANARY_SIZE)
|
|
|
|
pad += EMEM_CANARY_SIZE;
|
|
|
|
|
|
|
|
return pad;
|
|
|
|
}
|
2006-03-10 05:39:57 +00:00
|
|
|
|
2008-08-05 02:23:35 +00:00
|
|
|
/* used for debugging canaries, will block */
|
|
|
|
#ifdef DEBUG_INTENSE_CANARY_CHECKS
|
|
|
|
gboolean intense_canary_checking = FALSE;
|
|
|
|
|
|
|
|
/* used to intensivelly check ep canaries
|
|
|
|
*/
|
|
|
|
void ep_check_canary_integrity(const char* fmt, ...) {
|
2009-04-14 14:08:19 +00:00
|
|
|
va_list ap;
|
|
|
|
static gchar there[128] = {
|
|
|
|
'L','a','u','n','c','h',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
|
|
|
|
gchar here[128];
|
2008-08-05 02:23:35 +00:00
|
|
|
emem_chunk_t* npc = NULL;
|
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
if (! intense_canary_checking ) return;
|
2008-08-05 02:23:35 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
here[126] = '\0';
|
|
|
|
here[127] = '\0';
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
va_start(ap,fmt);
|
|
|
|
g_vsnprintf(here, 126,fmt, ap);
|
|
|
|
va_end(ap);
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2008-08-05 02:23:35 +00:00
|
|
|
for (npc = ep_packet_mem.free_list; npc != NULL; npc = npc->next) {
|
2009-04-14 14:08:19 +00:00
|
|
|
static unsigned i_ctr;
|
2008-08-05 02:23:35 +00:00
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
if (npc->canary_info->c_count > 0x00ffffff) {
|
2009-04-14 14:08:19 +00:00
|
|
|
g_error("ep_packet_mem.free_list was corrupted\nbetween: %s\nand: %s",there, here);
|
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
for (i_ctr = 0; i_ctr < npc->canary_info->c_count; i_ctr++) {
|
|
|
|
if (memcmp(npc->canary_info->canary[i_ctr], &ep_canary, npc->canary_info->cmp_len[i_ctr]) != 0) {
|
2008-08-05 02:23:35 +00:00
|
|
|
g_error("Per-packet memory corrupted\nbetween: %s\nand: %s",there, here);
|
2009-04-14 14:08:19 +00:00
|
|
|
}
|
2008-08-05 02:23:35 +00:00
|
|
|
}
|
2009-04-14 14:08:19 +00:00
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
strncpy(there,here,126);
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2008-08-05 02:23:35 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-01-10 21:12:48 +00:00
|
|
|
|
2005-07-22 07:46:58 +00:00
|
|
|
/* Initialize the packet-lifetime memory allocation pool.
|
2006-05-31 17:38:42 +00:00
|
|
|
* This function should be called only once when Wireshark or TShark starts
|
2005-07-22 07:46:58 +00:00
|
|
|
* up.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ep_init_chunk(void)
|
|
|
|
{
|
2006-01-09 23:11:40 +00:00
|
|
|
ep_packet_mem.free_list=NULL;
|
|
|
|
ep_packet_mem.used_list=NULL;
|
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
ep_debug_use_chunks = (gboolean) (!getenv("WIRESHARK_DEBUG_EP_NO_CHUNKS"));
|
|
|
|
ep_debug_use_canary = (gboolean) (!getenv("WIRESHARK_DEBUG_EP_NO_CANARY"));
|
|
|
|
|
2008-08-05 02:23:35 +00:00
|
|
|
#ifdef DEBUG_INTENSE_CANARY_CHECKS
|
2009-08-11 09:24:56 +00:00
|
|
|
intense_canary_checking = (gboolean)getenv("WIRESHARK_DEBUG_EP_INTENSE_CANARY");
|
2008-08-05 02:23:35 +00:00
|
|
|
#endif
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
if (ep_debug_use_canary)
|
|
|
|
emem_canary(ep_canary);
|
2006-04-28 16:40:39 +00:00
|
|
|
|
|
|
|
#if defined (_WIN32)
|
|
|
|
/* Set up our guard page info for Win32 */
|
|
|
|
GetSystemInfo(&sysinfo);
|
|
|
|
pagesize = sysinfo.dwPageSize;
|
|
|
|
|
2006-05-18 00:25:14 +00:00
|
|
|
/* calling GetVersionEx using the OSVERSIONINFO structure.
|
|
|
|
* OSVERSIONINFOEX requires Win NT4 with SP6 or newer NT Versions.
|
|
|
|
* OSVERSIONINFOEX will fail on Win9x and older NT Versions.
|
|
|
|
* See also:
|
|
|
|
* http://msdn.microsoft.com/library/en-us/sysinfo/base/getversionex.asp
|
|
|
|
* http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
|
|
|
|
* http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfoex_str.asp
|
|
|
|
*/
|
|
|
|
versinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
GetVersionEx(&versinfo);
|
|
|
|
|
2006-04-28 16:40:39 +00:00
|
|
|
#elif defined(USE_GUARD_PAGES)
|
|
|
|
pagesize = sysconf(_SC_PAGESIZE);
|
2006-06-17 02:31:56 +00:00
|
|
|
#ifdef NEED_DEV_ZERO
|
2008-05-23 05:55:34 +00:00
|
|
|
dev_zero_fd = ws_open("/dev/zero", O_RDWR);
|
2006-06-17 02:31:56 +00:00
|
|
|
g_assert(dev_zero_fd != -1);
|
|
|
|
#endif
|
2006-04-28 16:40:39 +00:00
|
|
|
#endif /* _WIN32 / USE_GUARD_PAGES */
|
2006-05-18 00:25:14 +00:00
|
|
|
}
|
2009-08-11 09:24:56 +00:00
|
|
|
|
2005-08-12 08:51:08 +00:00
|
|
|
/* Initialize the capture-lifetime memory allocation pool.
|
2006-05-31 17:38:42 +00:00
|
|
|
* This function should be called only once when Wireshark or TShark starts
|
2005-08-12 08:51:08 +00:00
|
|
|
* up.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
se_init_chunk(void)
|
|
|
|
{
|
2006-01-09 23:11:40 +00:00
|
|
|
se_packet_mem.free_list=NULL;
|
|
|
|
se_packet_mem.used_list=NULL;
|
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
se_debug_use_chunks = (gboolean) (!getenv("WIRESHARK_DEBUG_SE_NO_CHUNKS"));
|
|
|
|
se_debug_use_canary = (gboolean) (!getenv("WIRESHARK_DEBUG_SE_NO_CANARY"));
|
|
|
|
|
|
|
|
if (se_debug_use_canary)
|
|
|
|
emem_canary(se_canary);
|
2005-07-22 07:46:58 +00:00
|
|
|
}
|
|
|
|
|
2006-02-27 20:51:53 +00:00
|
|
|
static void
|
2009-08-11 09:24:56 +00:00
|
|
|
emem_create_chunk(emem_chunk_t **free_list, gboolean use_canary) {
|
2006-02-27 20:51:53 +00:00
|
|
|
#if defined (_WIN32)
|
|
|
|
BOOL ret;
|
|
|
|
char *buf_end, *prot1, *prot2;
|
|
|
|
DWORD oldprot;
|
|
|
|
#elif defined(USE_GUARD_PAGES)
|
2006-03-03 20:44:53 +00:00
|
|
|
int ret;
|
2006-02-27 20:51:53 +00:00
|
|
|
char *buf_end, *prot1, *prot2;
|
2006-04-28 16:40:39 +00:00
|
|
|
#endif /* _WIN32 / USE_GUARD_PAGES */
|
2006-02-27 20:51:53 +00:00
|
|
|
/* we dont have any free data, so we must allocate a new one */
|
|
|
|
if(!*free_list){
|
|
|
|
emem_chunk_t *npc;
|
|
|
|
npc = g_malloc(sizeof(emem_chunk_t));
|
|
|
|
npc->next = NULL;
|
2009-08-11 09:24:56 +00:00
|
|
|
if (use_canary) {
|
|
|
|
npc->canary_info = g_new(emem_canary_t, 1);
|
|
|
|
npc->canary_info->c_count = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
npc->canary_info = NULL;
|
2006-03-10 05:39:57 +00:00
|
|
|
|
2006-02-27 20:51:53 +00:00
|
|
|
*free_list = npc;
|
|
|
|
#if defined (_WIN32)
|
|
|
|
/*
|
|
|
|
* MSDN documents VirtualAlloc/VirtualProtect at
|
|
|
|
* http://msdn.microsoft.com/library/en-us/memory/base/creating_guard_pages.asp
|
|
|
|
*/
|
2006-04-26 21:06:52 +00:00
|
|
|
|
2006-02-27 20:51:53 +00:00
|
|
|
/* XXX - is MEM_COMMIT|MEM_RESERVE correct? */
|
|
|
|
npc->buf = VirtualAlloc(NULL, EMEM_PACKET_CHUNK_SIZE,
|
|
|
|
MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
|
2009-04-14 14:08:19 +00:00
|
|
|
if(npc->buf == NULL) {
|
|
|
|
THROW(OutOfMemoryError);
|
2007-01-15 05:16:13 +00:00
|
|
|
}
|
2006-02-27 20:51:53 +00:00
|
|
|
buf_end = npc->buf + EMEM_PACKET_CHUNK_SIZE;
|
|
|
|
|
|
|
|
/* Align our guard pages on page-sized boundaries */
|
|
|
|
prot1 = (char *) ((((int) npc->buf + pagesize - 1) / pagesize) * pagesize);
|
|
|
|
prot2 = (char *) ((((int) buf_end - (1 * pagesize)) / pagesize) * pagesize);
|
|
|
|
|
|
|
|
ret = VirtualProtect(prot1, pagesize, PAGE_NOACCESS, &oldprot);
|
2006-05-15 21:42:02 +00:00
|
|
|
g_assert(ret != 0 || versinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
2006-02-27 20:51:53 +00:00
|
|
|
ret = VirtualProtect(prot2, pagesize, PAGE_NOACCESS, &oldprot);
|
2006-05-15 21:42:02 +00:00
|
|
|
g_assert(ret != 0 || versinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
2006-02-27 20:51:53 +00:00
|
|
|
|
2009-04-07 16:36:52 +00:00
|
|
|
npc->amount_free_init = (unsigned int) (prot2 - prot1 - pagesize);
|
2006-02-27 20:51:53 +00:00
|
|
|
npc->amount_free = npc->amount_free_init;
|
2009-04-07 16:36:52 +00:00
|
|
|
npc->free_offset_init = (unsigned int) (prot1 - npc->buf) + pagesize;
|
2006-02-27 20:51:53 +00:00
|
|
|
npc->free_offset = npc->free_offset_init;
|
|
|
|
|
|
|
|
#elif defined(USE_GUARD_PAGES)
|
|
|
|
npc->buf = mmap(NULL, EMEM_PACKET_CHUNK_SIZE,
|
2006-06-17 02:31:56 +00:00
|
|
|
PROT_READ|PROT_WRITE, ANON_PAGE_MODE, ANON_FD, 0);
|
2009-04-14 14:08:19 +00:00
|
|
|
if(npc->buf == MAP_FAILED) {
|
|
|
|
/* XXX - what do we have to cleanup here? */
|
|
|
|
THROW(OutOfMemoryError);
|
2007-01-15 05:16:13 +00:00
|
|
|
}
|
2006-02-27 20:51:53 +00:00
|
|
|
buf_end = npc->buf + EMEM_PACKET_CHUNK_SIZE;
|
|
|
|
|
|
|
|
/* Align our guard pages on page-sized boundaries */
|
2006-03-03 20:44:53 +00:00
|
|
|
prot1 = (char *) ((((intptr_t) npc->buf + pagesize - 1) / pagesize) * pagesize);
|
|
|
|
prot2 = (char *) ((((intptr_t) buf_end - (1 * pagesize)) / pagesize) * pagesize);
|
2006-02-27 20:51:53 +00:00
|
|
|
ret = mprotect(prot1, pagesize, PROT_NONE);
|
|
|
|
g_assert(ret != -1);
|
|
|
|
ret = mprotect(prot2, pagesize, PROT_NONE);
|
|
|
|
g_assert(ret != -1);
|
|
|
|
|
|
|
|
npc->amount_free_init = prot2 - prot1 - pagesize;
|
|
|
|
npc->amount_free = npc->amount_free_init;
|
|
|
|
npc->free_offset_init = (prot1 - npc->buf) + pagesize;
|
|
|
|
npc->free_offset = npc->free_offset_init;
|
|
|
|
|
|
|
|
#else /* Is there a draft in here? */
|
2007-01-15 05:16:13 +00:00
|
|
|
npc->buf = malloc(EMEM_PACKET_CHUNK_SIZE);
|
2009-04-14 14:08:19 +00:00
|
|
|
if(npc->buf == NULL) {
|
|
|
|
THROW(OutOfMemoryError);
|
2007-01-15 05:16:13 +00:00
|
|
|
}
|
2006-02-27 20:51:53 +00:00
|
|
|
npc->amount_free_init = EMEM_PACKET_CHUNK_SIZE;
|
|
|
|
npc->amount_free = npc->amount_free_init;
|
|
|
|
npc->free_offset_init = 0;
|
|
|
|
npc->free_offset = npc->free_offset_init;
|
|
|
|
#endif /* USE_GUARD_PAGES */
|
2006-01-09 23:11:40 +00:00
|
|
|
}
|
2006-02-27 20:51:53 +00:00
|
|
|
}
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2009-08-09 19:23:13 +00:00
|
|
|
/* allocate 'size' amount of memory. */
|
|
|
|
static void *
|
2009-08-11 09:24:56 +00:00
|
|
|
emem_alloc(size_t size, emem_header_t *mem, gboolean use_chunks, guint8 *canary)
|
2005-07-22 07:46:58 +00:00
|
|
|
{
|
2006-03-07 16:31:47 +00:00
|
|
|
void *buf;
|
|
|
|
void *cptr;
|
2009-08-11 09:24:56 +00:00
|
|
|
guint8 pad;
|
2006-01-10 21:12:48 +00:00
|
|
|
emem_chunk_t *free_list;
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
if (use_chunks) {
|
|
|
|
gboolean use_canary = canary != NULL;
|
|
|
|
/* Round up to an 8 byte boundary. Make sure we have at least
|
2009-08-09 19:23:13 +00:00
|
|
|
* 8 pad bytes for our canary.
|
|
|
|
*/
|
2009-08-11 09:24:56 +00:00
|
|
|
if (use_canary)
|
|
|
|
pad = emem_canary_pad(size);
|
|
|
|
else
|
|
|
|
pad = 8;
|
|
|
|
|
2009-08-09 19:23:13 +00:00
|
|
|
size += pad;
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2009-08-09 19:23:13 +00:00
|
|
|
/* make sure we dont try to allocate too much (arbitrary limit) */
|
|
|
|
DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2));
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
emem_create_chunk(&mem->free_list, use_canary);
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2009-08-09 19:23:13 +00:00
|
|
|
/* oops, we need to allocate more memory to serve this request
|
|
|
|
* than we have free. move this node to the used list and try again
|
|
|
|
*/
|
2009-08-11 09:24:56 +00:00
|
|
|
if(size>mem->free_list->amount_free ||
|
|
|
|
(use_canary &&
|
|
|
|
mem->free_list->canary_info->c_count >= EMEM_ALLOCS_PER_CHUNK)) {
|
2009-08-09 19:23:13 +00:00
|
|
|
emem_chunk_t *npc;
|
|
|
|
npc=mem->free_list;
|
|
|
|
mem->free_list=mem->free_list->next;
|
|
|
|
npc->next=mem->used_list;
|
|
|
|
mem->used_list=npc;
|
|
|
|
}
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
emem_create_chunk(&mem->free_list, use_canary);
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2009-08-09 19:23:13 +00:00
|
|
|
free_list = mem->free_list;
|
2006-01-10 21:12:48 +00:00
|
|
|
|
2009-08-09 19:23:13 +00:00
|
|
|
buf = free_list->buf + free_list->free_offset;
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2009-08-09 19:23:13 +00:00
|
|
|
free_list->amount_free -= (unsigned int) size;
|
|
|
|
free_list->free_offset += (unsigned int) size;
|
2005-08-12 08:51:08 +00:00
|
|
|
|
2009-08-11 09:24:56 +00:00
|
|
|
if (use_canary) {
|
|
|
|
cptr = (char *)buf + size - pad;
|
|
|
|
memcpy(cptr, canary, pad);
|
|
|
|
free_list->canary_info->canary[free_list->canary_info->c_count] = cptr;
|
|
|
|
free_list->canary_info->cmp_len[free_list->canary_info->c_count] = pad;
|
|
|
|
free_list->canary_info->c_count++;
|
|
|
|
}
|
2009-08-09 19:23:13 +00:00
|
|
|
} else {
|
|
|
|
emem_chunk_t *npc;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2009-08-09 19:23:13 +00:00
|
|
|
npc=g_malloc(sizeof(emem_chunk_t));
|
|
|
|
npc->next=mem->used_list;
|
|
|
|
npc->buf=g_malloc(size);
|
2009-08-11 09:24:56 +00:00
|
|
|
npc->canary_info = NULL;
|
2009-08-09 19:23:13 +00:00
|
|
|
buf = npc->buf;
|
|
|
|
mem->used_list=npc;
|
|
|
|
}
|
2005-08-26 15:45:31 +00:00
|
|
|
|
2005-08-12 08:51:08 +00:00
|
|
|
return buf;
|
|
|
|
}
|
2009-08-09 19:23:13 +00:00
|
|
|
|
|
|
|
/* allocate 'size' amount of memory with an allocation lifetime until the
|
|
|
|
* next packet.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
ep_alloc(size_t size)
|
|
|
|
{
|
2009-08-11 09:24:56 +00:00
|
|
|
if (ep_debug_use_chunks)
|
|
|
|
if (ep_debug_use_canary)
|
|
|
|
return emem_alloc(size, &ep_packet_mem, TRUE, ep_canary);
|
|
|
|
else
|
|
|
|
return emem_alloc(size, &ep_packet_mem, TRUE, NULL);
|
|
|
|
else
|
|
|
|
return emem_alloc(size, &ep_packet_mem, FALSE, NULL);
|
2009-08-09 19:23:13 +00:00
|
|
|
}
|
|
|
|
|
2005-08-12 08:51:08 +00:00
|
|
|
/* allocate 'size' amount of memory with an allocation lifetime until the
|
|
|
|
* next capture.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
se_alloc(size_t size)
|
|
|
|
{
|
2009-08-11 09:24:56 +00:00
|
|
|
if (se_debug_use_chunks)
|
|
|
|
if (se_debug_use_canary)
|
|
|
|
return emem_alloc(size, &se_packet_mem, TRUE, se_canary);
|
|
|
|
else
|
|
|
|
return emem_alloc(size, &se_packet_mem, TRUE, NULL);
|
|
|
|
else
|
|
|
|
return emem_alloc(size, &se_packet_mem, FALSE, NULL);
|
2005-07-22 07:46:58 +00:00
|
|
|
}
|
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
void* ep_alloc0(size_t size) {
|
|
|
|
return memset(ep_alloc(size),'\0',size);
|
|
|
|
}
|
2005-07-24 00:29:57 +00:00
|
|
|
|
|
|
|
gchar* ep_strdup(const gchar* src) {
|
2009-04-07 16:36:52 +00:00
|
|
|
guint len = (guint) strlen(src);
|
2005-07-24 00:29:57 +00:00
|
|
|
gchar* dst;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
dst = strncpy(ep_alloc(len+1), src, len);
|
|
|
|
|
|
|
|
dst[len] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar* ep_strndup(const gchar* src, size_t len) {
|
2005-10-08 12:35:51 +00:00
|
|
|
gchar* dst = ep_alloc(len+1);
|
2005-10-10 08:24:56 +00:00
|
|
|
guint i;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2008-01-07 20:44:32 +00:00
|
|
|
for (i = 0; (i < len) && src[i]; i++)
|
2005-10-10 08:24:56 +00:00
|
|
|
dst[i] = src[i];
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-10-08 12:35:51 +00:00
|
|
|
dst[i] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2006-02-14 08:34:20 +00:00
|
|
|
void* ep_memdup(const void* src, size_t len) {
|
2005-07-24 00:29:57 +00:00
|
|
|
return memcpy(ep_alloc(len), src, len);
|
|
|
|
}
|
|
|
|
|
2005-10-10 08:24:56 +00:00
|
|
|
gchar* ep_strdup_vprintf(const gchar* fmt, va_list ap) {
|
|
|
|
va_list ap2;
|
2009-04-07 16:36:52 +00:00
|
|
|
gsize len;
|
2005-10-10 08:24:56 +00:00
|
|
|
gchar* dst;
|
|
|
|
|
|
|
|
G_VA_COPY(ap2, ap);
|
|
|
|
|
|
|
|
len = g_printf_string_upper_bound(fmt, ap);
|
|
|
|
|
|
|
|
dst = ep_alloc(len+1);
|
2009-04-07 16:36:52 +00:00
|
|
|
g_vsnprintf (dst, (gulong) len, fmt, ap2);
|
2005-10-10 08:24:56 +00:00
|
|
|
va_end(ap2);
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
gchar* ep_strdup_printf(const gchar* fmt, ...) {
|
|
|
|
va_list ap;
|
|
|
|
gchar* dst;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-24 00:29:57 +00:00
|
|
|
va_start(ap,fmt);
|
2005-10-10 08:24:56 +00:00
|
|
|
dst = ep_strdup_vprintf(fmt, ap);
|
2005-07-24 00:29:57 +00:00
|
|
|
va_end(ap);
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
gchar** ep_strsplit(const gchar* string, const gchar* sep, int max_tokens) {
|
|
|
|
gchar* splitted;
|
|
|
|
gchar* s;
|
|
|
|
guint tokens;
|
2005-07-27 00:45:02 +00:00
|
|
|
guint str_len;
|
|
|
|
guint sep_len;
|
2005-07-26 18:32:12 +00:00
|
|
|
guint i;
|
|
|
|
gchar** vec;
|
|
|
|
enum { AT_START, IN_PAD, IN_TOKEN } state;
|
|
|
|
guint curr_tok = 0;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
if ( ! string
|
|
|
|
|| ! sep
|
|
|
|
|| ! sep[0])
|
2005-07-26 18:32:12 +00:00
|
|
|
return NULL;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
s = splitted = ep_strdup(string);
|
2009-04-07 16:36:52 +00:00
|
|
|
str_len = (guint) strlen(splitted);
|
|
|
|
sep_len = (guint) strlen(sep);
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
if (max_tokens < 1) max_tokens = INT_MAX;
|
|
|
|
|
|
|
|
tokens = 1;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
while (tokens <= (guint)max_tokens && ( s = strstr(s,sep) )) {
|
|
|
|
tokens++;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
for(i=0; i < sep_len; i++ )
|
|
|
|
s[i] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
s += sep_len;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-07-27 00:45:02 +00:00
|
|
|
vec = ep_alloc_array(gchar*,tokens+1);
|
2005-07-26 18:32:12 +00:00
|
|
|
state = AT_START;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
for (i=0; i< str_len; i++) {
|
|
|
|
switch(state) {
|
|
|
|
case AT_START:
|
|
|
|
switch(splitted[i]) {
|
|
|
|
case '\0':
|
|
|
|
state = IN_PAD;
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
vec[curr_tok] = &(splitted[i]);
|
|
|
|
curr_tok++;
|
|
|
|
state = IN_TOKEN;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
case IN_TOKEN:
|
|
|
|
switch(splitted[i]) {
|
|
|
|
case '\0':
|
|
|
|
state = IN_PAD;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
case IN_PAD:
|
|
|
|
switch(splitted[i]) {
|
|
|
|
default:
|
|
|
|
vec[curr_tok] = &(splitted[i]);
|
|
|
|
curr_tok++;
|
|
|
|
state = IN_TOKEN;
|
|
|
|
case '\0':
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
vec[curr_tok] = NULL;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-07-26 18:32:12 +00:00
|
|
|
return vec;
|
|
|
|
}
|
2005-07-24 00:29:57 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
void* se_alloc0(size_t size) {
|
|
|
|
return memset(se_alloc(size),'\0',size);
|
|
|
|
}
|
|
|
|
|
2005-12-09 22:06:38 +00:00
|
|
|
/* If str is NULL, just return the string "<NULL>" so that the callers dont
|
|
|
|
* have to bother checking it.
|
|
|
|
*/
|
2005-08-16 00:55:08 +00:00
|
|
|
gchar* se_strdup(const gchar* src) {
|
2005-12-09 22:06:38 +00:00
|
|
|
guint len;
|
2005-08-16 00:55:08 +00:00
|
|
|
gchar* dst;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-12-09 22:06:38 +00:00
|
|
|
if(!src){
|
|
|
|
return "<NULL>";
|
|
|
|
}
|
|
|
|
|
2009-04-07 16:36:52 +00:00
|
|
|
len = (guint) strlen(src);
|
2005-08-16 00:55:08 +00:00
|
|
|
dst = strncpy(se_alloc(len+1), src, len);
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
dst[len] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar* se_strndup(const gchar* src, size_t len) {
|
2005-10-08 12:35:51 +00:00
|
|
|
gchar* dst = se_alloc(len+1);
|
2005-10-10 08:24:56 +00:00
|
|
|
guint i;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2008-01-07 20:44:32 +00:00
|
|
|
for (i = 0; (i < len) && src[i]; i++)
|
2005-10-10 08:24:56 +00:00
|
|
|
dst[i] = src[i];
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-10-08 12:35:51 +00:00
|
|
|
dst[i] = '\0';
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2006-02-14 08:34:20 +00:00
|
|
|
void* se_memdup(const void* src, size_t len) {
|
2005-08-16 00:55:08 +00:00
|
|
|
return memcpy(se_alloc(len), src, len);
|
|
|
|
}
|
|
|
|
|
2005-10-10 08:24:56 +00:00
|
|
|
gchar* se_strdup_vprintf(const gchar* fmt, va_list ap) {
|
|
|
|
va_list ap2;
|
2009-04-07 16:36:52 +00:00
|
|
|
gsize len;
|
2005-10-10 08:24:56 +00:00
|
|
|
gchar* dst;
|
|
|
|
|
|
|
|
G_VA_COPY(ap2, ap);
|
|
|
|
|
|
|
|
len = g_printf_string_upper_bound(fmt, ap);
|
|
|
|
|
|
|
|
dst = se_alloc(len+1);
|
2009-04-07 16:36:52 +00:00
|
|
|
g_vsnprintf (dst, (gulong) len, fmt, ap2);
|
2005-10-10 08:24:56 +00:00
|
|
|
va_end(ap2);
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
gchar* se_strdup_printf(const gchar* fmt, ...) {
|
|
|
|
va_list ap;
|
|
|
|
gchar* dst;
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2005-08-16 00:55:08 +00:00
|
|
|
va_start(ap,fmt);
|
2005-10-10 08:24:56 +00:00
|
|
|
dst = se_strdup_vprintf(fmt, ap);
|
2005-08-16 00:55:08 +00:00
|
|
|
va_end(ap);
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2009-08-09 20:10:19 +00:00
|
|
|
/* release all allocated memory back to the pool. */
|
|
|
|
static void
|
2009-08-11 09:24:56 +00:00
|
|
|
emem_free_all(emem_header_t *mem, gboolean use_chunks, guint8 *canary, emem_tree_t *trees)
|
2005-07-22 07:46:58 +00:00
|
|
|
{
|
|
|
|
emem_chunk_t *npc;
|
2009-08-09 20:10:19 +00:00
|
|
|
emem_tree_t *tree_list;
|
2006-01-09 23:11:40 +00:00
|
|
|
guint i;
|
2005-07-22 07:46:58 +00:00
|
|
|
|
2005-08-26 15:45:31 +00:00
|
|
|
/* move all used chunks over to the free list */
|
2009-08-09 20:10:19 +00:00
|
|
|
while(mem->used_list){
|
|
|
|
npc=mem->used_list;
|
|
|
|
mem->used_list=mem->used_list->next;
|
|
|
|
npc->next=mem->free_list;
|
|
|
|
mem->free_list=npc;
|
2005-08-12 08:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* clear them all out */
|
2009-08-09 20:10:19 +00:00
|
|
|
npc = mem->free_list;
|
2005-08-26 15:45:31 +00:00
|
|
|
while (npc != NULL) {
|
2009-08-11 09:24:56 +00:00
|
|
|
if (use_chunks) {
|
|
|
|
if (canary) {
|
|
|
|
for (i = 0; i < npc->canary_info->c_count; i++) {
|
|
|
|
if (memcmp(npc->canary_info->canary[i], canary, npc->canary_info->cmp_len[i]) != 0)
|
|
|
|
g_error("Memory corrupted");
|
|
|
|
}
|
|
|
|
npc->canary_info->c_count = 0;
|
2009-08-09 20:10:19 +00:00
|
|
|
}
|
|
|
|
npc->amount_free = npc->amount_free_init;
|
|
|
|
npc->free_offset = npc->free_offset_init;
|
|
|
|
npc = npc->next;
|
|
|
|
} else {
|
|
|
|
emem_chunk_t *next = npc->next;
|
|
|
|
|
|
|
|
g_free(npc->buf);
|
|
|
|
g_free(npc);
|
|
|
|
npc = next;
|
|
|
|
}
|
2005-08-12 08:51:08 +00:00
|
|
|
}
|
2005-08-26 15:45:31 +00:00
|
|
|
|
2009-08-09 20:10:19 +00:00
|
|
|
/* release/reset all allocated trees */
|
|
|
|
for(tree_list=trees;tree_list;tree_list=tree_list->next){
|
|
|
|
tree_list->tree=NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* release all allocated memory back to the pool. */
|
|
|
|
void
|
|
|
|
ep_free_all(void)
|
|
|
|
{
|
2009-08-11 09:24:56 +00:00
|
|
|
if (ep_debug_use_chunks)
|
|
|
|
if (ep_debug_use_canary)
|
|
|
|
emem_free_all(&ep_packet_mem, TRUE, ep_canary, NULL /* trees */);
|
|
|
|
else
|
|
|
|
emem_free_all(&ep_packet_mem, TRUE, NULL, NULL /* trees */);
|
|
|
|
else
|
|
|
|
emem_free_all(&ep_packet_mem, FALSE, NULL, NULL /* trees */);
|
|
|
|
|
|
|
|
if (!ep_debug_use_chunks)
|
|
|
|
ep_init_chunk();
|
2005-08-12 08:51:08 +00:00
|
|
|
}
|
2009-08-09 20:10:19 +00:00
|
|
|
|
|
|
|
/* release all allocated memory back to the pool. */
|
2005-08-12 08:51:08 +00:00
|
|
|
void
|
|
|
|
se_free_all(void)
|
|
|
|
{
|
2009-08-11 09:24:56 +00:00
|
|
|
if (se_debug_use_chunks)
|
|
|
|
if (se_debug_use_canary)
|
|
|
|
emem_free_all(&se_packet_mem, TRUE, se_canary, se_trees);
|
|
|
|
else
|
|
|
|
emem_free_all(&se_packet_mem, TRUE, NULL, se_trees);
|
|
|
|
else
|
|
|
|
emem_free_all(&se_packet_mem, FALSE, NULL, se_trees);
|
|
|
|
|
|
|
|
if (!se_debug_use_chunks)
|
|
|
|
se_init_chunk();
|
2005-07-22 07:46:58 +00:00
|
|
|
}
|
|
|
|
|
2005-10-01 10:36:57 +00:00
|
|
|
ep_stack_t ep_stack_new(void) {
|
2009-04-14 14:08:19 +00:00
|
|
|
ep_stack_t s = ep_new(struct _ep_stack_frame_t*);
|
|
|
|
*s = ep_new0(struct _ep_stack_frame_t);
|
|
|
|
return s;
|
2005-10-01 10:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* for ep_stack_t we'll keep the popped frames so we reuse them instead
|
|
|
|
of allocating new ones.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void* ep_stack_push(ep_stack_t stack, void* data) {
|
2009-04-14 14:08:19 +00:00
|
|
|
struct _ep_stack_frame_t* frame;
|
|
|
|
struct _ep_stack_frame_t* head = (*stack);
|
2005-10-01 10:36:57 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
if (head->above) {
|
|
|
|
frame = head->above;
|
|
|
|
} else {
|
|
|
|
frame = ep_new(struct _ep_stack_frame_t);
|
|
|
|
head->above = frame;
|
|
|
|
frame->below = head;
|
|
|
|
frame->above = NULL;
|
|
|
|
}
|
2005-10-01 10:36:57 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
frame->payload = data;
|
|
|
|
(*stack) = frame;
|
2005-10-01 10:36:57 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
return data;
|
2005-10-01 10:36:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void* ep_stack_pop(ep_stack_t stack) {
|
2006-01-09 23:11:40 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
if ((*stack)->below) {
|
|
|
|
(*stack) = (*stack)->below;
|
|
|
|
return (*stack)->above->payload;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-10-01 10:36:57 +00:00
|
|
|
}
|
|
|
|
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
|
2006-03-11 06:12:36 +00:00
|
|
|
#ifdef REMOVED
|
2006-08-14 08:29:29 +00:00
|
|
|
void print_tree_item(emem_tree_node_t *node, int level){
|
2006-03-11 06:12:36 +00:00
|
|
|
int i;
|
|
|
|
for(i=0;i<level;i++){
|
|
|
|
printf(" ");
|
|
|
|
}
|
2006-08-14 08:29:29 +00:00
|
|
|
printf("%s KEY:0x%08x node:0x%08x parent:0x%08x left:0x%08x right:0x%08x\n",node->u.rb_color==EMEM_TREE_RB_COLOR_BLACK?"BLACK":"RED",node->key32,(int)node,(int)node->parent,(int)node->left,(int)node->right);
|
2006-03-11 06:12:36 +00:00
|
|
|
if(node->left)
|
|
|
|
print_tree_item(node->left,level+1);
|
|
|
|
if(node->right)
|
|
|
|
print_tree_item(node->right,level+1);
|
|
|
|
}
|
|
|
|
|
2006-08-14 08:29:29 +00:00
|
|
|
void print_tree(emem_tree_node_t *node){
|
2006-03-11 06:12:36 +00:00
|
|
|
if(!node){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while(node->parent){
|
|
|
|
node=node->parent;
|
|
|
|
}
|
|
|
|
print_tree_item(node,0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* routines to manage se allocated red-black trees */
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_t *se_trees=NULL;
|
2006-03-05 04:01:34 +00:00
|
|
|
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_t *
|
2007-04-23 10:59:26 +00:00
|
|
|
se_tree_create(int type, const char *name)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_t *tree_list;
|
2006-03-05 04:01:34 +00:00
|
|
|
|
2006-08-14 08:29:29 +00:00
|
|
|
tree_list=malloc(sizeof(emem_tree_t));
|
2006-03-05 04:01:34 +00:00
|
|
|
tree_list->next=se_trees;
|
|
|
|
tree_list->type=type;
|
|
|
|
tree_list->tree=NULL;
|
2006-03-11 13:02:41 +00:00
|
|
|
tree_list->name=name;
|
2006-08-12 23:27:22 +00:00
|
|
|
tree_list->malloc=se_alloc;
|
2006-03-05 04:01:34 +00:00
|
|
|
se_trees=tree_list;
|
|
|
|
|
|
|
|
return tree_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void *
|
2006-08-14 09:36:15 +00:00
|
|
|
emem_tree_lookup32(emem_tree_t *se_tree, guint32 key)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *node;
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
node=se_tree->tree;
|
|
|
|
|
|
|
|
while(node){
|
|
|
|
if(key==node->key32){
|
|
|
|
return node->data;
|
|
|
|
}
|
|
|
|
if(key<node->key32){
|
|
|
|
node=node->left;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(key>node->key32){
|
|
|
|
node=node->right;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-03-18 06:15:39 +00:00
|
|
|
void *
|
2006-08-14 09:36:15 +00:00
|
|
|
emem_tree_lookup32_le(emem_tree_t *se_tree, guint32 key)
|
2006-03-18 06:15:39 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *node;
|
2006-03-18 06:15:39 +00:00
|
|
|
|
|
|
|
node=se_tree->tree;
|
|
|
|
|
|
|
|
if(!node){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while(node){
|
|
|
|
if(key==node->key32){
|
|
|
|
return node->data;
|
|
|
|
}
|
|
|
|
if(key<node->key32){
|
|
|
|
if(node->left){
|
|
|
|
node=node->left;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(key>node->key32){
|
|
|
|
if(node->right){
|
|
|
|
node=node->right;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-04-26 21:06:52 +00:00
|
|
|
/* If we are still at the root of the tree this means that this node
|
2009-04-14 14:08:19 +00:00
|
|
|
* is either smaller than the search key and then we return this
|
|
|
|
* node or else there is no smaller key available and then
|
2006-03-18 06:15:39 +00:00
|
|
|
* we return NULL.
|
|
|
|
*/
|
|
|
|
if(!node->parent){
|
|
|
|
if(key>node->key32){
|
|
|
|
return node->data;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(node->parent->left==node){
|
2006-04-26 21:06:52 +00:00
|
|
|
/* left child */
|
2006-03-18 06:15:39 +00:00
|
|
|
|
|
|
|
if(key>node->key32){
|
|
|
|
/* if this is a left child and its key is smaller than
|
|
|
|
* the search key, then this is the node we want.
|
|
|
|
*/
|
|
|
|
return node->data;
|
|
|
|
} else {
|
|
|
|
/* if this is a left child and its key is bigger than
|
|
|
|
* the search key, we have to check if any
|
|
|
|
* of our ancestors are smaller than the search key.
|
|
|
|
*/
|
|
|
|
while(node){
|
|
|
|
if(key>node->key32){
|
|
|
|
return node->data;
|
|
|
|
}
|
|
|
|
node=node->parent;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
2006-04-26 21:06:52 +00:00
|
|
|
/* right child */
|
2006-03-18 06:15:39 +00:00
|
|
|
|
|
|
|
if(node->key32<key){
|
2006-04-26 21:06:52 +00:00
|
|
|
/* if this is the right child and its key is smaller
|
2006-03-18 06:15:39 +00:00
|
|
|
* than the search key then this is the one we want.
|
|
|
|
*/
|
|
|
|
return node->data;
|
|
|
|
} else {
|
2006-04-26 21:06:52 +00:00
|
|
|
/* if this is the right child and its key is larger
|
|
|
|
* than the search key then our parent is the one we
|
2006-03-18 06:15:39 +00:00
|
|
|
* want.
|
|
|
|
*/
|
|
|
|
return node->parent->data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-03-05 04:01:34 +00:00
|
|
|
|
2006-08-14 08:29:29 +00:00
|
|
|
static inline emem_tree_node_t *
|
|
|
|
emem_tree_parent(emem_tree_node_t *node)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-03-11 23:16:34 +00:00
|
|
|
return node->parent;
|
|
|
|
}
|
|
|
|
|
2006-08-14 08:29:29 +00:00
|
|
|
static inline emem_tree_node_t *
|
|
|
|
emem_tree_grandparent(emem_tree_node_t *node)
|
2006-03-11 23:16:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *parent;
|
2006-03-11 23:16:34 +00:00
|
|
|
|
2006-08-12 22:43:12 +00:00
|
|
|
parent=emem_tree_parent(node);
|
2006-03-11 23:16:34 +00:00
|
|
|
if(parent){
|
|
|
|
return parent->parent;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-08-14 08:29:29 +00:00
|
|
|
static inline emem_tree_node_t *
|
|
|
|
emem_tree_uncle(emem_tree_node_t *node)
|
2006-03-11 23:16:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *parent, *grandparent;
|
2006-03-11 23:16:34 +00:00
|
|
|
|
2006-08-12 22:43:12 +00:00
|
|
|
parent=emem_tree_parent(node);
|
2006-03-11 23:16:34 +00:00
|
|
|
if(!parent){
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-08-12 22:43:12 +00:00
|
|
|
grandparent=emem_tree_parent(parent);
|
2006-03-11 23:16:34 +00:00
|
|
|
if(!grandparent){
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-03-05 04:01:34 +00:00
|
|
|
if(parent==grandparent->left){
|
|
|
|
return grandparent->right;
|
|
|
|
}
|
|
|
|
return grandparent->left;
|
|
|
|
}
|
|
|
|
|
2006-08-14 08:29:29 +00:00
|
|
|
static inline void rb_insert_case1(emem_tree_t *se_tree, emem_tree_node_t *node);
|
|
|
|
static inline void rb_insert_case2(emem_tree_t *se_tree, emem_tree_node_t *node);
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
static inline void
|
2006-08-14 08:29:29 +00:00
|
|
|
rotate_left(emem_tree_t *se_tree, emem_tree_node_t *node)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
|
|
|
if(node->parent){
|
|
|
|
if(node->parent->left==node){
|
|
|
|
node->parent->left=node->right;
|
|
|
|
} else {
|
|
|
|
node->parent->right=node->right;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
se_tree->tree=node->right;
|
|
|
|
}
|
|
|
|
node->right->parent=node->parent;
|
|
|
|
node->parent=node->right;
|
|
|
|
node->right=node->right->left;
|
|
|
|
if(node->right){
|
|
|
|
node->right->parent=node;
|
|
|
|
}
|
|
|
|
node->parent->left=node;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2006-08-14 08:29:29 +00:00
|
|
|
rotate_right(emem_tree_t *se_tree, emem_tree_node_t *node)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
|
|
|
if(node->parent){
|
|
|
|
if(node->parent->left==node){
|
|
|
|
node->parent->left=node->left;
|
|
|
|
} else {
|
|
|
|
node->parent->right=node->left;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
se_tree->tree=node->left;
|
|
|
|
}
|
|
|
|
node->left->parent=node->parent;
|
|
|
|
node->parent=node->left;
|
|
|
|
node->left=node->left->right;
|
|
|
|
if(node->left){
|
|
|
|
node->left->parent=node;
|
|
|
|
}
|
|
|
|
node->parent->right=node;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2006-08-14 08:29:29 +00:00
|
|
|
rb_insert_case5(emem_tree_t *se_tree, emem_tree_node_t *node)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *grandparent;
|
|
|
|
emem_tree_node_t *parent;
|
2006-03-11 23:16:34 +00:00
|
|
|
|
2006-08-12 22:43:12 +00:00
|
|
|
parent=emem_tree_parent(node);
|
|
|
|
grandparent=emem_tree_parent(parent);
|
2006-08-14 08:29:29 +00:00
|
|
|
parent->u.rb_color=EMEM_TREE_RB_COLOR_BLACK;
|
|
|
|
grandparent->u.rb_color=EMEM_TREE_RB_COLOR_RED;
|
2006-03-05 04:01:34 +00:00
|
|
|
if( (node==parent->left) && (parent==grandparent->left) ){
|
|
|
|
rotate_right(se_tree, grandparent);
|
|
|
|
} else {
|
|
|
|
rotate_left(se_tree, grandparent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2006-08-14 08:29:29 +00:00
|
|
|
rb_insert_case4(emem_tree_t *se_tree, emem_tree_node_t *node)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *grandparent;
|
|
|
|
emem_tree_node_t *parent;
|
2006-03-11 23:16:34 +00:00
|
|
|
|
2006-08-12 22:43:12 +00:00
|
|
|
parent=emem_tree_parent(node);
|
|
|
|
grandparent=emem_tree_parent(parent);
|
2006-03-11 23:16:34 +00:00
|
|
|
if(!grandparent){
|
|
|
|
return;
|
|
|
|
}
|
2006-03-05 04:01:34 +00:00
|
|
|
if( (node==parent->right) && (parent==grandparent->left) ){
|
|
|
|
rotate_left(se_tree, parent);
|
|
|
|
node=node->left;
|
|
|
|
} else if( (node==parent->left) && (parent==grandparent->right) ){
|
|
|
|
rotate_right(se_tree, parent);
|
|
|
|
node=node->right;
|
|
|
|
}
|
2006-03-11 23:16:34 +00:00
|
|
|
rb_insert_case5(se_tree, node);
|
2006-03-05 04:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2006-08-14 08:29:29 +00:00
|
|
|
rb_insert_case3(emem_tree_t *se_tree, emem_tree_node_t *node)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *grandparent;
|
|
|
|
emem_tree_node_t *parent;
|
|
|
|
emem_tree_node_t *uncle;
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-08-12 22:43:12 +00:00
|
|
|
uncle=emem_tree_uncle(node);
|
2006-08-14 08:29:29 +00:00
|
|
|
if(uncle && (uncle->u.rb_color==EMEM_TREE_RB_COLOR_RED)){
|
2006-08-12 22:43:12 +00:00
|
|
|
parent=emem_tree_parent(node);
|
2006-08-14 08:29:29 +00:00
|
|
|
parent->u.rb_color=EMEM_TREE_RB_COLOR_BLACK;
|
|
|
|
uncle->u.rb_color=EMEM_TREE_RB_COLOR_BLACK;
|
2006-08-12 22:43:12 +00:00
|
|
|
grandparent=emem_tree_grandparent(node);
|
2006-08-14 08:29:29 +00:00
|
|
|
grandparent->u.rb_color=EMEM_TREE_RB_COLOR_RED;
|
2006-03-11 06:12:36 +00:00
|
|
|
rb_insert_case1(se_tree, grandparent);
|
2006-03-05 04:01:34 +00:00
|
|
|
} else {
|
2006-03-11 23:16:34 +00:00
|
|
|
rb_insert_case4(se_tree, node);
|
2006-03-05 04:01:34 +00:00
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
}
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
static inline void
|
2006-08-14 08:29:29 +00:00
|
|
|
rb_insert_case2(emem_tree_t *se_tree, emem_tree_node_t *node)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *parent;
|
2006-03-11 23:16:34 +00:00
|
|
|
|
2006-08-12 22:43:12 +00:00
|
|
|
parent=emem_tree_parent(node);
|
2006-03-11 23:16:34 +00:00
|
|
|
/* parent is always non-NULL here */
|
2006-08-14 08:29:29 +00:00
|
|
|
if(parent->u.rb_color==EMEM_TREE_RB_COLOR_BLACK){
|
2006-03-05 04:01:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-03-11 23:16:34 +00:00
|
|
|
rb_insert_case3(se_tree, node);
|
2006-03-05 04:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2006-08-14 08:29:29 +00:00
|
|
|
rb_insert_case1(emem_tree_t *se_tree, emem_tree_node_t *node)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *parent;
|
2006-03-05 04:01:34 +00:00
|
|
|
|
2006-08-12 22:43:12 +00:00
|
|
|
parent=emem_tree_parent(node);
|
2006-03-05 04:01:34 +00:00
|
|
|
if(!parent){
|
2006-08-14 08:29:29 +00:00
|
|
|
node->u.rb_color=EMEM_TREE_RB_COLOR_BLACK;
|
2006-03-05 04:01:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-03-11 23:16:34 +00:00
|
|
|
rb_insert_case2(se_tree, node);
|
2006-03-05 04:01:34 +00:00
|
|
|
}
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2006-03-05 04:01:34 +00:00
|
|
|
/* insert a new node in the tree. if this node matches an already existing node
|
|
|
|
* then just replace the data for that node */
|
2006-03-07 16:31:47 +00:00
|
|
|
void
|
2006-08-14 09:36:15 +00:00
|
|
|
emem_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data)
|
2006-03-05 04:01:34 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *node;
|
2006-03-05 04:01:34 +00:00
|
|
|
|
|
|
|
node=se_tree->tree;
|
|
|
|
|
|
|
|
/* is this the first node ?*/
|
|
|
|
if(!node){
|
2006-08-14 08:29:29 +00:00
|
|
|
node=se_tree->malloc(sizeof(emem_tree_node_t));
|
2006-03-05 04:01:34 +00:00
|
|
|
switch(se_tree->type){
|
2006-08-14 08:29:29 +00:00
|
|
|
case EMEM_TREE_TYPE_RED_BLACK:
|
|
|
|
node->u.rb_color=EMEM_TREE_RB_COLOR_BLACK;
|
2006-03-05 04:01:34 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
node->parent=NULL;
|
|
|
|
node->left=NULL;
|
|
|
|
node->right=NULL;
|
|
|
|
node->key32=key;
|
|
|
|
node->data=data;
|
2007-12-04 01:44:05 +00:00
|
|
|
node->u.is_subtree = EMEM_TREE_NODE_IS_DATA;
|
2006-03-05 04:01:34 +00:00
|
|
|
se_tree->tree=node;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it was not the new root so walk the tree until we find where to
|
|
|
|
* insert this new leaf.
|
|
|
|
*/
|
|
|
|
while(1){
|
|
|
|
/* this node already exists, so just replace the data pointer*/
|
|
|
|
if(key==node->key32){
|
|
|
|
node->data=data;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(key<node->key32) {
|
|
|
|
if(!node->left){
|
|
|
|
/* new node to the left */
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *new_node;
|
|
|
|
new_node=se_tree->malloc(sizeof(emem_tree_node_t));
|
2006-03-05 04:01:34 +00:00
|
|
|
node->left=new_node;
|
|
|
|
new_node->parent=node;
|
|
|
|
new_node->left=NULL;
|
|
|
|
new_node->right=NULL;
|
|
|
|
new_node->key32=key;
|
|
|
|
new_node->data=data;
|
2007-12-04 01:44:05 +00:00
|
|
|
new_node->u.is_subtree=EMEM_TREE_NODE_IS_DATA;
|
2006-03-05 04:01:34 +00:00
|
|
|
node=new_node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node=node->left;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(key>node->key32) {
|
|
|
|
if(!node->right){
|
|
|
|
/* new node to the right */
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *new_node;
|
|
|
|
new_node=se_tree->malloc(sizeof(emem_tree_node_t));
|
2006-03-05 04:01:34 +00:00
|
|
|
node->right=new_node;
|
|
|
|
new_node->parent=node;
|
|
|
|
new_node->left=NULL;
|
|
|
|
new_node->right=NULL;
|
|
|
|
new_node->key32=key;
|
|
|
|
new_node->data=data;
|
2007-12-04 01:44:05 +00:00
|
|
|
new_node->u.is_subtree=EMEM_TREE_NODE_IS_DATA;
|
2006-03-05 04:01:34 +00:00
|
|
|
node=new_node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node=node->right;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* node will now point to the newly created node */
|
|
|
|
switch(se_tree->type){
|
2006-08-14 08:29:29 +00:00
|
|
|
case EMEM_TREE_TYPE_RED_BLACK:
|
|
|
|
node->u.rb_color=EMEM_TREE_RB_COLOR_RED;
|
2006-03-05 04:01:34 +00:00
|
|
|
rb_insert_case1(se_tree, node);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-04 01:44:05 +00:00
|
|
|
static void* lookup_or_insert32(emem_tree_t *se_tree, guint32 key, void*(*func)(void*),void* ud, int is_subtree) {
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *node;
|
2006-04-26 21:06:52 +00:00
|
|
|
|
2006-03-10 21:58:49 +00:00
|
|
|
node=se_tree->tree;
|
2006-04-26 21:06:52 +00:00
|
|
|
|
2006-03-10 21:58:49 +00:00
|
|
|
/* is this the first node ?*/
|
|
|
|
if(!node){
|
2006-08-14 08:29:29 +00:00
|
|
|
node=se_tree->malloc(sizeof(emem_tree_node_t));
|
2006-03-10 21:58:49 +00:00
|
|
|
switch(se_tree->type){
|
2006-08-14 08:29:29 +00:00
|
|
|
case EMEM_TREE_TYPE_RED_BLACK:
|
|
|
|
node->u.rb_color=EMEM_TREE_RB_COLOR_BLACK;
|
2006-03-10 21:58:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
node->parent=NULL;
|
|
|
|
node->left=NULL;
|
|
|
|
node->right=NULL;
|
|
|
|
node->key32=key;
|
|
|
|
node->data= func(ud);
|
2007-12-04 01:44:05 +00:00
|
|
|
node->u.is_subtree = is_subtree;
|
2006-03-10 21:58:49 +00:00
|
|
|
se_tree->tree=node;
|
|
|
|
return node->data;
|
|
|
|
}
|
2006-04-26 21:06:52 +00:00
|
|
|
|
2006-03-10 21:58:49 +00:00
|
|
|
/* it was not the new root so walk the tree until we find where to
|
|
|
|
* insert this new leaf.
|
|
|
|
*/
|
|
|
|
while(1){
|
|
|
|
/* this node already exists, so just return the data pointer*/
|
|
|
|
if(key==node->key32){
|
|
|
|
return node->data;
|
|
|
|
}
|
|
|
|
if(key<node->key32) {
|
|
|
|
if(!node->left){
|
|
|
|
/* new node to the left */
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *new_node;
|
|
|
|
new_node=se_tree->malloc(sizeof(emem_tree_node_t));
|
2006-03-10 21:58:49 +00:00
|
|
|
node->left=new_node;
|
|
|
|
new_node->parent=node;
|
|
|
|
new_node->left=NULL;
|
|
|
|
new_node->right=NULL;
|
|
|
|
new_node->key32=key;
|
|
|
|
new_node->data= func(ud);
|
2007-12-04 01:44:05 +00:00
|
|
|
new_node->u.is_subtree = is_subtree;
|
2006-03-10 21:58:49 +00:00
|
|
|
node=new_node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node=node->left;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(key>node->key32) {
|
|
|
|
if(!node->right){
|
|
|
|
/* new node to the right */
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_node_t *new_node;
|
|
|
|
new_node=se_tree->malloc(sizeof(emem_tree_node_t));
|
2006-03-10 21:58:49 +00:00
|
|
|
node->right=new_node;
|
|
|
|
new_node->parent=node;
|
|
|
|
new_node->left=NULL;
|
|
|
|
new_node->right=NULL;
|
|
|
|
new_node->key32=key;
|
|
|
|
new_node->data= func(ud);
|
2007-12-04 01:44:05 +00:00
|
|
|
new_node->u.is_subtree = is_subtree;
|
2006-03-10 21:58:49 +00:00
|
|
|
node=new_node;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
node=node->right;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2006-04-26 21:06:52 +00:00
|
|
|
|
2006-03-10 21:58:49 +00:00
|
|
|
/* node will now point to the newly created node */
|
|
|
|
switch(se_tree->type){
|
2006-08-14 08:29:29 +00:00
|
|
|
case EMEM_TREE_TYPE_RED_BLACK:
|
|
|
|
node->u.rb_color=EMEM_TREE_RB_COLOR_RED;
|
2006-03-10 21:58:49 +00:00
|
|
|
rb_insert_case1(se_tree, node);
|
|
|
|
break;
|
|
|
|
}
|
2006-04-26 21:06:52 +00:00
|
|
|
|
2006-03-10 21:58:49 +00:00
|
|
|
return node->data;
|
|
|
|
}
|
2006-03-05 04:01:34 +00:00
|
|
|
|
2006-03-07 16:31:47 +00:00
|
|
|
/* When the se data is released, this entire tree will dissapear as if it
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
* never existed including all metadata associated with the tree.
|
|
|
|
*/
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_t *
|
2007-04-23 10:59:26 +00:00
|
|
|
se_tree_create_non_persistent(int type, const char *name)
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_t *tree_list;
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
|
2006-08-14 08:29:29 +00:00
|
|
|
tree_list=se_alloc(sizeof(emem_tree_t));
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
tree_list->next=NULL;
|
|
|
|
tree_list->type=type;
|
|
|
|
tree_list->tree=NULL;
|
2006-03-11 13:02:41 +00:00
|
|
|
tree_list->name=name;
|
2006-08-12 23:27:22 +00:00
|
|
|
tree_list->malloc=se_alloc;
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
|
|
|
|
return tree_list;
|
|
|
|
}
|
|
|
|
|
2006-08-17 08:17:48 +00:00
|
|
|
/* This tree is PErmanent and will never be released
|
|
|
|
*/
|
|
|
|
emem_tree_t *
|
2008-06-25 03:05:19 +00:00
|
|
|
pe_tree_create(int type, const char *name)
|
2006-08-17 08:17:48 +00:00
|
|
|
{
|
|
|
|
emem_tree_t *tree_list;
|
|
|
|
|
|
|
|
tree_list=g_malloc(sizeof(emem_tree_t));
|
|
|
|
tree_list->next=NULL;
|
|
|
|
tree_list->type=type;
|
|
|
|
tree_list->tree=NULL;
|
|
|
|
tree_list->name=name;
|
2006-11-15 23:48:56 +00:00
|
|
|
tree_list->malloc=(void *(*)(size_t)) g_malloc;
|
2006-08-17 08:17:48 +00:00
|
|
|
|
|
|
|
return tree_list;
|
|
|
|
}
|
|
|
|
|
2006-08-14 09:36:15 +00:00
|
|
|
/* create another (sub)tree using the same memory allocation scope
|
|
|
|
* as the parent tree.
|
|
|
|
*/
|
|
|
|
static emem_tree_t *
|
2008-06-25 03:05:19 +00:00
|
|
|
emem_tree_create_subtree(emem_tree_t *parent_tree, const char *name)
|
2006-08-14 09:36:15 +00:00
|
|
|
{
|
|
|
|
emem_tree_t *tree_list;
|
|
|
|
|
|
|
|
tree_list=parent_tree->malloc(sizeof(emem_tree_t));
|
|
|
|
tree_list->next=NULL;
|
|
|
|
tree_list->type=parent_tree->type;
|
|
|
|
tree_list->tree=NULL;
|
|
|
|
tree_list->name=name;
|
|
|
|
tree_list->malloc=parent_tree->malloc;
|
|
|
|
|
|
|
|
return tree_list;
|
|
|
|
}
|
|
|
|
|
2006-03-10 21:58:49 +00:00
|
|
|
static void* create_sub_tree(void* d) {
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_t *se_tree = d;
|
2006-08-14 09:36:15 +00:00
|
|
|
return emem_tree_create_subtree(se_tree, "subtree");
|
2006-03-10 21:58:49 +00:00
|
|
|
}
|
|
|
|
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
/* insert a new node in the tree. if this node matches an already existing node
|
|
|
|
* then just replace the data for that node */
|
2006-03-10 21:58:49 +00:00
|
|
|
|
2006-03-07 16:31:47 +00:00
|
|
|
void
|
2006-08-14 09:36:15 +00:00
|
|
|
emem_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data)
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_t *next_tree;
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
|
|
|
|
if((key[0].length<1)||(key[0].length>100)){
|
2009-04-14 14:08:19 +00:00
|
|
|
DISSECTOR_ASSERT_NOT_REACHED();
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
}
|
|
|
|
if((key[0].length==1)&&(key[1].length==0)){
|
2006-08-14 09:36:15 +00:00
|
|
|
emem_tree_insert32(se_tree, *key[0].key, data);
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-04-26 21:06:52 +00:00
|
|
|
|
2007-12-04 01:44:05 +00:00
|
|
|
next_tree=lookup_or_insert32(se_tree, *key[0].key, create_sub_tree, se_tree, EMEM_TREE_NODE_IS_SUBTREE);
|
2006-03-10 21:58:49 +00:00
|
|
|
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
if(key[0].length==1){
|
|
|
|
key++;
|
|
|
|
} else {
|
|
|
|
key[0].length--;
|
|
|
|
key[0].key++;
|
|
|
|
}
|
2006-08-14 09:36:15 +00:00
|
|
|
emem_tree_insert32_array(next_tree, key, data);
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
2006-08-14 09:36:15 +00:00
|
|
|
emem_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key)
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
{
|
2006-08-14 08:29:29 +00:00
|
|
|
emem_tree_t *next_tree;
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
|
|
|
|
if((key[0].length<1)||(key[0].length>100)){
|
2009-04-14 14:08:19 +00:00
|
|
|
DISSECTOR_ASSERT_NOT_REACHED();
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
}
|
|
|
|
if((key[0].length==1)&&(key[1].length==0)){
|
2006-08-14 09:36:15 +00:00
|
|
|
return emem_tree_lookup32(se_tree, *key[0].key);
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
}
|
2006-08-14 09:36:15 +00:00
|
|
|
next_tree=emem_tree_lookup32(se_tree, *key[0].key);
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
if(!next_tree){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if(key[0].length==1){
|
|
|
|
key++;
|
|
|
|
} else {
|
|
|
|
key[0].length--;
|
|
|
|
key[0].key++;
|
|
|
|
}
|
2006-08-14 09:36:15 +00:00
|
|
|
return emem_tree_lookup32_array(next_tree, key);
|
add helper to build (red/black) trees from a key that is a vector of guin32 arrays.
test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.
these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
{ addr_len/4, &src_addr },
{ addr_len/4, &dst_addr },
{ 1, &src_port32 },
{ 1, &dst_port32 },
{ 1, &protocol32 },
{ 0, NULL }
}
(the nfs dissector needs a LOT of work. It is very painful to work with
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)
svn path=/trunk/; revision=17477
2006-03-06 10:25:19 +00:00
|
|
|
}
|
2006-03-07 01:15:29 +00:00
|
|
|
|
2006-03-07 06:33:47 +00:00
|
|
|
|
2007-12-04 03:26:50 +00:00
|
|
|
/* Strings are stored as an array of uint32 containing the string characters
|
2008-05-22 15:46:27 +00:00
|
|
|
with 4 characters in each uint32.
|
2007-12-04 03:26:50 +00:00
|
|
|
The first byte of the string is stored as the most significant byte.
|
|
|
|
If the string is not a multiple of 4 characters in length the last
|
|
|
|
uint32 containing the string bytes are padded with 0 bytes.
|
|
|
|
After the uint32's containing the string, there is one final terminator
|
|
|
|
uint32 with the value 0x00000001
|
|
|
|
*/
|
2007-01-25 06:51:30 +00:00
|
|
|
void
|
2007-12-04 03:26:50 +00:00
|
|
|
emem_tree_insert_string(emem_tree_t* se_tree, const gchar* k, void* v, guint32 flags)
|
|
|
|
{
|
|
|
|
emem_tree_key_t key[2];
|
|
|
|
guint32 *aligned=NULL;
|
2009-04-07 16:36:52 +00:00
|
|
|
guint32 len = (guint32) strlen(k);
|
2007-12-04 03:26:50 +00:00
|
|
|
guint32 div = (len+3)/4+1;
|
|
|
|
guint32 i;
|
|
|
|
guint32 tmp;
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2007-04-28 21:09:20 +00:00
|
|
|
aligned = malloc(div * sizeof (guint32));
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2007-12-04 03:26:50 +00:00
|
|
|
/* pack the bytes one one by one into guint32s */
|
|
|
|
tmp = 0;
|
|
|
|
for (i = 0;i < len;i++) {
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
|
|
ch = (unsigned char)k[i];
|
|
|
|
if (flags & EMEM_TREE_STRING_NOCASE) {
|
|
|
|
if(isupper(ch)) {
|
|
|
|
ch = tolower(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmp <<= 8;
|
|
|
|
tmp |= ch;
|
|
|
|
if (i%4 == 3) {
|
|
|
|
aligned[i/4] = tmp;
|
|
|
|
tmp = 0;
|
2008-05-22 15:46:27 +00:00
|
|
|
}
|
2007-12-04 03:26:50 +00:00
|
|
|
}
|
|
|
|
/* add required padding to the last uint32 */
|
|
|
|
if (i%4 != 0) {
|
|
|
|
while (i%4 != 0) {
|
|
|
|
i++;
|
|
|
|
tmp <<= 8;
|
|
|
|
}
|
|
|
|
aligned[i/4-1] = tmp;
|
2006-03-07 01:15:29 +00:00
|
|
|
}
|
2008-05-22 15:46:27 +00:00
|
|
|
|
2007-12-04 03:26:50 +00:00
|
|
|
/* add the terminator */
|
|
|
|
aligned[div-1] = 0x00000001;
|
|
|
|
|
|
|
|
key[0].length = div;
|
|
|
|
key[0].key = aligned;
|
|
|
|
key[1].length = 0;
|
|
|
|
key[1].key = NULL;
|
|
|
|
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2007-12-04 03:26:50 +00:00
|
|
|
emem_tree_insert32_array(se_tree, key, v);
|
2007-04-28 21:09:20 +00:00
|
|
|
free(aligned);
|
2006-03-07 01:15:29 +00:00
|
|
|
}
|
|
|
|
|
2006-08-14 09:36:15 +00:00
|
|
|
void *
|
2007-12-04 03:26:50 +00:00
|
|
|
emem_tree_lookup_string(emem_tree_t* se_tree, const gchar* k, guint32 flags)
|
|
|
|
{
|
|
|
|
emem_tree_key_t key[2];
|
|
|
|
guint32 *aligned=NULL;
|
2009-04-07 16:36:52 +00:00
|
|
|
guint32 len = (guint) strlen(k);
|
2007-12-04 03:26:50 +00:00
|
|
|
guint32 div = (len+3)/4+1;
|
|
|
|
guint32 i;
|
|
|
|
guint32 tmp;
|
2007-04-28 21:09:20 +00:00
|
|
|
void *ret;
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2007-04-28 21:09:20 +00:00
|
|
|
aligned = malloc(div * sizeof (guint32));
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2007-12-04 03:26:50 +00:00
|
|
|
/* pack the bytes one one by one into guint32s */
|
|
|
|
tmp = 0;
|
|
|
|
for (i = 0;i < len;i++) {
|
|
|
|
unsigned char ch;
|
|
|
|
|
|
|
|
ch = (unsigned char)k[i];
|
|
|
|
if (flags & EMEM_TREE_STRING_NOCASE) {
|
|
|
|
if(isupper(ch)) {
|
|
|
|
ch = tolower(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmp <<= 8;
|
|
|
|
tmp |= ch;
|
|
|
|
if (i%4 == 3) {
|
|
|
|
aligned[i/4] = tmp;
|
|
|
|
tmp = 0;
|
2008-05-22 15:46:27 +00:00
|
|
|
}
|
2007-12-04 03:26:50 +00:00
|
|
|
}
|
|
|
|
/* add required padding to the last uint32 */
|
|
|
|
if (i%4 != 0) {
|
|
|
|
while (i%4 != 0) {
|
|
|
|
i++;
|
|
|
|
tmp <<= 8;
|
|
|
|
}
|
|
|
|
aligned[i/4-1] = tmp;
|
2006-03-07 01:15:29 +00:00
|
|
|
}
|
2008-05-22 15:46:27 +00:00
|
|
|
|
2007-12-04 03:26:50 +00:00
|
|
|
/* add the terminator */
|
|
|
|
aligned[div-1] = 0x00000001;
|
|
|
|
|
|
|
|
key[0].length = div;
|
|
|
|
key[0].key = aligned;
|
|
|
|
key[1].length = 0;
|
|
|
|
key[1].key = NULL;
|
|
|
|
|
2006-03-07 16:31:47 +00:00
|
|
|
|
2007-04-28 21:09:20 +00:00
|
|
|
ret = emem_tree_lookup32_array(se_tree, key);
|
|
|
|
free(aligned);
|
|
|
|
return ret;
|
2006-03-07 01:15:29 +00:00
|
|
|
}
|
2006-11-11 22:39:25 +00:00
|
|
|
|
2007-12-03 22:47:23 +00:00
|
|
|
static gboolean
|
|
|
|
emem_tree_foreach_nodes(emem_tree_node_t* node, tree_foreach_func callback, void *user_data)
|
|
|
|
{
|
2007-12-04 01:44:05 +00:00
|
|
|
gboolean stop_traverse = FALSE;
|
2007-12-03 22:47:23 +00:00
|
|
|
|
|
|
|
if (!node)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if(node->left) {
|
|
|
|
stop_traverse = emem_tree_foreach_nodes(node->left, callback, user_data);
|
|
|
|
if (stop_traverse) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-04 01:44:05 +00:00
|
|
|
if (node->u.is_subtree == EMEM_TREE_NODE_IS_SUBTREE) {
|
|
|
|
stop_traverse = emem_tree_foreach(node->data, callback, user_data);
|
|
|
|
} else {
|
|
|
|
stop_traverse = callback(node->data, user_data);
|
|
|
|
}
|
|
|
|
|
2007-12-03 22:47:23 +00:00
|
|
|
if (stop_traverse) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(node->right) {
|
2007-12-04 01:44:05 +00:00
|
|
|
stop_traverse = emem_tree_foreach_nodes(node->right, callback, user_data);
|
2007-12-03 22:47:23 +00:00
|
|
|
if (stop_traverse) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-12-04 01:44:05 +00:00
|
|
|
gboolean
|
2007-12-03 22:47:23 +00:00
|
|
|
emem_tree_foreach(emem_tree_t* emem_tree, tree_foreach_func callback, void *user_data)
|
|
|
|
{
|
|
|
|
if (!emem_tree)
|
2007-12-04 01:44:05 +00:00
|
|
|
return FALSE;
|
2007-12-03 22:47:23 +00:00
|
|
|
|
2007-12-04 01:44:05 +00:00
|
|
|
if(!emem_tree->tree)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return emem_tree_foreach_nodes(emem_tree->tree, callback, user_data);
|
2007-12-03 22:47:23 +00:00
|
|
|
}
|
|
|
|
|
2006-11-11 22:39:25 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
emem_tree_print_nodes(emem_tree_node_t* node, int level)
|
|
|
|
{
|
|
|
|
int i;
|
2007-01-25 06:51:30 +00:00
|
|
|
|
|
|
|
if (!node)
|
|
|
|
return;
|
|
|
|
|
2006-11-11 22:39:25 +00:00
|
|
|
for(i=0;i<level;i++){
|
|
|
|
printf(" ");
|
|
|
|
}
|
2007-01-25 06:51:30 +00:00
|
|
|
|
2008-02-11 18:43:15 +00:00
|
|
|
printf("NODE:%p parent:%p left:0x%p right:%px key:%d data:%p\n",
|
|
|
|
(void *)node,(void *)(node->parent),(void *)(node->left),(void *)(node->right),
|
|
|
|
(node->key32),node->data);
|
2006-11-11 22:39:25 +00:00
|
|
|
if(node->left)
|
|
|
|
emem_tree_print_nodes(node->left, level+1);
|
|
|
|
if(node->right)
|
|
|
|
emem_tree_print_nodes(node->right, level+1);
|
|
|
|
}
|
|
|
|
void
|
|
|
|
emem_print_tree(emem_tree_t* emem_tree)
|
|
|
|
{
|
2007-01-25 06:51:30 +00:00
|
|
|
if (!emem_tree)
|
|
|
|
return;
|
|
|
|
|
2008-02-11 18:43:15 +00:00
|
|
|
printf("EMEM tree type:%d name:%s tree:%p\n",emem_tree->type,emem_tree->name,(void *)(emem_tree->tree));
|
2006-11-11 22:39:25 +00:00
|
|
|
if(emem_tree->tree)
|
|
|
|
emem_tree_print_nodes(emem_tree->tree, 0);
|
|
|
|
}
|
2009-03-27 23:05:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* String buffers
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Presumably we're using these routines for building strings for the tree.
|
|
|
|
* Use ITEM_LABEL_LENGTH as the basis for our default lengths.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define DEFAULT_STRBUF_LEN (ITEM_LABEL_LENGTH / 10)
|
|
|
|
#define MAX_STRBUF_LEN 65536
|
|
|
|
|
|
|
|
static gsize
|
2009-04-14 14:08:19 +00:00
|
|
|
next_size(gsize cur_alloc_len, gsize wanted_alloc_len, gsize max_alloc_len) {
|
|
|
|
if (max_alloc_len < 1 || max_alloc_len > MAX_STRBUF_LEN) {
|
|
|
|
max_alloc_len = MAX_STRBUF_LEN;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
if (cur_alloc_len < 1) {
|
|
|
|
cur_alloc_len = DEFAULT_STRBUF_LEN;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
while (cur_alloc_len < wanted_alloc_len) {
|
|
|
|
cur_alloc_len *= 2;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
return cur_alloc_len < max_alloc_len ? cur_alloc_len : max_alloc_len;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-04-14 14:08:19 +00:00
|
|
|
ep_strbuf_grow(emem_strbuf_t *strbuf, gsize wanted_alloc_len) {
|
2009-03-27 23:05:37 +00:00
|
|
|
gsize new_alloc_len;
|
|
|
|
gchar *new_str;
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
if (!strbuf || (wanted_alloc_len <= strbuf->alloc_len) || (strbuf->alloc_len >= strbuf->max_alloc_len)) {
|
2009-03-27 23:05:37 +00:00
|
|
|
return;
|
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
new_alloc_len = next_size(strbuf->alloc_len, wanted_alloc_len, strbuf->max_alloc_len);
|
|
|
|
new_str = ep_alloc(new_alloc_len);
|
|
|
|
g_strlcpy(new_str, strbuf->str, new_alloc_len);
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
strbuf->alloc_len = new_alloc_len;
|
|
|
|
strbuf->str = new_str;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
emem_strbuf_t *
|
2009-04-14 14:08:19 +00:00
|
|
|
ep_strbuf_sized_new(gsize alloc_len, gsize max_alloc_len) {
|
2009-03-27 23:05:37 +00:00
|
|
|
emem_strbuf_t *strbuf;
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-03-27 23:05:37 +00:00
|
|
|
strbuf = ep_alloc(sizeof(emem_strbuf_t));
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
if ((max_alloc_len == 0) || (max_alloc_len > MAX_STRBUF_LEN))
|
|
|
|
max_alloc_len = MAX_STRBUF_LEN;
|
|
|
|
if (alloc_len == 0)
|
|
|
|
alloc_len = 1;
|
|
|
|
else if (alloc_len > max_alloc_len)
|
|
|
|
alloc_len = max_alloc_len;
|
|
|
|
|
|
|
|
strbuf->str = ep_alloc(alloc_len);
|
|
|
|
strbuf->str[0] = '\0';
|
|
|
|
|
|
|
|
strbuf->len = 0;
|
|
|
|
strbuf->alloc_len = alloc_len;
|
|
|
|
strbuf->max_alloc_len = max_alloc_len;
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-03-27 23:05:37 +00:00
|
|
|
return strbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
emem_strbuf_t *
|
|
|
|
ep_strbuf_new(const gchar *init) {
|
|
|
|
emem_strbuf_t *strbuf;
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-03 17:32:32 +00:00
|
|
|
strbuf = ep_strbuf_sized_new(next_size(0, init?strlen(init):0, 0), 0);
|
2009-04-14 14:08:19 +00:00
|
|
|
if (init) {
|
|
|
|
gsize full_len;
|
|
|
|
full_len = g_strlcpy(strbuf->str, init, strbuf->alloc_len);
|
|
|
|
strbuf->len = MIN(full_len, strbuf->alloc_len-1);
|
|
|
|
}
|
|
|
|
|
2009-03-27 23:05:37 +00:00
|
|
|
return strbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
emem_strbuf_t *
|
|
|
|
ep_strbuf_new_label(const gchar *init) {
|
|
|
|
emem_strbuf_t *strbuf;
|
2009-04-14 14:08:19 +00:00
|
|
|
gsize full_len;
|
|
|
|
|
|
|
|
/* Be optimistic: Allocate default size strbuf string and only */
|
|
|
|
/* request an increase if needed. */
|
|
|
|
/* XXX: Is it reasonable to assume that much of the usage of */
|
|
|
|
/* ep_strbuf_new_label will have init==NULL or */
|
|
|
|
/* strlen(init) < DEFAULT_STRBUF_LEN) ??? */
|
|
|
|
strbuf = ep_strbuf_sized_new(DEFAULT_STRBUF_LEN, ITEM_LABEL_LENGTH);
|
|
|
|
|
|
|
|
if (!init)
|
|
|
|
return strbuf;
|
|
|
|
|
|
|
|
/* full_len does not count the trailing '\0'. */
|
|
|
|
full_len = g_strlcpy(strbuf->str, init, strbuf->alloc_len);
|
|
|
|
if (full_len < strbuf->alloc_len) {
|
|
|
|
strbuf->len += full_len;
|
|
|
|
} else {
|
|
|
|
strbuf = ep_strbuf_sized_new(full_len+1, ITEM_LABEL_LENGTH);
|
|
|
|
full_len = g_strlcpy(strbuf->str, init, strbuf->alloc_len);
|
|
|
|
strbuf->len = MIN(full_len, strbuf->alloc_len-1);
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-03-27 23:05:37 +00:00
|
|
|
return strbuf;
|
|
|
|
}
|
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
emem_strbuf_t *
|
2009-03-27 23:05:37 +00:00
|
|
|
ep_strbuf_append(emem_strbuf_t *strbuf, const gchar *str) {
|
2009-04-14 14:08:19 +00:00
|
|
|
gsize add_len, full_len;
|
2009-03-30 19:38:47 +00:00
|
|
|
|
|
|
|
if (!strbuf || !str || str[0] == '\0') {
|
2009-04-14 14:08:19 +00:00
|
|
|
return strbuf;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
2009-03-28 05:14:16 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
/* Be optimistic; try the g_strlcpy first & see if enough room. */
|
|
|
|
/* Note: full_len doesn't count the trailing '\0'; add_len does allow for same */
|
|
|
|
add_len = strbuf->alloc_len - strbuf->len;
|
|
|
|
full_len = g_strlcpy(&strbuf->str[strbuf->len], str, add_len);
|
|
|
|
if (full_len < add_len) {
|
|
|
|
strbuf->len += full_len;
|
|
|
|
} else {
|
|
|
|
strbuf->str[strbuf->len] = '\0'; /* end string at original length again */
|
|
|
|
ep_strbuf_grow(strbuf, strbuf->len + full_len + 1);
|
|
|
|
add_len = strbuf->alloc_len - strbuf->len;
|
|
|
|
full_len = g_strlcpy(&strbuf->str[strbuf->len], str, add_len);
|
|
|
|
strbuf->len += MIN(add_len-1, full_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return strbuf;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ep_strbuf_append_vprintf(emem_strbuf_t *strbuf, const gchar *format, va_list ap) {
|
|
|
|
va_list ap2;
|
|
|
|
gsize add_len, full_len;
|
|
|
|
|
|
|
|
G_VA_COPY(ap2, ap);
|
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
/* Be optimistic; try the g_vsnprintf first & see if enough room. */
|
|
|
|
/* Note: full_len doesn't count the trailing '\0'; add_len does allow for same. */
|
|
|
|
add_len = strbuf->alloc_len - strbuf->len;
|
|
|
|
full_len = g_vsnprintf(&strbuf->str[strbuf->len], (gulong) add_len, format, ap);
|
|
|
|
if (full_len < add_len) {
|
|
|
|
strbuf->len += full_len;
|
|
|
|
} else {
|
|
|
|
strbuf->str[strbuf->len] = '\0'; /* end string at original length again */
|
|
|
|
ep_strbuf_grow(strbuf, strbuf->len + full_len + 1);
|
2009-03-27 23:05:37 +00:00
|
|
|
add_len = strbuf->alloc_len - strbuf->len;
|
2009-04-14 14:08:19 +00:00
|
|
|
full_len = g_vsnprintf(&strbuf->str[strbuf->len], (gulong) add_len, format, ap2);
|
|
|
|
strbuf->len += MIN(add_len-1, full_len);
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
va_end(ap2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ep_strbuf_append_printf(emem_strbuf_t *strbuf, const gchar *format, ...) {
|
|
|
|
va_list ap;
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-03-27 23:05:37 +00:00
|
|
|
va_start(ap, format);
|
|
|
|
ep_strbuf_append_vprintf(strbuf, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2009-03-28 00:27:03 +00:00
|
|
|
void
|
|
|
|
ep_strbuf_printf(emem_strbuf_t *strbuf, const gchar *format, ...) {
|
|
|
|
va_list ap;
|
|
|
|
if (!strbuf) {
|
|
|
|
return;
|
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-03-28 00:27:03 +00:00
|
|
|
strbuf->len = 0;
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-03-28 00:27:03 +00:00
|
|
|
va_start(ap, format);
|
|
|
|
ep_strbuf_append_vprintf(strbuf, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
emem_strbuf_t *
|
2009-03-28 00:27:03 +00:00
|
|
|
ep_strbuf_append_c(emem_strbuf_t *strbuf, const gchar c) {
|
|
|
|
if (!strbuf) {
|
2009-04-14 14:08:19 +00:00
|
|
|
return strbuf;
|
2009-03-28 00:27:03 +00:00
|
|
|
}
|
2009-03-30 19:38:47 +00:00
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
/* +1 for the new character & +1 for the trailing '\0'. */
|
|
|
|
if (strbuf->alloc_len < strbuf->len + 1 + 1) {
|
|
|
|
ep_strbuf_grow(strbuf, strbuf->len + 1 + 1);
|
|
|
|
}
|
|
|
|
if (strbuf->alloc_len >= strbuf->len + 1 + 1) {
|
2009-03-28 00:27:03 +00:00
|
|
|
strbuf->str[strbuf->len] = c;
|
|
|
|
strbuf->len++;
|
|
|
|
strbuf->str[strbuf->len] = '\0';
|
|
|
|
}
|
2009-04-14 14:08:19 +00:00
|
|
|
|
|
|
|
return strbuf;
|
2009-03-28 00:27:03 +00:00
|
|
|
}
|
|
|
|
|
2009-04-14 14:08:19 +00:00
|
|
|
emem_strbuf_t *
|
2009-03-27 23:05:37 +00:00
|
|
|
ep_strbuf_truncate(emem_strbuf_t *strbuf, gsize len) {
|
|
|
|
if (!strbuf || len >= strbuf->len) {
|
2009-04-14 14:08:19 +00:00
|
|
|
return strbuf;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
|
|
|
|
2009-03-30 19:38:47 +00:00
|
|
|
strbuf->str[len] = '\0';
|
2009-03-27 23:05:37 +00:00
|
|
|
strbuf->len = len;
|
2009-04-14 14:08:19 +00:00
|
|
|
|
|
|
|
return strbuf;
|
2009-03-27 23:05:37 +00:00
|
|
|
}
|
2009-04-14 14:08:19 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Editor modelines
|
|
|
|
*
|
|
|
|
* Local Variables:
|
|
|
|
* c-basic-offset: 8
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: t
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* ex: set shiftwidth=8 tabstop=8 noexpandtab
|
|
|
|
* :indentSize=8:tabSize=8:noTabs=false:
|
|
|
|
*/
|