xref: /netbsd/common/lib/libppath/ppath.c (revision 6dd14d72)
1 /* $NetBSD: ppath.c,v 1.5 2020/06/06 22:28:07 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by David Young <dyoung@NetBSD.org>.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: ppath.c,v 1.5 2020/06/06 22:28:07 thorpej Exp $");
34 
35 #ifdef _KERNEL
36 #include <sys/systm.h>
37 #endif
38 #include <ppath/ppath.h>
39 #include <ppath/ppath_impl.h>
40 
41 enum _ppath_type {
42 	  PPATH_T_IDX = 0
43 	, PPATH_T_KEY = 1
44 };
45 
46 typedef enum _ppath_type ppath_type_t;
47 
48 struct _ppath_component {
49 	unsigned int	pc_refcnt;
50 	ppath_type_t	pc_type;
51 	union {
52 		char *u_key;
53 		unsigned int u_idx;
54 	} pc_u;
55 #define pc_key pc_u.u_key
56 #define pc_idx pc_u.u_idx
57 };
58 
59 struct _ppath {
60 	unsigned int	p_refcnt;
61 	unsigned int	p_len;
62 	ppath_component_t *p_cmpt[PPATH_MAX_COMPONENTS];
63 };
64 
65 static int ppath_copydel_object_of_type(prop_object_t, prop_object_t *,
66     const ppath_t *, prop_type_t);
67 static int ppath_copyset_object_helper(prop_object_t, prop_object_t *,
68     const ppath_t *, const prop_object_t);
69 
70 static void
ppath_strfree(char * s)71 ppath_strfree(char *s)
72 {
73 	size_t size = strlen(s) + 1;
74 
75 	ppath_free(s, size);
76 }
77 
78 static char *
ppath_strdup(const char * s)79 ppath_strdup(const char *s)
80 {
81 	size_t size = strlen(s) + 1;
82 	char *p;
83 
84 	if ((p = ppath_alloc(size)) == NULL)
85 		return NULL;
86 
87 	return strcpy(p, s);
88 }
89 
90 int
ppath_component_idx(const ppath_component_t * pc)91 ppath_component_idx(const ppath_component_t *pc)
92 {
93 	if (pc->pc_type != PPATH_T_IDX)
94 		return -1;
95 	return pc->pc_idx;
96 }
97 
98 const char *
ppath_component_key(const ppath_component_t * pc)99 ppath_component_key(const ppath_component_t *pc)
100 {
101 	if (pc->pc_type != PPATH_T_KEY)
102 		return NULL;
103 	return pc->pc_key;
104 }
105 
106 ppath_component_t *
ppath_idx(unsigned int idx)107 ppath_idx(unsigned int idx)
108 {
109 	ppath_component_t *pc;
110 
111 	if ((pc = ppath_alloc(sizeof(*pc))) == NULL)
112 		return NULL;
113 	pc->pc_idx = idx;
114 	pc->pc_type = PPATH_T_IDX;
115 	pc->pc_refcnt = 1;
116 	ppath_component_extant_inc();
117 	return pc;
118 }
119 
120 ppath_component_t *
ppath_key(const char * key)121 ppath_key(const char *key)
122 {
123 	ppath_component_t *pc;
124 
125 	if ((pc = ppath_alloc(sizeof(*pc))) == NULL)
126 		return NULL;
127 
128 	if ((pc->pc_key = ppath_strdup(key)) == NULL) {
129 		ppath_free(pc, sizeof(*pc));
130 		return NULL;
131 	}
132 	pc->pc_type = PPATH_T_KEY;
133 	pc->pc_refcnt = 1;
134 	ppath_component_extant_inc();
135 	return pc;
136 }
137 
138 ppath_component_t *
ppath_component_retain(ppath_component_t * pc)139 ppath_component_retain(ppath_component_t *pc)
140 {
141 	ppath_assert(pc->pc_refcnt != 0);
142 	pc->pc_refcnt++;
143 
144 	return pc;
145 }
146 
147 void
ppath_component_release(ppath_component_t * pc)148 ppath_component_release(ppath_component_t *pc)
149 {
150 	ppath_assert(pc->pc_refcnt != 0);
151 
152 	if (--pc->pc_refcnt != 0)
153 		return;
154 	if (pc->pc_type == PPATH_T_KEY)
155 		ppath_strfree(pc->pc_key);
156 	ppath_component_extant_dec();
157 	ppath_free(pc, sizeof(*pc));
158 }
159 
160 ppath_t *
ppath_create(void)161 ppath_create(void)
162 {
163 	ppath_t *p;
164 
165 	if ((p = ppath_alloc(sizeof(*p))) == NULL)
166 		return NULL;
167 
168 	p->p_refcnt = 1;
169 	ppath_extant_inc();
170 
171 	return p;
172 }
173 
174 ppath_t *
ppath_pop(ppath_t * p,ppath_component_t ** pcp)175 ppath_pop(ppath_t *p, ppath_component_t **pcp)
176 {
177 	ppath_component_t *pc;
178 
179 	if (p == NULL || p->p_len == 0)
180 		return NULL;
181 
182 	pc = p->p_cmpt[--p->p_len];
183 
184 	if (pcp != NULL)
185 		*pcp = pc;
186 	else
187 		ppath_component_release(pc);
188 
189 	return p;
190 }
191 
192 ppath_t *
ppath_push(ppath_t * p,ppath_component_t * pc)193 ppath_push(ppath_t *p, ppath_component_t *pc)
194 {
195 	if (p == NULL || p->p_len == __arraycount(p->p_cmpt))
196 		return NULL;
197 
198 	p->p_cmpt[p->p_len++] = ppath_component_retain(pc);
199 
200 	return p;
201 }
202 
203 ppath_component_t *
ppath_component_at(const ppath_t * p,unsigned int i)204 ppath_component_at(const ppath_t *p, unsigned int i)
205 {
206 	ppath_component_t *pc;
207 
208 	if (p == NULL || i >= p->p_len)
209 		return NULL;
210 
211 	pc = p->p_cmpt[i];
212 
213 	return ppath_component_retain(pc);
214 }
215 
216 unsigned int
ppath_length(const ppath_t * p)217 ppath_length(const ppath_t *p)
218 {
219 	return p->p_len;
220 }
221 
222 ppath_t *
ppath_subpath(const ppath_t * p,unsigned int first,unsigned int exclast)223 ppath_subpath(const ppath_t *p, unsigned int first, unsigned int exclast)
224 {
225 	unsigned int i;
226 	ppath_t *np;
227 	ppath_component_t *pc;
228 
229 	if (p == NULL || (np = ppath_create()) == NULL)
230 		return NULL;
231 
232 	for (i = first; i < exclast; i++) {
233 		if ((pc = ppath_component_at(p, i)) == NULL)
234 			break;
235 		ppath_push(np, pc);
236 		ppath_component_release(pc);
237 	}
238 	return np;
239 }
240 
241 ppath_t *
ppath_push_idx(ppath_t * p0,unsigned int idx)242 ppath_push_idx(ppath_t *p0, unsigned int idx)
243 {
244 	ppath_component_t *pc;
245 	ppath_t *p;
246 
247 	if ((pc = ppath_idx(idx)) == NULL)
248 		return NULL;
249 
250 	p = ppath_push(p0, pc);
251 	ppath_component_release(pc);
252 	return p;
253 }
254 
255 ppath_t *
ppath_push_key(ppath_t * p0,const char * key)256 ppath_push_key(ppath_t *p0, const char *key)
257 {
258 	ppath_component_t *pc;
259 	ppath_t *p;
260 
261 	if ((pc = ppath_key(key)) == NULL)
262 		return NULL;
263 
264 	p = ppath_push(p0, pc);
265 	ppath_component_release(pc);
266 	return p;
267 }
268 
269 ppath_t *
ppath_replace_idx(ppath_t * p,unsigned int idx)270 ppath_replace_idx(ppath_t *p, unsigned int idx)
271 {
272 	ppath_component_t *pc0, *pc;
273 
274 	if (p == NULL || p->p_len == 0)
275 		return NULL;
276 
277 	pc0 = p->p_cmpt[p->p_len - 1];
278 
279 	if (pc0->pc_type != PPATH_T_IDX)
280 		return NULL;
281 
282 	if ((pc = ppath_idx(idx)) == NULL)
283 		return NULL;
284 
285 	p->p_cmpt[p->p_len - 1] = pc;
286 	ppath_component_release(pc0);
287 
288 	return p;
289 }
290 
291 ppath_t *
ppath_replace_key(ppath_t * p,const char * key)292 ppath_replace_key(ppath_t *p, const char *key)
293 {
294 	ppath_component_t *pc0, *pc;
295 
296 	if (p == NULL || p->p_len == 0)
297 		return NULL;
298 
299 	pc0 = p->p_cmpt[p->p_len - 1];
300 
301 	if (pc0->pc_type != PPATH_T_KEY)
302 		return NULL;
303 
304 	if ((pc = ppath_key(key)) == NULL)
305 		return NULL;
306 
307 	p->p_cmpt[p->p_len - 1] = pc;
308 	ppath_component_release(pc0);
309 
310 	return p;
311 }
312 
313 ppath_t *
ppath_copy(const ppath_t * p0)314 ppath_copy(const ppath_t *p0)
315 {
316 	ppath_t *p;
317 	unsigned int i;
318 
319 	if ((p = ppath_create()) == NULL)
320 		return NULL;
321 
322 	for (i = 0; i < p0->p_len; i++)
323 		p->p_cmpt[i] = ppath_component_retain(p0->p_cmpt[i]);
324 	p->p_len = p0->p_len;
325 	return p;
326 }
327 
328 ppath_t *
ppath_retain(ppath_t * p)329 ppath_retain(ppath_t *p)
330 {
331 	assert(p->p_refcnt != 0);
332 
333 	p->p_refcnt++;
334 
335 	return p;
336 }
337 
338 void
ppath_release(ppath_t * p)339 ppath_release(ppath_t *p)
340 {
341 	unsigned int i;
342 
343 	assert(p->p_refcnt != 0);
344 
345 	if (--p->p_refcnt != 0)
346 		return;
347 
348 	for (i = 0; i < p->p_len; i++)
349 		ppath_component_release(p->p_cmpt[i]);
350 
351 	ppath_extant_dec();
352 	ppath_free(p, sizeof(*p));
353 }
354 
355 static prop_object_t
ppath_lookup_helper(prop_object_t o0,const ppath_t * p,prop_object_t * pop,ppath_component_t ** pcp,unsigned int * ip)356 ppath_lookup_helper(prop_object_t o0, const ppath_t *p, prop_object_t *pop,
357     ppath_component_t **pcp, unsigned int *ip)
358 {
359 	unsigned int i;
360 	prop_object_t o, po;
361 	ppath_type_t t;
362 	ppath_component_t *pc = NULL;
363 
364 	for (po = NULL, o = o0, i = 0; i < p->p_len && o != NULL; i++) {
365 		pc = p->p_cmpt[i];
366 		t = pc->pc_type;
367 		switch (prop_object_type(o)) {
368 		case PROP_TYPE_ARRAY:
369 			po = o;
370 			o = (t == PPATH_T_IDX)
371 			    ? prop_array_get(o, pc->pc_idx)
372 			    : NULL;
373 			break;
374 		case PROP_TYPE_DICTIONARY:
375 			po = o;
376 			o = (t == PPATH_T_KEY)
377 			    ? prop_dictionary_get(o, pc->pc_key)
378 			    : NULL;
379 			break;
380 		default:
381 			o = NULL;
382 			break;
383 		}
384 	}
385 	if (pop != NULL)
386 		*pop = po;
387 	if (pcp != NULL)
388 		*pcp = pc;
389 	if (ip != NULL)
390 		*ip = i;
391 	return o;
392 }
393 
394 prop_object_t
ppath_lookup(prop_object_t o,const ppath_t * p)395 ppath_lookup(prop_object_t o, const ppath_t *p)
396 {
397 	return ppath_lookup_helper(o, p, NULL, NULL, NULL);
398 }
399 
400 static int
ppath_create_object_and_release(prop_object_t o,const ppath_t * p,prop_object_t v)401 ppath_create_object_and_release(prop_object_t o, const ppath_t *p,
402     prop_object_t v)
403 {
404 	int rc;
405 
406 	rc = ppath_create_object(o, p, v);
407 	prop_object_release(v);
408 	return rc;
409 }
410 
411 int
ppath_create_string(prop_object_t o,const ppath_t * p,const char * s)412 ppath_create_string(prop_object_t o, const ppath_t *p, const char *s)
413 {
414 	return ppath_create_object_and_release(o, p,
415 	    prop_string_create_copy(s));
416 }
417 
418 int
ppath_create_data(prop_object_t o,const ppath_t * p,const void * data,size_t size)419 ppath_create_data(prop_object_t o, const ppath_t *p,
420     const void *data, size_t size)
421 {
422 	return ppath_create_object_and_release(o, p,
423 	    prop_data_create_copy(data, size));
424 }
425 
426 int
ppath_create_uint64(prop_object_t o,const ppath_t * p,uint64_t u)427 ppath_create_uint64(prop_object_t o, const ppath_t *p, uint64_t u)
428 {
429 	return ppath_create_object_and_release(o, p,
430 	    prop_number_create_unsigned(u));
431 }
432 
433 int
ppath_create_int64(prop_object_t o,const ppath_t * p,int64_t i)434 ppath_create_int64(prop_object_t o, const ppath_t *p, int64_t i)
435 {
436 	return ppath_create_object_and_release(o, p,
437 	    prop_number_create_signed(i));
438 }
439 
440 int
ppath_create_bool(prop_object_t o,const ppath_t * p,bool b)441 ppath_create_bool(prop_object_t o, const ppath_t *p, bool b)
442 {
443 	return ppath_create_object_and_release(o, p, prop_bool_create(b));
444 }
445 
446 int
ppath_create_object(prop_object_t o,const ppath_t * p,prop_object_t v)447 ppath_create_object(prop_object_t o, const ppath_t *p, prop_object_t v)
448 {
449 	unsigned int i;
450 	ppath_component_t *pc;
451 	prop_object_t po;
452 
453 	if (ppath_lookup_helper(o, p, &po, &pc, &i) != NULL)
454 		return EEXIST;
455 
456 	if (i != ppath_length(p))
457 		return ENOENT;
458 
459 	switch (pc->pc_type) {
460 	case PPATH_T_IDX:
461 		return prop_array_set(po, pc->pc_idx, v) ? 0 : ENOMEM;
462 	case PPATH_T_KEY:
463 		return prop_dictionary_set(po, pc->pc_key, v) ? 0 : ENOMEM;
464 	default:
465 		return ENOENT;
466 	}
467 }
468 
469 int
ppath_set_object(prop_object_t o,const ppath_t * p,prop_object_t v)470 ppath_set_object(prop_object_t o, const ppath_t *p, prop_object_t v)
471 {
472 	ppath_component_t *pc;
473 	prop_object_t po;
474 
475 	if (ppath_lookup_helper(o, p, &po, &pc, NULL) == NULL)
476 		return ENOENT;
477 
478 	switch (pc->pc_type) {
479 	case PPATH_T_IDX:
480 		return prop_array_set(po, pc->pc_idx, v) ? 0 : ENOMEM;
481 	case PPATH_T_KEY:
482 		return prop_dictionary_set(po, pc->pc_key, v) ? 0 : ENOMEM;
483 	default:
484 		return ENOENT;
485 	}
486 }
487 
488 static int
ppath_set_object_and_release(prop_object_t o,const ppath_t * p,prop_object_t v)489 ppath_set_object_and_release(prop_object_t o, const ppath_t *p, prop_object_t v)
490 {
491 	prop_object_t ov;
492 	int rc;
493 
494 	if (v == NULL)
495 		return ENOMEM;
496 
497 	if ((ov = ppath_lookup_helper(o, p, NULL, NULL, NULL)) == NULL)
498 		return ENOENT;
499 
500 	if (prop_object_type(ov) != prop_object_type(v))
501 		return EFTYPE;
502 
503 	rc = ppath_set_object(o, p, v);
504 	prop_object_release(v);
505 	return rc;
506 }
507 
508 int
ppath_get_object(prop_object_t o,const ppath_t * p,prop_object_t * vp)509 ppath_get_object(prop_object_t o, const ppath_t *p, prop_object_t *vp)
510 {
511 	prop_object_t v;
512 
513 	if ((v = ppath_lookup_helper(o, p, NULL, NULL, NULL)) == NULL)
514 		return ENOENT;
515 
516 	if (vp != NULL)
517 		*vp = v;
518 	return 0;
519 }
520 
521 static int
ppath_get_object_of_type(prop_object_t o,const ppath_t * p,prop_object_t * vp,prop_type_t t)522 ppath_get_object_of_type(prop_object_t o, const ppath_t *p, prop_object_t *vp,
523     prop_type_t t)
524 {
525 	int rc;
526 
527 	if ((rc = ppath_get_object(o, p, vp)) != 0)
528 		return rc;
529 
530 	return (prop_object_type(*vp) == t) ? 0 : EFTYPE;
531 }
532 
533 int
ppath_delete_object(prop_object_t o,const ppath_t * p)534 ppath_delete_object(prop_object_t o, const ppath_t *p)
535 {
536 	ppath_component_t *pc;
537 	prop_object_t po;
538 
539 	if (ppath_lookup_helper(o, p, &po, &pc, NULL) == NULL)
540 		return ENOENT;
541 
542 	switch (pc->pc_type) {
543 	case PPATH_T_IDX:
544 		prop_array_remove(po, pc->pc_idx);
545 		return 0;
546 	case PPATH_T_KEY:
547 		prop_dictionary_remove(po, pc->pc_key);
548 		return 0;
549 	default:
550 		return ENOENT;
551 	}
552 }
553 
554 static int
ppath_delete_object_of_type(prop_object_t o,const ppath_t * p,prop_type_t t)555 ppath_delete_object_of_type(prop_object_t o, const ppath_t *p, prop_type_t t)
556 {
557 	prop_object_t v;
558 
559 	if ((v = ppath_lookup_helper(o, p, NULL, NULL, NULL)) == NULL)
560 		return ENOENT;
561 
562 	if (prop_object_type(v) != t)
563 		return EFTYPE;
564 
565 	return ppath_delete_object(o, p);
566 }
567 
568 int
ppath_copydel_string(prop_object_t o,prop_object_t * op,const ppath_t * p)569 ppath_copydel_string(prop_object_t o, prop_object_t *op, const ppath_t *p)
570 {
571 	return ppath_copydel_object_of_type(o, op, p, PROP_TYPE_STRING);
572 }
573 
574 int
ppath_copydel_data(prop_object_t o,prop_object_t * op,const ppath_t * p)575 ppath_copydel_data(prop_object_t o, prop_object_t *op, const ppath_t *p)
576 {
577 	return ppath_copydel_object_of_type(o, op, p, PROP_TYPE_DATA);
578 }
579 
580 int
ppath_copydel_uint64(prop_object_t o,prop_object_t * op,const ppath_t * p)581 ppath_copydel_uint64(prop_object_t o, prop_object_t *op, const ppath_t *p)
582 {
583 	return ppath_copydel_object_of_type(o, op, p, PROP_TYPE_NUMBER);
584 }
585 
586 int
ppath_copydel_int64(prop_object_t o,prop_object_t * op,const ppath_t * p)587 ppath_copydel_int64(prop_object_t o, prop_object_t *op, const ppath_t *p)
588 {
589 	return ppath_copydel_object_of_type(o, op, p, PROP_TYPE_NUMBER);
590 }
591 
592 int
ppath_copydel_bool(prop_object_t o,prop_object_t * op,const ppath_t * p)593 ppath_copydel_bool(prop_object_t o, prop_object_t *op, const ppath_t *p)
594 {
595 	return ppath_copydel_object_of_type(o, op, p, PROP_TYPE_BOOL);
596 }
597 
598 static int
ppath_copydel_object_of_type(prop_object_t o,prop_object_t * op,const ppath_t * p,prop_type_t t)599 ppath_copydel_object_of_type(prop_object_t o, prop_object_t *op,
600     const ppath_t *p, prop_type_t t)
601 {
602 	prop_object_t v;
603 
604 	if ((v = ppath_lookup_helper(o, p, NULL, NULL, NULL)) == NULL)
605 		return ENOENT;
606 
607 	if (prop_object_type(v) != t)
608 		return EFTYPE;
609 
610 	return ppath_copydel_object(o, op, p);
611 }
612 
613 int
ppath_copydel_object(prop_object_t o,prop_object_t * op,const ppath_t * p)614 ppath_copydel_object(prop_object_t o, prop_object_t *op, const ppath_t *p)
615 {
616 	return ppath_copyset_object_helper(o, op, p, NULL);
617 }
618 
619 int
ppath_copyset_object(prop_object_t o,prop_object_t * op,const ppath_t * p,const prop_object_t v)620 ppath_copyset_object(prop_object_t o, prop_object_t *op, const ppath_t *p,
621     const prop_object_t v)
622 {
623 	ppath_assert(v != NULL);
624 	return ppath_copyset_object_helper(o, op, p, v);
625 }
626 
627 static int
ppath_copyset_object_helper(prop_object_t o,prop_object_t * op,const ppath_t * p0,const prop_object_t v0)628 ppath_copyset_object_helper(prop_object_t o, prop_object_t *op,
629     const ppath_t *p0, const prop_object_t v0)
630 {
631 	bool copy, success;
632 	ppath_component_t *npc, *pc;
633 	ppath_t *cp, *p;
634 	prop_object_t npo = NULL, po, v;
635 
636 	for (cp = p = ppath_copy(p0), v = v0;
637 	     p != NULL;
638 	     p = ppath_pop(p, NULL), v = npo) {
639 
640 		if (ppath_lookup_helper(o, p, &po, &pc, NULL) == NULL)
641 			return ENOENT;
642 
643 		if (pc == NULL)
644 			break;
645 
646 		if (ppath_lookup_helper(*op, p, &npo, &npc, NULL) == NULL)
647 			npo = po;
648 
649 		copy = (npo == po);
650 
651 		switch (pc->pc_type) {
652 		case PPATH_T_IDX:
653 			if (copy && (npo = prop_array_copy_mutable(po)) == NULL)
654 				return ENOMEM;
655 			success = (v == NULL)
656 			    ? (prop_array_remove(npo, pc->pc_idx), true)
657 			    : prop_array_set(npo, pc->pc_idx, v);
658 			break;
659 		case PPATH_T_KEY:
660 			if (copy &&
661 			    (npo = prop_dictionary_copy_mutable(po)) == NULL)
662 				return ENOMEM;
663 			success = (v == NULL)
664 			    ? (prop_dictionary_remove(npo, pc->pc_key), true)
665 			    : prop_dictionary_set(npo, pc->pc_key, v);
666 			break;
667 		default:
668 			return ENOENT;
669 		}
670 		if (!success) {
671 			if (copy)
672 				prop_object_release(npo);
673 			return ENOMEM;
674 		}
675 	}
676 
677 	if (cp == NULL)
678 		return ENOMEM;
679 
680 	ppath_release(cp);
681 
682 	if (op != NULL && npo != NULL)
683 		*op = npo;
684 	else if (npo != NULL)
685 		prop_object_release(npo);
686 
687 	return 0;
688 }
689 
690 static int
ppath_copyset_object_and_release(prop_object_t o,prop_object_t * op,const ppath_t * p,prop_object_t v)691 ppath_copyset_object_and_release(prop_object_t o, prop_object_t *op,
692     const ppath_t *p, prop_object_t v)
693 {
694 	prop_object_t ov;
695 	int rc;
696 
697 	if (v == NULL)
698 		return ENOMEM;
699 
700 	if ((ov = ppath_lookup_helper(o, p, NULL, NULL, NULL)) == NULL)
701 		return ENOENT;
702 
703 	if (prop_object_type(ov) != prop_object_type(v))
704 		return EFTYPE;
705 
706 	rc = ppath_copyset_object(o, op, p, v);
707 	prop_object_release(v);
708 	return rc;
709 }
710 
711 int
ppath_copyset_bool(prop_object_t o,prop_object_t * op,const ppath_t * p,bool b)712 ppath_copyset_bool(prop_object_t o, prop_object_t *op, const ppath_t *p, bool b)
713 {
714 	return ppath_copyset_object_and_release(o, op, p, prop_bool_create(b));
715 }
716 
717 int
ppath_set_bool(prop_object_t o,const ppath_t * p,bool b)718 ppath_set_bool(prop_object_t o, const ppath_t *p, bool b)
719 {
720 	return ppath_set_object_and_release(o, p, prop_bool_create(b));
721 }
722 
723 int
ppath_get_bool(prop_object_t o,const ppath_t * p,bool * bp)724 ppath_get_bool(prop_object_t o, const ppath_t *p, bool *bp)
725 {
726 	prop_object_t v;
727 	int rc;
728 
729 	if ((rc = ppath_get_object_of_type(o, p, &v, PROP_TYPE_BOOL)) != 0)
730 		return rc;
731 
732 	if (bp != NULL)
733 		*bp = prop_bool_true(v);
734 
735 	return 0;
736 }
737 
738 int
ppath_delete_bool(prop_object_t o,const ppath_t * p)739 ppath_delete_bool(prop_object_t o, const ppath_t *p)
740 {
741 	return ppath_delete_object_of_type(o, p, PROP_TYPE_BOOL);
742 }
743 
744 int
ppath_copyset_data(prop_object_t o,prop_object_t * op,const ppath_t * p,const void * data,size_t size)745 ppath_copyset_data(prop_object_t o, prop_object_t *op, const ppath_t *p,
746     const void *data, size_t size)
747 {
748 	return ppath_copyset_object_and_release(o, op, p,
749 	    prop_data_create_copy(data, size));
750 }
751 
752 int
ppath_set_data(prop_object_t o,const ppath_t * p,const void * data,size_t size)753 ppath_set_data(prop_object_t o, const ppath_t *p, const void *data, size_t size)
754 {
755 	return ppath_set_object_and_release(o, p,
756 	    prop_data_create_copy(data, size));
757 }
758 
759 int
ppath_get_data(prop_object_t o,const ppath_t * p,const void ** datap,size_t * sizep)760 ppath_get_data(prop_object_t o, const ppath_t *p, const void **datap,
761     size_t *sizep)
762 {
763 	prop_object_t v;
764 	int rc;
765 
766 	if ((rc = ppath_get_object_of_type(o, p, &v, PROP_TYPE_DATA)) != 0)
767 		return rc;
768 
769 	if (datap != NULL)
770 		*datap = prop_data_value(v);
771 	if (sizep != NULL)
772 		*sizep = prop_data_size(v);
773 
774 	return 0;
775 }
776 
777 int
ppath_dup_data(prop_object_t o,const ppath_t * p,void ** datap,size_t * sizep)778 ppath_dup_data(prop_object_t o, const ppath_t *p, void **datap, size_t *sizep)
779 {
780 	prop_object_t v;
781 	int rc;
782 
783 	if ((rc = ppath_get_object_of_type(o, p, &v, PROP_TYPE_DATA)) != 0)
784 		return rc;
785 
786 	const size_t data_size = prop_data_size(v);
787 
788 	if (datap != NULL) {
789 		void *buf = ppath_alloc(data_size);
790 		if (buf != NULL)
791 			(void) prop_data_copy_value(v, buf, data_size);
792 		*datap = buf;
793 	}
794 	if (sizep != NULL)
795 		*sizep = data_size;
796 
797 	return 0;
798 }
799 
800 int
ppath_delete_data(prop_object_t o,const ppath_t * p)801 ppath_delete_data(prop_object_t o, const ppath_t *p)
802 {
803 	return ppath_delete_object_of_type(o, p, PROP_TYPE_DATA);
804 }
805 
806 int
ppath_copyset_int64(prop_object_t o,prop_object_t * op,const ppath_t * p,int64_t i)807 ppath_copyset_int64(prop_object_t o, prop_object_t *op, const ppath_t *p,
808     int64_t i)
809 {
810 	return ppath_copyset_object_and_release(o, op, p,
811 	    prop_number_create_signed(i));
812 }
813 
814 int
ppath_set_int64(prop_object_t o,const ppath_t * p,int64_t i)815 ppath_set_int64(prop_object_t o, const ppath_t *p, int64_t i)
816 {
817 	return ppath_set_object_and_release(o, p,
818 	    prop_number_create_signed(i));
819 }
820 
821 int
ppath_get_int64(prop_object_t o,const ppath_t * p,int64_t * ip)822 ppath_get_int64(prop_object_t o, const ppath_t *p, int64_t *ip)
823 {
824 	prop_object_t v;
825 	int rc;
826 
827 	if ((rc = ppath_get_object_of_type(o, p, &v, PROP_TYPE_DATA)) != 0)
828 		return rc;
829 
830 	if (prop_number_unsigned(v))
831 		return EFTYPE;
832 
833 	if (ip != NULL)
834 		*ip = prop_number_signed_value(v);
835 
836 	return 0;
837 }
838 
839 int
ppath_delete_int64(prop_object_t o,const ppath_t * p)840 ppath_delete_int64(prop_object_t o, const ppath_t *p)
841 {
842 	return ppath_delete_object_of_type(o, p, PROP_TYPE_NUMBER);
843 }
844 
845 int
ppath_copyset_string(prop_object_t o,prop_object_t * op,const ppath_t * p,const char * s)846 ppath_copyset_string(prop_object_t o, prop_object_t *op, const ppath_t *p,
847     const char *s)
848 {
849 	return ppath_copyset_object_and_release(o, op, p,
850 	    prop_string_create_copy(s));
851 }
852 
853 int
ppath_set_string(prop_object_t o,const ppath_t * p,const char * s)854 ppath_set_string(prop_object_t o, const ppath_t *p, const char *s)
855 {
856 	return ppath_set_object_and_release(o, p,
857 	    prop_string_create_copy(s));
858 }
859 
860 int
ppath_get_string(prop_object_t o,const ppath_t * p,const char ** sp)861 ppath_get_string(prop_object_t o, const ppath_t *p, const char **sp)
862 {
863 	int rc;
864 	prop_object_t v;
865 
866 	if ((rc = ppath_get_object_of_type(o, p, &v, PROP_TYPE_STRING)) != 0)
867 		return rc;
868 
869 	if (sp != NULL)
870 		*sp = prop_string_value(v);
871 
872 	return 0;
873 }
874 
875 int
ppath_dup_string(prop_object_t o,const ppath_t * p,char ** sp)876 ppath_dup_string(prop_object_t o, const ppath_t *p, char **sp)
877 {
878 	int rc;
879 	prop_object_t v;
880 
881 	if ((rc = ppath_get_object_of_type(o, p, &v, PROP_TYPE_STRING)) != 0)
882 		return rc;
883 
884 	const size_t string_size = prop_string_size(v);
885 
886 	if (sp != NULL) {
887 		char *cp = ppath_alloc(string_size + 1);
888 		if (cp != NULL)
889 			(void)prop_string_copy_value(v, cp, string_size + 1);
890 		*sp = cp;
891 	}
892 
893 	return 0;
894 }
895 
896 int
ppath_delete_string(prop_object_t o,const ppath_t * p)897 ppath_delete_string(prop_object_t o, const ppath_t *p)
898 {
899 	return ppath_delete_object_of_type(o, p, PROP_TYPE_STRING);
900 }
901 
902 int
ppath_copyset_uint64(prop_object_t o,prop_object_t * op,const ppath_t * p,uint64_t u)903 ppath_copyset_uint64(prop_object_t o, prop_object_t *op, const ppath_t *p,
904     uint64_t u)
905 {
906 	return ppath_copyset_object_and_release(o, op, p,
907 	    prop_number_create_unsigned(u));
908 }
909 
910 int
ppath_set_uint64(prop_object_t o,const ppath_t * p,uint64_t u)911 ppath_set_uint64(prop_object_t o, const ppath_t *p, uint64_t u)
912 {
913 	return ppath_set_object_and_release(o, p,
914 	    prop_number_create_unsigned(u));
915 }
916 
917 int
ppath_get_uint64(prop_object_t o,const ppath_t * p,uint64_t * up)918 ppath_get_uint64(prop_object_t o, const ppath_t *p, uint64_t *up)
919 {
920 	prop_object_t v;
921 	int rc;
922 
923 	if ((rc = ppath_get_object_of_type(o, p, &v, PROP_TYPE_DATA)) != 0)
924 		return rc;
925 
926 	if (!prop_number_unsigned(v))
927 		return EFTYPE;
928 
929 	if (up != NULL)
930 		*up = prop_number_unsigned_value(v);
931 
932 	return 0;
933 }
934 
935 int
ppath_delete_uint64(prop_object_t o,const ppath_t * p)936 ppath_delete_uint64(prop_object_t o, const ppath_t *p)
937 {
938 	return ppath_delete_object_of_type(o, p, PROP_TYPE_NUMBER);
939 }
940