File: | obj-scan-build/libstore/../../libstore/kids.c |
Location: | line 204, column 17 |
Description: | Call to 'malloc' has an allocation size of 0 bytes |
1 | /* Managing sub-stores | |||
2 | ||||
3 | Copyright (C) 1995,96,97,2001,02 Free Software Foundation, Inc. | |||
4 | Written by Miles Bader <miles@gnu.org> | |||
5 | ||||
6 | This file is part of the GNU Hurd. | |||
7 | ||||
8 | The GNU Hurd is free software; you can redistribute it and/or | |||
9 | modify it under the terms of the GNU General Public License as | |||
10 | published by the Free Software Foundation; either version 2, or (at | |||
11 | your option) any later version. | |||
12 | ||||
13 | The GNU Hurd is distributed in the hope that it will be useful, but | |||
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
16 | 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ | |||
21 | ||||
22 | #include <stdlib.h> | |||
23 | #include <string.h> | |||
24 | #include <stdio.h> | |||
25 | #include <ctype.h> | |||
26 | ||||
27 | #include "store.h" | |||
28 | ||||
29 | /* Set STORE's current children list to (a copy of) CHILDREN and NUM_CHILDREN. */ | |||
30 | error_t | |||
31 | store_set_children (struct store *store, | |||
32 | struct store *const *children, size_t num_children) | |||
33 | { | |||
34 | unsigned size = num_children * sizeof (struct store *); | |||
35 | struct store **copy = malloc (size); | |||
36 | ||||
37 | if (!copy) | |||
38 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
39 | ||||
40 | if (store->children) | |||
41 | free (store->children); | |||
42 | ||||
43 | memcpy (copy, children, size); | |||
44 | store->children = copy; | |||
45 | store->num_children = num_children; | |||
46 | ||||
47 | return 0; | |||
48 | } | |||
49 | ||||
50 | /* Calls the allocate_encoding method in each child store of STORE, | |||
51 | propagating any errors. If any child does not hae such a method, | |||
52 | EOPNOTSUPP is returned. */ | |||
53 | error_t | |||
54 | store_allocate_child_encodings (const struct store *store, | |||
55 | struct store_enc *enc) | |||
56 | { | |||
57 | int i; | |||
58 | error_t err = 0; | |||
59 | for (i = 0; i < store->num_children && !err; i++) | |||
60 | { | |||
61 | struct store *k = store->children[i]; | |||
62 | if (k->class->allocate_encoding) | |||
63 | (*k->class->allocate_encoding) (k, enc); | |||
64 | else | |||
65 | err = EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
66 | } | |||
67 | return err; | |||
68 | } | |||
69 | ||||
70 | /* Calls the encode method in each child store of STORE, propagating any | |||
71 | errors. If any child does not hae such a method, EOPNOTSUPP is returned. */ | |||
72 | error_t | |||
73 | store_encode_children (const struct store *store, struct store_enc *enc) | |||
74 | { | |||
75 | int i; | |||
76 | error_t err = 0; | |||
77 | for (i = 0; i < store->num_children && !err; i++) | |||
78 | { | |||
79 | struct store *k = store->children[i]; | |||
80 | if (k->class->encode) | |||
81 | (*k->class->encode) (k, enc); | |||
82 | else | |||
83 | err = EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
84 | } | |||
85 | return err; | |||
86 | } | |||
87 | ||||
88 | /* Decodes NUM_CHILDREN from ENC, storing the results into successive | |||
89 | positions in CHILDREN. */ | |||
90 | error_t | |||
91 | store_decode_children (struct store_enc *enc, int num_children, | |||
92 | const struct store_class *const *classes, | |||
93 | struct store **children) | |||
94 | { | |||
95 | int i; | |||
96 | error_t err = 0; | |||
97 | for (i = 0; i < num_children && !err; i++) | |||
98 | err = store_decode (enc, classes, &children[i]); | |||
99 | if (err) | |||
100 | /* Deallocate anything we've already created. */ | |||
101 | while (--i >= 0) | |||
102 | store_free (children[i]); | |||
103 | return err; | |||
104 | } | |||
105 | ||||
106 | /* Set FLAGS in all children of STORE, and if successful, add FLAGS to | |||
107 | STORE's flags. */ | |||
108 | error_t | |||
109 | store_set_child_flags (struct store *store, int flags) | |||
110 | { | |||
111 | int i; | |||
112 | error_t err = 0; | |||
113 | int old_child_flags[store->num_children]; | |||
114 | ||||
115 | for (i = 0; i < store->num_children && !err; i++) | |||
116 | { | |||
117 | old_child_flags[i] = store->children[i]->flags; | |||
118 | err = store_set_flags (store->children[i], flags); | |||
119 | } | |||
120 | ||||
121 | if (err) | |||
122 | while (i-- > 0) | |||
123 | store_clear_flags (store->children[i], flags & ~old_child_flags[i]); | |||
124 | else | |||
125 | store->flags |= flags; | |||
126 | ||||
127 | return err; | |||
128 | } | |||
129 | ||||
130 | /* Clear FLAGS in all children of STORE, and if successful, remove FLAGS from | |||
131 | STORE's flags. */ | |||
132 | error_t | |||
133 | store_clear_child_flags (struct store *store, int flags) | |||
134 | { | |||
135 | int i; | |||
136 | error_t err = 0; | |||
137 | int old_child_flags[store->num_children]; | |||
138 | ||||
139 | for (i = 0; i < store->num_children && !err; i++) | |||
140 | { | |||
141 | old_child_flags[i] = store->children[i]->flags; | |||
142 | err = store_clear_flags (store->children[i], flags); | |||
143 | } | |||
144 | ||||
145 | if (err) | |||
146 | while (i-- > 0) | |||
147 | store_set_flags (store->children[i], flags & ~old_child_flags[i]); | |||
148 | else | |||
149 | store->flags &= ~flags; | |||
150 | ||||
151 | return err; | |||
152 | } | |||
153 | ||||
154 | /* Parse multiple store names in NAME, and open each individually, returning | |||
155 | all in the vector STORES, and the number in NUM_STORES. The syntax of | |||
156 | NAME is a single non-alpha-numeric separator character, followed by each | |||
157 | child store name separated by the same separator; each child name is | |||
158 | TYPE:NAME notation as parsed by store_typed_open. If every child uses the | |||
159 | same TYPE: prefix, then it may be factored out and put before the child | |||
160 | list instead (the two types of notation are differentiated by whether the | |||
161 | first character of name is alpha-numeric or not). */ | |||
162 | error_t | |||
163 | store_open_children (const char *name, int flags, | |||
164 | const struct store_class *const *classes, | |||
165 | struct store ***stores, size_t *num_stores) | |||
166 | { | |||
167 | char *pfx = 0; /* Prefix applied to each part name. */ | |||
168 | size_t pfx_len = 0; /* Space PFX + separator takes up. */ | |||
169 | char sep = *name; /* Character separating individual names. */ | |||
170 | ||||
171 | if (sep && isalnum (sep)((*__ctype_b_loc ())[(int) ((sep))] & (unsigned short int ) _ISalnum)) | |||
| ||||
172 | /* If the first character is a `name' character, it's likely to be either | |||
173 | a type prefix (e.g, TYPE:@NAME1@NAME2@), so we distribute the type | |||
174 | prefix among the elements (@TYPE:NAME1@TYPE:NAME2@). */ | |||
175 | { | |||
176 | const char *pfx_end = name; | |||
177 | ||||
178 | while (isalnum (*pfx_end)((*__ctype_b_loc ())[(int) ((*pfx_end))] & (unsigned short int) _ISalnum)) | |||
179 | pfx_end++; | |||
180 | ||||
181 | if (*pfx_end++ != ':') | |||
182 | return EINVAL((0x10 << 26) | ((22) & 0x3fff)); | |||
183 | ||||
184 | /* Make a copy of the prefix. */ | |||
185 | pfx = strndupa (name, pfx_end - name)(__extension__ ({ const char *__old = (name); size_t __len = strnlen (__old, (pfx_end - name)); char *__new = (char *) __builtin_alloca (__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old , __len); })); | |||
186 | pfx_len = pfx_end - name; | |||
187 | ||||
188 | sep = *pfx_end; | |||
189 | } | |||
190 | ||||
191 | if (sep) | |||
192 | /* Parse a list of store specs separated by SEP. */ | |||
193 | { | |||
194 | int k; | |||
195 | const char *p, *end; | |||
196 | error_t err = 0; | |||
197 | size_t count = 0; | |||
198 | ||||
199 | /* First, see how many there are. */ | |||
200 | for (p = name; p && p[1]; p = strchr (p + 1, sep)) | |||
201 | count++; | |||
202 | ||||
203 | /* Make a vector to hold them. */ | |||
204 | *stores = malloc (count * sizeof (struct store *)); | |||
| ||||
205 | *num_stores = count; | |||
206 | if (! *stores) | |||
207 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
208 | ||||
209 | memset (*stores, 0, count * sizeof(struct store *)); | |||
210 | ||||
211 | /* Open each child store. */ | |||
212 | for (p = name, k = 0; !err && p && p[1]; p = end, k++) | |||
213 | { | |||
214 | size_t kname_len; | |||
215 | ||||
216 | end = strchr (p + 1, sep); | |||
217 | kname_len = (end ? end - p - 1 : strlen (p + 1)); | |||
218 | ||||
219 | { | |||
220 | /* Allocate temporary child name on the stack. */ | |||
221 | char kname[pfx_len + kname_len + 1]; | |||
222 | ||||
223 | if (pfx) | |||
224 | /* Add type prefix to child name. */ | |||
225 | memcpy (kname, pfx, pfx_len); | |||
226 | ||||
227 | memcpy (kname + pfx_len, p + 1, kname_len); | |||
228 | kname[pfx_len + kname_len] = '\0'; | |||
229 | ||||
230 | err = store_typed_open (kname, flags, classes, &(*stores)[k]); | |||
231 | } | |||
232 | } | |||
233 | ||||
234 | if (err) | |||
235 | /* Failure opening some child, deallocate what we've done so far. */ | |||
236 | { | |||
237 | while (--k >= 0) | |||
238 | store_free ((*stores)[k]); | |||
239 | free (*stores); | |||
240 | } | |||
241 | ||||
242 | return err; | |||
243 | } | |||
244 | else | |||
245 | /* Empty list. */ | |||
246 | { | |||
247 | *stores = 0; | |||
248 | *num_stores = 0; | |||
249 | return 0; | |||
250 | } | |||
251 | } | |||
252 | ||||
253 | /* Try to come up with a name for the children in STORE, combining the names | |||
254 | of each child in a way that could be used to parse them with | |||
255 | store_open_children. This is done heuristically, and so may not succeed. | |||
256 | If a child doesn't have a name, EINVAL is returned. */ | |||
257 | error_t | |||
258 | store_children_name (const struct store *store, char **name) | |||
259 | { | |||
260 | static char try_seps[] = "@+=,._%|;^!~'&"; | |||
261 | struct store **kids = store->children; | |||
262 | size_t num_kids = store->num_children; | |||
263 | ||||
264 | if (num_kids == 0) | |||
265 | { | |||
266 | *name = strdup (""); | |||
267 | return *name ? 0 : ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
268 | } | |||
269 | else | |||
270 | { | |||
271 | int k; | |||
272 | char *s; /* Current separator in search for one. */ | |||
273 | int fail; /* If we couldn't use *S as as sep. */ | |||
274 | size_t total_len = 0; /* Length of name we will return. */ | |||
275 | ||||
276 | /* Detect children without names, and calculate the total length of the | |||
277 | name we will return (which is the sum of the lengths of the child | |||
278 | names plus room for the types and separator characters. */ | |||
279 | for (k = 0; k < num_kids; k++) | |||
280 | if (!kids[k] || !kids[k]->name) | |||
281 | return EINVAL((0x10 << 26) | ((22) & 0x3fff)); | |||
282 | else | |||
283 | total_len += | |||
284 | /* separator + type name + type separator + child name */ | |||
285 | 1 + strlen (kids[k]->class->name) + 1 + strlen (kids[k]->name); | |||
286 | ||||
287 | /* Look for a separator character from those in TRY_SEPS that doesn't | |||
288 | occur in any of the the child names. */ | |||
289 | for (s = try_seps, fail = 1; *s && fail; s++) | |||
290 | for (k = 0, fail = 0; k < num_kids && !fail; k++) | |||
291 | if (strchr (kids[k]->name, *s)) | |||
292 | fail = 1; | |||
293 | ||||
294 | if (*s) | |||
295 | /* We found a usable separator! */ | |||
296 | { | |||
297 | char *p = malloc (total_len + 1); | |||
298 | ||||
299 | if (! p) | |||
300 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
301 | *name = p; | |||
302 | ||||
303 | for (k = 0; k < num_kids; k++) | |||
304 | p += | |||
305 | sprintf (p, "%c%s:%s", *s, kids[k]->class->name, kids[k]->name); | |||
306 | ||||
307 | return 0; | |||
308 | } | |||
309 | else | |||
310 | return EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff)); | |||
311 | } | |||
312 | } |