1*1991Sheppo /*
2*1991Sheppo * CDDL HEADER START
3*1991Sheppo *
4*1991Sheppo * The contents of this file are subject to the terms of the
5*1991Sheppo * Common Development and Distribution License (the "License").
6*1991Sheppo * You may not use this file except in compliance with the License.
7*1991Sheppo *
8*1991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1991Sheppo * or http://www.opensolaris.org/os/licensing.
10*1991Sheppo * See the License for the specific language governing permissions
11*1991Sheppo * and limitations under the License.
12*1991Sheppo *
13*1991Sheppo * When distributing Covered Code, include this CDDL HEADER in each
14*1991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1991Sheppo * If applicable, add the following below this CDDL HEADER, with the
16*1991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying
17*1991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner]
18*1991Sheppo *
19*1991Sheppo * CDDL HEADER END
20*1991Sheppo */
21*1991Sheppo
22*1991Sheppo /*
23*1991Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24*1991Sheppo * Use is subject to license terms.
25*1991Sheppo */
26*1991Sheppo
27*1991Sheppo #pragma ident "%Z%%M% %I% %E% SMI"
28*1991Sheppo
29*1991Sheppo #include <sys/types.h>
30*1991Sheppo #ifdef _KERNEL
31*1991Sheppo #include <sys/systm.h>
32*1991Sheppo #else /* _KERNEL */
33*1991Sheppo #include <string.h>
34*1991Sheppo #include <strings.h>
35*1991Sheppo #endif /* _KERNEL */
36*1991Sheppo #include <sys/note.h>
37*1991Sheppo #include <sys/mdesc.h>
38*1991Sheppo #include <sys/mdesc_impl.h>
39*1991Sheppo
40*1991Sheppo #define MDD_FREE_CHECK(mdp, ptr, sz) \
41*1991Sheppo do { \
42*1991Sheppo if (ptr) mdp->freep(ptr, sz); \
43*1991Sheppo _NOTE(CONSTCOND) } while (0)
44*1991Sheppo
45*1991Sheppo #define MD_DIFF_MAGIC 0x4D445F4449464621ull /* 'MD_DIFF!' */
46*1991Sheppo #define MD_DIFF_NOMATCH (-1)
47*1991Sheppo #define MD_DIFF_MATCH (1)
48*1991Sheppo
49*1991Sheppo typedef struct {
50*1991Sheppo mde_cookie_t *mdep;
51*1991Sheppo uint_t nelem;
52*1991Sheppo } md_diff_t;
53*1991Sheppo
54*1991Sheppo typedef struct {
55*1991Sheppo uint64_t mdd_magic;
56*1991Sheppo md_diff_t added;
57*1991Sheppo md_diff_t removed;
58*1991Sheppo md_diff_t match1;
59*1991Sheppo md_diff_t match2;
60*1991Sheppo void *(*allocp)(size_t);
61*1991Sheppo void (*freep)(void *, size_t);
62*1991Sheppo } md_diff_impl_t;
63*1991Sheppo
64*1991Sheppo /*
65*1991Sheppo * Internal utility functions
66*1991Sheppo */
67*1991Sheppo static int mdd_scan_for_nodes(md_t *mdp, mde_cookie_t start,
68*1991Sheppo char *compnodep, int *countp, mde_cookie_t **nodespp);
69*1991Sheppo
70*1991Sheppo static boolean_t mdd_any_dup_nodes(md_impl_t *mdp, md_prop_match_t *pmp,
71*1991Sheppo int count, mde_cookie_t *nodesp);
72*1991Sheppo
73*1991Sheppo static int mdd_node_list_match(md_impl_t *md1, md_impl_t *md2,
74*1991Sheppo md_element_t *match_nodep, mde_cookie_t *match_listp,
75*1991Sheppo uint8_t *match_seenp, int start, int end, md_prop_match_t *match_elemsp);
76*1991Sheppo
77*1991Sheppo static int mdd_node_compare(md_impl_t *mdap, md_impl_t *mdbp,
78*1991Sheppo md_element_t *nodeap, md_element_t *nodebp, md_prop_match_t *match_elemsp);
79*1991Sheppo
80*1991Sheppo /*
81*1991Sheppo * Given two DAGs and information about how to uniquely identify
82*1991Sheppo * the nodes of interest, determine which nodes have been added
83*1991Sheppo * to the second MD, removed from the first MD, or exist in both
84*1991Sheppo * MDs. This information is recorded and can be accessed using the
85*1991Sheppo * opaque cookie returned to the caller.
86*1991Sheppo */
87*1991Sheppo md_diff_cookie_t
md_diff_init(md_t * md1p,mde_cookie_t start1,md_t * md2p,mde_cookie_t start2,char * compnodep,md_prop_match_t * match_fieldsp)88*1991Sheppo md_diff_init(md_t *md1p, mde_cookie_t start1, md_t *md2p, mde_cookie_t start2,
89*1991Sheppo char *compnodep, md_prop_match_t *match_fieldsp)
90*1991Sheppo {
91*1991Sheppo int idx;
92*1991Sheppo md_impl_t *md1 = (md_impl_t *)md1p;
93*1991Sheppo md_impl_t *md2 = (md_impl_t *)md2p;
94*1991Sheppo mde_cookie_t *md1nodesp = NULL;
95*1991Sheppo mde_cookie_t *md2nodesp = NULL;
96*1991Sheppo int md1count = 0;
97*1991Sheppo int md2count = 0;
98*1991Sheppo uint8_t *seenp = NULL;
99*1991Sheppo
100*1991Sheppo /* variables used to gather results */
101*1991Sheppo md_diff_impl_t *diff_res;
102*1991Sheppo mde_cookie_t *mde_add_scr;
103*1991Sheppo mde_cookie_t *mde_rem_scr;
104*1991Sheppo mde_cookie_t *mde_match1_scr;
105*1991Sheppo mde_cookie_t *mde_match2_scr;
106*1991Sheppo int nadd = 0;
107*1991Sheppo int nrem = 0;
108*1991Sheppo int nmatch = 0;
109*1991Sheppo
110*1991Sheppo /* sanity check params */
111*1991Sheppo if ((md1p == NULL) || (md2p == NULL))
112*1991Sheppo return (MD_INVAL_DIFF_COOKIE);
113*1991Sheppo
114*1991Sheppo if ((start1 == MDE_INVAL_ELEM_COOKIE) ||
115*1991Sheppo (start2 == MDE_INVAL_ELEM_COOKIE))
116*1991Sheppo return (MD_INVAL_DIFF_COOKIE);
117*1991Sheppo
118*1991Sheppo if ((compnodep == NULL) || (match_fieldsp == NULL))
119*1991Sheppo return (MD_INVAL_DIFF_COOKIE);
120*1991Sheppo
121*1991Sheppo /*
122*1991Sheppo * Prepare an array of the matching nodes from the first MD.
123*1991Sheppo */
124*1991Sheppo if (mdd_scan_for_nodes(md1p,
125*1991Sheppo start1, compnodep, &md1count, &md1nodesp) == -1)
126*1991Sheppo return (MD_INVAL_DIFF_COOKIE);
127*1991Sheppo
128*1991Sheppo /* sanity check that all nodes are unique */
129*1991Sheppo if (md1nodesp &&
130*1991Sheppo mdd_any_dup_nodes(md1, match_fieldsp, md1count, md1nodesp)) {
131*1991Sheppo MDD_FREE_CHECK(md1, md1nodesp, sizeof (mde_cookie_t) *
132*1991Sheppo md1count);
133*1991Sheppo return (MD_INVAL_DIFF_COOKIE);
134*1991Sheppo }
135*1991Sheppo
136*1991Sheppo
137*1991Sheppo /*
138*1991Sheppo * Prepare an array of the matching nodes from the second MD.
139*1991Sheppo */
140*1991Sheppo if (mdd_scan_for_nodes(md2p,
141*1991Sheppo start2, compnodep, &md2count, &md2nodesp) == -1)
142*1991Sheppo return (MD_INVAL_DIFF_COOKIE);
143*1991Sheppo
144*1991Sheppo /* sanity check that all nodes are unique */
145*1991Sheppo if (md2nodesp &&
146*1991Sheppo mdd_any_dup_nodes(md2, match_fieldsp, md2count, md2nodesp)) {
147*1991Sheppo MDD_FREE_CHECK(md1, md1nodesp, sizeof (mde_cookie_t) *
148*1991Sheppo md1count);
149*1991Sheppo MDD_FREE_CHECK(md2, md2nodesp, sizeof (mde_cookie_t) *
150*1991Sheppo md2count);
151*1991Sheppo return (MD_INVAL_DIFF_COOKIE);
152*1991Sheppo }
153*1991Sheppo
154*1991Sheppo /* setup our result structure */
155*1991Sheppo diff_res = md1->allocp(sizeof (md_diff_impl_t));
156*1991Sheppo bzero(diff_res, sizeof (md_diff_impl_t));
157*1991Sheppo diff_res->allocp = md1->allocp;
158*1991Sheppo diff_res->freep = md1->freep;
159*1991Sheppo diff_res->mdd_magic = MD_DIFF_MAGIC;
160*1991Sheppo
161*1991Sheppo /*
162*1991Sheppo * Special cases for empty lists
163*1991Sheppo */
164*1991Sheppo if ((md1count == 0) && (md2count != 0)) {
165*1991Sheppo /* all the nodes found were added */
166*1991Sheppo diff_res->added.mdep = md2nodesp;
167*1991Sheppo diff_res->added.nelem = md2count;
168*1991Sheppo return ((mde_cookie_t)diff_res);
169*1991Sheppo }
170*1991Sheppo
171*1991Sheppo if ((md1count != 0) && (md2count == 0)) {
172*1991Sheppo /* all the nodes found were removed */
173*1991Sheppo diff_res->removed.mdep = md1nodesp;
174*1991Sheppo diff_res->removed.nelem = md1count;
175*1991Sheppo return ((mde_cookie_t)diff_res);
176*1991Sheppo }
177*1991Sheppo
178*1991Sheppo if ((md1count == 0) && (md2count == 0))
179*1991Sheppo /* no nodes found */
180*1991Sheppo return ((mde_cookie_t)diff_res);
181*1991Sheppo
182*1991Sheppo /*
183*1991Sheppo * Both lists have some elements. Allocate some scratch
184*1991Sheppo * buffers to sort them into our three categories, added,
185*1991Sheppo * removed, and matched pairs.
186*1991Sheppo */
187*1991Sheppo mde_add_scr = diff_res->allocp(sizeof (mde_cookie_t) * md2count);
188*1991Sheppo mde_rem_scr = diff_res->allocp(sizeof (mde_cookie_t) * md1count);
189*1991Sheppo mde_match1_scr = diff_res->allocp(sizeof (mde_cookie_t) * md1count);
190*1991Sheppo mde_match2_scr = diff_res->allocp(sizeof (mde_cookie_t) * md2count);
191*1991Sheppo
192*1991Sheppo /* array of seen flags only needed for md2 */
193*1991Sheppo seenp = (uint8_t *)diff_res->allocp(sizeof (uint8_t) * md2count);
194*1991Sheppo bzero(seenp, sizeof (uint8_t) * md2count);
195*1991Sheppo
196*1991Sheppo /*
197*1991Sheppo * Make a pass through the md1 node array. Make note of
198*1991Sheppo * any nodes not in the md2 array, indicating that they
199*1991Sheppo * have been removed. Also keep track of the nodes that
200*1991Sheppo * are present in both arrays for the matched pair results.
201*1991Sheppo */
202*1991Sheppo for (idx = 0; idx < md1count; idx++) {
203*1991Sheppo
204*1991Sheppo md_element_t *elem = &(md1->mdep[md1nodesp[idx]]);
205*1991Sheppo
206*1991Sheppo int match = mdd_node_list_match(md1, md2, elem, md2nodesp,
207*1991Sheppo seenp, 0, md2count - 1, match_fieldsp);
208*1991Sheppo
209*1991Sheppo if (match == MD_DIFF_NOMATCH)
210*1991Sheppo /* record deleted node */
211*1991Sheppo mde_rem_scr[nrem++] = md1nodesp[idx];
212*1991Sheppo else {
213*1991Sheppo /* record matched node pair */
214*1991Sheppo mde_match1_scr[nmatch] = md1nodesp[idx];
215*1991Sheppo mde_match2_scr[nmatch] = md2nodesp[match];
216*1991Sheppo nmatch++;
217*1991Sheppo
218*1991Sheppo /* mark that this match has been recorded */
219*1991Sheppo seenp[match] = 1;
220*1991Sheppo }
221*1991Sheppo }
222*1991Sheppo
223*1991Sheppo /*
224*1991Sheppo * Make a pass through the md2 array. Any nodes that have
225*1991Sheppo * not been marked as seen have been added.
226*1991Sheppo */
227*1991Sheppo for (idx = 0; idx < md2count; idx++) {
228*1991Sheppo if (!seenp[idx])
229*1991Sheppo /* record added node */
230*1991Sheppo mde_add_scr[nadd++] = md2nodesp[idx];
231*1991Sheppo }
232*1991Sheppo
233*1991Sheppo /* fill in the added node list */
234*1991Sheppo if (nadd) {
235*1991Sheppo int addsz = sizeof (mde_cookie_t) * nadd;
236*1991Sheppo diff_res->added.mdep = (mde_cookie_t *)diff_res->allocp(addsz);
237*1991Sheppo
238*1991Sheppo bcopy(mde_add_scr, diff_res->added.mdep, addsz);
239*1991Sheppo
240*1991Sheppo diff_res->added.nelem = nadd;
241*1991Sheppo }
242*1991Sheppo
243*1991Sheppo /* fill in the removed node list */
244*1991Sheppo if (nrem) {
245*1991Sheppo int remsz = sizeof (mde_cookie_t) * nrem;
246*1991Sheppo diff_res->removed.mdep =
247*1991Sheppo (mde_cookie_t *)diff_res->allocp(remsz);
248*1991Sheppo
249*1991Sheppo bcopy(mde_rem_scr, diff_res->removed.mdep, remsz);
250*1991Sheppo diff_res->removed.nelem = nrem;
251*1991Sheppo }
252*1991Sheppo
253*1991Sheppo /* fill in the matching node lists */
254*1991Sheppo if (nmatch) {
255*1991Sheppo int matchsz = sizeof (mde_cookie_t) * nmatch;
256*1991Sheppo diff_res->match1.mdep =
257*1991Sheppo (mde_cookie_t *)diff_res->allocp(matchsz);
258*1991Sheppo diff_res->match2.mdep =
259*1991Sheppo (mde_cookie_t *)diff_res->allocp(matchsz);
260*1991Sheppo
261*1991Sheppo bcopy(mde_match1_scr, diff_res->match1.mdep, matchsz);
262*1991Sheppo bcopy(mde_match2_scr, diff_res->match2.mdep, matchsz);
263*1991Sheppo diff_res->match1.nelem = nmatch;
264*1991Sheppo diff_res->match2.nelem = nmatch;
265*1991Sheppo }
266*1991Sheppo
267*1991Sheppo /* clean up */
268*1991Sheppo md1->freep(md1nodesp, sizeof (mde_cookie_t) * md1count);
269*1991Sheppo md2->freep(md2nodesp, sizeof (mde_cookie_t) * md2count);
270*1991Sheppo
271*1991Sheppo diff_res->freep(mde_add_scr, sizeof (mde_cookie_t) * md2count);
272*1991Sheppo diff_res->freep(mde_rem_scr, sizeof (mde_cookie_t) * md1count);
273*1991Sheppo diff_res->freep(mde_match1_scr, sizeof (mde_cookie_t) * md1count);
274*1991Sheppo diff_res->freep(mde_match2_scr, sizeof (mde_cookie_t) * md2count);
275*1991Sheppo
276*1991Sheppo diff_res->freep(seenp, sizeof (uint8_t) * md2count);
277*1991Sheppo
278*1991Sheppo return ((md_diff_cookie_t)diff_res);
279*1991Sheppo }
280*1991Sheppo
281*1991Sheppo /*
282*1991Sheppo * Returns an array of the nodes added to the second MD in a
283*1991Sheppo * previous md_diff_init() call. Returns the number of elements
284*1991Sheppo * in the returned array. If the value is zero, the pointer
285*1991Sheppo * passed back will be NULL.
286*1991Sheppo */
287*1991Sheppo int
md_diff_added(md_diff_cookie_t mdd,mde_cookie_t ** mde_addedp)288*1991Sheppo md_diff_added(md_diff_cookie_t mdd, mde_cookie_t **mde_addedp)
289*1991Sheppo {
290*1991Sheppo md_diff_impl_t *mddp = (md_diff_impl_t *)mdd;
291*1991Sheppo
292*1991Sheppo if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC))
293*1991Sheppo return (-1);
294*1991Sheppo
295*1991Sheppo *mde_addedp = mddp->added.mdep;
296*1991Sheppo
297*1991Sheppo return (mddp->added.nelem);
298*1991Sheppo }
299*1991Sheppo
300*1991Sheppo /*
301*1991Sheppo * Returns an array of the nodes removed from the first MD in a
302*1991Sheppo * previous md_diff_init() call. Returns the number of elements
303*1991Sheppo * in the returned array. If the value is zero, the pointer
304*1991Sheppo * passed back will be NULL.
305*1991Sheppo */
306*1991Sheppo int
md_diff_removed(md_diff_cookie_t mdd,mde_cookie_t ** mde_removedp)307*1991Sheppo md_diff_removed(md_diff_cookie_t mdd, mde_cookie_t **mde_removedp)
308*1991Sheppo {
309*1991Sheppo md_diff_impl_t *mddp = (md_diff_impl_t *)mdd;
310*1991Sheppo
311*1991Sheppo if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC))
312*1991Sheppo return (-1);
313*1991Sheppo
314*1991Sheppo *mde_removedp = mddp->removed.mdep;
315*1991Sheppo
316*1991Sheppo return (mddp->removed.nelem);
317*1991Sheppo }
318*1991Sheppo
319*1991Sheppo /*
320*1991Sheppo * Returns a pair of parallel arrays that contain nodes that were
321*1991Sheppo * considered matching based on the match criteria passed in to
322*1991Sheppo * a previous md_diff_init() call. Returns the number of elements
323*1991Sheppo * in the arrays. If the value is zero, both pointers passed back
324*1991Sheppo * will be NULL.
325*1991Sheppo */
326*1991Sheppo int
md_diff_matched(md_diff_cookie_t mdd,mde_cookie_t ** mde_match1p,mde_cookie_t ** mde_match2p)327*1991Sheppo md_diff_matched(md_diff_cookie_t mdd, mde_cookie_t **mde_match1p,
328*1991Sheppo mde_cookie_t **mde_match2p)
329*1991Sheppo {
330*1991Sheppo md_diff_impl_t *mddp = (md_diff_impl_t *)mdd;
331*1991Sheppo
332*1991Sheppo if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC))
333*1991Sheppo return (-1);
334*1991Sheppo
335*1991Sheppo *mde_match1p = mddp->match1.mdep;
336*1991Sheppo *mde_match2p = mddp->match2.mdep;
337*1991Sheppo
338*1991Sheppo return (mddp->match1.nelem);
339*1991Sheppo }
340*1991Sheppo
341*1991Sheppo /*
342*1991Sheppo * Deallocate any storage used to store results of a previous
343*1991Sheppo * md_diff_init() call. Returns 0 on success and -1 on failure.
344*1991Sheppo */
345*1991Sheppo int
md_diff_fini(md_diff_cookie_t mdd)346*1991Sheppo md_diff_fini(md_diff_cookie_t mdd)
347*1991Sheppo {
348*1991Sheppo md_diff_impl_t *mddp = (md_diff_impl_t *)mdd;
349*1991Sheppo
350*1991Sheppo if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC))
351*1991Sheppo return (-1);
352*1991Sheppo
353*1991Sheppo mddp->mdd_magic = 0;
354*1991Sheppo
355*1991Sheppo MDD_FREE_CHECK(mddp, mddp->added.mdep, mddp->added.nelem *
356*1991Sheppo sizeof (mde_cookie_t));
357*1991Sheppo
358*1991Sheppo MDD_FREE_CHECK(mddp, mddp->removed.mdep, mddp->removed.nelem *
359*1991Sheppo sizeof (mde_cookie_t));
360*1991Sheppo
361*1991Sheppo MDD_FREE_CHECK(mddp, mddp->match1.mdep, mddp->match1.nelem *
362*1991Sheppo sizeof (mde_cookie_t));
363*1991Sheppo
364*1991Sheppo MDD_FREE_CHECK(mddp, mddp->match2.mdep, mddp->match2.nelem *
365*1991Sheppo sizeof (mde_cookie_t));
366*1991Sheppo
367*1991Sheppo mddp->freep(mddp, sizeof (md_diff_impl_t));
368*1991Sheppo
369*1991Sheppo return (0);
370*1991Sheppo }
371*1991Sheppo
372*1991Sheppo /*
373*1991Sheppo * Walk the "fwd" DAG in an MD and return an array of nodes that are
374*1991Sheppo * of the specified type. The start param is used to start the walk
375*1991Sheppo * from an arbitrary location in the DAG. Returns an array of nodes
376*1991Sheppo * as well as a count of the number of nodes in the array. If the
377*1991Sheppo * count is zero, the node pointer will be passed back as NULL.
378*1991Sheppo *
379*1991Sheppo * Returns: 0 success; -1 failure
380*1991Sheppo */
381*1991Sheppo static int
mdd_scan_for_nodes(md_t * mdp,mde_cookie_t start,char * compnodep,int * countp,mde_cookie_t ** nodespp)382*1991Sheppo mdd_scan_for_nodes(md_t *mdp,
383*1991Sheppo mde_cookie_t start, char *compnodep, int *countp, mde_cookie_t **nodespp)
384*1991Sheppo {
385*1991Sheppo mde_str_cookie_t cname;
386*1991Sheppo mde_str_cookie_t aname;
387*1991Sheppo md_impl_t *mdip = (md_impl_t *)mdp;
388*1991Sheppo
389*1991Sheppo if (mdip == NULL)
390*1991Sheppo return (-1);
391*1991Sheppo
392*1991Sheppo cname = md_find_name(mdp, compnodep);
393*1991Sheppo aname = md_find_name(mdp, "fwd");
394*1991Sheppo
395*1991Sheppo /* get the number of nodes of interest in the DAG */
396*1991Sheppo *countp = md_scan_dag(mdp, start, cname, aname, NULL);
397*1991Sheppo if (*countp == 0) {
398*1991Sheppo *nodespp = NULL;
399*1991Sheppo return (0);
400*1991Sheppo }
401*1991Sheppo
402*1991Sheppo /* allocate the storage */
403*1991Sheppo *nodespp = mdip->allocp(sizeof (mde_cookie_t) * (*countp));
404*1991Sheppo
405*1991Sheppo /* populate our array with the matching nodes */
406*1991Sheppo (void) md_scan_dag(mdp, start, cname, aname, *nodespp);
407*1991Sheppo
408*1991Sheppo return (0);
409*1991Sheppo }
410*1991Sheppo
411*1991Sheppo /*
412*1991Sheppo * Walk an array of nodes and check if there are any duplicate
413*1991Sheppo * nodes. A duplicate is determined based on the specified match
414*1991Sheppo * criteria. Returns B_TRUE if there are any duplicates and B_FALSE
415*1991Sheppo * otherwise.
416*1991Sheppo */
417*1991Sheppo static boolean_t
mdd_any_dup_nodes(md_impl_t * mdp,md_prop_match_t * pmp,int count,mde_cookie_t * nodesp)418*1991Sheppo mdd_any_dup_nodes(md_impl_t *mdp, md_prop_match_t *pmp, int count,
419*1991Sheppo mde_cookie_t *nodesp)
420*1991Sheppo {
421*1991Sheppo int idx;
422*1991Sheppo int match;
423*1991Sheppo md_element_t *elem;
424*1991Sheppo
425*1991Sheppo ASSERT(count > 0 || nodesp == NULL);
426*1991Sheppo
427*1991Sheppo for (idx = 0; idx < count; idx++) {
428*1991Sheppo elem = &(mdp->mdep[nodesp[idx]]);
429*1991Sheppo
430*1991Sheppo match = mdd_node_list_match(mdp, mdp, elem, nodesp, NULL,
431*1991Sheppo idx + 1, count - 1, pmp);
432*1991Sheppo
433*1991Sheppo if (match != MD_DIFF_NOMATCH)
434*1991Sheppo return (B_TRUE);
435*1991Sheppo }
436*1991Sheppo
437*1991Sheppo return (B_FALSE);
438*1991Sheppo }
439*1991Sheppo
440*1991Sheppo /*
441*1991Sheppo * Given a node and a array of nodes, compare the node to all elements
442*1991Sheppo * in the specified start-end range of the array. If the node matches
443*1991Sheppo * one of the nodes in the array, return the index of that node. Otherwise
444*1991Sheppo * return MD_DIFF_NOMATCH.
445*1991Sheppo *
446*1991Sheppo * The optional seen array parameter can be used to optimize repeated
447*1991Sheppo * calls to this function. If the seen array indicates that an element
448*1991Sheppo * has already been matched, the full comparison is not necessary.
449*1991Sheppo */
450*1991Sheppo static int
mdd_node_list_match(md_impl_t * md1,md_impl_t * md2,md_element_t * match_nodep,mde_cookie_t * match_listp,uint8_t * match_seenp,int start,int end,md_prop_match_t * match_elemsp)451*1991Sheppo mdd_node_list_match(md_impl_t *md1, md_impl_t *md2, md_element_t *match_nodep,
452*1991Sheppo mde_cookie_t *match_listp, uint8_t *match_seenp, int start, int end,
453*1991Sheppo md_prop_match_t *match_elemsp)
454*1991Sheppo {
455*1991Sheppo int match;
456*1991Sheppo int idx;
457*1991Sheppo md_element_t *elem;
458*1991Sheppo
459*1991Sheppo for (idx = start; idx <= end; idx++) {
460*1991Sheppo
461*1991Sheppo if ((match_seenp != NULL) && (match_seenp[idx]))
462*1991Sheppo continue;
463*1991Sheppo
464*1991Sheppo elem = &(md2->mdep[match_listp[idx]]);
465*1991Sheppo
466*1991Sheppo match = mdd_node_compare(md1, md2, match_nodep, elem,
467*1991Sheppo match_elemsp);
468*1991Sheppo if (match == MD_DIFF_MATCH)
469*1991Sheppo return (idx);
470*1991Sheppo }
471*1991Sheppo
472*1991Sheppo return (MD_DIFF_NOMATCH);
473*1991Sheppo }
474*1991Sheppo
475*1991Sheppo /*
476*1991Sheppo * Given two nodes and a list of properties, compare the nodes.
477*1991Sheppo * A match is concluded if both nodes have all of the specified
478*1991Sheppo * properties and all the values of those properties are the
479*1991Sheppo * same. Returns MD_DIFF_NOMATCH if the nodes do not match and
480*1991Sheppo * MD_DIFF_MATCH otherwise.
481*1991Sheppo */
482*1991Sheppo static int
mdd_node_compare(md_impl_t * mdap,md_impl_t * mdbp,md_element_t * nodeap,md_element_t * nodebp,md_prop_match_t * match_elemsp)483*1991Sheppo mdd_node_compare(md_impl_t *mdap, md_impl_t *mdbp, md_element_t *nodeap,
484*1991Sheppo md_element_t *nodebp, md_prop_match_t *match_elemsp)
485*1991Sheppo {
486*1991Sheppo md_element_t *ap;
487*1991Sheppo md_element_t *bp;
488*1991Sheppo boolean_t nodea_interest;
489*1991Sheppo boolean_t nodeb_interest;
490*1991Sheppo int idx;
491*1991Sheppo
492*1991Sheppo /* make sure we are starting at the beginning of the nodes */
493*1991Sheppo if ((MDE_TAG(nodeap) != MDET_NODE) || (MDE_TAG(nodebp) != MDET_NODE))
494*1991Sheppo return (MD_DIFF_NOMATCH);
495*1991Sheppo
496*1991Sheppo for (idx = 0; match_elemsp[idx].type != MDET_LIST_END; idx++) {
497*1991Sheppo
498*1991Sheppo int type;
499*1991Sheppo
500*1991Sheppo nodea_interest = B_FALSE;
501*1991Sheppo nodeb_interest = B_FALSE;
502*1991Sheppo
503*1991Sheppo type = match_elemsp[idx].type;
504*1991Sheppo
505*1991Sheppo /*
506*1991Sheppo * Check node A for the property of interest
507*1991Sheppo */
508*1991Sheppo for (ap = nodeap; MDE_TAG(ap) != MDET_NODE_END; ap++) {
509*1991Sheppo char *elemname;
510*1991Sheppo
511*1991Sheppo if (MDE_TAG(ap) != type)
512*1991Sheppo continue;
513*1991Sheppo
514*1991Sheppo elemname = mdap->namep + MDE_NAME(ap);
515*1991Sheppo
516*1991Sheppo if (strcmp(elemname, match_elemsp[idx].namep) == 0) {
517*1991Sheppo /* found the property of interest */
518*1991Sheppo nodea_interest = B_TRUE;
519*1991Sheppo break;
520*1991Sheppo }
521*1991Sheppo }
522*1991Sheppo
523*1991Sheppo /* node A is not of interest */
524*1991Sheppo if (!nodea_interest)
525*1991Sheppo return (MD_DIFF_NOMATCH);
526*1991Sheppo
527*1991Sheppo /*
528*1991Sheppo * Check node B for the property of interest
529*1991Sheppo */
530*1991Sheppo for (bp = nodebp; MDE_TAG(bp) != MDET_NODE_END; bp++) {
531*1991Sheppo char *elemname;
532*1991Sheppo
533*1991Sheppo if (MDE_TAG(bp) != type)
534*1991Sheppo continue;
535*1991Sheppo
536*1991Sheppo elemname = mdbp->namep + MDE_NAME(bp);
537*1991Sheppo
538*1991Sheppo if (strcmp(elemname, match_elemsp[idx].namep) == 0) {
539*1991Sheppo nodeb_interest = B_TRUE;
540*1991Sheppo break;
541*1991Sheppo }
542*1991Sheppo }
543*1991Sheppo
544*1991Sheppo /* node B is not of interest */
545*1991Sheppo if (!nodeb_interest)
546*1991Sheppo return (MD_DIFF_NOMATCH);
547*1991Sheppo
548*1991Sheppo /*
549*1991Sheppo * Both nodes have the property of interest. The
550*1991Sheppo * nodes are not a match unless the value of that
551*1991Sheppo * property match
552*1991Sheppo */
553*1991Sheppo switch (type) {
554*1991Sheppo case MDET_PROP_VAL:
555*1991Sheppo if (MDE_PROP_VALUE(ap) != MDE_PROP_VALUE(bp))
556*1991Sheppo return (MD_DIFF_NOMATCH);
557*1991Sheppo break;
558*1991Sheppo
559*1991Sheppo case MDET_PROP_STR: {
560*1991Sheppo char *stra = (char *)(mdap->datap +
561*1991Sheppo MDE_PROP_DATA_OFFSET(ap));
562*1991Sheppo char *strb = (char *)(mdbp->datap +
563*1991Sheppo MDE_PROP_DATA_OFFSET(bp));
564*1991Sheppo
565*1991Sheppo if (strcmp(stra, strb) != 0)
566*1991Sheppo return (MD_DIFF_NOMATCH);
567*1991Sheppo break;
568*1991Sheppo }
569*1991Sheppo
570*1991Sheppo case MDET_PROP_DAT: {
571*1991Sheppo
572*1991Sheppo caddr_t dataa;
573*1991Sheppo caddr_t datab;
574*1991Sheppo
575*1991Sheppo if (MDE_PROP_DATA_LEN(ap) != MDE_PROP_DATA_LEN(bp))
576*1991Sheppo return (MD_DIFF_NOMATCH);
577*1991Sheppo
578*1991Sheppo dataa = (caddr_t)(mdap->datap +
579*1991Sheppo MDE_PROP_DATA_OFFSET(ap));
580*1991Sheppo datab = (caddr_t)(mdbp->datap +
581*1991Sheppo MDE_PROP_DATA_OFFSET(bp));
582*1991Sheppo
583*1991Sheppo if (memcmp(dataa, datab, MDE_PROP_DATA_LEN(ap)) != 0)
584*1991Sheppo return (MD_DIFF_NOMATCH);
585*1991Sheppo
586*1991Sheppo break;
587*1991Sheppo }
588*1991Sheppo
589*1991Sheppo default:
590*1991Sheppo /* unsupported prop type */
591*1991Sheppo return (MD_DIFF_NOMATCH);
592*1991Sheppo }
593*1991Sheppo }
594*1991Sheppo
595*1991Sheppo /*
596*1991Sheppo * All the specified properties exist in both
597*1991Sheppo * nodes and have the same value. The two nodes
598*1991Sheppo * match.
599*1991Sheppo */
600*1991Sheppo
601*1991Sheppo return (MD_DIFF_MATCH);
602*1991Sheppo }
603