Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /*
2 *
3 * registry.c
4 *
5 * $Source: /Users/ekr/tmp/nrappkit-dump/nrappkit/src/registry/registry_local.c,v $
6 * $Revision: 1.4 $
7 * $Date: 2007/11/21 00:09:13 $
8 *
9 * Datastore for tracking configuration and related info.
10 *
11 *
12 * Copyright (C) 2005, Network Resonance, Inc.
13 * Copyright (C) 2006, Network Resonance, Inc.
14 * All Rights Reserved
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of Network Resonance, Inc. nor the name of any
26 * contributors to this software may be used to endorse or promote
27 * products derived from this software without specific prior written
28 * permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
31 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
34 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGE.
41 *
42 *
43 */
45 #include <assert.h>
46 #include <string.h>
47 #ifndef WIN32
48 #include <strings.h>
49 #include <sys/param.h>
50 #include <netinet/in.h>
51 #endif
52 #ifdef OPENSSL
53 #include <openssl/ssl.h>
54 #endif
55 #include <ctype.h>
56 #include "registry.h"
57 #include "registry_int.h"
58 #include "registry_vtbl.h"
59 #include "r_assoc.h"
60 #include "nr_common.h"
61 #include "r_log.h"
62 #include "r_errors.h"
63 #include "r_macros.h"
65 /* if C were an object-oriented language, nr_scalar_registry_node and
66 * nr_array_registry_node would subclass nr_registry_node, but it isn't
67 * object-oriented language, so this is used in cases where the pointer
68 * could be of either type */
69 typedef struct nr_registry_node_ {
70 unsigned char type;
71 } nr_registry_node;
73 typedef struct nr_scalar_registry_node_ {
74 unsigned char type;
75 union {
76 char _char;
77 UCHAR _uchar;
78 INT2 _nr_int2;
79 UINT2 _nr_uint2;
80 INT4 _nr_int4;
81 UINT4 _nr_uint4;
82 INT8 _nr_int8;
83 UINT8 _nr_uint8;
84 double _double;
85 } scalar;
86 } nr_scalar_registry_node;
88 /* string, bytes */
89 typedef struct nr_array_registry_node_ {
90 unsigned char type;
91 struct {
92 unsigned int length;
93 unsigned char data[1];
94 } array;
95 } nr_array_registry_node;
97 static int nr_reg_local_init(nr_registry_module *me);
98 static int nr_reg_local_get_char(NR_registry name, char *data);
99 static int nr_reg_local_get_uchar(NR_registry name, UCHAR *data);
100 static int nr_reg_local_get_int2(NR_registry name, INT2 *data);
101 static int nr_reg_local_get_uint2(NR_registry name, UINT2 *data);
102 static int nr_reg_local_get_int4(NR_registry name, INT4 *data);
103 static int nr_reg_local_get_uint4(NR_registry name, UINT4 *data);
104 static int nr_reg_local_get_int8(NR_registry name, INT8 *data);
105 static int nr_reg_local_get_uint8(NR_registry name, UINT8 *data);
106 static int nr_reg_local_get_double(NR_registry name, double *data);
107 static int nr_reg_local_get_registry(NR_registry name, NR_registry data);
108 static int nr_reg_local_get_bytes(NR_registry name, UCHAR *data, size_t size, size_t *length);
109 static int nr_reg_local_get_string(NR_registry name, char *data, size_t size);
110 static int nr_reg_local_get_length(NR_registry name, size_t *len);
111 static int nr_reg_local_get_type(NR_registry name, NR_registry_type type);
112 static int nr_reg_local_set_char(NR_registry name, char data);
113 static int nr_reg_local_set_uchar(NR_registry name, UCHAR data);
114 static int nr_reg_local_set_int2(NR_registry name, INT2 data);
115 static int nr_reg_local_set_uint2(NR_registry name, UINT2 data);
116 static int nr_reg_local_set_int4(NR_registry name, INT4 data);
117 static int nr_reg_local_set_uint4(NR_registry name, UINT4 data);
118 static int nr_reg_local_set_int8(NR_registry name, INT8 data);
119 static int nr_reg_local_set_uint8(NR_registry name, UINT8 data);
120 static int nr_reg_local_set_double(NR_registry name, double data);
121 static int nr_reg_local_set_registry(NR_registry name);
122 static int nr_reg_local_set_bytes(NR_registry name, UCHAR *data, size_t length);
123 static int nr_reg_local_set_string(NR_registry name, char *data);
124 static int nr_reg_local_del(NR_registry name);
125 static int nr_reg_local_get_child_count(NR_registry parent, size_t *count);
126 static int nr_reg_local_get_children(NR_registry parent, NR_registry *data, size_t size, size_t *length);
127 static int nr_reg_local_fin(NR_registry name);
128 static int nr_reg_local_dump(int sorted);
129 static int nr_reg_insert_node(char *name, void *node);
130 static int nr_reg_change_node(char *name, void *node, void *old);
131 static int nr_reg_get(char *name, int type, void *out);
132 static int nr_reg_get_data(NR_registry name, nr_scalar_registry_node *node, void *out);
133 static int nr_reg_get_array(char *name, unsigned char type, UCHAR *out, size_t size, size_t *length);
134 static int nr_reg_set(char *name, int type, void *data);
135 static int nr_reg_set_array(char *name, unsigned char type, UCHAR *data, size_t length);
136 static int nr_reg_set_parent_registries(char *name);
138 /* make these static OLD_REGISTRY */
139 #if 0
140 static int nr_reg_fetch_node(char *name, unsigned char type, nr_registry_node **node, int *free_node);
141 static char *nr_reg_alloc_node_data(char *name, nr_registry_node *node, int *freeit);
142 #else
143 int nr_reg_fetch_node(char *name, unsigned char type, nr_registry_node **node, int *free_node);
144 char *nr_reg_alloc_node_data(char *name, nr_registry_node *node, int *freeit);
145 #endif
146 static int nr_reg_rfree(void *ptr);
147 #if 0 /* Unused currently */
148 static int nr_reg_noop(void *ptr);
149 #endif
150 static int nr_reg_compute_length(char *name, nr_registry_node *node, size_t *length);
151 char *nr_reg_action_name(int action);
153 /* the registry, containing mappings like "foo.bar.baz" to registry
154 * nodes, which are either of type nr_scalar_registry_node or
155 * nr_array_registry_node */
156 static r_assoc *nr_registry = 0;
158 #if 0 /* Unused currently */
159 static nr_array_registry_node nr_top_level_node;
160 #endif
162 typedef struct nr_reg_find_children_arg_ {
163 size_t size;
164 NR_registry *children;
165 size_t length;
166 } nr_reg_find_children_arg;
168 static int nr_reg_local_iter(char *prefix, int (*action)(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node), void *ptr);
169 static int nr_reg_local_iter_delete(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
170 static int nr_reg_local_find_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
171 static int nr_reg_local_count_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
172 static int nr_reg_local_dump_print(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node);
176 int
177 nr_reg_local_iter(NR_registry prefix, int (*action)(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node), void *ptr)
178 {
179 int r, _status;
180 r_assoc_iterator iter;
181 char *name;
182 int namel;
183 nr_registry_node *node;
184 int prefixl;
186 if (prefix == 0)
187 ABORT(R_INTERNAL);
189 if ((r=r_assoc_init_iter(nr_registry, &iter)))
190 ABORT(r);
192 prefixl = strlen(prefix);
194 for (;;) {
195 if ((r=r_assoc_iter(&iter, (void*)&name, &namel, (void*)&node))) {
196 if (r == R_EOD)
197 break;
198 else
199 ABORT(r);
200 }
202 /* subtract to remove the '\0' character from the string length */
203 --namel;
205 /* sanity check that the name is null-terminated */
206 assert(namel >= 0);
207 assert(name[namel] == '\0');
209 if (namel < 0 || name[namel] != '\0' || node == 0)
210 break;
212 /* 3 cases where action will be called:
213 * 1) prefix == ""
214 * 2) prefix == name
215 * 3) name == prefix + '.'
216 */
217 if (prefixl == 0
218 || ((namel == prefixl || (namel > prefixl && name[prefixl] == '.'))
219 && !strncmp(prefix, name, prefixl))) {
220 if ((r=action(ptr, &iter, prefix, name, node)))
221 ABORT(r);
222 }
223 }
225 _status=0;
226 abort:
228 return(_status);
229 }
231 int
232 nr_reg_local_iter_delete(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
233 {
234 int r, _status;
236 if ((r=r_assoc_iter_delete(iter)))
237 ABORT(r);
239 _status=0;
240 abort:
241 return(_status);
242 }
244 int
245 nr_reg_local_find_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
246 {
247 int _status;
248 int prefixl = strlen(prefix);
249 char *dot;
250 nr_reg_find_children_arg *arg = (void*)ptr;
252 assert(sizeof(*(arg->children)) == sizeof(NR_registry));
254 /* only grovel through immediate children */
255 if (prefixl == 0 || name[prefixl] == '.') {
256 if (name[prefixl] != '\0') {
257 dot = strchr(&name[prefixl+1], '.');
258 if (dot == 0) {
259 strncpy(arg->children[arg->length], name, sizeof(NR_registry)-1);
260 ++arg->length;
262 /* only grab as many as there are room for */
263 if (arg->length >= arg->size)
264 ABORT(R_INTERRUPTED);
265 }
266 }
267 }
269 _status = 0;
270 abort:
271 return _status;
272 }
274 int
275 nr_reg_local_count_children(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
276 {
277 int prefixl = strlen(prefix);
278 char *dot;
280 /* only count children */
281 if (name[prefixl] == '.') {
282 dot = strchr(&name[prefixl+1], '.');
283 if (dot == 0)
284 ++(*(unsigned int *)ptr);
285 }
286 else if (name[0] != '\0') {
287 if (prefixl == 0)
288 ++(*(unsigned int *)ptr);
289 }
291 return 0;
292 }
294 int
295 nr_reg_local_dump_print(void *ptr, r_assoc_iterator *iter, char *prefix, char *name, nr_registry_node *node)
296 {
297 int _status;
298 int freeit = 0;
299 char *data;
301 /* only print leaf nodes */
302 if (node->type != NR_REG_TYPE_REGISTRY) {
303 data = nr_reg_alloc_node_data(name, node, &freeit);
304 if (ptr)
305 fprintf((FILE*)ptr, "%s: %s\n", name, data);
306 else
307 r_log(NR_LOG_REGISTRY, LOG_INFO, "%s: %s", name, data);
308 if (freeit)
309 RFREE(data);
310 }
312 _status=0;
313 //abort:
314 return(_status);
315 }
318 #if 0 /* Unused currently */
319 int
320 nr_reg_noop(void *ptr)
321 {
322 return 0;
323 }
324 #endif
326 int
327 nr_reg_rfree(void *ptr)
328 {
329 RFREE(ptr);
330 return 0;
331 }
333 int
334 nr_reg_fetch_node(char *name, unsigned char type, nr_registry_node **node, int *free_node)
335 {
336 int r, _status;
338 if ((r=nr_reg_is_valid(name)))
339 ABORT(r);
341 *node = 0;
342 *free_node = 0;
344 if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)node)))
345 ABORT(r);
347 if ((*node)->type != type)
348 ABORT(R_FAILED);
350 _status=0;
351 abort:
352 if (_status) {
353 if (*node)
354 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Couldn't fetch node '%s' ('%s'), found '%s' instead",
355 name, nr_reg_type_name(type), nr_reg_type_name((*node)->type));
356 else
357 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Couldn't fetch node '%s' ('%s')",
358 name, nr_reg_type_name(type));
359 }
360 else {
361 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "Fetched node '%s' ('%s')",
362 name, nr_reg_type_name(type));
363 }
364 return(_status);
365 }
367 int
368 nr_reg_insert_node(char *name, void *node)
369 {
370 int r, _status;
372 if ((r=nr_reg_is_valid(name)))
373 ABORT(r);
375 /* since the registry application is not multi-threaded, a node being
376 * inserted should always be a new node because the registry app must
377 * have looked for a node with this key but not found it, so it is
378 * being created/inserted now using R_ASSOC_NEW */
379 if ((r=r_assoc_insert(nr_registry, name, strlen(name)+1, node, 0, nr_reg_rfree, R_ASSOC_NEW)))
380 ABORT(r);
382 if ((r=nr_reg_set_parent_registries(name)))
383 ABORT(r);
385 if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_ADD)))
386 ABORT(r);
388 _status=0;
389 abort:
390 if (r_logging(NR_LOG_REGISTRY, LOG_INFO)) {
391 int freeit;
392 char *data = nr_reg_alloc_node_data(name, (void*)node, &freeit);
393 r_log(NR_LOG_REGISTRY, LOG_INFO,
394 "insert '%s' (%s) %s: %s", name,
395 nr_reg_type_name(((nr_registry_node*)node)->type),
396 (_status ? "FAILED" : "succeeded"), data);
397 if (freeit)
398 RFREE(data);
399 }
400 return(_status);
401 }
403 int
404 nr_reg_change_node(char *name, void *node, void *old)
405 {
406 int r, _status;
408 if ((r=nr_reg_is_valid(name)))
409 ABORT(r);
411 if (old != node) {
412 if ((r=r_assoc_insert(nr_registry, name, strlen(name)+1, node, 0, nr_reg_rfree, R_ASSOC_REPLACE)))
413 ABORT(r);
414 }
416 if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_CHANGE)))
417 ABORT(r);
419 _status=0;
420 abort:
421 if (r_logging(NR_LOG_REGISTRY, LOG_INFO)) {
422 int freeit;
423 char *data = nr_reg_alloc_node_data(name, (void*)node, &freeit);
424 r_log(NR_LOG_REGISTRY, LOG_INFO,
425 "change '%s' (%s) %s: %s", name,
426 nr_reg_type_name(((nr_registry_node*)node)->type),
427 (_status ? "FAILED" : "succeeded"), data);
428 if (freeit)
429 RFREE(data);
430 }
431 return(_status);
432 }
434 char *
435 nr_reg_alloc_node_data(char *name, nr_registry_node *node, int *freeit)
436 {
437 char *s = 0;
438 int len;
439 int alloc = 0;
440 unsigned int i;
442 *freeit = 0;
444 switch (node->type) {
445 default:
446 alloc = 100; /* plenty of room for any of the scalar types */
447 break;
448 case NR_REG_TYPE_REGISTRY:
449 alloc = strlen(name) + 1;
450 break;
451 case NR_REG_TYPE_BYTES:
452 alloc = (2 * ((nr_array_registry_node*)node)->array.length) + 1;
453 break;
454 case NR_REG_TYPE_STRING:
455 alloc = 0;
456 break;
457 }
459 if (alloc > 0) {
460 s = (void*)RMALLOC(alloc);
461 if (!s)
462 return "";
464 *freeit = 1;
465 }
467 len = alloc;
469 switch (node->type) {
470 case NR_REG_TYPE_CHAR:
471 i = ((nr_scalar_registry_node*)node)->scalar._char;
472 if (isprint(i) && ! isspace(i))
473 snprintf(s, len, "%c", (char)i);
474 else
475 snprintf(s, len, "\\%03o", (char)i);
476 break;
477 case NR_REG_TYPE_UCHAR:
478 snprintf(s, len, "0x%02x", ((nr_scalar_registry_node*)node)->scalar._uchar);
479 break;
480 case NR_REG_TYPE_INT2:
481 snprintf(s, len, "%d", ((nr_scalar_registry_node*)node)->scalar._nr_int2);
482 break;
483 case NR_REG_TYPE_UINT2:
484 snprintf(s, len, "%u", ((nr_scalar_registry_node*)node)->scalar._nr_uint2);
485 break;
486 case NR_REG_TYPE_INT4:
487 snprintf(s, len, "%d", ((nr_scalar_registry_node*)node)->scalar._nr_int4);
488 break;
489 case NR_REG_TYPE_UINT4:
490 snprintf(s, len, "%u", ((nr_scalar_registry_node*)node)->scalar._nr_uint4);
491 break;
492 case NR_REG_TYPE_INT8:
493 snprintf(s, len, "%lld", ((nr_scalar_registry_node*)node)->scalar._nr_int8);
494 break;
495 case NR_REG_TYPE_UINT8:
496 snprintf(s, len, "%llu", ((nr_scalar_registry_node*)node)->scalar._nr_uint8);
497 break;
498 case NR_REG_TYPE_DOUBLE:
499 snprintf(s, len, "%#f", ((nr_scalar_registry_node*)node)->scalar._double);
500 break;
501 case NR_REG_TYPE_REGISTRY:
502 snprintf(s, len, "%s", name);
503 break;
504 case NR_REG_TYPE_BYTES:
505 for (i = 0; i < ((nr_array_registry_node*)node)->array.length; ++i) {
506 sprintf(&s[2*i], "%02x", ((nr_array_registry_node*)node)->array.data[i]);
507 }
508 break;
509 case NR_REG_TYPE_STRING:
510 s = (char*)((nr_array_registry_node*)node)->array.data;
511 break;
512 default:
513 assert(0); /* bad value */
514 *freeit = 0;
515 s = "";
516 break;
517 }
519 return s;
520 }
522 int
523 nr_reg_get(char *name, int type, void *out)
524 {
525 int r, _status;
526 nr_scalar_registry_node *node = 0;
527 int free_node = 0;
529 if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
530 ABORT(r);
532 if ((r=nr_reg_get_data(name, node, out)))
533 ABORT(r);
535 _status=0;
536 abort:
537 if (free_node) RFREE(node);
538 return(_status);
539 }
541 int
542 nr_reg_get_data(NR_registry name, nr_scalar_registry_node *node, void *out)
543 {
544 int _status;
546 switch (node->type) {
547 case NR_REG_TYPE_CHAR:
548 *(char*)out = node->scalar._char;
549 break;
550 case NR_REG_TYPE_UCHAR:
551 *(UCHAR*)out = node->scalar._uchar;
552 break;
553 case NR_REG_TYPE_INT2:
554 *(INT2*)out = node->scalar._nr_int2;
555 break;
556 case NR_REG_TYPE_UINT2:
557 *(UINT2*)out = node->scalar._nr_uint2;
558 break;
559 case NR_REG_TYPE_INT4:
560 *(INT4*)out = node->scalar._nr_int4;
561 break;
562 case NR_REG_TYPE_UINT4:
563 *(UINT4*)out = node->scalar._nr_uint4;
564 break;
565 case NR_REG_TYPE_INT8:
566 *(INT8*)out = node->scalar._nr_int8;
567 break;
568 case NR_REG_TYPE_UINT8:
569 *(UINT8*)out = node->scalar._nr_uint8;
570 break;
571 case NR_REG_TYPE_DOUBLE:
572 *(double*)out = node->scalar._double;
573 break;
574 default:
575 ABORT(R_INTERNAL);
576 break;
577 }
579 _status=0;
580 abort:
581 return(_status);
582 }
584 int
585 nr_reg_get_array(char *name, unsigned char type, unsigned char *out, size_t size, size_t *length)
586 {
587 int r, _status;
588 nr_array_registry_node *node = 0;
589 int free_node = 0;
591 if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
592 ABORT(r);
594 if (size < node->array.length)
595 ABORT(R_BAD_ARGS);
597 if (out != 0)
598 memcpy(out, node->array.data, node->array.length);
599 if (length != 0)
600 *length = node->array.length;
602 _status=0;
603 abort:
604 if (node && free_node) RFREE(node);
605 return(_status);
606 }
608 int
609 nr_reg_set(char *name, int type, void *data)
610 {
611 int r, _status;
612 nr_scalar_registry_node *node = 0;
613 int create_node = 0;
614 int changed = 0;
615 int free_node = 0;
617 if ((r=nr_reg_fetch_node(name, type, (void*)&node, &free_node)))
618 if (r == R_NOT_FOUND) {
619 create_node = 1;
620 free_node = 1;
621 }
622 else
623 ABORT(r);
625 if (create_node) {
626 if (!(node=(void*)RCALLOC(sizeof(nr_scalar_registry_node))))
627 ABORT(R_NO_MEMORY);
629 node->type = type;
630 }
631 else {
632 if (node->type != type)
633 ABORT(R_BAD_ARGS);
634 }
636 switch (type) {
637 #define CASE(TYPE, _name, type) \
638 case TYPE: \
639 if (node->scalar._name != *(type*)data) { \
640 node->scalar._name = *(type*)data; \
641 if (! create_node) \
642 changed = 1; \
643 } \
644 break;
645 CASE(NR_REG_TYPE_CHAR, _char, char)
646 CASE(NR_REG_TYPE_UCHAR, _uchar, UCHAR)
647 CASE(NR_REG_TYPE_INT2, _nr_int2, INT2)
648 CASE(NR_REG_TYPE_UINT2, _nr_uint2, UINT2)
649 CASE(NR_REG_TYPE_INT4, _nr_int4, INT4)
650 CASE(NR_REG_TYPE_UINT4, _nr_uint4, UINT4)
651 CASE(NR_REG_TYPE_INT8, _nr_int8, INT8)
652 CASE(NR_REG_TYPE_UINT8, _nr_uint8, UINT8)
653 CASE(NR_REG_TYPE_DOUBLE, _double, double)
654 #undef CASE
656 case NR_REG_TYPE_REGISTRY:
657 /* do nothing */
658 break;
660 default:
661 ABORT(R_INTERNAL);
662 break;
663 }
665 if (create_node) {
666 if ((r=nr_reg_insert_node(name, node)))
667 ABORT(r);
668 free_node = 0;
669 }
670 else {
671 if (changed) {
672 if ((r=nr_reg_change_node(name, node, node)))
673 ABORT(r);
674 free_node = 0;
675 }
676 }
678 _status=0;
679 abort:
680 if (_status) {
681 if (node && free_node) RFREE(node);
682 }
683 return(_status);
684 }
686 int
687 nr_reg_set_array(char *name, unsigned char type, UCHAR *data, size_t length)
688 {
689 int r, _status;
690 nr_array_registry_node *old = 0;
691 nr_array_registry_node *node = 0;
692 int free_node = 0;
693 int added = 0;
694 int changed = 0;
696 if ((r=nr_reg_fetch_node(name, type, (void*)&old, &free_node))) {
697 if (r != R_NOT_FOUND)
698 ABORT(r);
699 }
700 else {
701 assert(free_node == 0);
702 }
704 if (old) {
705 if (old->type != type)
706 ABORT(R_BAD_ARGS);
708 if (old->array.length != length
709 || memcmp(old->array.data, data, length)) {
710 changed = 1;
712 if (old->array.length < length) {
713 if (!(node=(void*)RCALLOC(sizeof(nr_array_registry_node)+length)))
714 ABORT(R_NO_MEMORY);
715 }
716 else {
717 node = old;
718 }
719 }
720 }
721 else {
722 if (!(node=(void*)RCALLOC(sizeof(nr_array_registry_node)+length)))
723 ABORT(R_NO_MEMORY);
725 added = 1;
726 }
728 if (added || changed) {
729 node->type = type;
730 node->array.length = length;
731 memcpy(node->array.data, data, length);
732 }
734 if (added) {
735 if ((r=nr_reg_insert_node(name, node)))
736 ABORT(r);
737 }
738 else if (changed) {
739 if ((r=nr_reg_change_node(name, node, old)))
740 ABORT(r);
741 }
743 _status=0;
744 abort:
745 return(_status);
746 }
748 int
749 nr_reg_set_parent_registries(char *name)
750 {
751 int r, _status;
752 char *parent = 0;
753 char *dot;
755 if ((parent = r_strdup(name)) == 0)
756 ABORT(R_NO_MEMORY);
758 if ((dot = strrchr(parent, '.')) != 0) {
759 *dot = '\0';
760 if ((r=NR_reg_set_registry(parent)))
761 ABORT(r);
762 }
764 _status=0;
765 abort:
766 if (parent) RFREE(parent);
767 return(_status);
768 }
774 /* NON-STATIC METHODS */
776 int
777 nr_reg_is_valid(NR_registry name)
778 {
779 int _status;
780 unsigned int length;
781 unsigned int i;
783 if (name == 0)
784 ABORT(R_BAD_ARGS);
786 /* make sure the key is null-terminated */
787 if (memchr(name, '\0', sizeof(NR_registry)) == 0)
788 ABORT(R_BAD_ARGS);
790 length = strlen(name);
792 /* cannot begin or end with a period */
793 if (name[0] == '.')
794 ABORT(R_BAD_ARGS);
795 if (strlen(name) > 0 && name[length-1] == '.')
796 ABORT(R_BAD_ARGS);
798 /* all characters cannot be space, and must be printable and not / */
799 for (i = 0; i < length; ++i) {
800 if (isspace(name[i]) || ! (isprint(name[i]) || name[i] == '/'))
801 ABORT(R_BAD_ARGS);
802 }
804 _status=0;
805 abort:
806 if (_status) {
807 r_log(NR_LOG_REGISTRY, LOG_DEBUG, "invalid name '%s'", name);
808 }
809 return(_status);
810 }
813 int
814 nr_reg_compute_length(char *name, nr_registry_node *in, size_t *length)
815 {
816 int _status;
817 nr_array_registry_node *node = (nr_array_registry_node*)in;
819 switch (node->type) {
820 case NR_REG_TYPE_STRING:
821 *length = node->array.length - 1;
822 break;
823 case NR_REG_TYPE_BYTES:
824 *length = node->array.length;
825 break;
826 case NR_REG_TYPE_CHAR:
827 *length = sizeof(char);
828 break;
829 case NR_REG_TYPE_UCHAR:
830 *length = sizeof(UCHAR);
831 break;
832 case NR_REG_TYPE_INT2:
833 case NR_REG_TYPE_UINT2:
834 *length = 2;
835 break;
836 case NR_REG_TYPE_INT4:
837 case NR_REG_TYPE_UINT4:
838 *length = 4;
839 break;
840 case NR_REG_TYPE_INT8:
841 case NR_REG_TYPE_UINT8:
842 *length = 8;
843 break;
844 case NR_REG_TYPE_DOUBLE:
845 *length = sizeof(double);
846 break;
847 case NR_REG_TYPE_REGISTRY:
848 *length = strlen(name);
849 break;
850 default:
851 ABORT(R_INTERNAL);
852 break;
853 }
855 _status=0;
856 abort:
857 return(_status);
858 }
861 /* VTBL METHODS */
863 int
864 nr_reg_local_init(nr_registry_module *me)
865 {
866 int r, _status;
868 if (nr_registry == 0) {
869 if ((r=r_assoc_create(&nr_registry, r_assoc_crc32_hash_compute, 12)))
870 ABORT(r);
872 if ((r=nr_reg_cb_init()))
873 ABORT(r);
875 /* make sure NR_TOP_LEVEL_REGISTRY always exists */
876 if ((r=nr_reg_local_set_registry(NR_TOP_LEVEL_REGISTRY)))
877 ABORT(r);
878 }
880 _status=0;
881 abort:
882 return(_status);
883 }
885 #define NRREGGET(func, TYPE, type) \
886 int \
887 func(NR_registry name, type *out) \
888 { \
889 return nr_reg_get(name, TYPE, out); \
890 }
892 NRREGGET(nr_reg_local_get_char, NR_REG_TYPE_CHAR, char)
893 NRREGGET(nr_reg_local_get_uchar, NR_REG_TYPE_UCHAR, UCHAR)
894 NRREGGET(nr_reg_local_get_int2, NR_REG_TYPE_INT2, INT2)
895 NRREGGET(nr_reg_local_get_uint2, NR_REG_TYPE_UINT2, UINT2)
896 NRREGGET(nr_reg_local_get_int4, NR_REG_TYPE_INT4, INT4)
897 NRREGGET(nr_reg_local_get_uint4, NR_REG_TYPE_UINT4, UINT4)
898 NRREGGET(nr_reg_local_get_int8, NR_REG_TYPE_INT8, INT8)
899 NRREGGET(nr_reg_local_get_uint8, NR_REG_TYPE_UINT8, UINT8)
900 NRREGGET(nr_reg_local_get_double, NR_REG_TYPE_DOUBLE, double)
902 int
903 nr_reg_local_get_registry(NR_registry name, NR_registry out)
904 {
905 int r, _status;
906 nr_scalar_registry_node *node = 0;
907 int free_node = 0;
909 if ((r=nr_reg_fetch_node(name, NR_REG_TYPE_REGISTRY, (void*)&node, &free_node)))
910 ABORT(r);
912 strncpy(out, name, sizeof(NR_registry));
914 _status=0;
915 abort:
916 if (free_node) RFREE(node);
917 return(_status);
919 }
921 int
922 nr_reg_local_get_bytes(NR_registry name, UCHAR *out, size_t size, size_t *length)
923 {
924 return nr_reg_get_array(name, NR_REG_TYPE_BYTES, out, size, length);
925 }
927 int
928 nr_reg_local_get_string(NR_registry name, char *out, size_t size)
929 {
930 return nr_reg_get_array(name, NR_REG_TYPE_STRING, (UCHAR*)out, size, 0);
931 }
933 int
934 nr_reg_local_get_length(NR_registry name, size_t *length)
935 {
936 int r, _status;
937 nr_registry_node *node = 0;
939 if ((r=nr_reg_is_valid(name)))
940 ABORT(r);
942 if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)&node)))
943 ABORT(r);
945 if ((r=nr_reg_compute_length(name, node, length)))
946 ABORT(r);
948 _status=0;
949 abort:
950 return(_status);
951 }
953 int
954 nr_reg_local_get_type(NR_registry name, NR_registry_type type)
955 {
956 int r, _status;
957 nr_registry_node *node = 0;
958 char *str;
960 if ((r=nr_reg_is_valid(name)))
961 ABORT(r);
963 if ((r=r_assoc_fetch(nr_registry, name, strlen(name)+1, (void*)&node)))
964 ABORT(r);
966 str = nr_reg_type_name(node->type);
967 if (! str)
968 ABORT(R_BAD_ARGS);
970 strncpy(type, str, sizeof(NR_registry_type));
972 _status=0;
973 abort:
974 return(_status);
975 }
978 #define NRREGSET(func, TYPE, type) \
979 int \
980 func(NR_registry name, type data) \
981 { \
982 return nr_reg_set(name, TYPE, &data); \
983 }
985 NRREGSET(nr_reg_local_set_char, NR_REG_TYPE_CHAR, char)
986 NRREGSET(nr_reg_local_set_uchar, NR_REG_TYPE_UCHAR, UCHAR)
987 NRREGSET(nr_reg_local_set_int2, NR_REG_TYPE_INT2, INT2)
988 NRREGSET(nr_reg_local_set_uint2, NR_REG_TYPE_UINT2, UINT2)
989 NRREGSET(nr_reg_local_set_int4, NR_REG_TYPE_INT4, INT4)
990 NRREGSET(nr_reg_local_set_uint4, NR_REG_TYPE_UINT4, UINT4)
991 NRREGSET(nr_reg_local_set_int8, NR_REG_TYPE_INT8, INT8)
992 NRREGSET(nr_reg_local_set_uint8, NR_REG_TYPE_UINT8, UINT8)
993 NRREGSET(nr_reg_local_set_double, NR_REG_TYPE_DOUBLE, double)
995 int
996 nr_reg_local_set_registry(NR_registry name)
997 {
998 return nr_reg_set(name, NR_REG_TYPE_REGISTRY, 0);
999 }
1001 int
1002 nr_reg_local_set_bytes(NR_registry name, unsigned char *data, size_t length)
1003 {
1004 return nr_reg_set_array(name, NR_REG_TYPE_BYTES, data, length);
1005 }
1007 int
1008 nr_reg_local_set_string(NR_registry name, char *data)
1009 {
1010 return nr_reg_set_array(name, NR_REG_TYPE_STRING, (UCHAR*)data, strlen(data)+1);
1011 }
1013 int
1014 nr_reg_local_del(NR_registry name)
1015 {
1016 int r, _status;
1018 if ((r=nr_reg_is_valid(name)))
1019 ABORT(r);
1021 /* delete from NR_registry */
1022 if ((r=nr_reg_local_iter(name, nr_reg_local_iter_delete, 0)))
1023 ABORT(r);
1025 if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_DELETE)))
1026 ABORT(r);
1028 /* if deleting from the root, re-insert the root */
1029 if (! strcasecmp(name, NR_TOP_LEVEL_REGISTRY)) {
1030 if ((r=nr_reg_local_set_registry(NR_TOP_LEVEL_REGISTRY)))
1031 ABORT(r);
1032 }
1034 _status=0;
1035 abort:
1036 r_log(NR_LOG_REGISTRY,
1037 (_status ? LOG_INFO : LOG_INFO),
1038 "delete of '%s' %s", name,
1039 (_status ? "FAILED" : "succeeded"));
1040 return(_status);
1041 }
1043 int
1044 nr_reg_local_get_child_count(char *parent, size_t *count)
1045 {
1046 int r, _status;
1047 nr_registry_node *ignore1;
1048 int ignore2;
1051 if ((r=nr_reg_is_valid(parent)))
1052 ABORT(r);
1054 /* test to see whether it is present */
1055 if ((r=nr_reg_fetch_node(parent, NR_REG_TYPE_REGISTRY, &ignore1, &ignore2)))
1056 ABORT(r);
1058 /* sanity check that there isn't any memory to free */
1059 assert(ignore2 == 0);
1061 *count = 0;
1063 if ((r=nr_reg_local_iter(parent, nr_reg_local_count_children, count)))
1064 ABORT(r);
1066 _status=0;
1067 abort:
1068 return(_status);
1069 }
1071 int
1072 nr_reg_local_get_children(NR_registry parent, NR_registry *data, size_t size, size_t *length)
1073 {
1074 int r, _status;
1075 nr_reg_find_children_arg arg;
1077 if ((r=nr_reg_is_valid(parent)))
1078 ABORT(r);
1080 arg.children = data;
1081 arg.size = size;
1082 arg.length = 0;
1084 if ((r=nr_reg_local_iter(parent, nr_reg_local_find_children, (void*)&arg))) {
1085 if (r == R_INTERRUPTED)
1086 ABORT(R_BAD_ARGS);
1087 else
1088 ABORT(r);
1089 }
1091 assert(sizeof(*arg.children) == sizeof(NR_registry));
1092 qsort(arg.children, arg.length, sizeof(*arg.children), (void*)strcasecmp);
1094 *length = arg.length;
1096 _status = 0;
1097 abort:
1098 return(_status);
1099 }
1101 int
1102 nr_reg_local_fin(NR_registry name)
1103 {
1104 int r, _status;
1106 if ((r=nr_reg_raise_event(name, NR_REG_CB_ACTION_FINAL)))
1107 ABORT(r);
1109 _status=0;
1110 abort:
1111 return(_status);
1112 }
1114 int
1115 nr_reg_local_dump(int sorted)
1116 {
1117 int r, _status;
1119 if ((r=nr_reg_local_iter(NR_TOP_LEVEL_REGISTRY, nr_reg_local_dump_print, 0)))
1120 ABORT(r);
1122 _status=0;
1123 abort:
1124 return(_status);
1125 }
1129 static nr_registry_module_vtbl nr_reg_local_vtbl = {
1130 nr_reg_local_init,
1131 nr_reg_local_get_char,
1132 nr_reg_local_get_uchar,
1133 nr_reg_local_get_int2,
1134 nr_reg_local_get_uint2,
1135 nr_reg_local_get_int4,
1136 nr_reg_local_get_uint4,
1137 nr_reg_local_get_int8,
1138 nr_reg_local_get_uint8,
1139 nr_reg_local_get_double,
1140 nr_reg_local_get_registry,
1141 nr_reg_local_get_bytes,
1142 nr_reg_local_get_string,
1143 nr_reg_local_get_length,
1144 nr_reg_local_get_type,
1145 nr_reg_local_set_char,
1146 nr_reg_local_set_uchar,
1147 nr_reg_local_set_int2,
1148 nr_reg_local_set_uint2,
1149 nr_reg_local_set_int4,
1150 nr_reg_local_set_uint4,
1151 nr_reg_local_set_int8,
1152 nr_reg_local_set_uint8,
1153 nr_reg_local_set_double,
1154 nr_reg_local_set_registry,
1155 nr_reg_local_set_bytes,
1156 nr_reg_local_set_string,
1157 nr_reg_local_del,
1158 nr_reg_local_get_child_count,
1159 nr_reg_local_get_children,
1160 nr_reg_local_fin,
1161 nr_reg_local_dump
1162 };
1164 static nr_registry_module nr_reg_local_module = { 0, &nr_reg_local_vtbl };
1166 void *NR_REG_MODE_LOCAL = &nr_reg_local_module;