90b07047d32c0f1554bc518ee43d5011522bf62c
[samba.git] / source3 / lib / membuffer.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba memory buffer functions
5    Copyright (C) Andrew Tridgell              1992-1997
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1997
7    
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.
12    
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.
17    
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.
21 */
22
23 /*******************************************************************
24  *
25  * Description: memory buffer / stream management.
26  * Author     : Luke K C Leighton
27  * Created    : Dec 1997
28  *
29
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.
33
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.
38  
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
42  * repetitively...
43
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)
47
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
50
51  ********************************************************************/
52
53
54 #include "includes.h"
55
56 extern int DEBUGLEVEL;
57
58 /*******************************************************************
59  initialise a memory buffer.
60  ********************************************************************/
61 void mem_init(struct mem_buf *buf, int margin)
62 {
63         buf->dynamic   = True;
64         buf->data      = NULL;
65         buf->data_size = 0;
66         buf->data_used = 0;
67
68         buf->margin    = margin;
69
70         buf->next      = NULL;
71
72         buf->offset.start = 0;
73         buf->offset.end   = 0;
74 }
75
76 /*******************************************************************
77  initialise a memory buffer.
78
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)
83 {
84         buf->dynamic   = dynamic;
85         buf->data      = data;
86         buf->data_size = size;
87         buf->data_used = size;
88
89         buf->margin    = margin;
90
91         buf->next      = NULL;
92
93         buf->offset.start = 0;
94         buf->offset.end   = size;
95 }
96
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)
102 {
103         memcpy(mem_to, mem_from, sizeof(*mem_to));
104
105         mem_init(mem_from, mem_from->margin);
106 }
107
108 /*******************************************************************
109  allocate a memory buffer.  assume it's empty
110  ********************************************************************/
111 BOOL mem_alloc_data(struct mem_buf *buf, int size)
112 {
113         if (!buf->dynamic)
114         {
115                 DEBUG(3,("mem_alloc_data: warning - memory buffer type is set to static\n"));
116         }
117
118         buf->data_size = size + buf->margin;
119         buf->data_used = size;
120
121         buf->data = malloc(buf->data_size);
122
123         if (buf->data == NULL)
124         {
125                 DEBUG(3,("mem_alloc: could not malloc size %d\n",
126                                           buf->data_size));
127                 mem_init(buf, buf->margin);
128
129                 return False;
130         }
131
132         bzero(buf->data, buf->data_size);
133
134         return True;
135 }
136
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)
142 {
143         uint32 end = offset + len;
144         char *q = NULL;
145         uint32 data_len = mem_buf_len(buf);
146         uint32 start_offset = offset;
147         struct mem_buf **bcp = &buf;
148         
149         if (buf == NULL || copy_into == NULL) return False;
150
151         DEBUG(200,("mem_buf_copy: data[%d..%d] offset %d len %d\n",
152                     buf->offset.start, data_len, offset, len));
153
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))
156         {
157                 uint32 copy_len = (*bcp)->offset.end - offset;
158
159                 DEBUG(200,("\tdata[%d..%d] - offset %d len %d\n",
160                         (*bcp)->offset.start, (*bcp)->offset.end,
161                         offset, copy_len));
162
163                 memcpy(copy_into, q, copy_len);
164         
165                 offset    += copy_len;
166                 copy_into += copy_len;
167         }
168
169         if ((*bcp) != NULL)
170         {
171                 DEBUG(200,("mem_buf_copy: copied %d bytes\n", offset - start_offset));
172         }
173         else
174         {
175                 DEBUG(200,("mem_buf_copy: failed\n"));
176         }
177
178         return buf != NULL;
179 }
180
181 /*******************************************************************
182  allocates a memory buffer structure
183  ********************************************************************/
184 BOOL mem_buf_init(struct mem_buf **buf, uint32 margin)
185 {
186         if (buf == NULL) return False;
187
188         if ((*buf) == NULL)
189         {
190                 (*buf) = malloc(sizeof(**buf));
191                 if ((*buf) != NULL) 
192                 {
193                         mem_init((*buf), margin);
194                         return True;
195                 }
196         }
197         else
198         {
199                 (*buf)->margin = margin;
200                 return True;
201         }
202         return False;
203 }
204
205 /*******************************************************************
206  frees up a memory buffer.
207  ********************************************************************/
208 void mem_buf_free(struct mem_buf **buf)
209 {
210         if (buf == NULL) return;
211         if ((*buf) == NULL) return;
212
213         mem_free_data(*buf);            /* delete memory data */
214         free(*buf);                     /* delete item */
215         (*buf) = NULL;
216 }
217
218 /*******************************************************************
219  frees a memory buffer chain.  assumes that all items are malloced.
220  ********************************************************************/
221 void mem_free_chain(struct mem_buf **buf)
222 {
223         if (buf == NULL) return;
224         if ((*buf) == NULL) return;
225
226         if ((*buf)->next != NULL)
227         {
228                 mem_free_chain(&((*buf)->next)); /* delete all other items in chain */
229         }
230         mem_buf_free(buf);
231 }
232
233 /*******************************************************************
234  frees a memory buffer.
235  ********************************************************************/
236 void mem_free_data(struct mem_buf *buf)
237 {
238         if (buf == NULL) return;
239
240         if (buf->data != NULL && buf->dynamic)
241         {
242                 free(buf->data);     /* delete data in this structure */
243         }
244         mem_init(buf, buf->margin);
245 }
246
247 /*******************************************************************
248  reallocate a memory buffer, including a safety margin
249  ********************************************************************/
250 BOOL mem_realloc_data(struct mem_buf *buf, int new_size)
251 {
252         char *new_data;
253
254         if (!buf->dynamic)
255         {
256                 DEBUG(3,("mem_realloc_data: memory buffer has not been dynamically allocated!\n"));
257                 return False;
258         }
259
260         if (new_size == 0)
261         {
262                 mem_free_data(buf);
263                 return True;
264         }
265
266         new_data = Realloc(buf->data, new_size + buf->margin);
267
268         if (new_data != NULL)
269         {
270                 buf->data = new_data;
271                 buf->data_size = new_size + buf->margin;
272                 buf->data_used = new_size;
273         }
274         else if (buf->data_size <= new_size)
275         {
276                 DEBUG(3,("mem_realloc: warning - could not realloc to %d(+%d)\n",
277                                   new_size, buf->margin));
278
279                 buf->data_used = new_size;
280         }
281         else 
282         {
283                 DEBUG(3,("mem_realloc: error - could not realloc to %d\n",
284                                   new_size));
285
286                 mem_free_data(buf);
287                 return False;
288         }
289
290         return True;
291 }
292
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)
297 {
298         if (new_size + (*buf)->margin >= (*buf)->data_size)
299         {
300                 if (io && !force_grow)
301                 {
302                         DEBUG(3,("mem_grow_data: cannot resize when reading from a data stream\n"));
303                 }
304                 else
305                 {
306                         return mem_realloc_data((*buf), new_size);
307                 }
308         }
309         return True;
310 }
311
312 /*******************************************************************
313  search for a memory buffer that falls within the specified offset
314  ********************************************************************/
315 BOOL mem_find(struct mem_buf **buf, uint32 offset)
316 {
317         struct mem_buf *f;
318         if (buf == NULL) return False;
319
320         f = *buf;
321
322         DEBUG(200,("mem_find: data[%d..%d] offset: %d\n",
323               f->offset.start, f->offset.end, offset));
324
325         while (f != NULL && offset >= f->offset.end)
326         {
327                 f = f->next;
328
329                 DEBUG(200,("mem_find: next[%d..%d]\n",
330               f->offset.start, f->offset.end));
331         }
332
333         (*buf) = f;
334
335         DEBUG(200,("mem_find: found data[%d..%d]\n",
336               (*buf)->offset.start,(*buf)->offset.end));
337
338         return f != NULL;
339 }
340
341
342 /*******************************************************************
343  add up the lengths of all sections.
344  ********************************************************************/
345 uint32 mem_buf_len(struct mem_buf *buf)
346 {
347         int len = 0;
348         while (buf != NULL)
349         {
350                 len += buf->offset.end - buf->offset.start;
351                 buf = buf->next;
352         }
353         return len;
354 }
355
356
357 /*******************************************************************
358  return the memory location specified by offset.  may return NULL.
359  ********************************************************************/
360 char *mem_data(struct mem_buf **buf, uint32 offset)
361 {
362         if (mem_find(buf, offset))
363         {
364                 return &((*buf)->data[offset - (*buf)->offset.start]);
365         }
366         return NULL;
367 }
368
369