/* **============================================================================== ** ** Open Management Infrastructure (OMI) ** ** Copyright (c) Microsoft Corporation ** ** Licensed under the Apache License, Version 2.0 (the "License"); you may not ** use this file except in compliance with the License. You may obtain a copy ** of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABLITY OR NON-INFRINGEMENT. ** ** See the Apache 2 License for the specific language governing permissions ** and limitations under the License. ** **============================================================================== */ #include #include #include #include #include #include #include "provreg.h" #include "regfile.h" typedef struct _ProvRegNamespaceNode { struct _ProvRegNamespaceNode* next; MI_ConstString ns; struct _ProvRegClassInheritanceNode* tree; } ProvRegNamespaceNode; typedef struct _ProvRegAssocBackLinkNode { struct _ProvRegAssocBackLinkNode* next; struct _ProvRegClassInheritanceNode* assocClass; } ProvRegAssocBackLinkNode; typedef struct _ProvRegClassInheritanceNode { MI_ConstString cn; struct _ProvRegClassInheritanceNode* parent; struct _ProvRegClassInheritanceNode* nextSibling; struct _ProvRegClassInheritanceNode* firstChild; /* assoc support */ /* left/right are not-null only for assoc class */ struct _ProvRegClassInheritanceNode* left; struct _ProvRegClassInheritanceNode* right; /* linked list of all assoc classes that refer this class */ ProvRegAssocBackLinkNode* associatorClasses; } ProvRegClassInheritanceNode; #if (MI_CHAR_TYPE == 1) #define MI_ScasecmpChar_MIChar Zcasecmp #else static int MI_ScasecmpChar_MIChar( const char* str1, const MI_Char* str2 ) { /* assuming str2 is ascii char-set only */ for(;;) { int c1 = tolower((unsigned char)*str1); int c2 = tolower((unsigned char)*str2); if (c1 != c2 ) { return c1 < c2 ? -1 : 1; } if (!c1) break; str1++; str2++; } return 0; } #endif /* returns last segment from the string or string itself; for example, for string abc,edf,ghk function returns 'ghk', 'edf' and 'abc' */ static char* _GetNextReverse(char** text, char delim) { char* start = *text; char* end; size_t len; /* If at end of string */ if (!*start) return NULL; len = strlen(start); /* end of string */ end = start + len; /* Remove trailing whitespace */ for (; end != start && isspace((unsigned char)end[-1]);) *--end = '\0'; /* Skip non-colon character characters */ for (; end != start && *end != delim; end--) ; if ( end == start ) { /* last block - move position to the end to point to \0 */ *text = start + len; } else { /* skip delimiter*/ *end = 0; end++; } /* Skip leading whitespace */ while (*end && isspace((unsigned char)*end)) end++; return end; } static char* _Strdup(Batch* batch, const char* s) { size_t size = strlen(s) + 1; char* p; size_t i; p = Batch_Get(batch, size * sizeof(char)); if (!p) return NULL; for (i = 0; i < size; i++) p[i] = s[i]; return p; } static MI_Char* _Strdup2(Batch* batch, const char* s) { size_t size = strlen(s) + 1; MI_Char* p; size_t i; p = Batch_Get(batch, size * sizeof(MI_Char)); if (!p) return NULL; for (i = 0; i < size; i++) p[i] = (MI_Char)s[i]; return p; } /* ********************************************************* */ /* *** namespace operations *** */ /* ********************************************************* */ ProvRegNamespaceNode* _FindNamespace( ProvReg* self, MI_ConstString ns) { /* find namespace node in the list */ ProvRegNamespaceNode* current = self->namespaces; while (current && Zcasecmp(ns,current->ns) != 0) current = current->next; return current; } ProvRegNamespaceNode* _FindOrCreateNamespace( ProvReg* self, MI_ConstString ns) { ProvRegNamespaceNode* item = _FindNamespace(self,ns); if (item) return item; item = (ProvRegNamespaceNode*)Batch_GetClear( &self->batch, sizeof(ProvRegNamespaceNode)); if (item) { item->ns = ns; /* no need to strdup, since it's already in batch*/ item->next = self->namespaces; self->namespaces = item; } return item; } /* ********************************************************* */ /* *** tree operations *** */ /* ********************************************************* */ ProvRegClassInheritanceNode* _GetNextTreeNodeLimittedBy( ProvRegClassInheritanceNode* item, ProvRegClassInheritanceNode* subtreeRoot) { /* first-child */ if (item->firstChild) return item->firstChild; /* sibling */ if (item->nextSibling) return item->nextSibling; /* sibling of direct or indirect parent*/ while (item && item->parent != subtreeRoot) { item = item->parent; if (item->nextSibling) return item->nextSibling; } /* end of tree */ return 0; } ProvRegClassInheritanceNode* _GetNextTreeNode( ProvRegClassInheritanceNode* item) { return _GetNextTreeNodeLimittedBy(item,0); } ProvRegClassInheritanceNode* _FindClassNodeInTreeByChar( ProvRegClassInheritanceNode* root, const char* cn) { while (root) { if (MI_ScasecmpChar_MIChar(cn,root->cn)==0) { return root; } root = _GetNextTreeNode(root); } return root; } ProvRegClassInheritanceNode* _FindClassNodeInTree( ProvRegClassInheritanceNode* root, const MI_Char* cn) { while (root) { if (Zcasecmp(cn,root->cn)==0) { return root; } root = _GetNextTreeNode(root); } return root; } MI_Boolean _ValidateTreeNodes( ProvRegClassInheritanceNode* derivedNode, ProvRegClassInheritanceNode* baseNode) { /* if we have no nodes - it's fine - no info yet*/ if ( !derivedNode && !baseNode ) return MI_TRUE; /* if we have both nodes - check they are child/parent */ if ( derivedNode && baseNode ) return derivedNode->parent == baseNode; /* base must be specified */ if ( derivedNode && !baseNode ) return MI_FALSE; /* only one node is known - ok */ return MI_TRUE; } static MI_Result _AddClassInheritanceInfo( ProvReg* self, MI_ConstString ns, const char* derivedClass, /* can be null */ const char* baseClass ) { /* get (or create if needed) namespace item */ ProvRegNamespaceNode* namespaceNode = _FindOrCreateNamespace(self,ns); ProvRegClassInheritanceNode* derivedNode, *baseNode; if (!namespaceNode) return MI_RESULT_FAILED; /* find classes' nodes */ derivedNode = derivedClass ? _FindClassNodeInTreeByChar(namespaceNode->tree, derivedClass) : 0; baseNode = _FindClassNodeInTreeByChar(namespaceNode->tree, baseClass); /* validate nodes */ if (!_ValidateTreeNodes(derivedNode,baseNode)) return MI_RESULT_INVALID_CLASS_HIERARCHY; /* create missing nodes and insert them into tree */ if ( !baseNode ) { baseNode = (ProvRegClassInheritanceNode*)Batch_GetClear( &self->batch, sizeof(ProvRegClassInheritanceNode)); if ( !baseNode ) return MI_RESULT_FAILED; baseNode->cn = _Strdup2(&self->batch, baseClass); if ( !baseNode->cn ) return MI_RESULT_FAILED; /* insert into tree */ baseNode->nextSibling = namespaceNode->tree; namespaceNode->tree = baseNode; } if ( !derivedNode && derivedClass) { derivedNode = (ProvRegClassInheritanceNode*)Batch_GetClear( &self->batch, sizeof(ProvRegClassInheritanceNode)); if ( !derivedNode ) return MI_RESULT_FAILED; derivedNode->cn = _Strdup2(&self->batch, derivedClass); if ( !derivedNode->cn ) return MI_RESULT_FAILED; /* add as a child */ derivedNode->parent = baseNode; derivedNode->nextSibling = baseNode->firstChild; baseNode->firstChild = derivedNode; } return MI_RESULT_OK; } static MI_Result _AddAssociation( ProvReg* self, MI_ConstString ns, const char* assoc, const char* left, const char* right) { /* find all related nodes */ ProvRegNamespaceNode* namespaceNode; ProvRegClassInheritanceNode *leftNode, *rightNode, *assocNode; /* check namespace */ namespaceNode = _FindNamespace(self,ns); if (!namespaceNode) return MI_RESULT_INVALID_NAMESPACE; /* find class */ leftNode = _FindClassNodeInTreeByChar(namespaceNode->tree, left); rightNode = _FindClassNodeInTreeByChar(namespaceNode->tree, right); assocNode = _FindClassNodeInTreeByChar(namespaceNode->tree, assoc); if (!leftNode || !rightNode || !assocNode) return MI_RESULT_INVALID_CLASS; /* add cross-links */ assocNode->left = leftNode; assocNode->right = rightNode; { ProvRegAssocBackLinkNode* newLinkItemLeft; newLinkItemLeft = (ProvRegAssocBackLinkNode*)Batch_GetClear( &self->batch, sizeof(ProvRegAssocBackLinkNode)); if (!newLinkItemLeft) return MI_RESULT_FAILED; newLinkItemLeft->assocClass = assocNode; newLinkItemLeft->next = leftNode->associatorClasses; leftNode->associatorClasses = newLinkItemLeft; } /* check if assoc links different classes */ if (leftNode != rightNode) { ProvRegAssocBackLinkNode* newLinkItemRight; newLinkItemRight = (ProvRegAssocBackLinkNode*)Batch_GetClear( &self->batch, sizeof(ProvRegAssocBackLinkNode)); if (!newLinkItemRight) return MI_RESULT_FAILED; newLinkItemRight->assocClass = assocNode; newLinkItemRight->next = rightNode->associatorClasses; rightNode->associatorClasses = newLinkItemRight; } return MI_RESULT_OK; } static MI_Result _GetSubclasses2( ProvReg* self, ProvRegEntry* e, char* p) { /* get all sub-classes */ char* baseClass = _GetNextReverse(&p, ':'); char* derivedClass = _GetNextReverse(&p, ':'); MI_Result r; /* expecting to find at least one class */ if (!baseClass) return MI_RESULT_INVALID_CLASS; while ( derivedClass ) { r = _AddClassInheritanceInfo(self, e->nameSpace, derivedClass, baseClass); if ( MI_RESULT_OK != r ) return r; baseClass = derivedClass; derivedClass = _GetNextReverse(&p, ':'); } /* add base class with no parent */ r = _AddClassInheritanceInfo(self, e->nameSpace, derivedClass, baseClass); if (MI_RESULT_OK != r) return r; e->className = _Strdup2(&self->batch, baseClass); if (!e->className) { return MI_RESULT_FAILED; } return MI_RESULT_OK; } static int _AddEntry( ProvReg* self, const char* nameSpace, RegFile* regFile, RegClass* regClass) { ProvRegEntry* e; #if 0 RegFile_Print(regFile, stdout); #endif /* Allocate new provider register entry */ e = (ProvRegEntry*)Batch_GetClear(&self->batch, sizeof(ProvRegEntry)); if (!e) return -1; /* ProvRegEntry.provInterface */ e->provInterface = PROV_INTERFACE_STATIK; /* ProvRegEntry.nameSpace */ e->nameSpace = _Strdup2(&self->batch, nameSpace); /* ProvRegEntry.libraryName */ e->libraryName = _Strdup(&self->batch, regFile->library); /* ProvRegEntry.hosting*/ e->hosting = PROV_HOSTING_INPROC; if (regClass->hosting) { char hosting[64]; Strlcpy(hosting, regClass->hosting, sizeof(hosting)); /* it either user name or one of two special values: * @inproc@ * @requestor@ */ if (strcmp(hosting, PROV_REG_HOSTING_INPROC) == 0) { e->hosting = PROV_HOSTING_INPROC; } else if (strcmp(hosting, PROV_REG_HOSTING_REQUESTOR) == 0) { e->hosting = PROV_HOSTING_REQUESTOR; } else { e->hosting = PROV_HOSTING_USER; e->user = _Strdup(&self->batch, hosting); if (!e->user) return -1; } } /* If an association */ if (regClass->refName1 && regClass->refName2) { if (_GetSubclasses2(self, e, regClass->refName1) != MI_RESULT_OK) return -1; if (_GetSubclasses2(self, e, regClass->refName2) != MI_RESULT_OK) return -1; if (_GetSubclasses2(self, e, regClass->name) != MI_RESULT_OK) return -1; if (_AddAssociation(self, e->nameSpace, regClass->name, regClass->refName1, regClass->refName2) != MI_RESULT_OK) { return -1; } } else { if (_GetSubclasses2(self, e, regClass->name) != MI_RESULT_OK) return -1; } /* Add entry to end of list */ { e->next = NULL; if (self->tail) { self->tail->next = e; self->tail = e; } else { self->tail = e; self->head = e; } } return 0; } MI_Result ProvReg_Init2(ProvReg* self) { Dir* dir = NULL; Dir* dir2 = NULL; RegFile* reg = NULL; Batch* b = NULL; /* Zero-fill self */ memset(self, 0, sizeof(*self)); /* Initialize batch allocator */ Batch_Init(&self->batch, BATCH_MAX_PAGES); b = &self->batch; /* Open the 'omiregister' directory */ dir = Dir_Open(GetPath(ID_REGISTERDIR)); if (!dir) return MI_RESULT_FAILED; /* For each namespace directory in 'omirgister' */ for (;;) { DirEnt* ent = Dir_Read(dir); if (!ent) break; /* Ignore system directories */ if (strcmp(ent->name, ".") == 0 || strcmp(ent->name, "..") == 0) continue; /* Skip 'CVS' directories */ if (strcmp(ent->name, "CVS") == 0) continue; /* Scan .reg files in the current namespace directory */ { char path[MAX_PATH_SIZE]; Strlcpy(path, GetPath(ID_REGISTERDIR), sizeof(path)); Strlcat(path, "/", sizeof(path)); Strlcat(path, ent->name, sizeof(path)); dir2 = Dir_Open(path); if (!dir2) { goto failed; } for (;;) { DirEnt* ent2 = Dir_Read(dir2); if (!ent2) break; /* Ignore system directories */ if (strcmp(ent2->name,".") == 0 || strcmp(ent2->name,"..") == 0) continue; /* Load the reg file */ { char regPath[MAX_PATH_SIZE]; /* Form path to .reg file */ Strlcpy(regPath, path, sizeof(regPath)); Strlcat(regPath, "/", sizeof(regPath)); Strlcat(regPath, ent2->name, sizeof(regPath)); /* Create new reg file object */ reg = RegFile_New(regPath); if (!reg) { goto failed; } /* For each class in the reg file */ { RegClass* rc; for (rc = reg->classesHead; rc; rc = rc->next) { char* p = ent->name; /* Transpose '#' characters to '/' characters */ while (*p) { if (*p == '#') *p = '/'; p++; } if (_AddEntry(self, ent->name, reg, rc) != 0) { goto failed; } } } /* Delete the current entry */ RegFile_Delete(reg); reg = NULL; } } /* Close the directory */ Dir_Close(dir2); dir2 = NULL; } } /* Close directory */ Dir_Close(dir); return MI_RESULT_OK; failed: if (dir) Dir_Close(dir); if (dir2) Dir_Close(dir2); return MI_RESULT_FAILED; } void ProvReg_Destroy( ProvReg* self) { Batch_Destroy(&self->batch); } void ProvReg_Dump( ProvReg* self, FILE* os) { ProvRegEntry* p; for (p = self->head; p; p = p->next) { fprintf(os, "==== ProvRegEntry\n"); fprintf(os, "provInterface[%u]\n", p->provInterface); Fzprintf(os, MI_T("nameSpace[%s]\n"), p->nameSpace); Fzprintf(os, MI_T("className[%s]\n"), p->className); fprintf(os, "libraryName[%s]\n", p->libraryName); } } const ProvRegEntry* ProvReg_FindProviderForClass( ProvReg* self, const MI_Char* nameSpace, const MI_Char* className) { ProvRegEntry* p; for (p = self->head; p; p = p->next) { if (Zcasecmp(p->className, className) == 0 && Zcasecmp(p->nameSpace, nameSpace) == 0) return p; } /* Not found */ return NULL; } /* returns ok or not-found; baseClass will be null if no base class exist */ MI_Result ProvReg_GetDirectBaseClass( ProvReg* self, const MI_Char* nameSpace, const MI_Char* className, const MI_Char** baseClass) { ProvRegClassInheritanceNode* classNode; ProvRegNamespaceNode* namespaceNode; /* clear out param */ *baseClass = 0; /* check namespace */ namespaceNode = _FindNamespace(self,nameSpace); if (!namespaceNode) return MI_RESULT_INVALID_NAMESPACE; /* find class */ classNode = _FindClassNodeInTree(namespaceNode->tree, className); if (!classNode) return MI_RESULT_INVALID_CLASS; if (classNode->parent) { *baseClass = classNode->parent->cn; } return MI_RESULT_OK; } /* enumerates classes derived classes: - if deep == false and className == null, returns all root classes - if deep == true and className == null, returns all classes - if deep == false and className provided, returns all classes directly derived from given - if deep == true and className provided, returns all classes derived from given */ MI_Result ProvReg_BeginClasses( ProvReg* self, const MI_Char* nameSpace, const MI_Char* className, MI_Boolean deep, ProvRegPosition* pos) { ProvRegNamespaceNode* namespaceNode; /* clear pos */ memset( pos, 0, sizeof(*pos)); pos->deep = deep; /* check namespace */ namespaceNode = _FindNamespace(self,nameSpace); if (!namespaceNode) return MI_RESULT_INVALID_NAMESPACE; /* find class */ if (className) { pos->start = _FindClassNodeInTree(namespaceNode->tree, className); if (!pos->start) return MI_RESULT_INVALID_CLASS; pos->current = pos->start->firstChild; } else { pos->start = 0; pos->current = namespaceNode->tree; } return MI_RESULT_OK; } MI_Result ProvReg_NextClass( ProvRegPosition* pos, const MI_Char** className, MI_Boolean* done) { if (!pos->current) { *className = 0; if (done) *done = MI_TRUE; return MI_RESULT_OK; } *className = pos->current->cn; if (pos->deep) { pos->current = _GetNextTreeNodeLimittedBy(pos->current,pos->start); } else { pos->current = pos->current->nextSibling; } if (done) *done = MI_FALSE; return MI_RESULT_OK; } MI_Result ProvReg_EndClasses( ProvRegPosition* pos) { memset( pos, -1, sizeof(*pos)); return MI_RESULT_OK; } /* returns enumerator to all registered association classes by given instance class and (optionally) assoc/result classes */ MI_EXPORT MI_Result ProvReg_BeginAssocClasses( ProvReg* self, const MI_Char* nameSpace, const MI_Char* className, const MI_Char* assocClassName, /* can be NULL */ const MI_Char* resultClassName, /* can be NULL */ ProvRegAssocPosition* pos) { ProvRegNamespaceNode* namespaceNode; if (!nameSpace || !className || !pos) return MI_RESULT_INVALID_PARAMETER; /* clear pos */ memset( pos, 0, sizeof(*pos)); /* check namespace */ namespaceNode = _FindNamespace(self,nameSpace); if (!namespaceNode) return MI_RESULT_INVALID_NAMESPACE; /* find class */ pos->currentLeft = _FindClassNodeInTree(namespaceNode->tree, className); if (!pos->currentLeft) return MI_RESULT_INVALID_CLASS; //pos->currentAssoc = pos->currentLeft->associatorClasses; /* validate optional parameters */ if (assocClassName) { ProvRegClassInheritanceNode* assocClassNode = _FindClassNodeInTree(namespaceNode->tree, assocClassName); if (!assocClassNode) return MI_RESULT_INVALID_CLASS; /* store node pointer */ pos->assocClass = assocClassNode; } if (resultClassName) { ProvRegClassInheritanceNode* resultClassNode = _FindClassNodeInTree(namespaceNode->tree, resultClassName); if (!resultClassNode) return MI_RESULT_INVALID_CLASS; /* store node pointer */ pos->resultClass = resultClassNode; } return MI_RESULT_OK; } static MI_Boolean _GetNextAssoc( ProvRegAssocPosition* pos) { /* check if we are at new node */ if (!pos->currentAssoc || !pos->currentLeft) { /* find class with assoc link */ while (pos->currentLeft && !pos->currentLeft->associatorClasses) pos->currentLeft = pos->currentLeft->parent; if (!pos->currentLeft) return MI_FALSE; pos->currentAssoc = pos->currentLeft->associatorClasses; return MI_TRUE; } pos->currentAssoc = pos->currentAssoc->next; if (pos->currentAssoc) return MI_TRUE; /* skip to parent */ pos->currentLeft = pos->currentLeft->parent; return _GetNextAssoc(pos); } static MI_Boolean _IsNodeOrParentOf( ProvRegClassInheritanceNode* parent, ProvRegClassInheritanceNode* node) { while (node) { if (node == parent) return MI_TRUE; node = node->parent; } return MI_FALSE; } MI_EXPORT MI_Result ProvReg_NextAssocClass( ProvRegAssocPosition* pos, const MI_Char** className, MI_Boolean* done) { /* navigate to next */ if (!pos->currentLeft) { if (done) *done = MI_TRUE; return MI_RESULT_OK; } while (_GetNextAssoc(pos)) { /* check filters */ if ( (!pos->assocClass || _IsNodeOrParentOf(pos->assocClass, pos->currentAssoc->assocClass)) && (!pos->resultClass || _IsNodeOrParentOf(pos->resultClass, pos->currentAssoc->assocClass->left != pos->currentLeft ? pos->currentAssoc->assocClass->left : pos->currentAssoc->assocClass->right) || _IsNodeOrParentOf( pos->currentAssoc->assocClass->left != pos->currentLeft ? pos->currentAssoc->assocClass->left : pos->currentAssoc->assocClass->right, pos->resultClass)) ) { *className = pos->currentAssoc->assocClass->cn; if (done) *done = MI_FALSE; return MI_RESULT_OK; } } if (done) *done = MI_TRUE; return MI_RESULT_OK; } MI_EXPORT MI_Result ProvReg_EndAssocClasses( ProvRegAssocPosition* pos) { memset( pos, -1, sizeof(*pos)); return MI_RESULT_OK; }