2 Unix SMB/Netbios implementation.
4 Samba memory buffer functions
5 Copyright (C) Andrew Tridgell 1992-1997
6 Copyright (C) Luke Kenneth Casson Leighton 1996-1997
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /*******************************************************************
25 * Description: memory buffer / stream management.
26 * Author : Luke K C Leighton
30 * this module is intended for use in streaming data in and out of
31 * buffers. it is intended that a single data stream be subdivided
32 * into manageable sections.
34 * for example, an rpc header contains a length field, but until the
35 * data has been created, the length is unknown. using this module,
36 * the header section can be tacked onto the front of the data memory
37 * list once the size of the data section preceding it is known.
39 * the "margin" can be used to over-run and retrospectively lengthen
40 * the buffer. this is to save time in some of the loops, where it is
41 * not particularly desirable to realloc data by 1, 2 or 4 bytes
44 * each memory buffer contains a start and end offset. the end of
45 * one buffer should equal to the start of the next in the chain.
46 * (end - start = len, instead of end - start + 1 = len)
48 * the debug log levels are very high in some of the routines: you
49 * have no idea how boring it gets staring at debug output from these
51 ********************************************************************/
56 extern int DEBUGLEVEL;
58 /*******************************************************************
59 initialise a memory buffer.
60 ********************************************************************/
61 void mem_init(struct mem_buf *buf, int margin)
72 buf->offset.start = 0;
76 /*******************************************************************
77 initialise a memory buffer.
79 dynamic indicates memory has been dynamically allocated.
80 if mem_free is called, the memory will be freed.
81 ********************************************************************/
82 void mem_create(struct mem_buf *buf, char *data, int size, int margin, BOOL dynamic)
84 buf->dynamic = dynamic;
86 buf->data_size = size;
87 buf->data_used = size;
93 buf->offset.start = 0;
94 buf->offset.end = size;
97 /*******************************************************************
98 takes a memory buffer out of one structure: puts it in the other.
99 NULLs the one that the buffer is being stolen from.
100 ********************************************************************/
101 void mem_take(struct mem_buf *mem_to, struct mem_buf *mem_from)
103 memcpy(mem_to, mem_from, sizeof(*mem_to));
105 mem_init(mem_from, mem_from->margin);
108 /*******************************************************************
109 allocate a memory buffer. assume it's empty
110 ********************************************************************/
111 BOOL mem_alloc_data(struct mem_buf *buf, int size)
115 DEBUG(3,("mem_alloc_data: warning - memory buffer type is set to static\n"));
118 buf->data_size = size + buf->margin;
119 buf->data_used = size;
121 buf->data = malloc(buf->data_size);
123 if (buf->data == NULL)
125 DEBUG(3,("mem_alloc: could not malloc size %d\n",
127 mem_init(buf, buf->margin);
132 bzero(buf->data, buf->data_size);
137 /*******************************************************************
138 allocates a memory buffer structure
139 ********************************************************************/
140 BOOL mem_buf_copy(char *copy_into, struct mem_buf *buf,
141 uint32 offset, uint32 len)
143 uint32 end = offset + len;
145 uint32 data_len = mem_buf_len(buf);
146 uint32 start_offset = offset;
147 struct mem_buf **bcp = &buf;
149 if (buf == NULL || copy_into == NULL) return False;
151 DEBUG(200,("mem_buf_copy: data[%d..%d] offset %d len %d\n",
152 buf->offset.start, data_len, offset, len));
154 /* there's probably an off-by-one bug, here, and i haven't even tested the code :-) */
155 while (offset < end && ((q = mem_data(bcp, offset)) != NULL))
157 uint32 copy_len = (*bcp)->offset.end - offset;
159 DEBUG(200,("\tdata[%d..%d] - offset %d len %d\n",
160 (*bcp)->offset.start, (*bcp)->offset.end,
163 memcpy(copy_into, q, copy_len);
166 copy_into += copy_len;
171 DEBUG(200,("mem_buf_copy: copied %d bytes\n", offset - start_offset));
175 DEBUG(200,("mem_buf_copy: failed\n"));
181 /*******************************************************************
182 allocates a memory buffer structure
183 ********************************************************************/
184 BOOL mem_buf_init(struct mem_buf **buf, uint32 margin)
186 if (buf == NULL) return False;
190 (*buf) = malloc(sizeof(**buf));
193 mem_init((*buf), margin);
199 (*buf)->margin = margin;
205 /*******************************************************************
206 frees up a memory buffer.
207 ********************************************************************/
208 void mem_buf_free(struct mem_buf **buf)
210 if (buf == NULL) return;
211 if ((*buf) == NULL) return;
213 mem_free_data(*buf); /* delete memory data */
214 free(*buf); /* delete item */
218 /*******************************************************************
219 frees a memory buffer chain. assumes that all items are malloced.
220 ********************************************************************/
221 void mem_free_chain(struct mem_buf **buf)
223 if (buf == NULL) return;
224 if ((*buf) == NULL) return;
226 if ((*buf)->next != NULL)
228 mem_free_chain(&((*buf)->next)); /* delete all other items in chain */
233 /*******************************************************************
234 frees a memory buffer.
235 ********************************************************************/
236 void mem_free_data(struct mem_buf *buf)
238 if (buf == NULL) return;
240 if (buf->data != NULL && buf->dynamic)
242 free(buf->data); /* delete data in this structure */
244 mem_init(buf, buf->margin);
247 /*******************************************************************
248 reallocate a memory buffer, including a safety margin
249 ********************************************************************/
250 BOOL mem_realloc_data(struct mem_buf *buf, int new_size)
256 DEBUG(3,("mem_realloc_data: memory buffer has not been dynamically allocated!\n"));
266 new_data = Realloc(buf->data, new_size + buf->margin);
268 if (new_data != NULL)
270 buf->data = new_data;
271 buf->data_size = new_size + buf->margin;
272 buf->data_used = new_size;
274 else if (buf->data_size <= new_size)
276 DEBUG(3,("mem_realloc: warning - could not realloc to %d(+%d)\n",
277 new_size, buf->margin));
279 buf->data_used = new_size;
283 DEBUG(3,("mem_realloc: error - could not realloc to %d\n",
293 /*******************************************************************
294 reallocate a memory buffer, retrospectively :-)
295 ********************************************************************/
296 BOOL mem_grow_data(struct mem_buf **buf, BOOL io, int new_size, BOOL force_grow)
298 if (new_size + (*buf)->margin >= (*buf)->data_size)
300 if (io && !force_grow)
302 DEBUG(3,("mem_grow_data: cannot resize when reading from a data stream\n"));
306 return mem_realloc_data((*buf), new_size);
312 /*******************************************************************
313 search for a memory buffer that falls within the specified offset
314 ********************************************************************/
315 BOOL mem_find(struct mem_buf **buf, uint32 offset)
318 if (buf == NULL) return False;
322 DEBUG(200,("mem_find: data[%d..%d] offset: %d\n",
323 f->offset.start, f->offset.end, offset));
325 while (f != NULL && offset >= f->offset.end)
329 DEBUG(200,("mem_find: next[%d..%d]\n",
330 f->offset.start, f->offset.end));
335 DEBUG(200,("mem_find: found data[%d..%d]\n",
336 (*buf)->offset.start,(*buf)->offset.end));
342 /*******************************************************************
343 add up the lengths of all sections.
344 ********************************************************************/
345 uint32 mem_buf_len(struct mem_buf *buf)
350 len += buf->offset.end - buf->offset.start;
357 /*******************************************************************
358 return the memory location specified by offset. may return NULL.
359 ********************************************************************/
360 char *mem_data(struct mem_buf **buf, uint32 offset)
362 if (mem_find(buf, offset))
364 return &((*buf)->data[offset - (*buf)->offset.start]);