1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <base/strings.h>
28 #include <base/io.h>
29 #include <base/dir.h>
30 #include <base/paths.h>
31 #include "provreg.h"
32 #include "regfile.h"
33
34 typedef struct _ProvRegNamespaceNode
35 {
36 struct _ProvRegNamespaceNode* next;
37 MI_ConstString ns;
38 struct _ProvRegClassInheritanceNode* tree;
39 }
40 ProvRegNamespaceNode;
41
42 typedef struct _ProvRegAssocBackLinkNode
43 mike 1.1 {
44 struct _ProvRegAssocBackLinkNode* next;
45 struct _ProvRegClassInheritanceNode* assocClass;
46 }
47 ProvRegAssocBackLinkNode;
48
49 typedef struct _ProvRegClassInheritanceNode
50 {
51 MI_ConstString cn;
52 struct _ProvRegClassInheritanceNode* parent;
53 struct _ProvRegClassInheritanceNode* nextSibling;
54 struct _ProvRegClassInheritanceNode* firstChild;
55 /* assoc support */
56 /* left/right are not-null only for assoc class */
57 struct _ProvRegClassInheritanceNode* left;
58 struct _ProvRegClassInheritanceNode* right;
59
60 /* linked list of all assoc classes that refer this class */
61 ProvRegAssocBackLinkNode* associatorClasses;
62 }
63 ProvRegClassInheritanceNode;
64 mike 1.1
65 #if (MI_CHAR_TYPE == 1)
66 #define MI_ScasecmpChar_MIChar Zcasecmp
67 #else
68 static int MI_ScasecmpChar_MIChar(
69 const char* str1,
70 const MI_Char* str2 )
71 {
72 /* assuming str2 is ascii char-set only */
73 for(;;)
74 {
75 int c1 = tolower((unsigned char)*str1);
76 int c2 = tolower((unsigned char)*str2);
77
78 if (c1 != c2 )
79 {
80 return c1 < c2 ? -1 : 1;
81 }
82 if (!c1)
83 break;
84
85 mike 1.1 str1++;
86 str2++;
87 }
88
89 return 0;
90 }
91 #endif
92
93 /* returns last segment from the string or string itself;
94 for example, for string abc,edf,ghk function returns 'ghk', 'edf' and 'abc' */
95 static char* _GetNextReverse(char** text, char delim)
96 {
97 char* start = *text;
98 char* end;
99 size_t len;
100
101 /* If at end of string */
102 if (!*start)
103 return NULL;
104
105 len = strlen(start);
106 mike 1.1
107 /* end of string */
108 end = start + len;
109
110 /* Remove trailing whitespace */
111 for (; end != start && isspace((unsigned char)end[-1]);)
112 *--end = '\0';
113
114 /* Skip non-colon character characters */
115 for (; end != start && *end != delim; end--)
116 ;
117
118 if ( end == start )
119 { /* last block - move position to the end to point to \0 */
120 *text = start + len;
121 }
122 else
123 { /* skip delimiter*/
124 *end = 0;
125 end++;
126 }
127 mike 1.1
128 /* Skip leading whitespace */
129 while (*end && isspace((unsigned char)*end))
130 end++;
131
132 return end;
133 }
134
135 static char* _Strdup(Batch* batch, const char* s)
136 {
137 size_t size = strlen(s) + 1;
138 char* p;
139 size_t i;
140
141 p = Batch_Get(batch, size * sizeof(char));
142
143 if (!p)
144 return NULL;
145
146 for (i = 0; i < size; i++)
147 p[i] = s[i];
148 mike 1.1
149 return p;
150 }
151
152 static MI_Char* _Strdup2(Batch* batch, const char* s)
153 {
154 size_t size = strlen(s) + 1;
155 MI_Char* p;
156 size_t i;
157
158 p = Batch_Get(batch, size * sizeof(MI_Char));
159
160 if (!p)
161 return NULL;
162
163 for (i = 0; i < size; i++)
164 p[i] = (MI_Char)s[i];
165
166 return p;
167 }
168
169 mike 1.1 /* ********************************************************* */
170 /* *** namespace operations *** */
171 /* ********************************************************* */
172
173 ProvRegNamespaceNode* _FindNamespace(
174 ProvReg* self,
175 MI_ConstString ns)
176 {
177 /* find namespace node in the list */
178 ProvRegNamespaceNode* current = self->namespaces;
179
180 while (current && Zcasecmp(ns,current->ns) != 0)
181 current = current->next;
182
183 return current;
184 }
185
186 ProvRegNamespaceNode* _FindOrCreateNamespace(
187 ProvReg* self,
188 MI_ConstString ns)
189 {
190 mike 1.1 ProvRegNamespaceNode* item = _FindNamespace(self,ns);
191
192 if (item)
193 return item;
194
195 item = (ProvRegNamespaceNode*)Batch_GetClear(
196 &self->batch, sizeof(ProvRegNamespaceNode));
197
198 if (item)
199 {
200 item->ns = ns; /* no need to strdup, since it's already in batch*/
201 item->next = self->namespaces;
202 self->namespaces = item;
203 }
204
205 return item;
206 }
207
208 /* ********************************************************* */
209 /* *** tree operations *** */
210 /* ********************************************************* */
211 mike 1.1 ProvRegClassInheritanceNode* _GetNextTreeNodeLimittedBy(
212 ProvRegClassInheritanceNode* item,
213 ProvRegClassInheritanceNode* subtreeRoot)
214 {
215 /* first-child */
216 if (item->firstChild)
217 return item->firstChild;
218
219 /* sibling */
220 if (item->nextSibling)
221 return item->nextSibling;
222
223 /* sibling of direct or indirect parent*/
224 while (item && item->parent != subtreeRoot)
225 {
226 item = item->parent;
227
228 if (item->nextSibling)
229 return item->nextSibling;
230 }
231
232 mike 1.1 /* end of tree */
233 return 0;
234 }
235
236 ProvRegClassInheritanceNode* _GetNextTreeNode(
237 ProvRegClassInheritanceNode* item)
238 {
239 return _GetNextTreeNodeLimittedBy(item,0);
240 }
241
242 ProvRegClassInheritanceNode* _FindClassNodeInTreeByChar(
243 ProvRegClassInheritanceNode* root,
244 const char* cn)
245 {
246 while (root)
247 {
248 if (MI_ScasecmpChar_MIChar(cn,root->cn)==0)
249 {
250 return root;
251 }
252 root = _GetNextTreeNode(root);
253 mike 1.1 }
254 return root;
255 }
256
257 ProvRegClassInheritanceNode* _FindClassNodeInTree(
258 ProvRegClassInheritanceNode* root,
259 const MI_Char* cn)
260 {
261 while (root)
262 {
263 if (Zcasecmp(cn,root->cn)==0)
264 {
265 return root;
266 }
267 root = _GetNextTreeNode(root);
268 }
269 return root;
270 }
271
272 MI_Boolean _ValidateTreeNodes(
273 ProvRegClassInheritanceNode* derivedNode,
274 mike 1.1 ProvRegClassInheritanceNode* baseNode)
275 {
276 /* if we have no nodes - it's fine - no info yet*/
277 if ( !derivedNode && !baseNode )
278 return MI_TRUE;
279
280 /* if we have both nodes - check they are child/parent */
281 if ( derivedNode && baseNode )
282 return derivedNode->parent == baseNode;
283
284 /* base must be specified */
285 if ( derivedNode && !baseNode )
286 return MI_FALSE;
287
288 /* only one node is known - ok */
289 return MI_TRUE;
290 }
291
292 static MI_Result _AddClassInheritanceInfo(
293 ProvReg* self,
294 MI_ConstString ns,
295 mike 1.1 const char* derivedClass, /* can be null */
296 const char* baseClass )
297 {
298 /* get (or create if needed) namespace item */
299 ProvRegNamespaceNode* namespaceNode = _FindOrCreateNamespace(self,ns);
300 ProvRegClassInheritanceNode* derivedNode, *baseNode;
301
302 if (!namespaceNode)
303 return MI_RESULT_FAILED;
304
305 /* find classes' nodes */
306 derivedNode = derivedClass ? _FindClassNodeInTreeByChar(namespaceNode->tree, derivedClass) : 0;
307 baseNode = _FindClassNodeInTreeByChar(namespaceNode->tree, baseClass);
308
309 /* validate nodes */
310 if (!_ValidateTreeNodes(derivedNode,baseNode))
311 return MI_RESULT_INVALID_CLASS_HIERARCHY;
312
313 /* create missing nodes and insert them into tree */
314 if ( !baseNode )
315 {
316 mike 1.1 baseNode = (ProvRegClassInheritanceNode*)Batch_GetClear(
317 &self->batch, sizeof(ProvRegClassInheritanceNode));
318
319 if ( !baseNode )
320 return MI_RESULT_FAILED;
321
322 baseNode->cn = _Strdup2(&self->batch, baseClass);
323
324 if ( !baseNode->cn )
325 return MI_RESULT_FAILED;
326
327 /* insert into tree */
328 baseNode->nextSibling = namespaceNode->tree;
329 namespaceNode->tree = baseNode;
330 }
331
332 if ( !derivedNode && derivedClass)
333 {
334 derivedNode = (ProvRegClassInheritanceNode*)Batch_GetClear(
335 &self->batch, sizeof(ProvRegClassInheritanceNode));
336
337 mike 1.1 if ( !derivedNode )
338 return MI_RESULT_FAILED;
339
340 derivedNode->cn = _Strdup2(&self->batch, derivedClass);
341
342 if ( !derivedNode->cn )
343 return MI_RESULT_FAILED;
344
345 /* add as a child */
346 derivedNode->parent = baseNode;
347 derivedNode->nextSibling = baseNode->firstChild;
348 baseNode->firstChild = derivedNode;
349 }
350
351 return MI_RESULT_OK;
352 }
353
354 static MI_Result _AddAssociation(
355 ProvReg* self,
356 MI_ConstString ns,
357 const char* assoc,
358 mike 1.1 const char* left,
359 const char* right)
360 {
361 /* find all related nodes */
362 ProvRegNamespaceNode* namespaceNode;
363 ProvRegClassInheritanceNode *leftNode, *rightNode, *assocNode;
364
365 /* check namespace */
366 namespaceNode = _FindNamespace(self,ns);
367
368 if (!namespaceNode)
369 return MI_RESULT_INVALID_NAMESPACE;
370
371 /* find class */
372 leftNode = _FindClassNodeInTreeByChar(namespaceNode->tree, left);
373 rightNode = _FindClassNodeInTreeByChar(namespaceNode->tree, right);
374 assocNode = _FindClassNodeInTreeByChar(namespaceNode->tree, assoc);
375
376 if (!leftNode || !rightNode || !assocNode)
377 return MI_RESULT_INVALID_CLASS;
378
379 mike 1.1 /* add cross-links */
380 assocNode->left = leftNode;
381 assocNode->right = rightNode;
382
383 {
384 ProvRegAssocBackLinkNode* newLinkItemLeft;
385 newLinkItemLeft = (ProvRegAssocBackLinkNode*)Batch_GetClear(
386 &self->batch, sizeof(ProvRegAssocBackLinkNode));
387
388 if (!newLinkItemLeft)
389 return MI_RESULT_FAILED;
390
391 newLinkItemLeft->assocClass = assocNode;
392 newLinkItemLeft->next = leftNode->associatorClasses;
393 leftNode->associatorClasses = newLinkItemLeft;
394 }
395
396 /* check if assoc links different classes */
397 if (leftNode != rightNode)
398 {
399 ProvRegAssocBackLinkNode* newLinkItemRight;
400 mike 1.1 newLinkItemRight = (ProvRegAssocBackLinkNode*)Batch_GetClear(
401 &self->batch, sizeof(ProvRegAssocBackLinkNode));
402 if (!newLinkItemRight)
403 return MI_RESULT_FAILED;
404
405 newLinkItemRight->assocClass = assocNode;
406 newLinkItemRight->next = rightNode->associatorClasses;
407 rightNode->associatorClasses = newLinkItemRight;
408 }
409
410 return MI_RESULT_OK;
411 }
412
413 static MI_Result _GetSubclasses2(
414 ProvReg* self,
415 ProvRegEntry* e,
416 char* p)
417 {
418 /* get all sub-classes */
419 char* baseClass = _GetNextReverse(&p, ':');
420 char* derivedClass = _GetNextReverse(&p, ':');
421 mike 1.1 MI_Result r;
422
423 /* expecting to find at least one class */
424 if (!baseClass)
425 return MI_RESULT_INVALID_CLASS;
426
427 while ( derivedClass )
428 {
429 r = _AddClassInheritanceInfo(self, e->nameSpace, derivedClass,
430 baseClass);
431
432 if ( MI_RESULT_OK != r )
433 return r;
434
435 baseClass = derivedClass;
436 derivedClass = _GetNextReverse(&p, ':');
437 }
438
439 /* add base class with no parent */
440 r = _AddClassInheritanceInfo(self, e->nameSpace, derivedClass, baseClass);
441 if (MI_RESULT_OK != r)
442 mike 1.1 return r;
443
444 e->className = _Strdup2(&self->batch, baseClass);
445 if (!e->className)
446 {
447 return MI_RESULT_FAILED;
448 }
449
450 return MI_RESULT_OK;
451 }
452
453 static int _AddEntry(
454 ProvReg* self,
455 const char* nameSpace,
456 RegFile* regFile,
457 RegClass* regClass)
458 {
459 ProvRegEntry* e;
460
461 #if 0
462 RegFile_Print(regFile, stdout);
463 mike 1.1 #endif
464
465 /* Allocate new provider register entry */
466 e = (ProvRegEntry*)Batch_GetClear(&self->batch, sizeof(ProvRegEntry));
467 if (!e)
468 return -1;
469
470 /* ProvRegEntry.provInterface */
471 e->provInterface = PROV_INTERFACE_STATIK;
472
473 /* ProvRegEntry.nameSpace */
474 e->nameSpace = _Strdup2(&self->batch, nameSpace);
475
476 /* ProvRegEntry.libraryName */
477 e->libraryName = _Strdup(&self->batch, regFile->library);
478
479 /* ProvRegEntry.hosting*/
480 e->hosting = PROV_HOSTING_INPROC;
481
482 if (regClass->hosting)
483 {
484 mike 1.1 char hosting[64];
485 Strlcpy(hosting, regClass->hosting, sizeof(hosting));
486
487 /* it either user name or one of two special values:
488 * @inproc@
489 * @requestor@
490 */
491 if (strcmp(hosting, PROV_REG_HOSTING_INPROC) == 0)
492 {
493 e->hosting = PROV_HOSTING_INPROC;
494 }
495 else if (strcmp(hosting, PROV_REG_HOSTING_REQUESTOR) == 0)
496 {
497 e->hosting = PROV_HOSTING_REQUESTOR;
498 }
499 else
500 {
501 e->hosting = PROV_HOSTING_USER;
502 e->user = _Strdup(&self->batch, hosting);
503 if (!e->user)
504 return -1;
505 mike 1.1 }
506 }
507
508 /* If an association */
509 if (regClass->refName1 && regClass->refName2)
510 {
511 if (_GetSubclasses2(self, e, regClass->refName1) != MI_RESULT_OK)
512 return -1;
513
514 if (_GetSubclasses2(self, e, regClass->refName2) != MI_RESULT_OK)
515 return -1;
516
517 if (_GetSubclasses2(self, e, regClass->name) != MI_RESULT_OK)
518 return -1;
519
520 if (_AddAssociation(self, e->nameSpace, regClass->name,
521 regClass->refName1, regClass->refName2) != MI_RESULT_OK)
522 {
523 return -1;
524 }
525 }
526 mike 1.1 else
527 {
528 if (_GetSubclasses2(self, e, regClass->name) != MI_RESULT_OK)
529 return -1;
530 }
531
532 /* Add entry to end of list */
533 {
534 e->next = NULL;
535
536 if (self->tail)
537 {
538 self->tail->next = e;
539 self->tail = e;
540 }
541 else
542 {
543 self->tail = e;
544 self->head = e;
545 }
546 }
547 mike 1.1
548 return 0;
549 }
550
551 MI_Result ProvReg_Init2(ProvReg* self)
552 {
553 Dir* dir = NULL;
554 Dir* dir2 = NULL;
555 RegFile* reg = NULL;
556 Batch* b = NULL;
557
558 /* Zero-fill self */
559 memset(self, 0, sizeof(*self));
560
561 /* Initialize batch allocator */
562 Batch_Init(&self->batch, BATCH_MAX_PAGES);
563 b = &self->batch;
564
565 /* Open the 'omiregister' directory */
566 dir = Dir_Open(GetPath(ID_REGISTERDIR));
567 if (!dir)
568 mike 1.1 return MI_RESULT_FAILED;
569
570 /* For each namespace directory in 'omirgister' */
571 for (;;)
572 {
573 DirEnt* ent = Dir_Read(dir);
574 if (!ent)
575 break;
576
577 /* Ignore system directories */
578 if (strcmp(ent->name, ".") == 0 || strcmp(ent->name, "..") == 0)
579 continue;
580
581 /* Skip 'CVS' directories */
582 if (strcmp(ent->name, "CVS") == 0)
583 continue;
584
585 /* Scan .reg files in the current namespace directory */
586 {
587 char path[MAX_PATH_SIZE];
588
589 mike 1.1 Strlcpy(path, GetPath(ID_REGISTERDIR), sizeof(path));
590 Strlcat(path, "/", sizeof(path));
591 Strlcat(path, ent->name, sizeof(path));
592
593 dir2 = Dir_Open(path);
594 if (!dir2)
595 {
596 goto failed;
597 }
598
599 for (;;)
600 {
601 DirEnt* ent2 = Dir_Read(dir2);
602 if (!ent2)
603 break;
604
605 /* Ignore system directories */
606 if (strcmp(ent2->name,".") == 0 || strcmp(ent2->name,"..") == 0)
607 continue;
608
609 /* Load the reg file */
610 mike 1.1 {
611 char regPath[MAX_PATH_SIZE];
612
613 /* Form path to .reg file */
614 Strlcpy(regPath, path, sizeof(regPath));
615 Strlcat(regPath, "/", sizeof(regPath));
616 Strlcat(regPath, ent2->name, sizeof(regPath));
617
618 /* Create new reg file object */
619 reg = RegFile_New(regPath);
620 if (!reg)
621 {
622 goto failed;
623 }
624
625 /* For each class in the reg file */
626 {
627 RegClass* rc;
628
629 for (rc = reg->classesHead; rc; rc = rc->next)
630 {
631 mike 1.1 char* p = ent->name;
632
633 /* Transpose '#' characters to '/' characters */
634 while (*p)
635 {
636 if (*p == '#')
637 *p = '/';
638 p++;
639 }
640
641 if (_AddEntry(self, ent->name, reg, rc) != 0)
642 {
643 goto failed;
644 }
645 }
646 }
647
648 /* Delete the current entry */
649 RegFile_Delete(reg);
650 reg = NULL;
651 }
652 mike 1.1 }
653
654 /* Close the directory */
655 Dir_Close(dir2);
656 dir2 = NULL;
657 }
658 }
659
660 /* Close directory */
661 Dir_Close(dir);
662
663 return MI_RESULT_OK;
664
665 failed:
666
667 if (dir)
668 Dir_Close(dir);
669
670 if (dir2)
671 Dir_Close(dir2);
672
673 mike 1.1 return MI_RESULT_FAILED;
674 }
675
676 void ProvReg_Destroy(
677 ProvReg* self)
678 {
679 Batch_Destroy(&self->batch);
680 }
681
682 void ProvReg_Dump(
683 ProvReg* self,
684 FILE* os)
685 {
686 ProvRegEntry* p;
687
688 for (p = self->head; p; p = p->next)
689 {
690 fprintf(os, "==== ProvRegEntry\n");
691 fprintf(os, "provInterface[%u]\n", p->provInterface);
692 Fzprintf(os, MI_T("nameSpace[%s]\n"), p->nameSpace);
693 Fzprintf(os, MI_T("className[%s]\n"), p->className);
694 mike 1.1 fprintf(os, "libraryName[%s]\n", p->libraryName);
695 }
696 }
697
698 const ProvRegEntry* ProvReg_FindProviderForClass(
699 ProvReg* self,
700 const MI_Char* nameSpace,
701 const MI_Char* className)
702 {
703 ProvRegEntry* p;
704
705 for (p = self->head; p; p = p->next)
706 {
707 if (Zcasecmp(p->className, className) == 0 &&
708 Zcasecmp(p->nameSpace, nameSpace) == 0)
709 return p;
710 }
711
712 /* Not found */
713 return NULL;
714 }
715 mike 1.1
716 /* returns ok or not-found; baseClass will be null if no base class exist */
717 MI_Result ProvReg_GetDirectBaseClass(
718 ProvReg* self,
719 const MI_Char* nameSpace,
720 const MI_Char* className,
721 const MI_Char** baseClass)
722 {
723 ProvRegClassInheritanceNode* classNode;
724 ProvRegNamespaceNode* namespaceNode;
725
726 /* clear out param */
727 *baseClass = 0;
728
729 /* check namespace */
730 namespaceNode = _FindNamespace(self,nameSpace);
731
732 if (!namespaceNode)
733 return MI_RESULT_INVALID_NAMESPACE;
734
735 /* find class */
736 mike 1.1 classNode = _FindClassNodeInTree(namespaceNode->tree, className);
737
738 if (!classNode)
739 return MI_RESULT_INVALID_CLASS;
740
741 if (classNode->parent)
742 {
743 *baseClass = classNode->parent->cn;
744 }
745
746 return MI_RESULT_OK;
747 }
748
749 /* enumerates classes derived classes:
750 - if deep == false and className == null, returns all root classes
751 - if deep == true and className == null, returns all classes
752 - if deep == false and className provided, returns all classes directly derived from given
753 - if deep == true and className provided, returns all classes derived from given
754 */
755 MI_Result ProvReg_BeginClasses(
756 ProvReg* self,
757 mike 1.1 const MI_Char* nameSpace,
758 const MI_Char* className,
759 MI_Boolean deep,
760 ProvRegPosition* pos)
761 {
762 ProvRegNamespaceNode* namespaceNode;
763
764 /* clear pos */
765 memset( pos, 0, sizeof(*pos));
766 pos->deep = deep;
767
768 /* check namespace */
769 namespaceNode = _FindNamespace(self,nameSpace);
770
771 if (!namespaceNode)
772 return MI_RESULT_INVALID_NAMESPACE;
773
774 /* find class */
775 if (className)
776 {
777 pos->start = _FindClassNodeInTree(namespaceNode->tree, className);
778 mike 1.1
779 if (!pos->start)
780 return MI_RESULT_INVALID_CLASS;
781
782 pos->current = pos->start->firstChild;
783 }
784 else
785 {
786 pos->start = 0;
787 pos->current = namespaceNode->tree;
788 }
789
790 return MI_RESULT_OK;
791 }
792
793 MI_Result ProvReg_NextClass(
794 ProvRegPosition* pos,
795 const MI_Char** className,
796 MI_Boolean* done)
797 {
798 if (!pos->current)
799 mike 1.1 {
800 *className = 0;
801
802 if (done)
803 *done = MI_TRUE;
804
805 return MI_RESULT_OK;
806 }
807
808 *className = pos->current->cn;
809
810 if (pos->deep)
811 {
812 pos->current = _GetNextTreeNodeLimittedBy(pos->current,pos->start);
813 }
814 else
815 {
816 pos->current = pos->current->nextSibling;
817 }
818
819 if (done)
820 mike 1.1 *done = MI_FALSE;
821
822 return MI_RESULT_OK;
823 }
824
825 MI_Result ProvReg_EndClasses(
826 ProvRegPosition* pos)
827 {
828 memset( pos, -1, sizeof(*pos));
829 return MI_RESULT_OK;
830 }
831
832
833
834 /* returns enumerator to all registered association classes by given instance class
835 and (optionally) assoc/result classes */
836 MI_EXPORT MI_Result ProvReg_BeginAssocClasses(
837 ProvReg* self,
838 const MI_Char* nameSpace,
839 const MI_Char* className,
840 const MI_Char* assocClassName, /* can be NULL */
841 mike 1.1 const MI_Char* resultClassName, /* can be NULL */
842 ProvRegAssocPosition* pos)
843 {
844 ProvRegNamespaceNode* namespaceNode;
845
846 if (!nameSpace || !className || !pos)
847 return MI_RESULT_INVALID_PARAMETER;
848
849 /* clear pos */
850 memset( pos, 0, sizeof(*pos));
851
852 /* check namespace */
853 namespaceNode = _FindNamespace(self,nameSpace);
854
855 if (!namespaceNode)
856 return MI_RESULT_INVALID_NAMESPACE;
857
858 /* find class */
859 pos->currentLeft = _FindClassNodeInTree(namespaceNode->tree, className);
860
861 if (!pos->currentLeft)
862 mike 1.1 return MI_RESULT_INVALID_CLASS;
863
864 //pos->currentAssoc = pos->currentLeft->associatorClasses;
865
866 /* validate optional parameters */
867 if (assocClassName)
868 {
869 ProvRegClassInheritanceNode* assocClassNode = _FindClassNodeInTree(namespaceNode->tree, assocClassName);
870
871 if (!assocClassNode)
872 return MI_RESULT_INVALID_CLASS;
873
874 /* store node pointer */
875 pos->assocClass = assocClassNode;
876 }
877
878 if (resultClassName)
879 {
880 ProvRegClassInheritanceNode* resultClassNode = _FindClassNodeInTree(namespaceNode->tree, resultClassName);
881
882 if (!resultClassNode)
883 mike 1.1 return MI_RESULT_INVALID_CLASS;
884
885 /* store node pointer */
886 pos->resultClass = resultClassNode;
887 }
888
889 return MI_RESULT_OK;
890 }
891
892 static MI_Boolean _GetNextAssoc(
893 ProvRegAssocPosition* pos)
894 {
895 /* check if we are at new node */
896 if (!pos->currentAssoc || !pos->currentLeft)
897 {
898 /* find class with assoc link */
899 while (pos->currentLeft && !pos->currentLeft->associatorClasses)
900 pos->currentLeft = pos->currentLeft->parent;
901
902 if (!pos->currentLeft)
903 return MI_FALSE;
904 mike 1.1
905 pos->currentAssoc = pos->currentLeft->associatorClasses;
906 return MI_TRUE;
907 }
908
909 pos->currentAssoc = pos->currentAssoc->next;
910
911 if (pos->currentAssoc)
912 return MI_TRUE;
913
914 /* skip to parent */
915 pos->currentLeft = pos->currentLeft->parent;
916 return _GetNextAssoc(pos);
917 }
918
919 static MI_Boolean _IsNodeOrParentOf(
920 ProvRegClassInheritanceNode* parent,
921 ProvRegClassInheritanceNode* node)
922 {
923 while (node)
924 {
925 mike 1.1 if (node == parent)
926 return MI_TRUE;
927
928 node = node->parent;
929 }
930 return MI_FALSE;
931 }
932
933 MI_EXPORT MI_Result ProvReg_NextAssocClass(
934 ProvRegAssocPosition* pos,
935 const MI_Char** className,
936 MI_Boolean* done)
937 {
938 /* navigate to next */
939 if (!pos->currentLeft)
940 {
941 if (done)
942 *done = MI_TRUE;
|