Rev 5191 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5191 | Rev 6324 | ||
---|---|---|---|
1 | /* simple-object.c -- simple routines to read and write object files. |
1 | /* simple-object.c -- simple routines to read and write object files. |
2 | Copyright 2010 Free Software Foundation, Inc. |
2 | Copyright 2010 Free Software Foundation, Inc. |
3 | Written by Ian Lance Taylor, Google. |
3 | Written by Ian Lance Taylor, Google. |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify it |
5 | This program is free software; you can redistribute it and/or modify it |
6 | under the terms of the GNU General Public License as published by the |
6 | under the terms of the GNU General Public License as published by the |
7 | Free Software Foundation; either version 2, or (at your option) any |
7 | Free Software Foundation; either version 2, or (at your option) any |
8 | later version. |
8 | later version. |
9 | 9 | ||
10 | This program is distributed in the hope that it will be useful, |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
13 | GNU General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU General Public License |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, 51 Franklin Street - Fifth Floor, |
17 | Foundation, 51 Franklin Street - Fifth Floor, |
18 | Boston, MA 02110-1301, USA. */ |
18 | Boston, MA 02110-1301, USA. */ |
19 | 19 | ||
20 | #include "config.h" |
20 | #include "config.h" |
21 | #include "libiberty.h" |
21 | #include "libiberty.h" |
22 | #include "simple-object.h" |
22 | #include "simple-object.h" |
23 | 23 | ||
24 | #include |
24 | #include |
25 | 25 | ||
26 | #ifdef HAVE_STDLIB_H |
26 | #ifdef HAVE_STDLIB_H |
27 | #include |
27 | #include |
28 | #endif |
28 | #endif |
29 | 29 | ||
30 | #ifdef HAVE_STDINT_H |
30 | #ifdef HAVE_STDINT_H |
31 | #include |
31 | #include |
32 | #endif |
32 | #endif |
33 | 33 | ||
34 | #ifdef HAVE_STRING_H |
34 | #ifdef HAVE_STRING_H |
35 | #include |
35 | #include |
36 | #endif |
36 | #endif |
37 | 37 | ||
38 | #ifdef HAVE_INTTYPES_H |
38 | #ifdef HAVE_INTTYPES_H |
39 | #include |
39 | #include |
40 | #endif |
40 | #endif |
41 | 41 | ||
42 | #ifndef SEEK_SET |
42 | #ifndef SEEK_SET |
43 | #define SEEK_SET 0 |
43 | #define SEEK_SET 0 |
44 | #endif |
44 | #endif |
45 | 45 | ||
46 | #include "simple-object-common.h" |
46 | #include "simple-object-common.h" |
47 | 47 | ||
48 | /* The known object file formats. */ |
48 | /* The known object file formats. */ |
49 | 49 | ||
50 | static const struct simple_object_functions * const format_functions[] = |
50 | static const struct simple_object_functions * const format_functions[] = |
51 | { |
51 | { |
52 | &simple_object_elf_functions, |
52 | &simple_object_elf_functions, |
53 | &simple_object_mach_o_functions, |
53 | &simple_object_mach_o_functions, |
54 | &simple_object_coff_functions, |
54 | &simple_object_coff_functions, |
55 | &simple_object_xcoff_functions |
55 | &simple_object_xcoff_functions |
56 | }; |
56 | }; |
57 | 57 | ||
58 | /* Read data from a file using the simple_object error reporting |
58 | /* Read data from a file using the simple_object error reporting |
59 | conventions. */ |
59 | conventions. */ |
60 | 60 | ||
61 | int |
61 | int |
62 | simple_object_internal_read (int descriptor, off_t offset, |
62 | simple_object_internal_read (int descriptor, off_t offset, |
63 | unsigned char *buffer, size_t size, |
63 | unsigned char *buffer, size_t size, |
64 | const char **errmsg, int *err) |
64 | const char **errmsg, int *err) |
65 | { |
65 | { |
66 | ssize_t got; |
- | |
67 | - | ||
68 | if (lseek (descriptor, offset, SEEK_SET) < 0) |
66 | if (lseek (descriptor, offset, SEEK_SET) < 0) |
69 | { |
67 | { |
70 | *errmsg = "lseek"; |
68 | *errmsg = "lseek"; |
71 | *err = errno; |
69 | *err = errno; |
72 | return 0; |
70 | return 0; |
73 | } |
71 | } |
- | 72 | ||
- | 73 | do |
|
74 | 74 | { |
|
75 | got = read (descriptor, buffer, size); |
75 | ssize_t got = read (descriptor, buffer, size); |
- | 76 | if (got == 0) |
|
- | 77 | break; |
|
- | 78 | else if (got > 0) |
|
- | 79 | { |
|
- | 80 | buffer += got; |
|
- | 81 | size -= got; |
|
- | 82 | } |
|
76 | if (got < 0) |
83 | else if (errno != EINTR) |
77 | { |
84 | { |
78 | *errmsg = "read"; |
85 | *errmsg = "read"; |
79 | *err = errno; |
86 | *err = errno; |
80 | return 0; |
87 | return 0; |
81 | } |
88 | } |
- | 89 | } |
|
- | 90 | while (size > 0); |
|
82 | 91 | ||
83 | if ((size_t) got < size) |
92 | if (size > 0) |
84 | { |
93 | { |
85 | *errmsg = "file too short"; |
94 | *errmsg = "file too short"; |
86 | *err = 0; |
95 | *err = 0; |
87 | return 0; |
96 | return 0; |
88 | } |
97 | } |
89 | 98 | ||
90 | return 1; |
99 | return 1; |
91 | } |
100 | } |
92 | 101 | ||
93 | /* Write data to a file using the simple_object error reporting |
102 | /* Write data to a file using the simple_object error reporting |
94 | conventions. */ |
103 | conventions. */ |
95 | 104 | ||
96 | int |
105 | int |
97 | simple_object_internal_write (int descriptor, off_t offset, |
106 | simple_object_internal_write (int descriptor, off_t offset, |
98 | const unsigned char *buffer, size_t size, |
107 | const unsigned char *buffer, size_t size, |
99 | const char **errmsg, int *err) |
108 | const char **errmsg, int *err) |
100 | { |
109 | { |
101 | ssize_t wrote; |
- | |
102 | - | ||
103 | if (lseek (descriptor, offset, SEEK_SET) < 0) |
110 | if (lseek (descriptor, offset, SEEK_SET) < 0) |
104 | { |
111 | { |
105 | *errmsg = "lseek"; |
112 | *errmsg = "lseek"; |
106 | *err = errno; |
113 | *err = errno; |
107 | return 0; |
114 | return 0; |
108 | } |
115 | } |
- | 116 | ||
- | 117 | do |
|
109 | 118 | { |
|
110 | wrote = write (descriptor, buffer, size); |
119 | ssize_t wrote = write (descriptor, buffer, size); |
- | 120 | if (wrote == 0) |
|
- | 121 | break; |
|
- | 122 | else if (wrote > 0) |
|
- | 123 | { |
|
- | 124 | buffer += wrote; |
|
- | 125 | size -= wrote; |
|
- | 126 | } |
|
111 | if (wrote < 0) |
127 | else if (errno != EINTR) |
112 | { |
128 | { |
113 | *errmsg = "write"; |
129 | *errmsg = "write"; |
114 | *err = errno; |
130 | *err = errno; |
115 | return 0; |
131 | return 0; |
116 | } |
132 | } |
- | 133 | } |
|
- | 134 | while (size > 0); |
|
117 | 135 | ||
118 | if ((size_t) wrote < size) |
136 | if (size > 0) |
119 | { |
137 | { |
120 | *errmsg = "short write"; |
138 | *errmsg = "short write"; |
121 | *err = 0; |
139 | *err = 0; |
122 | return 0; |
140 | return 0; |
123 | } |
141 | } |
124 | 142 | ||
125 | return 1; |
143 | return 1; |
126 | } |
144 | } |
127 | 145 | ||
128 | /* Open for read. */ |
146 | /* Open for read. */ |
129 | 147 | ||
130 | simple_object_read * |
148 | simple_object_read * |
131 | simple_object_start_read (int descriptor, off_t offset, |
149 | simple_object_start_read (int descriptor, off_t offset, |
132 | const char *segment_name, const char **errmsg, |
150 | const char *segment_name, const char **errmsg, |
133 | int *err) |
151 | int *err) |
134 | { |
152 | { |
135 | unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN]; |
153 | unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN]; |
136 | size_t len, i; |
154 | size_t len, i; |
137 | 155 | ||
138 | if (!simple_object_internal_read (descriptor, offset, header, |
156 | if (!simple_object_internal_read (descriptor, offset, header, |
139 | SIMPLE_OBJECT_MATCH_HEADER_LEN, |
157 | SIMPLE_OBJECT_MATCH_HEADER_LEN, |
140 | errmsg, err)) |
158 | errmsg, err)) |
141 | return NULL; |
159 | return NULL; |
142 | 160 | ||
143 | len = sizeof (format_functions) / sizeof (format_functions[0]); |
161 | len = sizeof (format_functions) / sizeof (format_functions[0]); |
144 | for (i = 0; i < len; ++i) |
162 | for (i = 0; i < len; ++i) |
145 | { |
163 | { |
146 | void *data; |
164 | void *data; |
147 | 165 | ||
148 | data = format_functions[i]->match (header, descriptor, offset, |
166 | data = format_functions[i]->match (header, descriptor, offset, |
149 | segment_name, errmsg, err); |
167 | segment_name, errmsg, err); |
150 | if (data != NULL) |
168 | if (data != NULL) |
151 | { |
169 | { |
152 | simple_object_read *ret; |
170 | simple_object_read *ret; |
153 | 171 | ||
154 | ret = XNEW (simple_object_read); |
172 | ret = XNEW (simple_object_read); |
155 | ret->descriptor = descriptor; |
173 | ret->descriptor = descriptor; |
156 | ret->offset = offset; |
174 | ret->offset = offset; |
157 | ret->functions = format_functions[i]; |
175 | ret->functions = format_functions[i]; |
158 | ret->data = data; |
176 | ret->data = data; |
159 | return ret; |
177 | return ret; |
160 | } |
178 | } |
161 | } |
179 | } |
162 | 180 | ||
163 | *errmsg = "file not recognized"; |
181 | *errmsg = "file not recognized"; |
164 | *err = 0; |
182 | *err = 0; |
165 | return NULL; |
183 | return NULL; |
166 | } |
184 | } |
167 | 185 | ||
168 | /* Find all sections. */ |
186 | /* Find all sections. */ |
169 | 187 | ||
170 | const char * |
188 | const char * |
171 | simple_object_find_sections (simple_object_read *sobj, |
189 | simple_object_find_sections (simple_object_read *sobj, |
172 | int (*pfn) (void *, const char *, off_t, off_t), |
190 | int (*pfn) (void *, const char *, off_t, off_t), |
173 | void *data, |
191 | void *data, |
174 | int *err) |
192 | int *err) |
175 | { |
193 | { |
176 | return sobj->functions->find_sections (sobj, pfn, data, err); |
194 | return sobj->functions->find_sections (sobj, pfn, data, err); |
177 | } |
195 | } |
178 | 196 | ||
179 | /* Internal data passed to find_one_section. */ |
197 | /* Internal data passed to find_one_section. */ |
180 | 198 | ||
181 | struct find_one_section_data |
199 | struct find_one_section_data |
182 | { |
200 | { |
183 | /* The section we are looking for. */ |
201 | /* The section we are looking for. */ |
184 | const char *name; |
202 | const char *name; |
185 | /* Where to store the section offset. */ |
203 | /* Where to store the section offset. */ |
186 | off_t *offset; |
204 | off_t *offset; |
187 | /* Where to store the section length. */ |
205 | /* Where to store the section length. */ |
188 | off_t *length; |
206 | off_t *length; |
189 | /* Set if the name is found. */ |
207 | /* Set if the name is found. */ |
190 | int found; |
208 | int found; |
191 | }; |
209 | }; |
192 | 210 | ||
193 | /* Internal function passed to find_sections. */ |
211 | /* Internal function passed to find_sections. */ |
194 | 212 | ||
195 | static int |
213 | static int |
196 | find_one_section (void *data, const char *name, off_t offset, off_t length) |
214 | find_one_section (void *data, const char *name, off_t offset, off_t length) |
197 | { |
215 | { |
198 | struct find_one_section_data *fosd = (struct find_one_section_data *) data; |
216 | struct find_one_section_data *fosd = (struct find_one_section_data *) data; |
199 | 217 | ||
200 | if (strcmp (name, fosd->name) != 0) |
218 | if (strcmp (name, fosd->name) != 0) |
201 | return 1; |
219 | return 1; |
202 | 220 | ||
203 | *fosd->offset = offset; |
221 | *fosd->offset = offset; |
204 | *fosd->length = length; |
222 | *fosd->length = length; |
205 | fosd->found = 1; |
223 | fosd->found = 1; |
206 | 224 | ||
207 | /* Stop iteration. */ |
225 | /* Stop iteration. */ |
208 | return 0; |
226 | return 0; |
209 | } |
227 | } |
210 | 228 | ||
211 | /* Find a section. */ |
229 | /* Find a section. */ |
212 | 230 | ||
213 | int |
231 | int |
214 | simple_object_find_section (simple_object_read *sobj, const char *name, |
232 | simple_object_find_section (simple_object_read *sobj, const char *name, |
215 | off_t *offset, off_t *length, |
233 | off_t *offset, off_t *length, |
216 | const char **errmsg, int *err) |
234 | const char **errmsg, int *err) |
217 | { |
235 | { |
218 | struct find_one_section_data fosd; |
236 | struct find_one_section_data fosd; |
219 | 237 | ||
220 | fosd.name = name; |
238 | fosd.name = name; |
221 | fosd.offset = offset; |
239 | fosd.offset = offset; |
222 | fosd.length = length; |
240 | fosd.length = length; |
223 | fosd.found = 0; |
241 | fosd.found = 0; |
224 | 242 | ||
225 | *errmsg = simple_object_find_sections (sobj, find_one_section, |
243 | *errmsg = simple_object_find_sections (sobj, find_one_section, |
226 | (void *) &fosd, err); |
244 | (void *) &fosd, err); |
227 | if (*errmsg != NULL) |
245 | if (*errmsg != NULL) |
228 | return 0; |
246 | return 0; |
229 | if (!fosd.found) |
247 | if (!fosd.found) |
230 | return 0; |
248 | return 0; |
231 | return 1; |
249 | return 1; |
232 | } |
250 | } |
233 | 251 | ||
234 | /* Fetch attributes. */ |
252 | /* Fetch attributes. */ |
235 | 253 | ||
236 | simple_object_attributes * |
254 | simple_object_attributes * |
237 | simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg, |
255 | simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg, |
238 | int *err) |
256 | int *err) |
239 | { |
257 | { |
240 | void *data; |
258 | void *data; |
241 | simple_object_attributes *ret; |
259 | simple_object_attributes *ret; |
242 | 260 | ||
243 | data = sobj->functions->fetch_attributes (sobj, errmsg, err); |
261 | data = sobj->functions->fetch_attributes (sobj, errmsg, err); |
244 | if (data == NULL) |
262 | if (data == NULL) |
245 | return NULL; |
263 | return NULL; |
246 | ret = XNEW (simple_object_attributes); |
264 | ret = XNEW (simple_object_attributes); |
247 | ret->functions = sobj->functions; |
265 | ret->functions = sobj->functions; |
248 | ret->data = data; |
266 | ret->data = data; |
249 | return ret; |
267 | return ret; |
250 | } |
268 | } |
251 | 269 | ||
252 | /* Release an simple_object_read. */ |
270 | /* Release an simple_object_read. */ |
253 | 271 | ||
254 | void |
272 | void |
255 | simple_object_release_read (simple_object_read *sobj) |
273 | simple_object_release_read (simple_object_read *sobj) |
256 | { |
274 | { |
257 | sobj->functions->release_read (sobj->data); |
275 | sobj->functions->release_read (sobj->data); |
258 | XDELETE (sobj); |
276 | XDELETE (sobj); |
259 | } |
277 | } |
260 | 278 | ||
261 | /* Merge attributes. */ |
279 | /* Merge attributes. */ |
262 | 280 | ||
263 | const char * |
281 | const char * |
264 | simple_object_attributes_merge (simple_object_attributes *to, |
282 | simple_object_attributes_merge (simple_object_attributes *to, |
265 | simple_object_attributes *from, |
283 | simple_object_attributes *from, |
266 | int *err) |
284 | int *err) |
267 | { |
285 | { |
268 | if (to->functions != from->functions) |
286 | if (to->functions != from->functions) |
269 | { |
287 | { |
270 | *err = 0; |
288 | *err = 0; |
271 | return "different object file format"; |
289 | return "different object file format"; |
272 | } |
290 | } |
273 | return to->functions->attributes_merge (to->data, from->data, err); |
291 | return to->functions->attributes_merge (to->data, from->data, err); |
274 | } |
292 | } |
275 | 293 | ||
276 | /* Release an attributes structure. */ |
294 | /* Release an attributes structure. */ |
277 | 295 | ||
278 | void |
296 | void |
279 | simple_object_release_attributes (simple_object_attributes *attrs) |
297 | simple_object_release_attributes (simple_object_attributes *attrs) |
280 | { |
298 | { |
281 | attrs->functions->release_attributes (attrs->data); |
299 | attrs->functions->release_attributes (attrs->data); |
282 | XDELETE (attrs); |
300 | XDELETE (attrs); |
283 | } |
301 | } |
284 | 302 | ||
285 | /* Start creating an object file. */ |
303 | /* Start creating an object file. */ |
286 | 304 | ||
287 | simple_object_write * |
305 | simple_object_write * |
288 | simple_object_start_write (simple_object_attributes *attrs, |
306 | simple_object_start_write (simple_object_attributes *attrs, |
289 | const char *segment_name, const char **errmsg, |
307 | const char *segment_name, const char **errmsg, |
290 | int *err) |
308 | int *err) |
291 | { |
309 | { |
292 | void *data; |
310 | void *data; |
293 | simple_object_write *ret; |
311 | simple_object_write *ret; |
294 | 312 | ||
295 | data = attrs->functions->start_write (attrs->data, errmsg, err); |
313 | data = attrs->functions->start_write (attrs->data, errmsg, err); |
296 | if (data == NULL) |
314 | if (data == NULL) |
297 | return NULL; |
315 | return NULL; |
298 | ret = XNEW (simple_object_write); |
316 | ret = XNEW (simple_object_write); |
299 | ret->functions = attrs->functions; |
317 | ret->functions = attrs->functions; |
300 | ret->segment_name = xstrdup (segment_name); |
318 | ret->segment_name = xstrdup (segment_name); |
301 | ret->sections = NULL; |
319 | ret->sections = NULL; |
302 | ret->last_section = NULL; |
320 | ret->last_section = NULL; |
303 | ret->data = data; |
321 | ret->data = data; |
304 | return ret; |
322 | return ret; |
305 | } |
323 | } |
306 | 324 | ||
307 | /* Start creating a section. */ |
325 | /* Start creating a section. */ |
308 | 326 | ||
309 | simple_object_write_section * |
327 | simple_object_write_section * |
310 | simple_object_write_create_section (simple_object_write *sobj, const char *name, |
328 | simple_object_write_create_section (simple_object_write *sobj, const char *name, |
311 | unsigned int align, |
329 | unsigned int align, |
312 | const char **errmsg ATTRIBUTE_UNUSED, |
330 | const char **errmsg ATTRIBUTE_UNUSED, |
313 | int *err ATTRIBUTE_UNUSED) |
331 | int *err ATTRIBUTE_UNUSED) |
314 | { |
332 | { |
315 | simple_object_write_section *ret; |
333 | simple_object_write_section *ret; |
316 | 334 | ||
317 | ret = XNEW (simple_object_write_section); |
335 | ret = XNEW (simple_object_write_section); |
318 | ret->next = NULL; |
336 | ret->next = NULL; |
319 | ret->name = xstrdup (name); |
337 | ret->name = xstrdup (name); |
320 | ret->align = align; |
338 | ret->align = align; |
321 | ret->buffers = NULL; |
339 | ret->buffers = NULL; |
322 | ret->last_buffer = NULL; |
340 | ret->last_buffer = NULL; |
323 | 341 | ||
324 | if (sobj->last_section == NULL) |
342 | if (sobj->last_section == NULL) |
325 | { |
343 | { |
326 | sobj->sections = ret; |
344 | sobj->sections = ret; |
327 | sobj->last_section = ret; |
345 | sobj->last_section = ret; |
328 | } |
346 | } |
329 | else |
347 | else |
330 | { |
348 | { |
331 | sobj->last_section->next = ret; |
349 | sobj->last_section->next = ret; |
332 | sobj->last_section = ret; |
350 | sobj->last_section = ret; |
333 | } |
351 | } |
334 | 352 | ||
335 | return ret; |
353 | return ret; |
336 | } |
354 | } |
337 | 355 | ||
338 | /* Add data to a section. */ |
356 | /* Add data to a section. */ |
339 | 357 | ||
340 | const char * |
358 | const char * |
341 | simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED, |
359 | simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED, |
342 | simple_object_write_section *section, |
360 | simple_object_write_section *section, |
343 | const void *buffer, |
361 | const void *buffer, |
344 | size_t size, int copy, |
362 | size_t size, int copy, |
345 | int *err ATTRIBUTE_UNUSED) |
363 | int *err ATTRIBUTE_UNUSED) |
346 | { |
364 | { |
347 | struct simple_object_write_section_buffer *wsb; |
365 | struct simple_object_write_section_buffer *wsb; |
348 | 366 | ||
349 | wsb = XNEW (struct simple_object_write_section_buffer); |
367 | wsb = XNEW (struct simple_object_write_section_buffer); |
350 | wsb->next = NULL; |
368 | wsb->next = NULL; |
351 | wsb->size = size; |
369 | wsb->size = size; |
352 | 370 | ||
353 | if (!copy) |
371 | if (!copy) |
354 | { |
372 | { |
355 | wsb->buffer = buffer; |
373 | wsb->buffer = buffer; |
356 | wsb->free_buffer = NULL; |
374 | wsb->free_buffer = NULL; |
357 | } |
375 | } |
358 | else |
376 | else |
359 | { |
377 | { |
360 | wsb->free_buffer = (void *) XNEWVEC (char, size); |
378 | wsb->free_buffer = (void *) XNEWVEC (char, size); |
361 | memcpy (wsb->free_buffer, buffer, size); |
379 | memcpy (wsb->free_buffer, buffer, size); |
362 | wsb->buffer = wsb->free_buffer; |
380 | wsb->buffer = wsb->free_buffer; |
363 | } |
381 | } |
364 | 382 | ||
365 | if (section->last_buffer == NULL) |
383 | if (section->last_buffer == NULL) |
366 | { |
384 | { |
367 | section->buffers = wsb; |
385 | section->buffers = wsb; |
368 | section->last_buffer = wsb; |
386 | section->last_buffer = wsb; |
369 | } |
387 | } |
370 | else |
388 | else |
371 | { |
389 | { |
372 | section->last_buffer->next = wsb; |
390 | section->last_buffer->next = wsb; |
373 | section->last_buffer = wsb; |
391 | section->last_buffer = wsb; |
374 | } |
392 | } |
375 | 393 | ||
376 | return NULL; |
394 | return NULL; |
377 | } |
395 | } |
378 | 396 | ||
379 | /* Write the complete object file. */ |
397 | /* Write the complete object file. */ |
380 | 398 | ||
381 | const char * |
399 | const char * |
382 | simple_object_write_to_file (simple_object_write *sobj, int descriptor, |
400 | simple_object_write_to_file (simple_object_write *sobj, int descriptor, |
383 | int *err) |
401 | int *err) |
384 | { |
402 | { |
385 | return sobj->functions->write_to_file (sobj, descriptor, err); |
403 | return sobj->functions->write_to_file (sobj, descriptor, err); |
386 | } |
404 | } |
387 | 405 | ||
388 | /* Release an simple_object_write. */ |
406 | /* Release an simple_object_write. */ |
389 | 407 | ||
390 | void |
408 | void |
391 | simple_object_release_write (simple_object_write *sobj) |
409 | simple_object_release_write (simple_object_write *sobj) |
392 | { |
410 | { |
393 | simple_object_write_section *section; |
411 | simple_object_write_section *section; |
394 | 412 | ||
395 | free (sobj->segment_name); |
413 | free (sobj->segment_name); |
396 | 414 | ||
397 | section = sobj->sections; |
415 | section = sobj->sections; |
398 | while (section != NULL) |
416 | while (section != NULL) |
399 | { |
417 | { |
400 | struct simple_object_write_section_buffer *buffer; |
418 | struct simple_object_write_section_buffer *buffer; |
401 | simple_object_write_section *next_section; |
419 | simple_object_write_section *next_section; |
402 | 420 | ||
403 | buffer = section->buffers; |
421 | buffer = section->buffers; |
404 | while (buffer != NULL) |
422 | while (buffer != NULL) |
405 | { |
423 | { |
406 | struct simple_object_write_section_buffer *next_buffer; |
424 | struct simple_object_write_section_buffer *next_buffer; |
407 | 425 | ||
408 | if (buffer->free_buffer != NULL) |
426 | if (buffer->free_buffer != NULL) |
409 | XDELETEVEC (buffer->free_buffer); |
427 | XDELETEVEC (buffer->free_buffer); |
410 | next_buffer = buffer->next; |
428 | next_buffer = buffer->next; |
411 | XDELETE (buffer); |
429 | XDELETE (buffer); |
412 | buffer = next_buffer; |
430 | buffer = next_buffer; |
413 | } |
431 | } |
414 | 432 | ||
415 | next_section = section->next; |
433 | next_section = section->next; |
416 | free (section->name); |
434 | free (section->name); |
417 | XDELETE (section); |
435 | XDELETE (section); |
418 | section = next_section; |
436 | section = next_section; |
419 | } |
437 | } |
420 | 438 | ||
421 | sobj->functions->release_write (sobj->data); |
439 | sobj->functions->release_write (sobj->data); |
422 | XDELETE (sobj); |
440 | XDELETE (sobj); |
423 | }>>>>>>> |
441 | }>>> |