4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
34 #include <sys/mdesc.h>
35 #include <sys/mdesc_impl.h>
36 #include <sys/sysmacros.h>
37 #include "mdesc_mutable.h"
39 static void md_free_prop(mmd_t
*mdp
, md_prop_t
*propp
);
40 static void md_free_string(mmd_t
*mdp
, md_string_t
*msp
);
41 static void md_free_data_block(mmd_t
*mdp
, md_data_block_t
*mdbp
);
44 md_byte_hash(uint8_t *bp
, int len
)
49 for (i
= 0; i
< len
; i
++) {
51 hash
= (hash
>> 27) | (hash
<< 5) | bp
[i
];
58 md_find_string(mmd_t
*mdp
, char *strp
, uint32_t *hashp
)
63 hash
= md_byte_hash((uint8_t *)strp
, strlen(strp
));
68 CHAIN_ITER(mdp
->string_list
, msp
) {
69 if (msp
->hash
== hash
&& strcmp(msp
->strp
, strp
) == 0)
77 md_new_string(mmd_t
*mdp
, char *strp
)
82 msp
= md_find_string(mdp
, strp
, &hash
);
84 msp
= calloc(1, sizeof (md_string_t
));
87 msp
->strp
= strdup(strp
);
88 if (msp
->strp
== NULL
) {
92 msp
->size
= strlen(strp
) + 1;
95 msp
->build_offset
= MD_OFFSET_UNDEF
;
96 CHAIN_ADD(mdp
->string_list
, msp
);
103 static md_data_block_t
*
104 md_find_data_block(mmd_t
*mdp
, uint8_t *datap
, int len
, uint32_t *hashp
)
106 md_data_block_t
*dbp
;
109 hash
= md_byte_hash(datap
, len
);
114 CHAIN_ITER(mdp
->data_block_list
, dbp
) {
115 if (dbp
->size
== len
&&
116 dbp
->hash
== hash
&& bcmp(dbp
->datap
, datap
, len
) == 0)
123 static md_data_block_t
*
124 md_new_data_block(mmd_t
*mdp
, uint8_t *bufp
, int len
)
126 md_data_block_t
*dbp
;
129 dbp
= md_find_data_block(mdp
, bufp
, len
, &hash
);
131 dbp
= calloc(1, sizeof (md_data_block_t
));
134 dbp
->datap
= malloc(len
);
135 if (dbp
->datap
== NULL
) {
139 (void) memcpy(dbp
->datap
, bufp
, len
);
143 dbp
->build_offset
= MD_OFFSET_UNDEF
;
144 CHAIN_ADD(mdp
->data_block_list
, dbp
);
152 md_new_node(mmd_t
*mdp
, char *sp
)
156 nodep
= calloc(1, sizeof (md_node_t
));
159 nodep
->typep
= md_new_string(mdp
, sp
);
160 if (nodep
->typep
== NULL
) {
164 CHAIN_ADD(mdp
->node_list
, nodep
);
170 md_new_property(mmd_t
*mdp
, md_node_t
*nodep
, uint8_t type
, char *sp
)
174 propp
= calloc(1, sizeof (md_prop_t
));
178 propp
->sp
= md_new_string(mdp
, sp
);
179 if (propp
->sp
== NULL
) {
184 CHAIN_ADD(nodep
->prop_list
, propp
);
190 md_add_value_property(mmd_t
*mdp
, md_node_t
*nodep
, char *sp
, uint64_t value
)
194 propp
= md_new_property(mdp
, nodep
, MDET_PROP_VAL
, sp
);
197 propp
->d
.value
= value
;
202 md_add_string_property(mmd_t
*mdp
, md_node_t
*nodep
, char *sp
, char *bufp
)
205 md_data_block_t
*dbp
;
207 dbp
= md_new_data_block(mdp
, (uint8_t *)bufp
, strlen(bufp
) + 1);
210 propp
= md_new_property(mdp
, nodep
, MDET_PROP_STR
, sp
);
212 md_free_data_block(mdp
, dbp
);
220 md_add_data_property(mmd_t
*mdp
, md_node_t
*nodep
, char *sp
, int len
,
224 md_data_block_t
*dbp
;
226 dbp
= md_new_data_block(mdp
, bufp
, len
);
230 propp
= md_new_property(mdp
, nodep
, MDET_PROP_DAT
, sp
);
232 md_free_data_block(mdp
, dbp
);
240 md_add_arc_property(mmd_t
*mdp
, md_node_t
*nodep
, char *arcnamep
,
245 propp
= md_new_property(mdp
, nodep
, MDET_PROP_ARC
, arcnamep
);
248 propp
->d
.arc
.is_ptr
= B_TRUE
;
249 propp
->d
.arc
.val
.nodep
= tgtnodep
;
254 md_link_new_node(mmd_t
*mdp
, char *nodenamep
, md_node_t
*parentnodep
,
255 char *linktonewp
, char *linkbackp
)
259 nodep
= md_new_node(mdp
, nodenamep
);
263 ASSERT(linktonewp
!= NULL
);
264 ASSERT(parentnodep
!= NULL
&& !parentnodep
->deleted
);
266 if (md_add_arc_property(mdp
, parentnodep
, linktonewp
, nodep
) != 0) {
270 if (linkbackp
!= NULL
) {
271 if (md_add_arc_property(mdp
,
272 nodep
, linkbackp
, parentnodep
) != 0) {
281 md_destroy(mmd_t
*mdp
)
285 for (nodep
= CHAIN_START(mdp
->node_list
); nodep
!= NULL
; ) {
286 md_node_t
*tmp_nodep
;
288 tmp_nodep
= nodep
->nextp
;
289 md_free_node(mdp
, nodep
);
294 /* should have deleted all the string refs by here */
295 ASSERT(CHAIN_LENGTH(mdp
->string_list
) == 0);
300 md_free_node(mmd_t
*mdp
, md_node_t
*nodep
)
304 if (nodep
->typep
!= NULL
)
305 md_free_string(mdp
, nodep
->typep
);
307 for (propp
= CHAIN_START(nodep
->prop_list
); propp
!= NULL
; ) {
308 md_prop_t
*tmp_propp
;
310 tmp_propp
= propp
->nextp
;
311 md_free_prop(mdp
, propp
);
320 md_free_prop(mmd_t
*mdp
, md_prop_t
*propp
)
322 if (propp
->sp
!= NULL
)
323 md_free_string(mdp
, propp
->sp
);
325 switch (propp
->type
) {
334 md_free_data_block(mdp
, propp
->d
.dbp
);
345 md_free_string(mmd_t
*mdp
, md_string_t
*msp
)
347 ASSERT(msp
->ref_cnt
> 0);
351 if (msp
->ref_cnt
== 0) {
353 mdp
->string_list
.startp
= msp
->nextp
;
359 md_free_data_block(mmd_t
*mdp
, md_data_block_t
*mdbp
)
361 ASSERT(mdbp
->ref_cnt
> 0);
365 if (mdbp
->ref_cnt
== 0) {
367 mdp
->data_block_list
.startp
= mdbp
->nextp
;
375 return ((mmd_t
*)calloc(1, sizeof (mmd_t
)));
379 md_fix_name(md_element_t
*mdep
, md_prop_t
*propp
)
381 mdep
->name_len
= htomd8(propp
->sp
->size
- 1);
382 mdep
->name_offset
= htomd32(propp
->sp
->build_offset
);
386 create_mde(md_element_t
*mdep
, int type
, md_node_t
*nodep
, md_prop_t
*propp
)
388 (void) memset(mdep
, 0, MD_ELEMENT_SIZE
);
389 mdep
->tag
= htomd8(type
);
393 mdep
->d
.prop_idx
= htomd32(nodep
->next_index
);
394 mdep
->name_len
= htomd8(nodep
->typep
->size
- 1);
395 mdep
->name_offset
= htomd32(nodep
->typep
->build_offset
);
399 ASSERT(propp
->d
.arc
.is_ptr
);
400 mdep
->d
.prop_idx
= htomd64(propp
->d
.arc
.val
.nodep
->build_index
);
401 md_fix_name(mdep
, propp
);
405 mdep
->d
.prop_val
= htomd64(propp
->d
.value
);
406 md_fix_name(mdep
, propp
);
411 mdep
->d
.prop_data
.offset
= htomd32(propp
->d
.dbp
->build_offset
);
412 mdep
->d
.prop_data
.len
= htomd32(propp
->d
.dbp
->size
);
413 md_fix_name(mdep
, propp
);
427 md_gen_bin(mmd_t
*mdp
, uint8_t **bufvalp
)
431 md_data_block_t
*mdbp
;
435 uint32_t strings_size
;
436 uint32_t data_block_size
;
439 uint8_t *string_bufferp
;
440 uint8_t *data_block_bufferp
;
443 * Skip through strings to compute offsets.
446 for (msp
= CHAIN_START(mdp
->string_list
); msp
!= NULL
;
448 msp
->build_offset
= offset
;
451 strings_size
= P2ROUNDUP(offset
, MD_ALIGNMENT_SIZE
);
454 * Skip through data blocks to compute offsets.
458 for (mdbp
= CHAIN_START(mdp
->data_block_list
); mdbp
!= NULL
;
459 mdbp
= mdbp
->nextp
) {
460 mdbp
->build_offset
= offset
;
461 offset
+= mdbp
->size
;
462 offset
= P2ROUNDUP(offset
, MD_ALIGNMENT_SIZE
);
464 data_block_size
= P2ROUNDUP(offset
, MD_ALIGNMENT_SIZE
);
467 * Compute the MD elements required to build the element list.
468 * For each node there is a node start and end, and one
469 * element for each property.
473 for (nodep
= CHAIN_START(mdp
->node_list
); nodep
!= NULL
;
474 nodep
= nodep
->nextp
) {
475 nodep
->build_index
= offset
;
476 offset
+= 2 + CHAIN_LENGTH(nodep
->prop_list
);
477 nodep
->next_index
= offset
;
479 offset
+= 1; /* add the LIST_END element */
481 total_size
= MD_HEADER_SIZE
+ offset
* MD_ELEMENT_SIZE
+
482 strings_size
+ data_block_size
;
485 * Allocate output buffer.
488 bufferp
= calloc(total_size
, sizeof (uint8_t));
493 mdhp
= (md_header_t
*)bufferp
;
495 string_bufferp
= bufferp
+ MD_HEADER_SIZE
+ offset
* MD_ELEMENT_SIZE
;
496 data_block_bufferp
= string_bufferp
+ strings_size
;
498 mdhp
->transport_version
= htomd32(MD_TRANSPORT_VERSION
);
499 mdhp
->node_blk_sz
= htomd32(offset
* MD_ELEMENT_SIZE
);
500 mdhp
->name_blk_sz
= htomd32(strings_size
);
501 mdhp
->data_blk_sz
= htomd32(data_block_size
);
504 * Build the element list.
505 * For each node there is a node start and end, and one
506 * element for each property.
511 mdep
= (md_element_t
*)(bufferp
+ MD_HEADER_SIZE
);
512 for (nodep
= CHAIN_START(mdp
->node_list
); nodep
!= NULL
;
513 nodep
= nodep
->nextp
) {
516 create_mde(mdep
, MDET_NODE
, nodep
, NULL
);
519 for (propp
= CHAIN_START(nodep
->prop_list
); propp
!= NULL
;
520 propp
= propp
->nextp
) {
521 create_mde(mdep
, propp
->type
, nodep
, propp
);
525 create_mde(mdep
, MDET_NODE_END
, NULL
, NULL
);
529 create_mde(mdep
, MDET_LIST_END
, NULL
, NULL
);
533 * Quick sanity check.
536 ASSERT(((uint8_t *)mdep
) == ((uint8_t *)string_bufferp
));
539 * Skip through strings and stash them..
543 for (msp
= CHAIN_START(mdp
->string_list
); msp
!= NULL
;
545 (void) memcpy(string_bufferp
+ msp
->build_offset
, msp
->strp
,
550 * Skip through data blocks and stash them.
554 for (mdbp
= CHAIN_START(mdp
->data_block_list
); mdbp
!= NULL
;
555 mdbp
= mdbp
->nextp
) {
556 (void) memcpy(data_block_bufferp
+ mdbp
->build_offset
,
557 mdbp
->datap
, mdbp
->size
);