diff --git a/include/nwnss/include/seqUpdater.h b/include/nwnss/include/seqUpdater.h new file mode 100644 index 0000000..94d83cb --- /dev/null +++ b/include/nwnss/include/seqUpdater.h @@ -0,0 +1,47 @@ +/**************************************************************************** + | + | (C) Copyright 2001 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: taysom $ + | $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $ + | + | $RCSfile$ + | $Revision: 465 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | This defines globals and prototypes for the background checker. + +-------------------------------------------------------------------------*/ +#ifndef _SEQUPDATER_H_ +#define _SEQUPDATER_H_ + +#if zLINUX +extern void SEQ_StartProcess(void); +extern void SEQ_StopProcess(void); +extern void SEQ_Sleep(NINT seconds); +extern void SEQ_Wakeup(void); +#endif + +#endif /* _SEQUPDATER_H_ */ diff --git a/src/nwnss/CMakeLists.txt b/src/nwnss/CMakeLists.txt index 8e53ecf..02010f4 100644 --- a/src/nwnss/CMakeLists.txt +++ b/src/nwnss/CMakeLists.txt @@ -184,6 +184,18 @@ add_library(nwnss SHARED comn/common/comnEFL.c comn/common/comnLog.c comn/common/checker.c + comn/common/cSA.c + comn/common/hmc.c + comn/common/repair.c + comn/common/cmdLineRecovery.c + comn/common/seqUpdater.c + comn/common/comnStartup.c + comn/sbs/sbsMgmt.c + comn/authsys/zasAuthModel.c + comn/authsys/zasAuthSpace.c + comn/authsys/zasAuthCache.c + comn/authsys/unixAuthModel.c + comn/compression/nwAlgo.c comn/common/ndpIdBrokerShared.c library/misc/sysimp.c comn/main/comnCmdline.c diff --git a/src/nwnss/comn/authsys/unixAuthModel.c b/src/nwnss/comn/authsys/unixAuthModel.c new file mode 100644 index 0000000..15f1559 --- /dev/null +++ b/src/nwnss/comn/authsys/unixAuthModel.c @@ -0,0 +1,512 @@ +/**************************************************************************** + | + | (C) Copyright 2003 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | Novell Storage Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2005-08-10 01:03:51 +0530 (Wed, 10 Aug 2005) $ + | + | $RCSfile$ + | $Revision: 1177 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | These are the authorization routines for the Unix authorization + | model. + +-------------------------------------------------------------------------*/ +#include + +#include +#include +#include +#include /* NSS Library*/ + +#include "zParams.h" +#include "pssConnection.h" +#include "msgName.h" +#include "objectIDStore.h" +#include "checker.h" +#include "unixAuthModel.h" +#include "unixAuthSpace.h" +#include "zasAuthSpace.h" + +/*------------------------------------------------------------------------- + * Global variables + *-------------------------------------------------------------------------*/ +NINT UXASindex; /* the index assigned to the Unix authorization space */ +BOOL UXASAuthStarted = FALSE; +NINT UX_InitialMode = 0x750; + +struct AuthModelOps_s UnixAuthorizeModelOps; + +/*************************************************************************** + * This will be called at Authorization model init time + ***************************************************************************/ +STATUS UXAS_Startup(void) +{ + GeneralMsg_s genMsg; + AuthModelBeast_s *authModel; + AuthSpaceBeast_s *authSpace; + + ASSERT_MPKNSS_LOCK(); + COMN_STRUCT_INIT(genMsg); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + if ((authModel = COMN_RegisterAuthorizeModel(&genMsg, AUTH_MODEL_VERSION, + zFTYPE_UNIX_AUTH_MODEL, MSGNot("Unix"), &UnixAuthorizeModelOps)) == NULL) + { + return zFAILURE; + } + + if ((authSpace = COMN_RegisterAuthorizeSpace(&genMsg, authModel, + zFTYPE_UNIX_AUTH_SPACE, MSGNot("UnixToUnix"), + (AuthSpaceOps_s *)&UnixAuthorizeSpaceOps)) == NULL) + { + return zFAILURE; + } + + if ((authSpace = COMN_RegisterAuthorizeSpace(&genMsg, authModel, + zFTYPE_ZAS_AUTH_SPACE, MSGNot("NetWareToUnix"), + (AuthSpaceOps_s *)&NetWareToUnixAuthorizeSpaceOps)) == NULL) + { + return zFAILURE; + } + + UXASAuthStarted = TRUE; + return zOK; +} + +/*************************************************************************** + * This will be called at Authorization shutdown time + ***************************************************************************/ +void UXAS_Shutdown(void) +{ + ASSERT_MPKNSS_LOCK(); + UXASAuthStarted = FALSE; + return; +} + +/*************************************************************************** + * This routine is called when an auth beast is allocated in memory + * (it may still be on disk) + ***************************************************************************/ +STATUS UXAUTH_ConstructAuthBeast( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast) +{ + UXASAuthorizeInfo_s *authInfo; + AuthCtrl_s *connInfo; + + ASSERT_MPKNSS_LOCK(); + authInfo = (UXASAuthorizeInfo_s *)zalloc(sizeof(UXASAuthorizeInfo_s)); + if (authInfo == NULL) + { + SetErrno(genMsg,zERR_NO_MEMORY); + return zFAILURE; + } + + authBeast->AUTHauthInfo.unx = authInfo; + connInfo = &genMsg->pssConn.ptr->authInfo; + authInfo->p.version = UXAS_CURRENT_AUTH_VERSION; + authInfo->p.groupID = zINVALID_USERID; +// if (connInfo->numAuthenticatedIDs > 1) +// { +// authInfo->p.groupID = connInfo->authenticatedIDs[1]; +// } + + authInfo->p.mode = UX_InitialMode; + return zOK; +} + +/*************************************************************************** + * This routine is called when an auth beast is freed from memory + * (it may still be on disk) + ***************************************************************************/ +void UXAUTH_DestructAuthBeast( + AuthBeast_s *authBeast) +{ + ASSERT_MPKNSS_LOCK(); + free(authBeast->AUTHauthInfo.unx); + return; +} + +/*************************************************************************** + * This routine is called when an auth beast is written to storage + ***************************************************************************/ +NINT UXAUTH_PackedSize( + AuthBeast_s *authBeast) +{ + ASSERT_MPKNSS_LOCK(); + return sizeof(UXASPersistentAuthInfo_s); +} + +/*************************************************************************** + * This routine is called when an auth beast is written to storage + ***************************************************************************/ +BYTE *UXAUTH_PackAuthBeast( + AuthBeast_s *authBeast, + BYTE *storeBuffer) +{ + UXASAuthorizeInfo_s *authInfo; + + ASSERT_MPKNSS_LOCK(); + authInfo = authBeast->AUTHauthInfo.unx; + memcpy(storeBuffer, &authInfo->p, sizeof(UXASPersistentAuthInfo_s)); + return storeBuffer + sizeof(UXASPersistentAuthInfo_s); +} + +/************************************************************************** + * This routine is called when we have done a "getPackedSize" but we can't + * do the pack due to an error. + ***************************************************************************/ +void UXAUTH_NoPackAuthBeastCleanup( + AuthBeast_s *authBeast) +{ + ASSERT_MPKNSS_LOCK(); + return; +} + +/*************************************************************************** + * This routine is called when an auth beast is read from storage + ***************************************************************************/ +BYTE *UXAUTH_UnpackAuthBeast( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + BYTE *storeBuffer) +{ + UXASAuthorizeInfo_s *authInfo; + + ASSERT_MPKNSS_LOCK(); + authInfo = authBeast->AUTHauthInfo.unx; + + zASSERT (authBeast->AUTHbeastVersion == CURRENT_BEAST_VERSION); + memcpy(&authInfo->p, storeBuffer, sizeof(UXASPersistentAuthInfo_s)); + return storeBuffer + sizeof(UXASPersistentAuthInfo_s); +} + + +/*************************************************************************** + * + * This routine is called when a name is added to the name tree. + * + ***************************************************************************/ +STATUS UXAUTH_AddAuthInfo( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZid, + Latch_s *parentLatch) +{ + return zOK; +} + + +/*************************************************************************** + * + * This routine is called when a name is deleted from the name tree + * + ***************************************************************************/ +STATUS UXAUTH_RemoveAuthInfo( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZid, + Xaction_s *xaction) +{ + return zOK; +} + +/*************************************************************************** + * + * This routine is called when a file is actually deleted. It cleans up the + * associated overflow beasts. + * + ***************************************************************************/ +STATUS UXAUTH_DeleteAuthInfo( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZid) +{ + return zOK; +} + +/*************************************************************************** + * + * This routine is called to determine if there is auth info that needs + * to be cleaned up. If so then it returns TRUE. + * + ***************************************************************************/ +BOOL UXAUTH_IsAuthInfo( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast) +{ + return FALSE; +} + +/**************************************************************************** + * This routine is used to initialize the authorization info for a newly + * created volume. It must only change items in the volume's rootdir. + * The caller will have the rootdir xlatched and will ensure that the + * rootdir gets written and the latch released on successful return. On + * error return the volume will not get created. + *****************************************************************************/ +STATUS UXAUTH_InitVolumeAuthInfo( + GeneralMsg_s *genMsg, + Volume_s *volBeast) +{ +#if NSS_DEBUG IS_ENABLED + AuthBeast_s *rootdir = (AuthBeast_s *)volBeast->rootdir; + + ASSERT_MPKNSS_LOCK(); + ASSERT_XLATCH(&rootdir->AUTHbeastLatch); +#endif + return(zOK); +} + +/**************************************************************************** + * + * This routine removes a list of trustees from all objects in a given + * volume. Currently it is calling a routine that is also called from + * the authorization space for some symantic agent requests. The authorization + * space routine could have been placed directly in the ops tables, but since + * this is an infrequently used call I gave it its own routine to avoid + * confusion. + * + ****************************************************************************/ +STATUS UXAUTH_RemoveIDsFromAVolume( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *IDlist, + NINT IDcount) +{ + SearchMsg_s searchMsg; + NINT i; + File_s *file; + + ASSERT_MPKNSS_LOCK(); + COMN_STRUCT_INIT(searchMsg); + COMN_SETUP_SEARCH_MSG (&searchMsg, 0, + SMAPOPT_32BitMode | SMAPOPT_searchAllDirs | SMAPOPT_matchAllEntries, + zNTYPE_FILE); + + COMN_SET_NAMING_MSG_PARSEMODE(nameMsg, NAMPMODE_DoNotResolveLeafName); + if (COMN_WildOpen(genMsg, nameMsg, &searchMsg) != zOK) + { + goto cleanup; + } + + /* search all entries for the user IDs */ + for(;;) + { /* look at each file in the system */ + genMsg->flags |= DO_NOT_SEND_FSHOOKS; + if (COMN_WildRead(genMsg, nameMsg, &searchMsg) != zOK) + { + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + if (GetErrno(genMsg) == zERR_NAME_NOT_FOUND_IN_DIRECTORY) + { /* normal end */ + ClearErrno(genMsg); + COMN_WildClose(genMsg, &searchMsg); + return zOK; + } + goto cleanupClose; + } + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + file = nameMsg->curFile; + + for (i = 0; i < IDcount; i++) + { /* check each user in the list */ + if (LB_GUIDCompare(&file->auth.authInfo.unx->p.groupID, &IDlist[i]) + == 0) + { + file->auth.authInfo.unx->p.groupID = zINVALID_USERID; + COMN_MARK_BEAST_DIRTY(&file->FILEroot); + } + } + } + +cleanupClose: + COMN_WildClose(genMsg, &searchMsg); +cleanup: + return zFAILURE; +} + +/**************************************************************************** + * + * This function adds the NDS object GUIDs to the User store for all + * structures in the ZAS auth model. + * + ****************************************************************************/ +STATUS UXAUTH_AddObjectNames( + GeneralMsg_s *genMsg, + Volume_s *volume, + AuthBeast_s *beast) +{ + UXASAuthorizeInfo_s *authInfo; + + /* Add the trustees and visibility entries */ + authInfo = beast->AUTHauthInfo.unx; + OID_AddEntryIfNotThere(genMsg, volume, &beast->authInfo.unx->p.groupID); + ClearErrno(genMsg); + return zOK; +} + +/**************************************************************************** + * + * This function checks the IDs for a beast to see if they are still good + * + ****************************************************************************/ +STATUS UXAUTH_CheckUserIDs( + GeneralMsg_s *genMsg, + Volume_s *volume, + AuthBeast_s *beast) +{ + UXASAuthorizeInfo_s *authInfo; + BOOL isOK; + + authInfo = beast->AUTHauthInfo.unx; + + if (CHK_VerifyID(genMsg, volume, &beast->authInfo.unx->p.groupID, + &isOK) == zOK) + { + if (!isOK) + { + beast->authInfo.unx->p.groupID = zINVALID_USERID; + COMN_MARK_BEAST_DIRTY(&beast->AUTHroot); + } + } + + return zOK; +} + +/*************************************************************************** + * + * This routine is called when the information for the authorization system + * (i.e. caching) may need to be invalidated. + * + ***************************************************************************/ +STATUS UXAUTH_InvalidateAuthInfo( + GeneralMsg_s *genMsg) +{ + return zOK; +} + +/**************************************************************************** + * + * This function changes the authorization Owner ID for a beast + * + ****************************************************************************/ +STATUS UXAS_ChangeOwner( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + AuthBeast_s *beast, + UserID_t *newOwner) +{ + ModifyInfoMsg_s infoMsg; + zInfo_s info; + + info.id.owner = *newOwner; + COMN_STRUCT_INIT(infoMsg); + COMN_SETUP_MODIFY_INFO_MSG(&infoMsg, zMOD_OWNER_ID, &info, + zINFO_VERSION_A); + + return COMN_ModifyInfo(genMsg, nameMsg, &infoMsg); +} + +/**************************************************************************** + * + * This function changes the authorization group ID for a beast + * + ****************************************************************************/ +STATUS UXAS_ChangeGroup( + AuthBeast_s *beast, + UserID_t *newGroup) +{ + beast->authInfo.unx->p.groupID = *newGroup; + COMN_MARK_BEAST_DIRTY(&beast->AUTHroot); + return zOK; +} + +/**************************************************************************** + * + * This function changes the Unix mode bits for a beast + * + ****************************************************************************/ +STATUS UXAS_ChangeMode( + AuthBeast_s *beast, + NINT mode) +{ + beast->authInfo.unx->p.mode = mode; + COMN_MARK_BEAST_DIRTY(&beast->AUTHroot); + return zOK; +} + +/**************************************************************************** + * + * This function get the authorization info for the Unix auth model. + * + ****************************************************************************/ +STATUS UXAS_GetAuthInfo( + AuthBeast_s *beast, + UserID_t *groupID, + NINT *mode) +{ + *groupID = beast->authInfo.unx->p.groupID; + *mode = beast->authInfo.unx->p.mode; + return zOK; +} + +/**************************************************************************** + * + * This function puts a 32 bit Unix ID into the correct field of the GUID. + * + ****************************************************************************/ +void UXAS_StoreIDInGUID( + NINT id, + UserID_t *guid) +{ + guid->timeLow = id; + guid->clockSeqHighAndReserved = -1; /* indicate this is a numeric ID not a GUID */ + return; +} + +/*************************************************************************** + * The authorization operations for the system + ***************************************************************************/ +struct AuthModelOps_s UnixAuthorizeModelOps = +{ + UXAUTH_ConstructAuthBeast, + UXAUTH_DestructAuthBeast, + UXAUTH_PackedSize, + UXAUTH_PackAuthBeast, + UXAUTH_NoPackAuthBeastCleanup, + UXAUTH_UnpackAuthBeast, + UXAUTH_AddAuthInfo, + UXAUTH_RemoveAuthInfo, + UXAUTH_DeleteAuthInfo, + UXAUTH_IsAuthInfo, + UXAUTH_MayIDoThis, + UXAUTH_InitVolumeAuthInfo, + UXAUTH_RemoveIDsFromAVolume, + UXAUTH_AddObjectNames, + UXAUTH_CheckUserIDs, + UXAUTH_InvalidateAuthInfo, +}; diff --git a/src/nwnss/comn/authsys/zasAuthCache.c b/src/nwnss/comn/authsys/zasAuthCache.c new file mode 100644 index 0000000..c30bfaf --- /dev/null +++ b/src/nwnss/comn/authsys/zasAuthCache.c @@ -0,0 +1,439 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) Initialization module + | + |--------------------------------------------------------------------------- + | + | $Author: cteerlink $ + | $Date: 2006-12-01 04:07:06 +0530 (Fri, 01 Dec 2006) $ + | + | $RCSfile$ + | $Revision: 1712 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | This is the authorization cash for the system. + +-------------------------------------------------------------------------*/ +#include + +#include +#include +#include +#include +#include "zasAuthCache.h" +#include "pssStartup.h" +#include "csa.h" + +AuthCacheCtrl_s AuthCache = /* control head for the authorization hash */ +{ + {0}, /* latch */ + 0, /* activation count */ + HASH_TABLE_SIZE - 1, /* hashMask */ + NULL, /* pointer to hash array */ + {NULL, NULL}, /* LRU */ + DEFAULT_AUTH_CACHE_SIZE, /* max number of entries */ + 0, /* number of entries in the cache */ + 0, /* signature count */ + 0 /* reset count */ +}; + + +/************************************************************************** + * This will initialize the authorization cache for the entire system + **************************************************************************/ +STATUS ZAS_CacheInit( + GeneralMsg_s *genMsg) +{ + NINT i; + NINT hashSize; + + ASSERT_MPKNSS_LOCK(); + X_LATCH(&AuthCache.latch); + if (AuthCache.hash == NULL) + { /* first init */ + hashSize = AuthCache.maxEntries; + + AuthCache.hash = zalloc(hashSize * sizeof(DQhead_t)); + if (AuthCache.hash == NULL) + { + SetErrno (genMsg, zERR_NO_MEMORY); + UNX_LATCH(&AuthCache.latch); + return zFAILURE; + } + for (i=0; i < hashSize; i++) + { + DQ_INIT(&(*AuthCache.hash)[i]); + } + AuthCache.hashMask = hashSize - 1; + DQ_INIT(&AuthCache.LRUqueue); + AuthCache.numEntries = 0; + AuthCache.signatureCount = 0; + AuthCache.activationCount = 0; + AuthCache.resetCount = 0; + } + AuthCache.activationCount++; + UNX_LATCH(&AuthCache.latch); + return zOK; +} + +/************************************************************************** + * This will cleanup the authorization cache for the entire system. + **************************************************************************/ +void ZAS_CacheUninit(void) +{ + DQhead_t *hp; + NINT i; + AuthCacheNode_s *item; + + ASSERT_MPKNSS_LOCK(); + X_LATCH(&AuthCache.latch); + if (AuthCache.activationCount == 1 && AuthCache.hash != NULL) + { + for (hp=&(*AuthCache.hash)[0],i=AuthCache.hashMask+1;i > 0;hp++,i--) + { + for (;;) + { + DQ_DEQ(hp, item, AuthCacheNode_s, hashLink); + if (item != NULL) + free(item); + else + break; + } + zASSERT(DQ_EMPTY(hp)); + } + + free(AuthCache.hash); + AuthCache.hash = NULL; + DQ_INIT(&AuthCache.LRUqueue); + } + AuthCache.activationCount--; + UNX_LATCH(&AuthCache.latch); +} + + +/************************************************************************** + * This generates the HASH value for an entry + **************************************************************************/ +STATIC NINT ZAS_Hash( + NINT domainID, + EffectiveACL_s *EACL) +{ + NINT hash=0; + NINT index; + + ASSERT_MPKNSS_LOCK(); + ASSERT_LATCH(&AuthCache.latch); + for (index = 0; index < EACL->numEntries; index++) + { + hash += EACL->entry[index].trusteeID.timeLow; + hash += EACL->entry[index].rights; + } + hash += domainID << 8; +// aprintf(LGREEN, MSGNot("Hash=%x\n"),hash); + return hash; +} + + +/************************************************************************** + * This will try and locate an item in the auth cache. If found it will + * return a pointer to the AuthCache_s structure. If not found it returns + * a NULL. + * + * WARNING + * The restart count is part of the cache key!!!! + * You must first ensure that the volume's activation count == AuthBeast's + * restart count. This is not tested here for performance reasons. + * + **************************************************************************/ +AuthCacheNode_s *ZAS_GetEACLCacheEntry( + NINT cacheIndex, + NINT signature) +{ + AuthCacheNode_s *cacheNode; + DQhead_t *hashptr; + + ASSERT_MPKNSS_LOCK(); + if (cacheIndex == INVALID_EACL_CACHE_INDEX) + return NULL; + +// X_LATCH(&AuthCache.latch); + if (cacheIndex > (AuthCache.maxEntries - 1)) + { + return NULL; + } + hashptr = &(*AuthCache.hash)[cacheIndex]; + DQ_FOREACH(hashptr, cacheNode, AuthCacheNode_s, hashLink) + { + if (signature == cacheNode->signature) + { + DQ_RMV(cacheNode, LRUlink); + DQ_ENQ(&AuthCache.LRUqueue, cacheNode, LRUlink); +// UNX_LATCH(&AuthCache.latch); + return cacheNode; + } + } +// UNX_LATCH(&AuthCache.latch); + return NULL; +} + + +/************************************************************************** + * This will add the given EACL to the cache. It checks to see if the entry + * is already there. If it is, the cache node is returned and the new entry + * is freed. Otherwise, the entry is added and the new cache ID is returned. + **************************************************************************/ +AuthCacheNode_s *ZAS_AddEACLCacheEntry( + AuthCacheNode_s *newEntry, + NINT inputResetCount, + LONG *cacheIndex) +{ + AuthCacheNode_s *cacheNode; + DQhead_t *hashptr; + + ASSERT_MPKNSS_LOCK(); + ASSERT_XLATCH(&AuthCache.latch); +// X_LATCH(&AuthCache.latch); + if (inputResetCount != AuthCache.resetCount) + { /* The cache that newEntry is based on has been reset */ +// UNX_LATCH(&AuthCache.latch); + return NULL; + } + + newEntry->hashValue = ZAS_Hash(newEntry->domainID, &newEntry->EACL); + *cacheIndex = newEntry->hashValue & AuthCache.hashMask; + hashptr = &(*AuthCache.hash)[*cacheIndex]; + DQ_FOREACH(hashptr, cacheNode, AuthCacheNode_s, hashLink) + { + if (newEntry->hashValue == cacheNode->hashValue && + newEntry->EACL.numEntries == cacheNode->EACL.numEntries && + newEntry->domainID == cacheNode->domainID) + { /* these the same entry */ + if (memcmp(&newEntry->EACL.entry, &cacheNode->EACL.entry, + newEntry->EACL.numEntries * sizeof(ACLEntry_s)) == 0) + { + /* fix up the LRU queue */ + DQ_RMV(cacheNode, LRUlink); + DQ_ENQ(&AuthCache.LRUqueue, cacheNode, LRUlink); + free(newEntry); +// UNX_LATCH(&AuthCache.latch); +#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, MSGNot("Put cache entry at end of LRU")); +// ZAS_DisplayCache(); +#endif + return cacheNode; + } + } + } + + /* we only get here if the entry is not found */ + while (AuthCache.numEntries >= AuthCache.maxEntries) + { /* if we have all the entries allowed */ + DQ_DEQ(&AuthCache.LRUqueue, cacheNode, AuthCacheNode_s, LRUlink); + DQ_RMV(cacheNode, hashLink); + AuthCache.numEntries--; + free(cacheNode); + } + AuthCache.numEntries++; + newEntry->signature = AuthCache.signatureCount++; + NULLIFY(&newEntry->hashLink); + DQ_PUSH(&(*AuthCache.hash)[*cacheIndex], newEntry, hashLink); /* link of hash list */ + NULLIFY(&newEntry->LRUlink); + DQ_ENQ(&AuthCache.LRUqueue, newEntry, LRUlink); /* link to the LRU queue */ +// UNX_LATCH(&AuthCache.latch); +#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, MSGNot("Added a cache entry")); +// ZAS_DisplayCache(); +#endif + return newEntry; +} + + +/************************************************************************** + * This will try and locate an item in the auth cache. If found it will + * remove it. + **************************************************************************/ +void ZAS_RemoveEACLCacheEntry( + NINT cacheIndex, + NINT signature) +{ + AuthCacheNode_s *cacheNode; + DQhead_t *hashptr; + ASSERT_MPKNSS_LOCK(); + if (cacheIndex == INVALID_EACL_CACHE_INDEX) + return; + + if (cacheIndex > (AuthCache.maxEntries - 1)) + { + return; + } + + X_LATCH(&AuthCache.latch); + hashptr = &(*AuthCache.hash)[cacheIndex]; + DQ_FOREACH(hashptr, cacheNode, AuthCacheNode_s, hashLink) + { + if (signature == cacheNode->signature) + { + DQ_RMV(cacheNode, LRUlink); + DQ_RMV(cacheNode, hashLink); + free(cacheNode); + AuthCache.numEntries--; + UNX_LATCH(&AuthCache.latch); + return; + } + } + UNX_LATCH(&AuthCache.latch); + return; +} + + +/************************************************************************** + * This will invalidate the cache entries that might not be valid since an + * ACL entry has changed. + **************************************************************************/ +STATUS ZAS_InvalidateEACLCacheEntries( + GeneralMsg_s *genMsg, + UserID_t *trusteeID, + BOOL checkXLSS) +{ + AuthCacheNode_s *cacheNode; + AuthCacheNode_s *holdCacheNode; + DQhead_t *hashPtr; + NINT hashIndex; + NINT listIndex; + +#if NSS_DEBUG IS_ENABLED +AuthPartialResets++; +#endif + ASSERT_MPKNSS_LOCK(); + X_LATCH(&AuthCache.latch); + AuthCache.resetCount++; + for (hashIndex=0; hashIndex <= AuthCache.hashMask; hashIndex++) + { /* for each hash table entry */ + hashPtr = &(*AuthCache.hash)[hashIndex]; + DQ_FOREACH(hashPtr, cacheNode, AuthCacheNode_s, hashLink) + { + for (listIndex=0; listIndex < cacheNode->EACL.numEntries; + listIndex++) + { /* for each EACL entry */ + if (LB_GUIDCompare(&cacheNode->EACL.entry[listIndex].trusteeID, + trusteeID) == 0) + { /* if this is the correct entry */ + holdCacheNode = cacheNode; + cacheNode = OPREV(cacheNode, AuthCacheNode_s, hashLink); + DQ_RMV(holdCacheNode, LRUlink); + DQ_RMV(holdCacheNode, hashLink); + free(holdCacheNode); + AuthCache.numEntries--; + break; + } + } + } + } + UNX_LATCH(&AuthCache.latch); + if (checkXLSS) + { + CSA_InvalidateAuthCache(genMsg, trusteeID, FALSE); + } + return zOK; +} + +/************************************************************************** + * This will invalidate all EACL cache entries. + * + **************************************************************************/ +STATUS ZAS_InvalidateEntireEACLCache( + GeneralMsg_s *genMsg, + BOOL checkXLSS) +{ + AuthCacheNode_s *cacheNode; + AuthCacheNode_s *holdCacheNode; + DQhead_t *hashPtr; + NINT hashIndex; + +#if NSS_DEBUG IS_ENABLED +AuthResets++; +#endif + ASSERT_MPKNSS_LOCK(); + X_LATCH(&AuthCache.latch); + AuthCache.resetCount++; + for (hashIndex=0; hashIndex <= AuthCache.hashMask; hashIndex++) + { /* for each hash table entry */ + hashPtr = &(*AuthCache.hash)[hashIndex]; + DQ_FOREACH(hashPtr, cacheNode, AuthCacheNode_s, hashLink) + { + holdCacheNode = cacheNode; + cacheNode = OPREV(cacheNode, AuthCacheNode_s, hashLink); + DQ_RMV(holdCacheNode, LRUlink); + DQ_RMV(holdCacheNode, hashLink); + free(holdCacheNode); + AuthCache.numEntries--; + } + } + UNX_LATCH(&AuthCache.latch); + zASSERT(AuthCache.numEntries == 0); + if (checkXLSS) + { + UserID_t trusteeID; + CSA_InvalidateAuthCache(genMsg, &trusteeID, TRUE); + } + return zOK; +} + +#if NSS_DEBUG IS_ENABLED +/************************************************************************** + * This will go through and display all AuthCache nodes. + **************************************************************************/ +void ZAS_DisplayCache(void) +{ + DQhead_t *hashp; + NINT i,j; + AuthCacheNode_s *node; + + ASSERT_MPKNSS_LOCK(); +// wActivate(zDbgScreen); +// wPause(zDbgScreen,-1); + DBG_DebugPrintf(LGRAY,MSGNot("-------- AuthCache Contents --------\n")); + S_LATCH(&AuthCache.latch); + if (AuthCache.hash != NULL) + { + zASSERT(AuthCache.numEntries <= AuthCache.maxEntries); + for (hashp=&(*AuthCache.hash)[0],i=0; i <= AuthCache.hashMask; hashp++,i++) + { + DQ_FOREACH(hashp, node, AuthCacheNode_s, hashLink) + { + DBG_DebugPrintf(GREEN,MSGNot("Hash=%3d Signature=%3d Domain=%3d\n"), + i, node->signature, node->domainID); + for (j = 0; j < node->EACL.numEntries; j++) + { + DBG_DebugPrintf(LGRAY,MSGNot(" trustee=0x%08x rights=0x%04x attributes=0x%04x\n"), + node->EACL.entry[j].trusteeID, + node->EACL.entry[j].rights, + node->EACL.entry[j].attributes); + } + } + } + } + UNS_LATCH(&AuthCache.latch); +// wPause(zDbgScreen,0); +} +#endif diff --git a/src/nwnss/comn/authsys/zasAuthModel.c b/src/nwnss/comn/authsys/zasAuthModel.c new file mode 100644 index 0000000..2c991cb --- /dev/null +++ b/src/nwnss/comn/authsys/zasAuthModel.c @@ -0,0 +1,5792 @@ +/**************************************************************************** + | + | (C) Copyright 1996 - 2005 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | Novell Storage Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: gpachner $ + | $Date: 2008-04-11 02:30:25 +0530 (Fri, 11 Apr 2008) $ + | + | $RCSfile$ + | $Revision: 2315 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | These are the authorization routines that are model specific. + +-------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include /* NetWare Source*/ + +#include +#include +#include +#include + +#include /* NSS Library*/ + +#include "zParams.h" +#include "zasAuthModel.h" +#include "zasAuthSpace.h" +#include "unixAuthSpace.h" +#include "msgGen.h" +#include "zasAuthCache.h" +#include "pssConnection.h" +#include "comnPublics.h" +#include "comnBeasts.h" +//#include "sanwErr.h" +#include "volume.h" +#include "pssStartup.h" +#include "msgName.h" +#include "nameSpace.h" +#include "comnZAS.h" +#include "guid.h" +#include "adminVolume.h" +#include "comnLock.h" +#include "objectIDStore.h" +#include "xAdminVolume.h" +#include "checker.h" +#include "nssPubs.h" +#include "hardLinkBeast.h" + +/*------------------------------------------------------------------------- + * Global variables + *-------------------------------------------------------------------------*/ +NINT ZASindex; /* the index assigned to the Z authorization space */ +BOOL AuthorizeStarted = FALSE; + +STATUS ZAS_RemoveLatchedACLEntry( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + UserID_t *trusteeID, + NINT purgedFileFlag, + Xaction_s *xaction); + +STATUS ZAS_CountVis( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + NINT *entryCount); + +STATUS ZAS_GetAllVis( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + VisEntry_s *vis, + NINT count); + +/* Visibility rebuild stats */ +typedef struct VisRebuildStats_s +{ + QUAD VisNumBeasts; + QUAD VisNumOverflowRemoved; + QUAD VisNumFilesCleaned; + QUAD VisNumTrusteesProcessed; +} VisRebuildStats_s; + +typedef struct VisRebParms_s +{ + Volume_s *vol; + unicode_t name[zMAX_COMPONENT_NAME]; +} VisRebParms_s; + +/**************************************************************************** + * + ****************************************************************************/ +void *ZAS_LookupOverflowBeast ( + GeneralMsg_s *genMsg, + void *voidVol, + Zid_t zid, + NINT latchType, + NINT classID) +{ + RootBeast_s *beast; + + beast = BEASTHASH_LookupByZid(genMsg, voidVol, zid, latchType); + + if (beast == NULL) + { + return NULL; + } + + if (!(COMN_IsDerivedFrom(beast, classID))) + { + zASSERT("Overflow beast is not the correct type" == NULL); + COMN_UnlatchAndRelease(&beast, latchType); + return NULL; + } + return beast; +} + + +/**************************************************************************** + * + ****************************************************************************/ + +#if NSS_DEBUG IS_ENABLED +/* Authorization useage information */ +NINT AuthResets = 0; +NINT AuthPartialResets = 0; +NINT AuthERRequests = 0; +NINT AuthERHits = 0; +NINT AuthERImmediateHits = 0; + +/**************************************************************************** + * + ****************************************************************************/ +void DEBUG_Display_Visibility( + AuthBeast_s *authBeast) + +{ + NINT entry; + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + GeneralMsg_s genMsg; + + ASSERT_MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE(&genMsg); + DBG_DebugPrintf(GREEN, MSGNot("\nVisiblibilty entries for ZID 0x%Lx\n"), authBeast->AUTHzid); + authInfo = authBeast->AUTHauthInfo.zas; + + /* display the entries in the main beast */ + for (entry=0; entry < authInfo->p.numVisibilityTrusteesAssigned; entry++) + { + DBG_DebugPrintf(CYAN, MSGNot(" (%d) Trustee: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x Count: %d\n"), + entry, + authInfo->p.visibilityList[entry].trusteeID.timeLow, + authInfo->p.visibilityList[entry].trusteeID.timeMid, + authInfo->p.visibilityList[entry].trusteeID.timeHighAndVersion, + authInfo->p.visibilityList[entry].trusteeID.clockSeqHighAndReserved, + authInfo->p.visibilityList[entry].trusteeID.clockSeqLow, + authInfo->p.visibilityList[entry].trusteeID.node[0], + authInfo->p.visibilityList[entry].trusteeID.node[1], + authInfo->p.visibilityList[entry].trusteeID.node[2], + authInfo->p.visibilityList[entry].trusteeID.node[3], + authInfo->p.visibilityList[entry].trusteeID.node[4], + authInfo->p.visibilityList[entry].trusteeID.node[5], + authInfo->p.visibilityList[entry].count); + } + + /* display the entries in the overflow beasts */ + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + /* get the next overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(&genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + DBG_DebugPrintf(RED, MSGNot("Error opening an overflow beast: %d\n"), GetErrno(&genMsg)); + return; + } + + for (entry=0; entry < overflowBeast->p.numEntries; entry++) + { + DBG_DebugPrintf(LBLUE, MSGNot(" (%d) Trustee: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x Count: %d\n"), + entry, + overflowBeast->vis[entry].trusteeID.timeLow, + overflowBeast->vis[entry].trusteeID.timeMid, + overflowBeast->vis[entry].trusteeID.timeHighAndVersion, + overflowBeast->vis[entry].trusteeID.clockSeqHighAndReserved, + overflowBeast->vis[entry].trusteeID.clockSeqLow, + overflowBeast->vis[entry].trusteeID.node[0], + overflowBeast->vis[entry].trusteeID.node[1], + overflowBeast->vis[entry].trusteeID.node[2], + overflowBeast->vis[entry].trusteeID.node[3], + overflowBeast->vis[entry].trusteeID.node[4], + overflowBeast->vis[entry].trusteeID.node[5], + overflowBeast->vis[entry].count); + } + + overflowZid = overflowBeast->p.nextOverflowZid; + zASSERT((overflowZid == zINVALID_ZID) || + (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES)); + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } +} + +#endif + +/*************************************************************************** + * The authorization operations for the system + * (FixFixFix6 -- these should be loaded) + ***************************************************************************/ +struct AuthModelOps_s ZASAuthorizeModelOps = +{ + VAUTH_ConstructAuthBeast, + VAUTH_DestructAuthBeast, + VAUTH_PackedSize, + VAUTH_PackAuthBeast, + VAUTH_NoPackAuthBeastCleanup, + VAUTH_UnpackAuthBeast, + VAUTH_AddAuthInfo, + VAUTH_RemoveAuthInfo, + VAUTH_DeleteAuthInfo, + VAUTH_IsAuthInfo, + VAUTH_MayIDoThis, + VAUTH_InitVolumeAuthInfo, + VAUTH_RemoveIDsFromAVolume, + VAUTH_AddObjectNames, + VAUTH_CheckUserIDs, + VAUTH_InvalidateAuthInfo, +}; + +/*************************************************************************** + * This will be called at Authorization model init time + ***************************************************************************/ +STATUS ZAS_Startup(void) +{ + GeneralMsg_s genMsg; + AuthModelBeast_s *authModel; + AuthSpaceBeast_s *authSpace; + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_Startup); + COMN_STRUCT_INIT(genMsg); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + if ((authModel = COMN_RegisterAuthorizeModel(&genMsg, AUTH_MODEL_VERSION, + zFTYPE_ZAS_AUTH_MODEL, MSGNot("NetWare"), + &ZASAuthorizeModelOps)) == NULL) + { + RTN_STATUS(zFAILURE); + } + + if ((authSpace = COMN_RegisterAuthorizeSpace(&genMsg, authModel, + zFTYPE_ZAS_AUTH_SPACE, MSGNot("NetWareToNetWare"), + (AuthSpaceOps_s *)&ZASAuthorizeSpaceOps)) == NULL) + { + RTN_STATUS(zFAILURE); + } + ZASindex = authSpace->spaceIndex; + + if (ZAS_CacheInit(&genMsg) != zOK) + { + RTN_STATUS(zFAILURE); + } + + if ((authSpace = COMN_RegisterAuthorizeSpace(&genMsg, authModel, + zFTYPE_UNIX_AUTH_SPACE, MSGNot("UnixToNetWare"), + (AuthSpaceOps_s *)&UnixToNetWareAuthorizeSpaceOps)) == NULL) + { + RTN_STATUS(zFAILURE); + } + UXASindex = authSpace->spaceIndex; + + AuthorizeStarted = TRUE; + RTN_STATUS(zOK); +} + +/*************************************************************************** + * This will be called at Authorization shutdown time + ***************************************************************************/ +void ZAS_Shutdown(void) +{ + ENTER(TAUTH, ZAS_Shutdown); + ASSERT_MPKNSS_LOCK(); + ZAS_CacheUninit(); + AuthorizeStarted = FALSE; + RTN_VOID(); +} + +/*************************************************************************** + * This routine is called when an auth beast is allocated in memory + * (it may still be on disk) + ***************************************************************************/ +STATUS VAUTH_ConstructAuthBeast( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast) +{ + ZASAuthorizeInfo_s *authInfo; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_ConstructAuthBeast); + authInfo = (ZASAuthorizeInfo_s *)zalloc(sizeof(ZASAuthorizeInfo_s)); + if (authInfo == NULL) + { + SetErrno(genMsg,zERR_NO_MEMORY); + RTN_STATUS(zFAILURE); + } + + authBeast->AUTHauthInfo.zas = authInfo; + +/* authInfo->p.inheritedRightsMask = zAUTHORIZE_SUPERVISOR; *//* always allow superviser to inherit */ + authInfo->p.inheritedRightsMask = -1; /* allow all rights */ + authInfo->p.cacheIndex = INVALID_EACL_CACHE_INDEX; + authInfo->p.version = CURRENT_AUTH_VERSION; + authInfo->flags = 0; + + RTN_STATUS(zOK); +} + +/*************************************************************************** + * This routine is called when an auth beast is freed from memory + * (it may still be on disk) + ***************************************************************************/ +void VAUTH_DestructAuthBeast( + AuthBeast_s *authBeast) +{ + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_DestructAuthBeast); + free(authBeast->AUTHauthInfo.zas); + RTN_VOID(); +} + +/*************************************************************************** + * This routine is called when an auth beast is written to storage + ***************************************************************************/ +NINT VAUTH_PackedSize( + AuthBeast_s *authBeast) +{ + ZASAuthorizeInfo_s *authInfo; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_PackedSize); + authInfo = authBeast->AUTHauthInfo.zas; + if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE)) + S_LATCH(&authInfo->authLatch); + RTN_NINT(sizeof(ZASPersistentAuthInfo_s) - + (sizeof(authInfo->p.ACL) + sizeof(authInfo->p.visibilityList)) + + sizeof(ACLEntry_s) * authInfo->p.numTrusteesAssigned + + sizeof(VisEntry_s) * authInfo->p.numVisibilityTrusteesAssigned); +} + +/*************************************************************************** + * This routine is called when an auth beast is written to storage + ***************************************************************************/ +BYTE *VAUTH_PackAuthBeast( + AuthBeast_s *authBeast, + BYTE *storeBuffer) +{ + ZASAuthorizeInfo_s *authInfo; + NINT len; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_PackAuthBeast); + authInfo = authBeast->AUTHauthInfo.zas; + zASSERT((authInfo->flags & ZAS_ALLOW_FORCED_WRITE) || + (authBeast->AUTHauthInfo.zas->authLatch.count != 0)); +// now being latched in VAUTH_PackedSize +// if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE)) +// S_LATCH(&authInfo->authLatch); + len = sizeof(ZASPersistentAuthInfo_s) - + (sizeof(authInfo->p.ACL) + sizeof(authInfo->p.visibilityList)); + memcpy(storeBuffer, &authInfo->p, len); + storeBuffer += len; + len = sizeof(ACLEntry_s) * authInfo->p.numTrusteesAssigned; + memcpy(storeBuffer, &authInfo->p.ACL, len); + storeBuffer += len; + len = sizeof(VisEntry_s) * authInfo->p.numVisibilityTrusteesAssigned; + memcpy(storeBuffer, &authInfo->p.visibilityList, len); + if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE)) + UNS_LATCH(&authInfo->authLatch); + RTN_PTR(storeBuffer + len); +} + +/************************************************************************** + * This routine is called when we have done a "getPackedSize" but we can't + * do the pack do to an error. This will cleanup the latch that we + * aquired at "getPackedSize" time. + ***************************************************************************/ +void VAUTH_NoPackAuthBeastCleanup( + AuthBeast_s *authBeast) +{ + ZASAuthorizeInfo_s *authInfo; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_NoPackAuthBeastCleanup); + + authInfo = authBeast->AUTHauthInfo.zas; + if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE)) + UNS_LATCH(&authInfo->authLatch); + + RTN_VOID(); +} + +/*************************************************************************** + * This routine is called when an auth beast is read from storage + ***************************************************************************/ +BYTE *VAUTH_UnpackAuthBeast( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + BYTE *storeBuffer) +{ + ZASAuthorizeInfo_s *authInfo; + V1_ZASPersistentAuthInfo_s *oldInfo; + V1_ACLEntry_s *oldACLEntry; + V1_VisEntry_s *oldVisEntry; + NINT len; + NINT count; + STATUS status; + NINT inner; + VisEntry_s temp; + NINT convertCount; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_UnpackAuthBeast); + authInfo = authBeast->AUTHauthInfo.zas; + X_LATCH(&authInfo->authLatch); + + /* + * Perform an on-the-fly upgrade upgrade of the auth beast. In the + * future we will check the version number in the persistent auth + * info. Since we are adding it in version two we cannot check it + * this time. + */ +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check code here to ensure the new version is handled correctly." +#endif + if (authBeast->AUTHbeastVersion == BEAST_VERSION_1) + { +#if NSS_DEBUG IS_ENABLED +DBG_DebugPrintf(LMAGENTA,"On-the-fly: authorization\n"); +#endif +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still correct." +#endif + oldInfo = (V1_ZASPersistentAuthInfo_s *)storeBuffer; + authInfo->p.version = CURRENT_AUTH_VERSION; + authInfo->p.extra1 = 0; + authInfo->p.extra2 = 0; + authInfo->p.cacheIndex = oldInfo->cacheIndex; + authInfo->p.restartCount = oldInfo->restartCount; + authInfo->p.signature = oldInfo->signature; + authInfo->p.inheritedRightsMask = oldInfo->inheritedRightsMask; + authInfo->p.trusteeOverflow = oldInfo->trusteeOverflow; + authInfo->p.visibilityOverflow = oldInfo->visibilityOverflow; + authInfo->p.numTrusteesAssigned = oldInfo->numTrusteesAssigned; + authInfo->p.numVisibilityTrusteesAssigned = + oldInfo->numVisibilityTrusteesAssigned; + storeBuffer += sizeof(V1_ZASPersistentAuthInfo_s); + + if( (authInfo->p.numTrusteesAssigned > MAX_TRUSTEES_IN_BEAST) || + (authInfo->p.numVisibilityTrusteesAssigned > MAX_VISIBILITY_TRUSTEES_IN_BEAST) ) + { + storeBuffer = NULL; + SetErrno( genMsg, zERR_BEAST_CORRUPTED ); + } + else + { + /* + * If there are visibility overflow beasts that will need to + * be fixed up then set the version to a previous value. + */ + if (authInfo->p.visibilityOverflow != zINVALID_ZID) + { + authInfo->p.version = CURRENT_AUTH_VERSION - 1; + } + + /* Convert ACL entries */ + if (authInfo->p.numTrusteesAssigned > 0) + { + oldACLEntry = (V1_ACLEntry_s *)storeBuffer; + convertCount = 0; + for (count = 0; count < authInfo->p.numTrusteesAssigned; count++) + { +#if zNETWARE + /* + * If there is an error converting then the entry is ignored. + */ + if (COMN_MapNDSIDToGUID(&status, oldACLEntry->trusteeID, + &authInfo->p.ACL[convertCount].trusteeID) == zOK) + { + authInfo->p.ACL[convertCount].rights = oldACLEntry->rights; + authInfo->p.ACL[convertCount].attributes = + oldACLEntry->attributes; + convertCount++; + } + #if NSS_DEBUG IS_ENABLED + else + { + DBG_DebugPrintf(LRED, "VAUTH_UnpackAuthBeast: Ignored an invalid ACL entry\n"); + } + #endif +#endif +#if zLINUX + status = zFAILURE; + printk(KERN_ALERT "VAUTH_UnpackAuthBeast: Ignored an old-version ACL entry\n"); +#endif + oldACLEntry++; + } + authInfo->p.numTrusteesAssigned = convertCount; + storeBuffer = (BYTE *)oldACLEntry ; + } + + /* Convert Visibility entries */ + if (authInfo->p.numVisibilityTrusteesAssigned > 0) + { + oldVisEntry = (V1_VisEntry_s *)storeBuffer; + convertCount = 0; + for (count = 0; count < authInfo->p.numVisibilityTrusteesAssigned; + count++) + { +#if zNETWARE + if (COMN_MapNDSIDToGUID(&status, oldVisEntry->trusteeID, + &authInfo->p.visibilityList[convertCount].trusteeID) == zOK) + { + authInfo->p.visibilityList[convertCount].count = + oldVisEntry->count; + #if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LBLUE, + "VAUTH_UnpackAuthBeast: Valid visibility entry. ID=%x GUID=%x-%x\n", + oldVisEntry->trusteeID, + authInfo->p.visibilityList[convertCount].trusteeID.timeLow, + authInfo->p.visibilityList[convertCount].trusteeID.node[5]); + #endif + convertCount++; + } + #if NSS_DEBUG IS_ENABLED + else + { + DBG_DebugPrintf(LRED, + "VAUTH_UnpackAuthBeast: Ignored an invalid visibility entry. ID=%x\n", + oldVisEntry->trusteeID); + } + #endif +#endif +#if zLINUX + status = zFAILURE; + printk(KERN_ALERT "VAUTH_UnpackAuthBeast: Ignored an old-version visibility entry\n"); +#endif + oldVisEntry++; + } + authInfo->p.numVisibilityTrusteesAssigned = convertCount; + storeBuffer = (BYTE *)oldVisEntry ; + + /* Sort the entries */ + for (count = 1; count < authInfo->p.numVisibilityTrusteesAssigned; + count++) + { + for (inner = 0; + inner < authInfo->p.numVisibilityTrusteesAssigned - count; inner++) + { + if (LB_GUIDCompare(&authInfo->p.visibilityList[inner].trusteeID, + &authInfo->p.visibilityList[inner + 1].trusteeID) > 0) + { + temp = authInfo->p.visibilityList[inner]; + authInfo->p.visibilityList[inner] = + authInfo->p.visibilityList[inner + 1]; + authInfo->p.visibilityList[inner + 1] = temp; + } + } + } + } + } + } + else + { + len = sizeof(ZASPersistentAuthInfo_s) - + (sizeof(authInfo->p.ACL) + sizeof(authInfo->p.visibilityList)); + memcpy(&authInfo->p, storeBuffer, len); + storeBuffer += len; + /* Bug#377670 - Need to place the data into authInfo->p before testing + that it has legal values. Before counts would be 0 always so we + did not catch corrupt beasts and then would corrupt lots of memory. */ + if( (authInfo->p.numTrusteesAssigned > MAX_TRUSTEES_IN_BEAST) || + (authInfo->p.numVisibilityTrusteesAssigned > MAX_VISIBILITY_TRUSTEES_IN_BEAST) ) + { + storeBuffer = NULL; + SetErrno( genMsg, zERR_BEAST_CORRUPTED ); + } + else + { + len = sizeof(ACLEntry_s) * authInfo->p.numTrusteesAssigned; + memcpy(&authInfo->p.ACL, storeBuffer, len); + storeBuffer += len; + len = sizeof(ACLEntry_s) * authInfo->p.numVisibilityTrusteesAssigned; + memcpy(&authInfo->p.visibilityList, storeBuffer, len); + storeBuffer += len; + } + + /* The following lines are for the cluster file system read only vol */ + if ((authBeast->AUTHvolume->VOLenabledAttributes & zATTR_READONLY) && + (!(genMsg->flags & UPDATE_EXISTING_BEAST))) + { + authInfo->p.signature = 0; + authInfo->p.restartCount = 0; + authInfo->p.cacheIndex = INVALID_EACL_CACHE_INDEX; + } + } + UNX_LATCH(&authInfo->authLatch); + RTN_PTR(storeBuffer); +} + +///**************************************************************************** +// * findVisTrustee +// * Use a binary search to find a visibility trustee in an overflow beast. +// * Returns the index into the overflow beast. If the entry is not found +// * it returns the next higher value (the place to insert it); +// ****************************************************************************/ +//NINT findVisTrustee( +// ZasVisOverflowBeast_s *overflowBeast; +// NINT trusteeID) +//{ +// LONG midID; +// NINT start; +// NINT end; +// NINT mid; +// +// start = 0; +// end = overflowBeast->p.numEntries; +// do +// { +// mid = (start + end) / 2; +// midID = overflowBeast->vis[mid].trusteeID; +// if(trusteeID <= midID) +// { +// if (trusteeID == midID) +// return mid; +// end = mid; +// } +// else +// { +// start = mid + 1; +// } +// } while(start < end); +// +// return end; /* not found */ +//} + + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the conversion code below is still needed. It was" +#error "used to convert beast version 1 to beast version 2." +#endif +/**************************************************************************** + * + * This routine converts an ACL overflow beast from beast version 1 to + * beast version 2. It is done here instead of the unpack routine because + * one beast may create many. The unpack routine has already converted the + * IDs to GUIDs. + * + ****************************************************************************/ +STATUS ZAS_ConvertACLFromVersionOne ( + GeneralMsg_s *genMsg, + ZasAclOverflowBeast_s *overflowBeast) +{ + NINT numToMove; + ZasAclOverflowBeast_s *newOverflowBeast; + STATUS status; + Xaction_s *xaction; + BOOL needToDownLatch = FALSE; + + if (overflowBeast->ACLObeastVersion > BEAST_VERSION_1) + { + zASSERT(overflowBeast->p.numEntries <= MAX_ACL_OVERFLOW_ENTRIES); + return zOK; + } + + /* + * This is an older beast that could hold more entries. It + * will now be split up into multiple beasts if it is too big + * for the current version. This code can be removed when we + * are no longer converting from version 1 beasts. + */ + ASSERT_LATCH(&overflowBeast->ACLObeastLatch); + if (!IS_XLATCHED(&overflowBeast->ACLObeastLatch)) + { + UP_LATCH(&overflowBeast->ACLObeastLatch); + if (overflowBeast->p.numEntries <= MAX_ACL_OVERFLOW_ENTRIES) + { /* We now don't need to convert -- it was done by someone else while we were uplatching */ + DOWN_LATCH(&overflowBeast->ACLObeastLatch); + return zOK; + } + needToDownLatch = TRUE; + } + +#if NSS_DEBUG IS_ENABLED +DBG_DebugPrintf(LBLUE,"After on-the-fly: ACL overflow\n"); +#endif + xaction = COMN_BeginXLocal(overflowBeast); + /* Create new beasts to handle the excess */ + while (overflowBeast->p.numEntries > MAX_ACL_OVERFLOW_ENTRIES) + { + newOverflowBeast = (ZasAclOverflowBeast_s *)BST_create(genMsg, + zFTYPE_ZAS_ACL_OVERFLOW, overflowBeast->ACLOvolume, xaction); + if (overflowBeast == NULL) + { + goto cleanup; + } + + numToMove = overflowBeast->p.numEntries % MAX_ACL_OVERFLOW_ENTRIES; + if (numToMove == 0) + { + numToMove = MAX_ACL_OVERFLOW_ENTRIES; + } + newOverflowBeast->numAlloced = numToMove; + /* free the memory alloced by the BST_create */ + free(newOverflowBeast->acl); + newOverflowBeast->acl = + malloc(newOverflowBeast->numAlloced * sizeof (ACLEntry_s)); + if (newOverflowBeast->acl == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + UNX_LATCH(&newOverflowBeast->ACLObeastLatch); + BST_free(newOverflowBeast); + goto cleanup; + } + overflowBeast->p.numEntries -= numToMove; + /* insert entries in the new beast */ + memcpy(newOverflowBeast->acl, + &overflowBeast->acl[overflowBeast->p.numEntries], + sizeof(ACLEntry_s) * numToMove); + + newOverflowBeast->ACLObstState |= BST_STATE_NEW; + newOverflowBeast->p.numEntries = numToMove; + + /* fix up the links */ + newOverflowBeast->p.nextOverflowZid = + overflowBeast->p.nextOverflowZid; + overflowBeast->p.nextOverflowZid = newOverflowBeast->ACLOzid; + + /* write out the new beast */ + COMN_MARK_BEAST_XLOCAL(&newOverflowBeast->ACLOroot, xaction); + status = COMN_ForceBeastWrite(genMsg, newOverflowBeast, xaction); + BEASTHASH_Insert(&newOverflowBeast->ACLOroot); + COMN_UnlatchAndRelease(&newOverflowBeast, XLATCHED); + if (status != zOK) + { + goto cleanup; + } + } + /* update the original beast */ + COMN_MARK_BEAST_XLOCAL(&overflowBeast->ACLOroot, xaction); + status = COMN_ForceBeastWrite(genMsg, overflowBeast, xaction); + if (status != zOK) + { + goto cleanup; + } + COMN_EndXLocal(overflowBeast, &xaction); + if (needToDownLatch) + { + DOWN_LATCH(&overflowBeast->ACLObeastLatch); + } + return zOK; + +cleanup: + COMN_EndXLocal(overflowBeast, &xaction); + if (needToDownLatch) + { + DOWN_LATCH(&overflowBeast->ACLObeastLatch); + } + return zFAILURE; +} + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the conversion code below is still needed. It was" +#error "used to convert beast version 1 to beast version 2." +#endif +/**************************************************************************** + * + * This routine converts all VIS overflow beasts on this auth beast + * from beast version 1 to beast version 2. It is done here instead of the + * unpack routine because one beast may create many. The unpack routine has + * already converted the IDs to GUIDs. + * + * The routine reads in all of visibility entries from the old beasts, sorts + * them and them writes them out again in the new format. + * + * If there is no transaction active then one is created. + * + ****************************************************************************/ +STATUS ZAS_ConvertVisFromVersionOne ( + GeneralMsg_s *genMsg, + Xaction_s *passedInXaction, + AuthBeast_s *authBeast) +{ + ZasVisOverflowBeast_s *overflowBeast = NULL; + ZasVisOverflowBeast_s *prevOverflowBeast = NULL; + ZASAuthorizeInfo_s *authInfo; + NINT numToMove; + NINT numMoved = 0; + NINT count; + NINT inner; + VisEntry_s *holdVis = NULL; + NINT totalEntries; + Xaction_s *xaction; + BOOL needToDownLatch = FALSE; + BOOL downAuthBeastLatch = FALSE; + Zid_t overflowZid; + VisEntry_s temp; + STATUS status; + BOOL clearForceFlag = FALSE; + + + authInfo = authBeast->AUTHauthInfo.zas; + if (authInfo->p.version == CURRENT_AUTH_VERSION) + { + return zOK; + } + if (!(IS_LATCHED(&authBeast->AUTHbeastLatch))) + { + /*Cannot convert visibility if we don't have a latch */ + /* Do not know if we can get a latch without deadlocking if we + * come in here without a latch + */ + return zFAILURE; + } + ASSERT_LATCH(&authBeast->AUTHbeastLatch); + ASSERT_LATCH(&authInfo->authLatch); + +#if NSS_DEBUG IS_ENABLED +DBG_DebugPrintf(LBLUE,"After on-the-fly: visibility overflow\n"); +#endif + + if (IS_XLATCHED(&authBeast->AUTHbeastLatch)) + { + if (!IS_XLATCHED(&authInfo->authLatch)) + { + UP_LATCH(&authInfo->authLatch); + needToDownLatch = TRUE; + } + } + else + { + if (IS_XLATCHED(&authInfo->authLatch)) + { + UNX_LATCH(&authInfo->authLatch); + } + else + { + UNS_LATCH(&authInfo->authLatch); + needToDownLatch = TRUE; + } + UP_LATCH(&authBeast->AUTHbeastLatch); + downAuthBeastLatch = TRUE; + X_LATCH(&authInfo->authLatch); + } + + if (authInfo->p.version == CURRENT_AUTH_VERSION) + { + /* We now don't need to convert -- it was done by someone else + * while we were uplatching */ + status = zOK; + goto fixupLatchesAndReturnStatus; + } + + ASSERT_XLATCH(&authBeast->AUTHbeastLatch); + ASSERT_XLATCH(&authInfo->authLatch); + + if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE)) + { + authInfo->flags |= ZAS_ALLOW_FORCED_WRITE; + clearForceFlag = TRUE; + } + + /**************************************** + * Count the entries + ****************************************/ + + totalEntries = authInfo->p.numVisibilityTrusteesAssigned; + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + /* get the next overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + goto cleanup; + } + + totalEntries += overflowBeast->p.numEntries; + + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + /* Get the needed memory block */ + if (totalEntries != 0) + { + holdVis = malloc(totalEntries * sizeof (VisEntry_s)); + if (holdVis == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + goto cleanup; + } + } + + /**************************************** + * Read all of the entries into memory + ****************************************/ + + /* read the entries from the main beast */ + for (numToMove = 0; numToMove < authInfo->p.numVisibilityTrusteesAssigned; + numToMove++) + { + if (LB_GUIDCompare(&authInfo->p.visibilityList[numToMove].trusteeID, + &zINVALID_USERID) != 0) + { + holdVis[numMoved++] = authInfo->p.visibilityList[numToMove]; + } +#if NSS_DEBUG IS_ENABLED + else + { + DBG_DebugPrintf(LRED, "ZAS_ConvertVisFromVersionOne: Ignored an invalid visibility entry\n"); + } +#endif + } + + /* read the entries from the overflow beasts */ + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + /* get the next overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + goto cleanupFree; + } + + for (numToMove = 0; numToMove < overflowBeast->p.numEntries; + numToMove++) + { + if (LB_GUIDCompare(&overflowBeast->vis[numToMove].trusteeID, + &zINVALID_USERID) != 0) + { + holdVis[numMoved++] = overflowBeast->vis[numToMove]; + } +#if NSS_DEBUG IS_ENABLED + else + { + DBG_DebugPrintf(LRED, "ZAS_ConvertVisFromVersionOne: Ignored an invalid overflow visibility entry\n"); + } +#endif + } + + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + totalEntries = numMoved; + + /**************************************** + * Sort the entries + ****************************************/ + + for (count = 1; count < totalEntries; count++) + { + for (inner = 0; + inner < totalEntries - count; inner++) + { + if (LB_GUIDCompare(&holdVis[inner].trusteeID, + &holdVis[inner + 1].trusteeID) > 0) + { + temp = holdVis[inner]; + holdVis[inner] = holdVis[inner + 1]; + holdVis[inner + 1] = temp; + } + } + } + +//#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, "Convert visibility structure after sorting:\n"); +// for (count=0; count < totalEntries; count++) +// { +// DBG_DebugPrintf(LBLUE, MSGNot(" (%d) Trustee: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x Count: %d\n"), +// count, +// holdVis[count].trusteeID.timeLow, +// holdVis[count].trusteeID.timeMid, +// holdVis[count].trusteeID.timeHighAndVersion, +// holdVis[count].trusteeID.clockSeqHighAndReserved, +// holdVis[count].trusteeID.clockSeqLow, +// holdVis[count].trusteeID.node[0], +// holdVis[count].trusteeID.node[1], +// holdVis[count].trusteeID.node[2], +// holdVis[count].trusteeID.node[3], +// holdVis[count].trusteeID.node[4], +// holdVis[count].trusteeID.node[5], +// holdVis[count].count); +// } +//#endif + /**************************************** + * Write out the new overflow beasts + ****************************************/ + + xaction = (passedInXaction == NULL) ? COMN_BeginXLocal(authBeast) : + passedInXaction; + + numMoved = 0; + + /* fill up the main beast */ + authInfo->p.numVisibilityTrusteesAssigned = + totalEntries > MAX_VISIBILITY_TRUSTEES_IN_BEAST ? + MAX_VISIBILITY_TRUSTEES_IN_BEAST : + totalEntries; + + for (numToMove = 0; numToMove < authInfo->p.numVisibilityTrusteesAssigned; + numToMove++) + { + authInfo->p.visibilityList[numToMove] = holdVis[numMoved++]; + } + + /* Remove the old beasts */ + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + /* get the next overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + goto cleanupXaction; + } + + overflowZid = overflowBeast->p.nextOverflowZid; + if (BST_delete(genMsg, NULL, overflowBeast, NULL, NULL, xaction, + FALSE, TRUE) != zOK) + { + zASSERT("Failed to remove old beasts during conversion" == 0); + } + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + authInfo->p.visibilityOverflow = zINVALID_ZID; + + /* create the new beasts */ + while (numMoved < totalEntries) + { + overflowBeast = (ZasVisOverflowBeast_s *)BST_create(genMsg, + zFTYPE_ZAS_VIS_OVERFLOW, authBeast->AUTHvolume, xaction); + if (overflowBeast == NULL) + { + goto cleanupXaction; + } + + numToMove = ((totalEntries - numMoved) >= MAX_VIS_OVERFLOW_ENTRIES) ? + MAX_VIS_OVERFLOW_ENTRIES : totalEntries - numMoved; + + overflowBeast->numAlloced = numToMove; + free(overflowBeast->vis); /* this was alloced by the constructor */ + overflowBeast->vis = + malloc(overflowBeast->numAlloced * sizeof (VisEntry_s)); + if (overflowBeast->vis == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + UNX_LATCH(&overflowBeast->VISObeastLatch); + BST_free(overflowBeast); + goto cleanupXaction; + } + /* insert entries in the new beast */ + memcpy(overflowBeast->vis, &holdVis[numMoved], + sizeof(VisEntry_s) * numToMove); + + numMoved += numToMove; + + overflowBeast->VISObstState |= BST_STATE_NEW; + overflowBeast->p.numEntries = numToMove; + + /* fix up the links */ + overflowBeast->p.nextOverflowZid = zINVALID_ZID; + if (prevOverflowBeast == NULL) + { /* link to the main beast */ + authInfo->p.visibilityOverflow = overflowBeast->VISOzid; + } + else + { + prevOverflowBeast->p.nextOverflowZid = overflowBeast->VISOzid; + /* write out the previous beast */ + + BEASTHASH_Insert(&prevOverflowBeast->VISOroot); + COMN_MARK_BEAST_XLOCAL(&prevOverflowBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, prevOverflowBeast, xaction); + zASSERT(prevOverflowBeast->VISOuseCount > 1); + COMN_UnlatchAndRelease(&prevOverflowBeast, XLATCHED); + } + + prevOverflowBeast = overflowBeast; + } + + /* write out the final beast if we need to */ + if (prevOverflowBeast != NULL) + { + BEASTHASH_Insert(&prevOverflowBeast->VISOroot); + COMN_MARK_BEAST_XLOCAL(&prevOverflowBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, prevOverflowBeast, xaction); + zASSERT(prevOverflowBeast->VISOuseCount > 1); + COMN_UnlatchAndRelease(&prevOverflowBeast, XLATCHED); + } + + /* write out the main beast */ + authInfo->p.version = CURRENT_AUTH_VERSION; + + COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction); + COMN_ForceBeastWrite(genMsg, authBeast, xaction); + + /* If the transaction was started in this routine then end it */ + if (passedInXaction == NULL) + { + COMN_EndXLocal(authBeast, &xaction); + } + + if (holdVis != NULL) + { + free(holdVis); + } + status = zOK; + +fixupLatchesAndReturnStatus: + if (clearForceFlag) + { + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + } + if (downAuthBeastLatch) + { + UNX_LATCH(&authInfo->authLatch); + DOWN_LATCH(&authBeast->AUTHbeastLatch); + if (needToDownLatch) + { + S_LATCH(&authInfo->authLatch); + } + else + { + X_LATCH(&authInfo->authLatch); + } + } + else + { + if (needToDownLatch) + { + DOWN_LATCH(&authInfo->authLatch); + } + } + return status; + + +cleanupXaction: + /* If the transaction was started in this routine then end it */ + if (passedInXaction == NULL) + { + COMN_EndXLocal(authBeast, &xaction); + } +cleanupFree: + if (holdVis != NULL) + { + free(holdVis); + } +cleanup: + status = zFAILURE; + goto fixupLatchesAndReturnStatus; + +} + + +/**************************************************************************** + * This routine will find a trustee and return a pointer to the visibility + * info. + * + * output: returnBeast - The beast where the entry is found or where it + * should be inserted. Returned opened and latched. If it is + * null then there are no overflow beasts OR we got an error + * on lookup of an overflow beast! + * + * entryPtr - A pointer to the found entry. If the trustee is not + * found then then a null is returned. + * + * entry - The index into either the authInfo in the main beast or + * the visibility info in the overflow beast. + * If an entry is found then it points to the entry, or it points + * to the location where a new entry should be inserted. The + * insertion point is the place to insert and not a free 'slot'. + * IDs are kept in order so everything must be memmoved and etc. + * + * parentZid - the zid of the parent beast. If invalid then the + * parent was the main beast. + * + ****************************************************************************/ +STATUS ZAS_FindVisibilityTrustee( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the xaction below is still needed." +#endif + Xaction_s *xaction, + UserID_t *trusteeID, + NINT latchType, + VisEntry_s **entryPtr, + NINT *entry, + ZasVisOverflowBeast_s **returnBeast, + Zid_t *parentZid) +{ + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *overflowBeast; + ZasVisOverflowBeast_s *prevOverflowBeast = NULL; + Zid_t overflowZid; + UserID_t midID; + NINT start; + NINT end; + NINT mid; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_FindVisibilityTrustee); + authInfo = authBeast->AUTHauthInfo.zas; + ASSERT_LATCH(&authInfo->authLatch); + *returnBeast = NULL; + *parentZid = zINVALID_ZID; + *entryPtr = NULL; + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertVisFromVersionOne(genMsg, xaction, authBeast) != zOK) + { + RTN_STATUS(zFAILURE); + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + /* search the main beast for the visibility trustee */ + for (*entry=0; *entry < authInfo->p.numVisibilityTrusteesAssigned; + (*entry)++) + { + if (LB_GUIDCompare(&authInfo->p.visibilityList[*entry].trusteeID, + trusteeID) > 0) + { + *entryPtr = NULL; + RTN_STATUS(zOK); + } + if (LB_GUIDCompare(&authInfo->p.visibilityList[*entry].trusteeID, + trusteeID) == 0) + { + *entryPtr = &authInfo->p.visibilityList[*entry]; + RTN_STATUS(zOK); + } + } + + overflowBeast = NULL; + + /* search the overflow beasts for the visibility trustee */ + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { /* find an overflow beast with an open entry */ + + /* get the next overflow beast */ + prevOverflowBeast = overflowBeast; + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, latchType, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* + * Error -- fix up the beast so it looks like it did not have + * another overflow (simple self-healing). + */ + zASSERT("Error looking up visibility overflow beast" == NULL); + *returnBeast = prevOverflowBeast; + if (prevOverflowBeast) + { + prevOverflowBeast->p.nextOverflowZid = zINVALID_ZID; + } + else + { + authInfo->p.visibilityOverflow = zINVALID_ZID; + } + *entryPtr = NULL; + RTN_STATUS(zOK); + } + if (prevOverflowBeast != NULL) + { + COMN_UnlatchAndRelease(&prevOverflowBeast, latchType); + } + + *entry = end = overflowBeast->p.numEntries; + if ( end == 0 ) + { /* not found -- return the insertion point */ +/* *entry = end; Already set */ + *returnBeast = overflowBeast; + *entryPtr = NULL; /* not found */ + RTN_STATUS(zOK); + } + if (LB_GUIDCompare(trusteeID, &overflowBeast->vis[end-1].trusteeID) <= 0) + { /* it should fall in this record */ + /* use a binary search to find the entry */ + start = 0; + do + { + mid = (start + end) / 2; + midID = overflowBeast->vis[mid].trusteeID; + if(LB_GUIDCompare(trusteeID, &midID) <= 0) + { + if (LB_GUIDCompare(trusteeID, &midID) == 0) + { /* found the trustee entry */ + *returnBeast = overflowBeast; + *entry = mid; + *entryPtr = &overflowBeast->vis[mid]; + RTN_STATUS(zOK); + } + end = mid; + } + else + { + start = mid + 1; + } + } while(start < end); + + /* not found -- return the insertion point */ + *entry = end; + *returnBeast = overflowBeast; + *entryPtr = NULL; /* not found */ + RTN_STATUS(zOK); + } + + *parentZid = overflowZid; + overflowZid = overflowBeast->p.nextOverflowZid; + zASSERT((overflowZid == zINVALID_ZID) || + (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES)); + } + *returnBeast = overflowBeast; + *entryPtr = NULL; + RTN_STATUS(zOK); +} + +/**************************************************************************** + * This routines will get the visibility entries for a single auth Beast. + * + * Parameter: + * genMsg + * authBeast The beast we will search for visibility + * maxEntries The maximum number of entries that can be returned + * visEntries A buffer that will be filled in this routine + * numReturned The number of + ****************************************************************************/ +STATUS ZAS_GetVisibilityEntries( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, /* The beast we will search for visibility */ + NINT maxEntries, /* The maximum number of entries that can be returned */ + VisEntry_s *visEntries, /* A buffer that will be filled in this routine */ + NINT *numReturned) /* The number of entries being returned. + If there are more entries than space + in the buffer the return count will be + -1, and the buffer will be filled */ +{ + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + NINT count; + + ENTER(TAUTH, ZAS_GetVisibilityEntries); + authInfo = authBeast->AUTHauthInfo.zas; + S_LATCH(&authInfo->authLatch); + + + /* search the main beast for the visibility trustee */ + for (*numReturned = 0; + *numReturned < authInfo->p.numVisibilityTrusteesAssigned; + (*numReturned)++) + { + if (*numReturned >= maxEntries) + { + *numReturned = -1; + goto finished; + } + visEntries[*numReturned] = authInfo->p.visibilityList[*numReturned]; + } + + /* search the overflow beasts for the visibility trustee */ + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + /* get the next overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + UNS_LATCH(&authInfo->authLatch); + RTN_STATUS(zFAILURE); + } + + for (count = 0; count < overflowBeast->p.numEntries; count++) + { + if (*numReturned >= maxEntries) + { + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + *numReturned = -1; + goto finished; + } + visEntries[(*numReturned)++] = overflowBeast->vis[count]; + } + + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } +finished: + UNS_LATCH(&authInfo->authLatch); + RTN_STATUS(zOK); +} + + +/**************************************************************************** + * This routine will add visibility rights up the tree for an object. + * + ****************************************************************************/ +AuthBeast_s *ZAS_InternalMakeItVisible( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Volume_s *volume, + UserID_t *trusteeIDList, + NINT *trusteeCount, + FixVisibPLog_s *pLogLocPtrList) +{ + Zid_t overflowZid = zINVALID_ZID; + Zid_t dummyZid; + ZASAuthorizeInfo_s *authInfo; + Zid_t parentZID = authBeast->AUTHzid; + AuthBeast_s *pBeast; + VisEntry_s *visEntry; + VisEntry_s holdEntry; + VisEntry_s tempEntry; + ZasVisOverflowBeast_s *overflowBeast; + ZasVisOverflowBeast_s *parentBeast; + NINT entryIndex; + BOOL writeMainBeast = FALSE; + Xaction_s *xaction; + PurgeLogMsg_s purgeLogMsg; + UserID_t *trusteeID = trusteeIDList; + FixVisibPLog_s *pLogLocPtr = pLogLocPtrList; + NINT i; + + ASSERT_MPKNSS_LOCK(); + + authInfo = authBeast->AUTHauthInfo.zas; + + X_LATCH(&authInfo->authLatch); + authInfo->flags |= ZAS_ALLOW_FORCED_WRITE; + +//#if NSS_DEBUG IS_ENABLED +//DBG_DebugPrintf(GREEN, MSGNot("\nEntering Insert Visibility -- Trustee: %x"), *trusteeID); +//DEBUG_Display_Visibility(authBeast); +//#endif + + /** NOTE: It is ok to do a forcebeastwrite on the overflow beast, and + ** unlatch the beast before the transaction ends, because + ** we have a latch on the auth beast until after the xaction + ** ends, and no one can get the overflow beast without first + ** getting a latch on the auth beast. + **/ + + for (i = 0; i < *trusteeCount; ) + { + xaction = COMN_BeginXLocal(authBeast); + + zASSERT(pLogLocPtr != NULL); + + SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, pLogLocPtr, + VIS_ACTION_ADD, parentZID, trusteeID); + if (authBeast->AUTHcomnVolOps.VOL_removePurgeLogEntry( + genMsg, authBeast->AUTHvolume, + PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction) != zOK) + { + goto errorTryNextTrustee; + } + + holdEntry.trusteeID = zINVALID_USERID; + if (ZAS_FindVisibilityTrustee(genMsg, authBeast, xaction, trusteeID, + XLATCHED, &visEntry, &entryIndex, + &overflowBeast, &dummyZid) != zOK) + { + /* error */ + goto errorTryNextTrustee; + } + if (visEntry != NULL) + { /* if it is found */ + visEntry->count++; + if (overflowBeast == NULL) + { /* in the main beast */ + COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction); + COMN_ForceBeastWrite(genMsg, authBeast, xaction); + } + else + { /* in an overflow beast */ + COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, overflowBeast, xaction); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + +//#if NSS_DEBUG IS_ENABLED +//DBG_DebugPrintf(GREEN, MSGNot("\n(1)Exiting Insert Visibility -- Trustee: %x"), *trusteeID); +//DEBUG_Display_Visibility(authBeast); +//#endif + goto visibilityDoneForThisTrustee; + } + else + { /* add a new entry */ + if (overflowBeast == NULL) + { /* the new entry should go in the main beast */ + zASSERT(authInfo->p.numVisibilityTrusteesAssigned <= + MAX_VISIBILITY_TRUSTEES_IN_BEAST); + zASSERT(entryIndex <= authInfo->p.numVisibilityTrusteesAssigned); + if (authInfo->p.numVisibilityTrusteesAssigned == + MAX_VISIBILITY_TRUSTEES_IN_BEAST) + { /* the main beast is full */ + overflowZid = authInfo->p.visibilityOverflow; + if (entryIndex == MAX_VISIBILITY_TRUSTEES_IN_BEAST) + { /* the new entry should go in the overflow */ + holdEntry.trusteeID = *trusteeID; + holdEntry.count = 1; + } + else + { /* the new entry goes in the main beast */ + /* save the last entry to move it to the next beast */ + holdEntry = authInfo->p.visibilityList[ + MAX_VISIBILITY_TRUSTEES_IN_BEAST - 1]; + memmove(&authInfo->p.visibilityList[entryIndex + 1], + &authInfo->p.visibilityList[entryIndex], + ((MAX_VISIBILITY_TRUSTEES_IN_BEAST - 1) - + entryIndex) * sizeof(VisEntry_s)); + authInfo->p.visibilityList[entryIndex].trusteeID = + *trusteeID; + authInfo->p.visibilityList[entryIndex].count = 1; + writeMainBeast = TRUE; + } + /* insert holdEntry at the front of the overflow beast */ + entryIndex = 0; + /* open the overflow beast if needed */ + if (overflowZid != zINVALID_ZID) + { + overflowBeast = ZAS_LookupOverflowBeast(genMsg, + authBeast->AUTHvolume, overflowZid, + XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + goto errorTryNextTrustee; + } + } + } + else + { + zASSERT(overflowZid == zINVALID_ZID); + memmove(&authInfo->p.visibilityList[entryIndex+1], + &authInfo->p.visibilityList[entryIndex], + (authInfo->p.numVisibilityTrusteesAssigned - entryIndex) + * sizeof(VisEntry_s)); + authInfo->p.numVisibilityTrusteesAssigned++; + authInfo->p.visibilityList[entryIndex].trusteeID = + *trusteeID; + authInfo->p.visibilityList[entryIndex].count = 1; + writeMainBeast = TRUE; + } + } + else + { /* adding an entry to the overflow beast */ + overflowZid = overflowBeast->VISOzid; + holdEntry.trusteeID = *trusteeID; + holdEntry.count = 1; + } + + /* + * Insert into an overflow beast. + * + * If an insert to a full overflow beast has occured then shift + * all entries in beasts that follow up one slot. + */ + + while (overflowZid != zINVALID_ZID) + { /* while there are still overflow beasts */ + zASSERT(overflowBeast->p.numEntries <= MAX_VIS_OVERFLOW_ENTRIES); + zASSERT(entryIndex <= overflowBeast->p.numEntries); + overflowZid = overflowBeast->p.nextOverflowZid; + if (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES) + { /* if the beast is full */ + if (entryIndex < MAX_VIS_OVERFLOW_ENTRIES) + { /* entry goes in this beast */ + tempEntry = overflowBeast->vis[MAX_VIS_OVERFLOW_ENTRIES + - 1]; + memmove(&overflowBeast->vis[entryIndex + 1], + &overflowBeast->vis[entryIndex], + ((MAX_VIS_OVERFLOW_ENTRIES - 1) - entryIndex) * + sizeof(VisEntry_s)); + overflowBeast->vis[entryIndex].trusteeID = + holdEntry.trusteeID; + overflowBeast->vis[entryIndex].count = holdEntry.count; + holdEntry = tempEntry; + } + else + { /* entry will go in a new overflow beast */ + zASSERT(overflowZid == zINVALID_ZID); + } + } + else + { /* there is still room in the beast */ + VisEntry_s *vis; + zASSERT(overflowZid == zINVALID_ZID); + if (overflowBeast->p.numEntries >= + overflowBeast->numAlloced) + { /* we need to make the memory structure bigger */ + overflowBeast->numAlloced += OVERFLOW_ALLOC_UNIT; + vis = (VisEntry_s *)realloc(overflowBeast->vis, + overflowBeast->numAlloced * sizeof (VisEntry_s)); + if (vis == NULL) + { + overflowBeast->numAlloced -= OVERFLOW_ALLOC_UNIT; + SetErrno(genMsg, zERR_NO_MEMORY); + goto errorTryNextTrustee; + } + overflowBeast->vis = vis; + } + memmove(&overflowBeast->vis[entryIndex+1], + &overflowBeast->vis[entryIndex], + (overflowBeast->p.numEntries -entryIndex) * + sizeof(VisEntry_s)); + overflowBeast->p.numEntries++; + overflowBeast->vis[entryIndex].trusteeID = + holdEntry.trusteeID; + overflowBeast->vis[entryIndex].count = holdEntry.count; + holdEntry.trusteeID = zINVALID_USERID; + } + + /* always insert at the front after the first insert */ + entryIndex = 0; + + if (overflowZid != zINVALID_ZID) + { + COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, overflowBeast, xaction); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + + overflowBeast = ZAS_LookupOverflowBeast(genMsg, + authBeast->AUTHvolume, overflowZid, XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + goto errorTryNextTrustee; + } + } + } + + /* Create a new beast if needed */ + if (LB_GUIDCompare(&holdEntry.trusteeID, &zINVALID_USERID) != 0) + { + parentBeast = overflowBeast; + overflowBeast = (ZasVisOverflowBeast_s *)BST_create(genMsg, + zFTYPE_ZAS_VIS_OVERFLOW, authBeast->AUTHvolume, xaction); + if (overflowBeast == NULL) + { + if (parentBeast != NULL) + { + COMN_UnlatchAndRelease(&parentBeast, XLATCHED); + } + goto errorTryNextTrustee; + } + + /* link the new beast to the ones already there */ + if (parentBeast == NULL) + { /* link to main beast */ + authInfo->p.visibilityOverflow = overflowBeast->VISOzid; + writeMainBeast = TRUE; + } + else + { /* link to another overflow beast */ + parentBeast->p.nextOverflowZid = overflowBeast->VISOzid; + COMN_MARK_BEAST_XLOCAL(&parentBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, parentBeast, xaction); + COMN_UnlatchAndRelease(&parentBeast, XLATCHED); + } + BEASTHASH_Insert(&overflowBeast->VISOroot); + overflowBeast->VISObstState |= BST_STATE_NEW; + overflowBeast->p.numEntries = 1; + overflowBeast->vis[0] = holdEntry; + } + if (overflowBeast != NULL) + { + COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, overflowBeast, xaction); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + } + if (writeMainBeast) + { /* if the main beast is dirty */ + COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction); + COMN_ForceBeastWrite(genMsg, authBeast, xaction); + writeMainBeast = FALSE; + } + +//#if NSS_DEBUG IS_ENABLED +//DBG_DebugPrintf(GREEN, MSGNot("\n(2)Exiting Insert Visibility -- Trustee: %x"), *trusteeID); +//DEBUG_Display_Visibility(authBeast); +//#endif + + if (authBeast->AUTHzid != zROOTDIR_ZID) + { + SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, pLogLocPtr, + VIS_ACTION_ADD, authBeast->AUTHfirstParentZid, trusteeID); + if (authBeast->AUTHcomnVolOps.VOL_addPurgeLogEntry( + genMsg, authBeast->AUTHvolume, + PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction) != zOK) + { + goto errorTryNextTrustee; + } + } + trusteeID++; + pLogLocPtr++; + i++; + COMN_EndXLocal(authBeast, &xaction); + continue; + +errorTryNextTrustee: + errPrintf(WHERE, Module, 713, + MSG("Error adding visibility for a trustee.\n", 1193)); +visibilityDoneForThisTrustee: + (*trusteeCount)--; + *trusteeID = trusteeIDList[*trusteeCount]; + *pLogLocPtr = pLogLocPtrList[*trusteeCount]; + COMN_EndXLocal(authBeast, &xaction); + continue; + } + + xaction = COMN_BeginXLocal(authBeast); + VOL_insertEFLEntry(genMsg, &authBeast->AUTHroot, + EFL_FILE_STATE_MODIFY_METADATA, NULL, xaction); + COMN_EndXLocal(authBeast, &xaction); + + if ((authBeast->AUTHzid == zROOTDIR_ZID) || (*trusteeCount == 0)) + { + goto doneFixingVisibility; + } + parentZID = authBeast->AUTHfirstParentZid; + + /* We do not want a yield between the UNX_LATCH of authBeast and + * X_LATCH request of the parent Beast below. Hence we look + * up the parent beast first in unlatched mode and then later + * request a latch on it + * + * This routine's calling function has to guarantee that when we + * return from here, the first thing we do is request a latch + * on the returned pBeast, without any yields in between + */ + pBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, volume, + parentZID, NOTLATCHED); + if (pBeast == NULL) + { /* error */ + SetErrno(genMsg, zERR_UNABLE_TO_OPEN_BEAST); + goto errorCleanup; + } + + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + UNX_LATCH(&authInfo->authLatch); + UNX_LATCH(&authBeast->AUTHbeastLatch); + + return pBeast; + + +errorCleanup: + errPrintf(WHERE, Module, 713, + MSG("Error adding visibility for trustees just added\n", 986)); + +doneFixingVisibility: + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + UNX_LATCH(&authInfo->authLatch); + COMN_UnlatchAndRelease(&authBeast, XLATCHED); + + return NULL; +} + + +/**************************************************************************** + * + * This routine will setup to remove visibility up the tree + * + ***************************************************************************/ +AuthBeast_s *ZAS_InternalRemoveVisibility( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Volume_s *volume, + UserID_t *trusteeIDList, + NINT *trusteeCount, + FixVisibPLog_s *pLogLocPtrList) +{ + Zid_t parentZID = authBeast->AUTHzid; + Zid_t overflowZid; + Zid_t overflowParentZid; + ZASAuthorizeInfo_s *authInfo; + VisEntry_s *VisEntry; + ZasVisOverflowBeast_s *overflowBeast; + ZasVisOverflowBeast_s *parentBeast; + NINT entryIndex; + BOOL writeMainBeast = FALSE; + Xaction_s *xaction; + PurgeLogMsg_s purgeLogMsg; + AuthBeast_s *pBeast; + UserID_t *trusteeID = trusteeIDList; + FixVisibPLog_s *pLogLocPtr = pLogLocPtrList; + NINT i; + + ASSERT_MPKNSS_LOCK(); + + authInfo = authBeast->AUTHauthInfo.zas; + X_LATCH(&authInfo->authLatch); + authInfo->flags |= ZAS_ALLOW_FORCED_WRITE; + +//#if NSS_DEBUG IS_ENABLED +//DBG_DebugPrintf(GREEN, MSGNot("\nEntering Remove Visibility -- Trustee: %x"), *trusteeID); +//DEBUG_Display_Visibility(authBeast); +//#endif + + /** NOTE: It is ok to do a forcebeastwrite on the overflow beast, and + ** unlatch the beast before the transaction ends, because + ** we have a latch on the auth beast until after the xaction + ** ends, and no one can get the overflow beast without first + ** getting a latch on the auth beast. + **/ + + for (i = 0; i < *trusteeCount; ) + { + xaction = COMN_BeginXLocal(authBeast); + + SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, pLogLocPtr, + VIS_ACTION_REMOVE, parentZID, trusteeID); + if (authBeast->AUTHcomnVolOps.VOL_removePurgeLogEntry( + genMsg, authBeast->AUTHvolume, + PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction) != zOK) + { + goto errorTryNextTrustee; + } + + if (ZAS_FindVisibilityTrustee(genMsg, authBeast, xaction, trusteeID, + XLATCHED, &VisEntry, &entryIndex, &overflowBeast, + &overflowParentZid) != zOK) + { + goto errorTryNextTrustee; + } + if (VisEntry == NULL) + { + /* if the entry is not found then get out. This should not happen */ + if (overflowBeast != NULL) + { + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + SetErrno(genMsg, zERR_TRUSTEE_NOT_FOUND); + zASSERT("Trustee not found when trying to remove visibility" == 0); + goto errorTryNextTrustee; + } + + /* + * if it is found + */ + if(--VisEntry->count == 0) + { /* if the count is zero then remove the entry */ + if (overflowBeast == NULL) + { /* remove from the main beast */ + authInfo->p.numVisibilityTrusteesAssigned--; + memmove(&authInfo->p.visibilityList[entryIndex], + &authInfo->p.visibilityList[entryIndex + 1], + (authInfo->p.numVisibilityTrusteesAssigned - entryIndex) + * sizeof(VisEntry_s)); + overflowZid = authInfo->p.visibilityOverflow; + writeMainBeast = TRUE; + } + else + { /* remove from an overflow beast */ + overflowBeast->p.numEntries--; + memmove(&overflowBeast->vis[entryIndex], + &overflowBeast->vis[entryIndex + 1], + (overflowBeast->p.numEntries - entryIndex) * + sizeof(VisEntry_s)); + overflowZid = overflowBeast->p.nextOverflowZid; + } + + /* + * handle shifting entries in the overflow beasts + */ + while (overflowZid != zINVALID_ZID) + { /* while there are overflow beasts */ + parentBeast = overflowBeast; + if (parentBeast == NULL) + { + overflowParentZid = zINVALID_ZID; + } + else + { + overflowParentZid = parentBeast->VISOzid; + } + + overflowBeast = ZAS_LookupOverflowBeast(genMsg, + authBeast->AUTHvolume, overflowZid, XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { + if (parentBeast) + { + COMN_UnlatchAndRelease(&parentBeast, XLATCHED); + } + goto errorTryNextTrustee; + } + + if (parentBeast == NULL) + { /* moving into the main beast */ + authInfo->p.visibilityList[ + MAX_VISIBILITY_TRUSTEES_IN_BEAST - 1] = + overflowBeast->vis[0]; + authInfo->p.numVisibilityTrusteesAssigned++; + zASSERT(MAX_VISIBILITY_TRUSTEES_IN_BEAST == + authInfo->p.numVisibilityTrusteesAssigned); + } + else + { /* moving into an overflow beast */ + parentBeast->vis[MAX_VIS_OVERFLOW_ENTRIES - 1] = + overflowBeast->vis[0]; + parentBeast->p.numEntries++; + zASSERT(MAX_VIS_OVERFLOW_ENTRIES==parentBeast->p.numEntries); + COMN_MARK_BEAST_XLOCAL(&parentBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, parentBeast, xaction); + COMN_UnlatchAndRelease(&parentBeast, XLATCHED); + } + overflowBeast->p.numEntries--; + memmove(&overflowBeast->vis[0], + &overflowBeast->vis[1], + overflowBeast->p.numEntries * sizeof(VisEntry_s)); + overflowZid = overflowBeast->p.nextOverflowZid; + } + + if (overflowBeast != NULL) + { + /* + * Check to see if the overflow beast should be deleted. + */ + if (overflowBeast->p.numEntries == 0) + { /* the overflow beast is empty */ + zASSERT(overflowZid == zINVALID_ZID); + if (BST_delete(genMsg, NULL, overflowBeast, NULL, NULL, + xaction, FALSE, TRUE) != zOK) + { + zASSERT("Failed to delete trustee overflow beast"==NULL); + } + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + if (overflowParentZid == zINVALID_ZID) + { /* the parent is the main beast */ + authInfo->p.visibilityOverflow = zINVALID_ZID; + writeMainBeast = TRUE; + } + else + { /* the parent is another overflow beast */ + parentBeast = ZAS_LookupOverflowBeast(genMsg, + authBeast->AUTHvolume, overflowParentZid, + XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (parentBeast == NULL) + { + goto errorTryNextTrustee; + } + parentBeast->p.nextOverflowZid = zINVALID_ZID; + COMN_MARK_BEAST_XLOCAL(&parentBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, parentBeast, xaction); + COMN_UnlatchAndRelease(&parentBeast, XLATCHED); + } + } + else + { + COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, overflowBeast, xaction); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + } + } + else + { + if (overflowBeast == NULL) + { /* in the main beast */ + COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction); + COMN_ForceBeastWrite(genMsg, authBeast, xaction); + } + else + { /* in an overflow beast */ + COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction); + COMN_ForceBeastWrite(genMsg, overflowBeast, xaction); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + +//#if NSS_DEBUG IS_ENABLED +//DBG_DebugPrintf(GREEN, MSGNot("\n(1)Exiting Remove Visibility -- Trustee: %x"), *trusteeID); +//DEBUG_Display_Visibility(authBeast); +//#endif + + goto visibilityDoneForThisTrustee; + } + if (writeMainBeast) + { /* if the main beast is dirty */ + COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction); + COMN_ForceBeastWrite(genMsg, authBeast, xaction); + writeMainBeast = FALSE; + } + +//#if NSS_DEBUG IS_ENABLED +//DBG_DebugPrintf(GREEN, MSGNot("\n(2)Exiting Remove Visibility -- Trustee: %x"), *trusteeID); +//DEBUG_Display_Visibility(authBeast); +//#endif + + if (authBeast->AUTHzid != zROOTDIR_ZID) + { + SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, pLogLocPtr, + VIS_ACTION_REMOVE, authBeast->AUTHfirstParentZid, trusteeID); + if (authBeast->AUTHcomnVolOps.VOL_addPurgeLogEntry( + genMsg, authBeast->AUTHvolume, + PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction) != zOK) + { + goto errorTryNextTrustee; + } + } + trusteeID++; + pLogLocPtr++; + i++; + COMN_EndXLocal(authBeast, &xaction); + continue; + +errorTryNextTrustee: + errPrintf(WHERE, Module, 713, + MSG("Error removing visibility for a trustee.\n", 1194)); +visibilityDoneForThisTrustee: + (*trusteeCount)--; + *trusteeID = trusteeIDList[*trusteeCount]; + *pLogLocPtr = pLogLocPtrList[*trusteeCount]; + COMN_EndXLocal(authBeast, &xaction); + continue; + } + + xaction = COMN_BeginXLocal(authBeast); + VOL_insertEFLEntry(genMsg, &authBeast->AUTHroot, + EFL_FILE_STATE_MODIFY_METADATA, NULL, xaction); + COMN_EndXLocal(authBeast, &xaction); + + if ((authBeast->AUTHzid == zROOTDIR_ZID) || (*trusteeCount == 0)) + { + goto doneFixingVisibility; + } + parentZID = authBeast->AUTHfirstParentZid; + + /* We do not want a yield between the UNX_LATCH of authBeast and + * X_LATCH request of the parent Beast below. Hence we look + * up the parent beast first in unlatched mode and then later + * request a latch on it + * + * This routine's calling function has to guarantee that when we + * return from here, the first thing we do is request a latch + * on the returned pBeast, without any yields in between + */ + pBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, volume, + parentZID, NOTLATCHED); + if (pBeast == NULL) + { /* error */ + SetErrno(genMsg, zERR_UNABLE_TO_OPEN_BEAST); + goto errorCleanup; + } + + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + UNX_LATCH(&authInfo->authLatch); + UNX_LATCH(&authBeast->AUTHbeastLatch); + + return pBeast; + + +errorCleanup: + errPrintf(WHERE, Module, 714, + MSG("Error removing visibility for trustees just removed\n", 987)); + +doneFixingVisibility: + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + UNX_LATCH(&authInfo->authLatch); + COMN_UnlatchAndRelease(&authBeast, XLATCHED); + + return NULL; +} + + +/**************************************************************************** + * + * These routines will switch from fsm to scheduling a work (after we get a + * latch on the parent beast we are fixing visibility on). + * + ***************************************************************************/ +void ZAS_FixVisibilityThread(FsmLite_s *fsm); + +void ZAS_FixVisibilityGotParentLatch(FsmLite_s *fsm) +{ + TotalVisibilityProcesses++; + WORK_Schedule(fsm, ZAS_FixVisibilityThread, 0); + return; +} + +void ZAS_FixVisibilityThread(FsmLite_s *fsm) +{ + GeneralMsg_s genMsg; + FixVisibPurgeLogFsm_s *workFsm = (FixVisibPurgeLogFsm_s *)fsm; + AuthBeast_s *authBeast; + + ASSERT_MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + zASSERT(workFsm->action == VIS_ACTION_REMOVE || + workFsm->action == VIS_ACTION_ADD); + + authBeast = workFsm->parentBeast; + + switch (workFsm->action) + { + case VIS_ACTION_ADD: + workFsm->parentBeast = ZAS_InternalMakeItVisible( + &genMsg, + workFsm->parentBeast, + workFsm->volume, + workFsm->trusteeID, + &workFsm->trusteeCount, + workFsm->purgeLogLocations); + break; + + case VIS_ACTION_REMOVE: + workFsm->parentBeast = ZAS_InternalRemoveVisibility( + &genMsg, + workFsm->parentBeast, + workFsm->volume, + workFsm->trusteeID, + &workFsm->trusteeCount, + workFsm->purgeLogLocations); + break; + } + + TotalVisibilityProcesses--; + + /* IMPORTANT NOTE: If the return values from ZAS_MakeItVisible & + * ZAS_InternalRemovingVisibility are non-NULL, the last thing they + * do is UNX_LATCH the previous parentBeast (we have it saved in the + * authBeast pointer. + * + * There should be no yield between the return from that call and + * queueing for a X_LATCH using the FSM_X_LATCH below. So do not put + * any code here. + * + * A NULL return from the above routines implies that visibility + * has been added/removed and all the beasts have been unlatched, + * and released. All we need to do is cleanup the workFsm + */ + if (workFsm->parentBeast != NULL) + { + FSM_X_LATCH(&workFsm->parentBeast->AUTHbeastLatch, &workFsm->fsm, + ZAS_FixVisibilityGotParentLatch); + COMN_Release(&authBeast); + } + else + { + --workFsm->volume->VOLv_keepActiveUseCount; + free(workFsm); + } + return; +} + +/**************************************************************************** + * + * This routine will set up fsm to add/remove visibility up the tree + * + ***************************************************************************/ +STATUS ZAS_FixVisibilityFsmStart( + GeneralMsg_s *genMsg, + Xaction_s *xaction, + AuthBeast_s *authBeast, + Zid_t parentZID, + UserID_t *trusteeID, + NINT trusteeCount, + BOOL checkForVisRebuild, + LONG action) +{ + PurgeLogMsg_s purgeLogMsg; + FixVisibPurgeLogFsm_s *workFsm; + STATUS status = zOK; + AuthBeast_s *parentBeast; + FixVisibPLog_s *pLogLocations; + NINT i; + Volume_s *vol = authBeast->AUTHvolume; + + ASSERT_MPKNSS_LOCK(); + /*This routine assumes the beast is already open and the auth latch is set*/ + + ENTER(TAUTH, ZAS_FixVisibilityFsmStart); + ASSERT_XLATCH(&authBeast->AUTHauthInfo.zas->authLatch); + zASSERT(action == VIS_ACTION_ADD || action == VIS_ACTION_REMOVE); + + /* + * If the visibility lists of the volume are being rebuilt then return + * unless we are already in the rebuild pass and the rebuild has passed + * the beast we are adding to. + */ + if (checkForVisRebuild && (vol->v_statusFlag & VOL_SF_CLEAN_VIS_SCHEDULED)) + { + if (vol->v_statusFlag & VOL_SF_CLEAN_VIS_REBUILD) + { + if (authBeast->AUTHzid >= vol->VOLzidInProcess) + { + return zOK; + } + } + else + { + return zOK; + } + } + + if (authBeast->AUTHzid == zROOTDIR_ZID) + { + RTN_STATUS(zOK); + } + + if (trusteeCount == 0) + { + RTN_STATUS(zOK); + } + + workFsm = zalloc(sizeof(FixVisibPurgeLogFsm_s) + + (trusteeCount * sizeof(UserID_t)) + + (trusteeCount * sizeof(FixVisibPLog_s))); + if (workFsm == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + RTN_STATUS(zFAILURE); + } + /* We lookup the beast not latched since it can yield, before we + * unlock the previous beast. We want the unlock and request for + * the latch on this beast to be simultaneous, without a yield + * in between. + */ + parentBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, + authBeast->AUTHvolume, parentZID, NOTLATCHED); + if (parentBeast == NULL) + { + ForceSetErrno(genMsg, zERR_UNABLE_TO_OPEN_BEAST); + free(workFsm); + RTN_STATUS(zFAILURE); + } + + FSMLITE_INIT(&workFsm->fsm, MSGNot("FSM to fix visibility"), 0); + workFsm->parentBeast = parentBeast; + workFsm->trusteeID = (UserID_t *)((ADDR)workFsm + + sizeof(FixVisibPurgeLogFsm_s)); + workFsm->trusteeCount = trusteeCount; + workFsm->volume = authBeast->AUTHvolume; + workFsm->action = action; + memcpy(workFsm->trusteeID, trusteeID, (trusteeCount * sizeof(UserID_t))); + workFsm->purgeLogLocations = (FixVisibPLog_s *)((ADDR)workFsm + + sizeof(FixVisibPurgeLogFsm_s) + + (trusteeCount * sizeof(UserID_t))); + + ++workFsm->volume->VOLv_keepActiveUseCount; + + pLogLocations = workFsm->purgeLogLocations; + + for (i = 0; i < trusteeCount; i++) + { + SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, + pLogLocations, action, parentZID, trusteeID); + + status = authBeast->AUTHcomnVolOps.VOL_addPurgeLogEntry( + genMsg, authBeast->AUTHvolume, + PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction); + + if (status == zOK) + { + trusteeID++; + pLogLocations++; + } + else + { + break; + } + } + + if (status != zOK) + { + --workFsm->volume->VOLv_keepActiveUseCount; + free(workFsm); + RTN_STATUS(zFAILURE); + } + + FSM_X_LATCH(&workFsm->parentBeast->AUTHbeastLatch, &workFsm->fsm, + ZAS_FixVisibilityGotParentLatch); + + RTN_STATUS(zOK); +} + + +/**************************************************************************** + * + * This routine will start a fsm to add visibility up the tree + * + ***************************************************************************/ +STATUS ZAS_MakeItVisible( + GeneralMsg_s *genMsg, + Xaction_s *xaction, + AuthBeast_s *authBeast, + Zid_t parentZID, + UserID_t *trusteeID, + NINT trusteeCount, + BOOL checkForVisRebuild) +{ + return ZAS_FixVisibilityFsmStart(genMsg, xaction, authBeast, parentZID, + trusteeID, trusteeCount, + checkForVisRebuild, VIS_ACTION_ADD); +} + + +/**************************************************************************** + * + * This routine will start a fsm to remove visibility up the tree + * + ***************************************************************************/ +STATUS ZAS_RemoveVisibility( + GeneralMsg_s *genMsg, + Xaction_s *xaction, + AuthBeast_s *authBeast, + Zid_t parentZID, + UserID_t *trusteeID, + NINT trusteeCount, + BOOL checkForVisRebuild) +{ + return ZAS_FixVisibilityFsmStart(genMsg, xaction, authBeast, parentZID, + trusteeID, trusteeCount, checkForVisRebuild, + VIS_ACTION_REMOVE); +} + + +/*************************************************************************** + * + * This routine is called from PlayPurgeLog to finish fixing up visibility + * + ***************************************************************************/ +STATUS ZAS_FixVisibility( + GeneralMsg_s *genMsg, + NINT action, + Volume_s *volume, + Zid_t parentZID, + UserID_t *trusteeID, + void *purgeLogLoc) +{ + STATUS status = zOK; + UserID_t localTrusteeID = *trusteeID; + AuthBeast_s *authBeast; + AuthBeast_s *parentBeast; + NINT trusteeCount = 1; + + + parentBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, volume, + parentZID, NOTLATCHED); + if (parentBeast == NULL) + { + ForceSetErrno(genMsg, zERR_UNABLE_TO_OPEN_BEAST); + return zFAILURE; + } + + TotalVisibilityProcesses++; + + X_LATCH(&parentBeast->AUTHbeastLatch); + ClearErrno(genMsg); + + for (;;) + { + authBeast = parentBeast; + + switch (action) + { + case VIS_ACTION_ADD: + parentBeast = ZAS_InternalMakeItVisible(genMsg, parentBeast, + volume, &localTrusteeID, &trusteeCount, purgeLogLoc); + break; + + case VIS_ACTION_REMOVE: + parentBeast = ZAS_InternalRemoveVisibility(genMsg, parentBeast, + volume, &localTrusteeID, &trusteeCount, purgeLogLoc); + break; + } + TotalVisibilityProcesses--; + if (parentBeast == NULL) + { + if (GetErrno(genMsg) != zOK) + { + status = zFAILURE; + } + break; + } + else + { + TotalVisibilityProcesses++; + X_LATCH(&parentBeast->AUTHbeastLatch); + COMN_Release(&authBeast); + } + } + + return status; +} + + +/**************************************************************************** + * This routine will check visibility rights for an object + ****************************************************************************/ +STATUS ZAS_CheckInheritedVisibility( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + NINT numIDs, + UserID_t *IDs) +{ + Zid_t dummyZid; + NINT connectIndex; + NINT entryIndex; + VisEntry_s *entry; + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *beast; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_CheckInheritedVisibility); + + authInfo = authBeast->AUTHauthInfo.zas; + S_LATCH(&authInfo->authLatch); + if ((authInfo->p.numVisibilityTrusteesAssigned > 0) || + (authInfo->p.visibilityOverflow != zINVALID_ZID)) + { /* there are visibility entries */ + for (connectIndex = 0; connectIndex < numIDs; + connectIndex++) + { /* for each entry in the connection structure */ + if (ZAS_FindVisibilityTrustee(genMsg, authBeast, NULL, + &IDs[connectIndex], + SLATCHED, &entry, &entryIndex, &beast, &dummyZid) != zOK) + { + goto error; + } + if (beast != NULL) + { + COMN_UnlatchAndRelease(&beast, SLATCHED); + } + if (entry != NULL) + { + UNS_LATCH(&authInfo->authLatch); + RTN_STATUS(zOK); + } + } + } + /* visibility not found */ +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED, MSGNot("Trustees in the connection structure:\n")); + for (connectIndex = 0; connectIndex < numIDs; + connectIndex++) + { + DBG_DebugPrintf(CYAN, MSGNot(" (%d) Trustee: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n"), + connectIndex, + IDs[connectIndex].timeLow, + IDs[connectIndex].timeMid, + IDs[connectIndex].timeHighAndVersion, + IDs[connectIndex].clockSeqHighAndReserved, + IDs[connectIndex].clockSeqLow, + IDs[connectIndex].node[0], + IDs[connectIndex].node[1], + IDs[connectIndex].node[2], + IDs[connectIndex].node[3], + IDs[connectIndex].node[4], + IDs[connectIndex].node[5]); + } + DEBUG_Display_Visibility(authBeast); + DBG_DebugPrintf(LRED, "\n"); +#endif +error: + UNS_LATCH(&authInfo->authLatch); + RTN_STATUS(zFAILURE); +} +EXPORT_SYMBOL(ZAS_CheckInheritedVisibility); + +/*************************************************************************** + * + * This routine adds all of the ACLs in a beast to the visibility. + * + ***************************************************************************/ +STATUS ZAS_AddBeastVisibility( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZid, + BOOL includeVisEntries, + VisRebuildStats_s *stats, + BOOL checkForVisRebuild) +{ + ZASAuthorizeInfo_s *authInfo; + Xaction_s *xaction; + NINT originalCount; + ACLEntry_s *allACLs = NULL; + UserID_t *trusteeID = NULL; + VisEntry_s *allVis = NULL; + NINT i; + STATUS status = zOK; + + ASSERT_MPKNSS_LOCK(); + + /* + * Fix up the visibility inheritance + */ + authInfo = authBeast->AUTHauthInfo.zas; + + if (authInfo->p.numTrusteesAssigned == 0) + { + if (includeVisEntries) + { + if (authInfo->p.numVisibilityTrusteesAssigned == 0) + { + return zOK; + } + } + else + { + return zOK; + } + } + + X_LATCH(&authInfo->authLatch); + if (authInfo->p.numTrusteesAssigned != 0) + { + NINT trusteeCount; + + if (ZAS_CountACLs(genMsg, authBeast, &originalCount) != zOK) + { + status = zFAILURE; + goto exit; + } + zASSERT(originalCount > 0); + + if ((allACLs = malloc(originalCount * sizeof(ACLEntry_s))) == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exit; + } + if ((trusteeID = malloc(originalCount * sizeof(UserID_t))) == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exit; + } + if (ZAS_GetAllACLs(genMsg, authBeast, allACLs, originalCount) != zOK) + { + status = zFAILURE; + goto exit; + } + + /* + * We do not want to add visibility if the trustee has no rights, so + * remove any entries where there are no rights. + */ + trusteeCount = 0; + for (i = 0; i < originalCount; i++) + { + trusteeID[trusteeCount] = allACLs[i].trusteeID; + if (allACLs[i].rights) + { + trusteeCount++; + } + } + + if (trusteeCount != 0) + { + if (stats) + { + stats->VisNumTrusteesProcessed += trusteeCount; + } + + /* + * Update the visibility entries up the tree + */ + xaction = COMN_BeginXLocal(authBeast); + + ZAS_MakeItVisible(genMsg, xaction, authBeast, parentZid, trusteeID, + trusteeCount, checkForVisRebuild); + + COMN_EndXLocal(authBeast, &xaction); + } + + free(trusteeID); + trusteeID = NULL; + free(allACLs); + allACLs = NULL; + } + + /* + * Fix up the visibility inheritance for exisiting visibility entries + */ + + if (includeVisEntries && authInfo->p.numVisibilityTrusteesAssigned != 0) + { + if (ZAS_CountVis(genMsg, authBeast, &originalCount) != zOK) + { + status = zFAILURE; + goto exit; + } + zASSERT(originalCount > 0); + + if ((allVis = malloc(originalCount * sizeof(VisEntry_s))) == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exit; + } + if ((trusteeID = malloc(originalCount * sizeof(UserID_t))) == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exit; + } + if (ZAS_GetAllVis(genMsg, authBeast, allVis, originalCount) != zOK) + { + status = zFAILURE; + goto exit; + } + + /* + * Move an entry into the trustee array for each visibility entry + * to be added. + */ + for (i = 0; i < originalCount; i++) + { + trusteeID[i] = allVis[i].trusteeID; + } + + /* + * Update the visibility entries up the tree + */ + xaction = COMN_BeginXLocal(authBeast); + + ZAS_MakeItVisible(genMsg, xaction, authBeast, parentZid, trusteeID, + originalCount, checkForVisRebuild); + + COMN_EndXLocal(authBeast, &xaction); + } + +exit: + free(trusteeID); + free(allACLs); + UNX_LATCH(&authInfo->authLatch); + + return status; +} + +/*************************************************************************** + * + * This routine is called when a name is added to the name tree. It adds + * the trustees in the ACL to the visiblity list. + * + ***************************************************************************/ +STATUS VAUTH_AddAuthInfo( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZid, + Latch_s *parentLatch) +{ + return ZAS_AddBeastVisibility(genMsg, authBeast, parentZid, TRUE, NULL, TRUE); +} + + +/*************************************************************************** + * + * This routine is called when a name is deleted from the name tree + * + ***************************************************************************/ +STATUS VAUTH_RemoveAuthInfo( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZid, + Xaction_s *xaction) +{ + ZASAuthorizeInfo_s *authInfo; + NINT originalCount; + ACLEntry_s *allACLs = NULL; + VisEntry_s *allVis = NULL; + UserID_t *trusteeID = NULL; + NINT i; + STATUS status = zOK; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_RemoveAuthInfo); + + /* + * Fix up the visibility inheritance for ACLs + */ + authInfo = authBeast->AUTHauthInfo.zas; + + if (authInfo->p.numTrusteesAssigned == 0 && + authInfo->p.numVisibilityTrusteesAssigned == 0) + { /* if there are no trustees assigned then just return */ + RTN_STATUS(zOK); + } + + X_LATCH(&authInfo->authLatch); + if (authInfo->p.numTrusteesAssigned != 0) + { + NINT trusteeCount; + + if (ZAS_CountACLs(genMsg, authBeast, &originalCount) != zOK) + { + status = zFAILURE; + goto exit; + } + zASSERT(originalCount > 0); + + if ((allACLs = malloc(originalCount * sizeof(ACLEntry_s))) == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exit; + } + if ((trusteeID = malloc(originalCount * sizeof(UserID_t))) == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exit; + } + if (ZAS_GetAllACLs(genMsg, authBeast, allACLs, originalCount) != zOK) + { + status = zFAILURE; + goto exit; + } + + /* + * We do not want to remove visibility if the trustee has no rights, so + * remove any entries where there are no rights. + */ + trusteeCount = 0; + for (i = 0; i < originalCount; i++) + { + trusteeID[trusteeCount] = allACLs[i].trusteeID; + if (allACLs[i].rights) + { + trusteeCount++; + } + } + + if (trusteeCount != 0) + { + /* + * Remove the visibility for the trustee from the entries up the tree + */ + ZAS_RemoveVisibility(genMsg, xaction, authBeast, parentZid, trusteeID, + trusteeCount, TRUE); + } + + free(trusteeID); + trusteeID = NULL; + free(allACLs); + allACLs = NULL; + } + + /* + * Fix up the visibility inheritance for exisiting visibility entries + */ + + if (authInfo->p.numVisibilityTrusteesAssigned != 0) + { + if (ZAS_CountVis(genMsg, authBeast, &originalCount) != zOK) + { + status = zFAILURE; + goto exit; + } + zASSERT(originalCount > 0); + + if ((allVis = malloc(originalCount * sizeof(VisEntry_s))) == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exit; + } + if ((trusteeID = malloc(originalCount * sizeof(UserID_t))) == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exit; + } + if (ZAS_GetAllVis(genMsg, authBeast, allVis, originalCount) != zOK) + { + status = zFAILURE; + goto exit; + } + + /* + * Move an entry into the trustee array for each visibility entry + * to be added. + */ + for (i = 0; i < originalCount; i++) + { + trusteeID[i] = allVis[i].trusteeID; + } + + /* + * Remove the visibility for the trustee from the entries up the tree + */ + ZAS_RemoveVisibility(genMsg, xaction, authBeast, parentZid, trusteeID, + originalCount, TRUE); + } + +exit: + free(trusteeID); + free(allACLs); + free(allVis); + UNX_LATCH(&authInfo->authLatch); + + RTN_STATUS(status); +} + +/*************************************************************************** + * + * This routine is called when a file is actually deleted. It cleans up the + * associated overflow beasts. + * + ***************************************************************************/ +STATUS VAUTH_DeleteAuthInfo( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZid) +{ + ZASAuthorizeInfo_s *authInfo; + Xaction_s *xaction; + ZasAclOverflowBeast_s *aclOverflowBeast; + ZasVisOverflowBeast_s *visOverflowBeast; + Zid_t overflowZid; + STATUS status; + + ASSERT_MPKNSS_LOCK(); + + authInfo = authBeast->AUTHauthInfo.zas; + + X_LATCH(&authInfo->authLatch); + + /* Remove the ACL overflow beasts */ + xaction = COMN_BeginXLocal(authBeast); + + /* Remove all ACL overflow beasts */ + overflowZid = authInfo->p.trusteeOverflow; + while (overflowZid != zINVALID_ZID) + { /* find an overflow beast with an open entry */ + aclOverflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (aclOverflowBeast == NULL) + { /* error */ + status = zFAILURE; + goto exit; + } + + overflowZid = aclOverflowBeast->p.nextOverflowZid; + BST_delete(genMsg, NULL, aclOverflowBeast, NULL, NULL, + xaction, FALSE, TRUE); + COMN_UnlatchAndRelease(&aclOverflowBeast, XLATCHED); + } + status = zOK; + + /* Remove all visibility overflow beasts */ + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { /* find an overflow beast with an open entry */ + visOverflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (visOverflowBeast == NULL) + { /* error */ + status = zFAILURE; + goto exit; + } + + overflowZid = visOverflowBeast->p.nextOverflowZid; + BST_delete(genMsg, NULL, visOverflowBeast, NULL, NULL, + xaction, FALSE, TRUE); + COMN_UnlatchAndRelease(&visOverflowBeast, XLATCHED); + } + status = zOK; + +exit: + COMN_EndXLocal(authBeast, &xaction); + + UNX_LATCH(&authInfo->authLatch); + + return status; +} + +/*************************************************************************** + * + * This routine is called to determine if there is auth info that needs + * to be cleaned up. If so then it returns TRUE. + * + ***************************************************************************/ +BOOL VAUTH_IsAuthInfo( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast) +{ + ZASAuthorizeInfo_s *authInfo; + + ASSERT_MPKNSS_LOCK(); + + authInfo = authBeast->AUTHauthInfo.zas; + + if (authInfo->p.numTrusteesAssigned != 0) + { + return TRUE; + } + + if (authInfo->p.trusteeOverflow != zINVALID_ZID) + { + return TRUE; + } + + return FALSE; +} + +/**************************************************************************** + * This routine is used to initialize the authorization info for a newly + * created volume. It must only change items in the volume's rootdir. + * The caller will have the rootdir xlatched and will ensure that the + * rootdir gets written and the latch released on successful return. On + * error return the volume will not get created. + *****************************************************************************/ +STATUS VAUTH_InitVolumeAuthInfo( + GeneralMsg_s *genMsg, + Volume_s *volBeast) +{ + AuthBeast_s *rootdir = (AuthBeast_s *)volBeast->rootdir; + + ASSERT_MPKNSS_LOCK(); + ASSERT_XLATCH(&rootdir->AUTHbeastLatch); + + /* allow no inheritance on rootdir */ + rootdir->AUTHauthInfo.zas->p.inheritedRightsMask = 0; + return(zOK); +} + +typedef struct SaveTrusteeEntry_s +{ + NINT trusteeID; + NINT rights; + NINT attributes; +} SaveTrusteeEntry_s; + +/**************************************************************************** + * + * This routine removes a list of trustees from all objects in a given + * volume. Currently it is calling a routine that is also called from + * the authorization space for some symantic agent requests. The authorization + * space routine could have been placed directly in the ops tables, but since + * this is an infrequently used call I gave it its own routine to avoid + * confusion. + * + ****************************************************************************/ +STATUS VAUTH_RemoveIDsFromAVolume( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *IDlist, + NINT IDcount) +{ + ASSERT_MPKNSS_LOCK(); + return VAUTH_PurgeACLEntriesFromTree(genMsg, nameMsg, IDlist, IDcount); +} + +/**************************************************************************** + * + * This function repairs a beast with a bad overflow zid + * + ****************************************************************************/ +void VAUTH_FixOverflowLink( + GeneralMsg_s *genMsg, + Volume_s *volume, + AuthBeast_s *beast, + Zid_t overflowZid) +{ + ZasAclOverflowBeast_s *overflowBeast; + NINT unicodeLen; + unicode_t *name; + + if (overflowZid == zINVALID_ZID) + { /* The bad zid is in the file beast */ + beast->AUTHauthInfo.zas->p.trusteeOverflow = zINVALID_ZID; + COMN_MARK_BEAST_DIRTY(&beast->AUTHroot); + } + else + { /* The bad zid is in an overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, volume, overflowZid, + XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (overflowBeast == NULL) + { + return; + } + overflowBeast->p.nextOverflowZid = zINVALID_ZID; + COMN_MARK_BEAST_DIRTY(&overflowBeast->ACLOroot); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + if (COMN_IsDerivedFrom(beast, zFTYPE_FILE)) + { + name = malloc((zMAX_COMPONENT_NAME + 1) * sizeof(unicode_t)); + if (name) + { + COMN_GetNameFromBeast(genMsg, (File_s *)beast, /* cnt zFNU_FIRST_PARENT,*/ + zNSPACE_LONG, zMAX_COMPONENT_NAME, name, &unicodeLen); + name[unicodeLen] = L'\0'; + aprintf(LRED, "Fixed bad authorization overflow link on file %U\n", + name); + free(name); + } + } + else + { + aprintf(LRED, "Fixed bad authorization overflow link. Zid=%Lu", + beast->AUTHzid); + } +} + +/**************************************************************************** + * + * This function adds the NDS object GUIDs to the User store for all + * structures in the ZAS auth model. + * + ****************************************************************************/ +STATUS VAUTH_CheckUserIDs( + GeneralMsg_s *genMsg, + Volume_s *volume, + AuthBeast_s *beast) +{ + ZASAuthorizeInfo_s *authInfo; + NINT entry; + ZasAclOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + BOOL isOK; + NINT numBadIDs; + Zid_t previousZid; + typedef struct Stack_s { + UserID_t badIDs[MAX_ACL_OVERFLOW_ENTRIES]; + } Stack_s; + STACK_ALLOC(); + + authInfo = beast->AUTHauthInfo.zas; + X_LATCH(&authInfo->authLatch); + + /* Check the trustees in the beast and the ACL overflow beasts */ + for (entry=0; entry < authInfo->p.numTrusteesAssigned; entry++) + { + UserID_t userID = authInfo->p.ACL[entry].trusteeID; + + if (CHK_VerifyID(genMsg, volume, &userID, &isOK) != zOK) + { + continue; + } + if (!isOK) + { + ZAS_RemoveLatchedACLEntry(genMsg, beast, &userID, TRUE, NULL); + } + } + + /* check the overflow beasts for the entry */ + overflowZid = authInfo->p.trusteeOverflow; + previousZid = zINVALID_ZID; + while (overflowZid != zINVALID_ZID) + { /* find an overflow beast with an open entry */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, volume, overflowZid, + SLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + zASSERT("Error getting ACL overflow beast" == NULL); + VAUTH_FixOverflowLink(genMsg, volume, beast, previousZid); + break; + } + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK) + { + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + STACK_FREE(); + return(zFAILURE); + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + numBadIDs = 0; + for (entry = 0; entry < overflowBeast->p.numEntries; entry++) + { + if (CHK_VerifyID(genMsg, volume, &overflowBeast->acl[entry].trusteeID, + &isOK) != zOK) + { + continue; + } + if (!isOK) + { + aStack->badIDs[numBadIDs++] = overflowBeast->acl[entry].trusteeID; + } + } + UNS_LATCH(&overflowBeast->ACLObeastLatch); + + /* + * We save up the bad IDs and remove them after the latch has been + * released so that we do not deadlock. + */ + while (numBadIDs > 0) + { +// DBG_DebugPrintf(LRED, "VAUTH_CheckUserIDs: removing user 0x%x\n", aStack->badIDs[numBadIDs - 1].timeLow); + ZAS_RemoveLatchedACLEntry(genMsg, beast, + &aStack->badIDs[--numBadIDs], TRUE, NULL); + } + previousZid = overflowZid; + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_Release(&overflowBeast); + } + + UNX_LATCH(&authInfo->authLatch); + STACK_FREE(); + return zOK; +} + +/**************************************************************************** + * + * This function adds the NDS object GUIDs to the User store for all + * structures in the ZAS auth model. + * + ****************************************************************************/ +STATUS VAUTH_AddObjectNames( + GeneralMsg_s *genMsg, + Volume_s *volume, + AuthBeast_s *beast) +{ + ZASAuthorizeInfo_s *authInfo; + NINT entry; + + /* Add the trustees and visibility entries */ + authInfo = beast->AUTHauthInfo.zas; + for (entry=0; entry < authInfo->p.numTrusteesAssigned; entry++) + { + OID_AddEntryIfNotThere(genMsg, volume, + &authInfo->p.ACL[entry].trusteeID); + } + for (entry=0; entry < authInfo->p.numVisibilityTrusteesAssigned; + entry++) + { + OID_AddEntryIfNotThere(genMsg, volume, + &authInfo->p.visibilityList[entry].trusteeID); + } + return zOK; +} + +/*************************************************************************** + * + * This routine is called when the information for the authorization system + * (i.e. caching) may need to be invalidated. + * + ***************************************************************************/ +STATUS VAUTH_InvalidateAuthInfo( + GeneralMsg_s *genMsg) +{ + return ZAS_InvalidateEntireEACLCache(genMsg, TRUE); +} + +/**************************************************************************** + * This routine will count ACL entries for a file. + ****************************************************************************/ +STATUS ZAS_CountACLs( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + NINT *count) +{ + ZASAuthorizeInfo_s *authInfo; + ZasAclOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_CountACLs); + + authInfo = authBeast->AUTHauthInfo.zas; + ASSERT_LATCH(&authInfo->authLatch); + + *count = authInfo->p.numTrusteesAssigned; + + /* check the overflow beasts for the entry */ + overflowZid = authInfo->p.trusteeOverflow; + while (overflowZid != zINVALID_ZID) + { /* get the next overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + RTN_STATUS(zFAILURE); + } + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK) + { + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + RTN_STATUS(zFAILURE); + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + *count += overflowBeast->p.numEntries; + + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + /* entry not found */ + RTN_STATUS(zOK); +} + +/**************************************************************************** + * This routine will count visibility entries for a file. + ****************************************************************************/ +STATUS ZAS_CountVis( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + NINT *count) +{ + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + + ASSERT_MPKNSS_LOCK(); + + authInfo = authBeast->AUTHauthInfo.zas; + ASSERT_LATCH(&authInfo->authLatch); + + *count = authInfo->p.numVisibilityTrusteesAssigned; + + /* check the overflow beasts for the entry */ + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { /* get the next overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + return zFAILURE; + } + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertVisFromVersionOne(genMsg, NULL, authBeast) != zOK) + { + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + return zFAILURE; + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + *count += overflowBeast->p.numEntries; + + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + /* entry not found */ + return zOK; +} + +/**************************************************************************** + * This routine will get an ACL entry for a file. If the sequence number is + * -1 or 0 then it gets the first entry, otherwise it gets the next one in + * the sequence. A returned sequence number of -1 means there are no more + * entries + ****************************************************************************/ +STATUS ZAS_GetAnACL( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + NINT *sequence, + UserID_t *trusteeID, + NINT *rights, + NINT *attributes) +{ + ZASAuthorizeInfo_s *authInfo; + ZasAclOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + NINT entry; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_GetAnACL); + + if (*sequence == -1) + { /* get the first entry */ + *sequence = 0; + } + + authInfo = authBeast->AUTHauthInfo.zas; + //FixFixFix: Need to think about this one:ASSERT_LATCH(&authInfo->authLatch); + + entry = *sequence; + (*sequence)++; + + /* check the main beast for the entry */ + if (entry < authInfo->p.numTrusteesAssigned) + { /* if the entry is in the main beast */ + *trusteeID = authInfo->p.ACL[entry].trusteeID; + *rights = authInfo->p.ACL[entry].rights; + *attributes = authInfo->p.ACL[entry].attributes; + RTN_STATUS(zOK); + } + + /* check the overflow beasts for the entry */ + overflowZid = authInfo->p.trusteeOverflow; + entry -= authInfo->p.numTrusteesAssigned; + while (overflowZid != zINVALID_ZID) + { /* find an overflow beast with an open entry */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + RTN_STATUS(zFAILURE); + } + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK) + { + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + RTN_STATUS(zFAILURE); + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + if (entry < overflowBeast->p.numEntries) + { + *trusteeID = overflowBeast->acl[entry].trusteeID; + *rights = overflowBeast->acl[entry].rights; + *attributes = overflowBeast->acl[entry].attributes; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + RTN_STATUS(zOK); + } + overflowZid = overflowBeast->p.nextOverflowZid; + entry -= overflowBeast->p.numEntries; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + /* entry not found */ + *sequence = -1; + RTN_STATUS(zOK); +} + +/**************************************************************************** + * This routine will get all ACL entries for a file. + * trusteeID is a pointer to an array to fill in the trustee IDs. + * count is the size of the array. + ****************************************************************************/ +STATUS ZAS_GetAllACLs( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + ACLEntry_s *acl, + NINT count) +{ + ZASAuthorizeInfo_s *authInfo; + ZasAclOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + NINT entry; + NINT i; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_GetAllACLs); + + authInfo = authBeast->AUTHauthInfo.zas; + ASSERT_LATCH(&authInfo->authLatch); + + entry = 0; + + /* check the main beast for the entry */ + for (i = 0; ((i < authInfo->p.numTrusteesAssigned) && (entry < count)); + entry++, i++) + { + acl[entry] = authInfo->p.ACL[i]; + } + + if (entry == count) + { + RTN_STATUS(zOK); + } + /* check the overflow beasts for the entry */ + overflowZid = authInfo->p.trusteeOverflow; + while (overflowZid != zINVALID_ZID) + { /* get the next overflow entry */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + RTN_STATUS(zFAILURE); + } + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK) + { + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + RTN_STATUS(zFAILURE); + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + for (i = 0; ((i < overflowBeast->p.numEntries) && (entry < count)); + entry++, i++) + { + acl[entry] = overflowBeast->acl[i]; + } + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + if (entry == count) + { + RTN_STATUS(zOK); + } + } + + zASSERT(entry == count); + RTN_STATUS(zOK); +} + +/**************************************************************************** + * This routine will get all visibility entries for a file. + * trusteeID is a pointer to an array to fill in the trustee IDs. + * count is the size of the array. + ****************************************************************************/ +STATUS ZAS_GetAllVis( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + VisEntry_s *vis, + NINT count) +{ + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + NINT entry = 0; + NINT i; + + ASSERT_MPKNSS_LOCK(); + + authInfo = authBeast->AUTHauthInfo.zas; + ASSERT_LATCH(&authInfo->authLatch); + + /* check the main beast for the entry */ + for (i = 0; i < authInfo->p.numVisibilityTrusteesAssigned; i++) + { + zASSERT(entry < count); + if (entry < count) + { + vis[entry++] = authInfo->p.visibilityList[i]; + } + } + + /* check the overflow beasts for the entry */ + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { /* get the next overflow beast */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + return zFAILURE; + } + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertVisFromVersionOne(genMsg, NULL, authBeast) != zOK) + { + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + return zFAILURE; + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + for (i = 0; i < overflowBeast->p.numEntries; i++) + { + zASSERT(entry < count); + if (entry < count) + { + vis[entry++] = overflowBeast->vis[i]; + } + } + + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + zASSERT(entry == count); + return zOK; +} + +/**************************************************************************** + * This routine will find a trustee and return a pointer to the trustee + * info and if it is in the overflow then a pointer the overflow beast is + * returned. + * If it is in the overflow then the overflow beast is returned open and + * latched. + ****************************************************************************/ +ACLEntry_s *ZAS_FindTrustee( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + UserID_t *trusteeID, + ZasAclOverflowBeast_s **returnBeast) +{ + ZASAuthorizeInfo_s *authInfo; + ZasAclOverflowBeast_s *overflowBeast; + Zid_t overflowZid; + NINT entry; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_FindTrustee); + authInfo = authBeast->AUTHauthInfo.zas; + ASSERT_LATCH(&authInfo->authLatch); + *returnBeast = NULL; + + /* search the main beast for the trustee */ + for (entry=0; entry < authInfo->p.numTrusteesAssigned; entry++) + { + if (LB_GUIDCompare(&authInfo->p.ACL[entry].trusteeID, trusteeID) == 0) + { + RTN_PTR(&authInfo->p.ACL[entry]); + } + } + + /* search the overflow beasts for the trustee */ + overflowZid = authInfo->p.trusteeOverflow; + while (overflowZid != zINVALID_ZID) + { + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + RTN_PTR(NULL); + } + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK) + { + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + RTN_PTR(NULL); + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + for (entry=0; entry < overflowBeast->p.numEntries; entry++) + { + if (LB_GUIDCompare(&overflowBeast->acl[entry].trusteeID, trusteeID) == 0) + { + *returnBeast = overflowBeast; + RTN_PTR(&overflowBeast->acl[entry]); + } + } + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + RTN_PTR(NULL); +} + +/**************************************************************************** + * This routine will add room for a trustee and return a pointer to the trustee + * info and a pointer to the overflow beast if it is added to the overflow. + * If it is in the overflow then the overflow beast is returned open and + * latched. + ****************************************************************************/ +ACLEntry_s *ZAS_AddTrustee( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Xaction_s *xaction, + BOOL *writeMainBeast, + ZasAclOverflowBeast_s **returnBeast) +{ + ACLEntry_s *aclEntry; + ZASAuthorizeInfo_s *authInfo; + Zid_t overflowZid; + ZasAclOverflowBeast_s *overflowBeast; + ZasAclOverflowBeast_s *oldOverflowBeast = NULL; + STATUS status; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_AddTrustee); + *writeMainBeast = FALSE; + authInfo = authBeast->AUTHauthInfo.zas; + ASSERT_LATCH(&authInfo->authLatch); + if (authInfo->p.numTrusteesAssigned < MAX_TRUSTEES_IN_BEAST) + { /* if there is still space in the main beast */ + aclEntry = &authInfo->p.ACL[authInfo->p.numTrusteesAssigned++]; + *returnBeast = NULL; + *writeMainBeast = TRUE; + } + else + { /* move to the overflow beasts */ + overflowZid = authInfo->p.trusteeOverflow; + if (authInfo->p.trusteeOverflow != zINVALID_ZID) + { + for (;;) + { /* find an overflow beast with an open entry */ + overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (overflowBeast == NULL) + { /* error */ + RTN_PTR(NULL); + } + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK) + { + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + RTN_PTR(NULL); + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + if (overflowBeast->p.numEntries < MAX_ACL_OVERFLOW_ENTRIES) + { /* if there is room in this node */ + if (overflowBeast->p.numEntries >= overflowBeast->numAlloced) + { /* if we need to make the memory structure bigger */ + ACLEntry_s *acl; + overflowBeast->numAlloced += OVERFLOW_ALLOC_UNIT; + acl = realloc(overflowBeast->acl, + overflowBeast->numAlloced * sizeof (ACLEntry_s)); + if (acl == NULL) + { + overflowBeast->numAlloced -= OVERFLOW_ALLOC_UNIT; + SetErrno(genMsg, zERR_NO_MEMORY); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + RTN_PTR(NULL); + } + overflowBeast->acl = acl; + } + aclEntry = &overflowBeast->acl[overflowBeast->p.numEntries++]; + *returnBeast = overflowBeast; + RTN_PTR(aclEntry); + } + overflowZid = overflowBeast->p.nextOverflowZid; + oldOverflowBeast = overflowBeast; + if (overflowZid != zINVALID_ZID) + { + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + oldOverflowBeast = NULL; + } + else + { /* no open entries in the overflow beasts */ + break; + } + } + } + + /* + * Add a new overflow beast + */ + + overflowBeast = (ZasAclOverflowBeast_s *)BST_create(genMsg, + zFTYPE_ZAS_ACL_OVERFLOW, authBeast->AUTHvolume, xaction); + if (overflowBeast == NULL) + { + if (oldOverflowBeast != NULL) + { + COMN_UnlatchAndRelease(&oldOverflowBeast, XLATCHED); + } + RTN_PTR(NULL); + } + + /* link the new beast to the ones already there */ + if (oldOverflowBeast == NULL) + { /* link to main beast */ + authInfo->p.trusteeOverflow = overflowBeast->ACLOzid; + *writeMainBeast = TRUE; + } + else + { /* link to another overflow beast */ + oldOverflowBeast->p.nextOverflowZid = overflowBeast->ACLOzid; + COMN_MARK_BEAST_XLOCAL(&oldOverflowBeast->ACLOroot, xaction); + status = COMN_ForceBeastWrite(genMsg, oldOverflowBeast, xaction); + COMN_UnlatchAndRelease(&oldOverflowBeast, XLATCHED); + if (status != zOK) + { + UNX_LATCH(&overflowBeast->ACLObeastLatch); + BST_free(overflowBeast); + RTN_PTR(NULL); + } + } + BEASTHASH_Insert(&overflowBeast->ACLOroot); + overflowBeast->ACLObstState |= BST_STATE_NEW; + overflowBeast->p.numEntries = 1; + aclEntry = &overflowBeast->acl[0]; + *returnBeast = overflowBeast; + } + RTN_PTR(aclEntry); +} + +/**************************************************************************** + * This routine will add a new trustee and rights to the given beast + ****************************************************************************/ +STATUS ZAS_AddACLEntry( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + UserID_t *trusteeID, + NINT rights, + NINT attributes) +{ + ZASAuthorizeInfo_s *authInfo; + ACLEntry_s *ACLEntry; + ZasAclOverflowBeast_s *overflowBeast; + Xaction_s *xaction; + BOOL writeMainBeast = FALSE; + Zid_t hlZid; + HardLinkBeast_s *hlBeast; + BOOL modifyMetaDataTime = TRUE; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_AddACLEntry); + + /* Defect #306666. We can't allow unlicensed connection access */ + if (!ConnectionIsLoggedIn(genMsg->pssConn.id)) + { + /* They are not logged in (LICENCED), so limit their access */ + SetErrno(genMsg, zERR_NO_SET_PRIVILEGE); + goto cleanupError; + } + if (authBeast->AUTHvolume->VOLenabledAttributes & zATTR_READONLY) + { + SetErrno(genMsg, zERR_VOLUME_READ_ONLY); + return zFAILURE; + } + OID_SaveObjectID(authBeast->AUTHvolume, trusteeID); + + authInfo = authBeast->AUTHauthInfo.zas; + X_LATCH(&authInfo->authLatch); + + /* begin the transaction for adding an ACL */ + xaction = COMN_BeginXLocal(authBeast); + if ((ACLEntry = ZAS_FindTrustee(genMsg, authBeast, trusteeID, + &overflowBeast)) == NULL) + { /* could not find the trustee */ + if ((ACLEntry = ZAS_AddTrustee(genMsg, authBeast, xaction, + &writeMainBeast, &overflowBeast)) == NULL) + { /* error */ + goto cleanupUnlatch; + } + ACLEntry->rights = 0; + + if (!(authBeast->AUTHattributes & zFA_SUBDIRECTORY) || + authBeast->AUTHcomnOps.BST_isDirectoryEmpty(genMsg, &authBeast->AUTHnamed, zNTYPE_FILE)) + { /* this object has no object below it */ + ZAS_RemoveEACLCacheEntry(authInfo->p.cacheIndex, authInfo->p.signature); + } + else + { + ZAS_InvalidateEntireEACLCache(genMsg, TRUE); + } + } + else + { + /* + * we need to invalidate all entries because inheritance masking can + * cause a trustee ID to not be in a cache entry that would be + * affected if a right is added that is not masked out. + */ + if (ACLEntry->rights != rights) + { /* if it is actually changing */ + ZAS_InvalidateEntireEACLCache(genMsg, TRUE); + } + } + + + /* + * If this is a hardlink primary beast, we need to add/remove visibility + * for all parents, not just the first parent. + */ + if ((authBeast->AUTHhardLinkZid != zINVALID_ZID) && + !(authBeast->AUTHattributes & zFA_HARDLINK)) + { + for (hlZid = authBeast->AUTHhardLinkZid; hlZid != zINVALID_ZID; ) + { + hlBeast = COMN_LookupByZid(genMsg,authBeast->AUTHvolume,hlZid, + NOTLATCHED,TRUE); + if (hlBeast != NULL) + { + /* + * If rights are being given where there were none then update the + * visibility. If rights are being set to zero when they were non-zero + * before then remove the visibility. Entries that have a trustee that + * has no rights should not make directories above them visible. + */ + if (rights && !ACLEntry->rights) + { + /* FixFixFix6 -- need to do this for each parent */ + ZAS_MakeItVisible(genMsg, xaction, authBeast, + hlBeast->HARDLfirstParentZid, trusteeID, 1, TRUE); + } else if (!rights && ACLEntry->rights) + { + /* FixFixFix6 -- need to remove visiblility on all parents */ + ZAS_RemoveVisibility(genMsg, xaction, authBeast, + hlBeast->HARDLfirstParentZid, trusteeID, 1, TRUE); + } + + hlZid = hlBeast->HARDLhardLinkZid; + COMN_Release(&hlBeast); + } + else + { + zASSERT("Broken hard link chain"==NULL); + hlZid = zINVALID_ZID; + } + } + } + else + { + zASSERT(!(authBeast->AUTHattributes & zFA_HARDLINK)); + + /* + * If rights are being given where there were none then update the + * visibility. If rights are being set to zero when they were non-zero + * before then remove the visibility. Entries that have a trustee that + * has no rights should not make directories above them visible. + */ + if (rights && !ACLEntry->rights) + { + /* FixFixFix6 -- need to do this for each parent */ + ZAS_MakeItVisible(genMsg, xaction, authBeast, + authBeast->AUTHfirstParentZid, trusteeID, 1, TRUE); + } else if (!rights && ACLEntry->rights) + { + /* FixFixFix6 -- need to remove visiblility on all parents */ + ZAS_RemoveVisibility(genMsg, xaction, authBeast, + authBeast->AUTHfirstParentZid, trusteeID, 1, TRUE); + } + } + + /* fill in the ACL */ + ACLEntry->trusteeID = *trusteeID; + ACLEntry->rights = rights; + ACLEntry->attributes = attributes; + + if (!(authBeast->AUTHattributes & zFA_ATTR_ARCHIVE)) + { + authBeast->AUTHattributes |= zFA_ATTR_ARCHIVE; + writeMainBeast = TRUE; + } + + if ((modifyMetaDataTime) && (COMN_IsDerivedFrom(authBeast, zFTYPE_FILE))) + { + File_s *file = (File_s *)authBeast; + file->FILEmetaDataModifiedTime = GetUTCTime(); + writeMainBeast = TRUE; + } + + if (writeMainBeast || (overflowBeast == NULL)) + { /* if the main beast is dirty */ + authInfo->flags |= ZAS_ALLOW_FORCED_WRITE; + COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction); + if (COMN_ForceBeastWrite(genMsg, authBeast, xaction) != zOK) + { + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + goto cleanupUnlatch; + } + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + } + + if (overflowBeast != NULL) + { /* if the entry is in the overflow beast */ + COMN_MARK_BEAST_XLOCAL(&overflowBeast->ACLOroot, xaction); + if (COMN_ForceBeastWrite(genMsg, overflowBeast, xaction) != zOK) + { + goto cleanupUnlatch; + } + } + + if (overflowBeast != NULL) + { + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + + authInfo->flags |= ZAS_ALLOW_FORCED_WRITE; + VOL_insertEFLEntry(genMsg, &authBeast->AUTHroot, + EFL_FILE_STATE_MODIFY_METADATA, NULL, xaction); + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + + UNX_LATCH(&authInfo->authLatch); + COMN_EndXLocal(authBeast, &xaction); + RTN_STATUS(zOK); + +cleanupUnlatch: + if (overflowBeast != NULL) + { + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + UNX_LATCH(&authInfo->authLatch); + COMN_EndXLocal(authBeast, &xaction); + +cleanupError: + RTN_STATUS(zFAILURE); +} + +/**************************************************************************** + * Remove a beast and link the previous to the next. + ****************************************************************************/ +void ZAS_RemoveOverflowBeast( + GeneralMsg_s *genMsg, + ZasAclOverflowBeast_s *delBeast, + ZasAclOverflowBeast_s *prevBeast, + ZASAuthorizeInfo_s *authInfo, + BOOL *forceMainBeast, + Xaction_s *xaction) +{ + if (prevBeast == NULL) + { /* if linked from the main beast then unlink */ + authInfo->p.trusteeOverflow = delBeast->p.nextOverflowZid; + *forceMainBeast = TRUE; + } + else + { + prevBeast->p.nextOverflowZid = delBeast->p.nextOverflowZid; + COMN_MARK_BEAST_XLOCAL(&prevBeast->ACLOroot, xaction); + COMN_ForceBeastWrite(genMsg, prevBeast, xaction); + zASSERT(GetErrno(genMsg) == zOK); + ClearErrno(genMsg); + } + BST_delete(genMsg, NULL, delBeast, NULL, NULL, xaction, FALSE, TRUE); + COMN_UnlatchAndRelease(&delBeast, XLATCHED); + zASSERT(GetErrno(genMsg) == zOK); + ClearErrno(genMsg); + return; +} + +/**************************************************************************** + * This routine will remove a trustee from either the main beast or from + * an overflow beast. + ****************************************************************************/ +STATUS ZAS_RemoveTrustee( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + UserID_t *trusteeID, + NINT *rights, + Xaction_s *xaction) +{ + ACLEntry_s *aclEntry; + Zid_t overflowZid; + Zid_t lastGoodZid = zINVALID_ZID; + ZASAuthorizeInfo_s *authInfo; + ZasAclOverflowBeast_s *deleteBeast = NULL; + ZasAclOverflowBeast_s *lastBeast = NULL; + ZasAclOverflowBeast_s *prevBeast = NULL; + STATUS status = zOK; + BOOL forceMainBeast = FALSE; + BOOL forceDeleteBeast = FALSE; + BOOL releasePrevious = FALSE; + NINT entry; + BOOL modifyMetaDataTime = TRUE; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_RemoveTrustee); + + authInfo = authBeast->AUTHauthInfo.zas; + ASSERT_LATCH(&authInfo->authLatch); + + /* + * Find the location where the trustee is to be deleted from. + */ + + overflowZid = authInfo->p.trusteeOverflow; + + /* search the main beast for the trustee */ + for (entry=0; entry < authInfo->p.numTrusteesAssigned; entry++) + { + if (LB_GUIDCompare(&authInfo->p.ACL[entry].trusteeID, trusteeID) == 0) + { + aclEntry = &authInfo->p.ACL[entry]; + forceMainBeast = TRUE; + goto findLast; + } + } + + /* search the overflow beasts for the trustee */ + while (overflowZid != zINVALID_ZID) + { /* find an overflow beast with an open entry */ + if (prevBeast != NULL && releasePrevious) + { + COMN_UnlatchAndRelease(&prevBeast, XLATCHED); + } + prevBeast = deleteBeast; + deleteBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (deleteBeast == NULL) + { /* error */ + status = zFAILURE; + goto cleanup; + } + lastGoodZid = overflowZid; +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertACLFromVersionOne(genMsg, deleteBeast) != zOK) + { + COMN_UnlatchAndRelease(&deleteBeast, XLATCHED); + status = zFAILURE; + goto cleanup; + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + overflowZid = deleteBeast->p.nextOverflowZid; + if (deleteBeast->p.numEntries == 0) + { + releasePrevious = FALSE; + ZAS_RemoveOverflowBeast(genMsg, deleteBeast, prevBeast, authInfo, + &forceMainBeast, xaction); + if (overflowZid != zINVALID_ZID) + { + deleteBeast = prevBeast; + } + else + { + deleteBeast = NULL; + } + } + else + { + releasePrevious = TRUE; + for (entry=0; entry < deleteBeast->p.numEntries; entry++) + { + if (LB_GUIDCompare(&deleteBeast->acl[entry].trusteeID, trusteeID) == 0) + { + aclEntry = &deleteBeast->acl[entry]; + forceDeleteBeast = TRUE; + goto findLast; + } + } + } + } + /* could not find trustee */ + SetErrno(genMsg, zERR_TRUSTEE_NOT_FOUND); + status = zFAILURE; + goto cleanup; + +findLast: + /* return the rights for the trustee being deleted */ + *rights = aclEntry->rights; + + /* + * Find the last beast in the list of overflow beasts. The + * previous beast in the list must also be found in case we need to + * unlink it. + */ + lastBeast = deleteBeast; + while (overflowZid != zINVALID_ZID) + { /* find the last beast */ + BOOL sameBeast; + + if (prevBeast != NULL && prevBeast != deleteBeast && releasePrevious) + { + COMN_UnlatchAndRelease(&prevBeast, XLATCHED); + sameBeast = FALSE; + } + else + { + sameBeast = TRUE; + } + prevBeast = lastBeast; + lastBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW); + if (lastBeast == NULL) + { /* error */ + /* Treat the last good beast as if it were the last beast */ + if (lastGoodZid != zINVALID_ZID) + { + if (sameBeast) + { + lastBeast = deleteBeast; + } + else + { + lastBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + lastGoodZid, XLATCHED, FALSE); + if (lastBeast == NULL) + { + /* + * This should never happen since we just found this beast on + * the last loop through. + */ + status = zFAILURE; + goto cleanup; + } + } + lastBeast->p.nextOverflowZid = zINVALID_ZID; + } + else + { + authInfo->p.trusteeOverflow = zINVALID_ZID; + } + overflowZid = zINVALID_ZID; + break; + } + lastGoodZid = overflowZid; + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + if (ZAS_ConvertACLFromVersionOne(genMsg, lastBeast) != zOK) + { + COMN_UnlatchAndRelease(&lastBeast, XLATCHED); + status = zFAILURE; + goto cleanup; + } + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + overflowZid = lastBeast->p.nextOverflowZid; + if (lastBeast->p.numEntries == 0) + { + releasePrevious = FALSE; + ZAS_RemoveOverflowBeast(genMsg, lastBeast, prevBeast, authInfo, + &forceMainBeast, xaction); + lastBeast = prevBeast; + } + else + { + releasePrevious = TRUE; + } + } + + /* + * Delete the entry by taking the last entry in the last beast and moving + * it to the deleted location. + */ + + if (deleteBeast == NULL && lastBeast == NULL) + { /* if there are no overflow records - just working on main beast*/ + ZAS_DELETE_ENTRY(authInfo->p.numTrusteesAssigned, aclEntry, + authInfo->p.ACL); + forceMainBeast = TRUE; + } + else + { /* moving entry from overflow to main */ + ZAS_DELETE_ENTRY(lastBeast->p.numEntries, aclEntry, lastBeast->acl); + /* + * If the last beast is empty then get rid of it unless it was already + * reset to the previous because the "old" last beast was removed + * because it had no entries. In this case the previous beast + * was used as the last beast and we have lost track of the beast + * previous to that so we cannot remove the "new" last beast. + */ + if ((lastBeast->p.numEntries == 0) && + (lastBeast != prevBeast)) + { /* if the last beast is empty get rid of it. */ + ZAS_RemoveOverflowBeast(genMsg, lastBeast, prevBeast, authInfo, + &forceMainBeast, xaction); + if (deleteBeast == lastBeast) + { + forceDeleteBeast = FALSE; + deleteBeast = NULL; + } + lastBeast = NULL; + } + else + { + if (deleteBeast != lastBeast) + { /* if the beast we are deleting from and the last beast are not the same then write */ + COMN_MARK_BEAST_XLOCAL(&lastBeast->ACLOroot, xaction); + if (COMN_ForceBeastWrite(genMsg, lastBeast, xaction) != zOK) + { + status = zFAILURE; + goto cleanup; + } + } + } + } + + if (!(authBeast->AUTHattributes & zFA_ATTR_ARCHIVE)) + { + authBeast->AUTHattributes |= zFA_ATTR_ARCHIVE; + forceMainBeast = TRUE; + } + + if ((modifyMetaDataTime) && (COMN_IsDerivedFrom(authBeast, zFTYPE_FILE))) + { + File_s *file = (File_s *)authBeast; + file->FILEmetaDataModifiedTime = GetUTCTime(); + forceMainBeast = TRUE; + } + + if (forceMainBeast) + { + authInfo->flags |= ZAS_ALLOW_FORCED_WRITE; + COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction); + if (COMN_ForceBeastWrite(genMsg, authBeast, xaction) != zOK) + { + status = zFAILURE; + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + goto cleanup; + } + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + } + if (forceDeleteBeast) + { + COMN_MARK_BEAST_XLOCAL(&deleteBeast->ACLOroot, xaction); + if (COMN_ForceBeastWrite(genMsg, deleteBeast, xaction) != zOK) + { + status = zFAILURE; + goto cleanup; + } + } + +cleanup: + if (deleteBeast != NULL && + deleteBeast != lastBeast && + deleteBeast != prevBeast) + { + COMN_UnlatchAndRelease(&deleteBeast, XLATCHED); + } + if (lastBeast != NULL && + lastBeast != prevBeast) + { + COMN_UnlatchAndRelease(&lastBeast, XLATCHED); + } + if (prevBeast != NULL) + { + COMN_UnlatchAndRelease(&prevBeast, XLATCHED); + } + RTN_STATUS(status); +} + +/**************************************************************************** + * + * This routine will remove trustee and rights from a file system object. + * This function assumes that auth latch is already held. + * + ****************************************************************************/ +STATUS ZAS_RemoveLatchedACLEntry( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + UserID_t *trusteeID, + NINT purgedFileFlag, + Xaction_s *xaction) + /* FixFixFix6 -- + * need to do the right thing when files are going to salvage */ +{ + ZASAuthorizeInfo_s *authInfo; + Xaction_s *localXaction; + NINT rights; + Zid_t hlZid; + HardLinkBeast_s *hlBeast; + + ASSERT_MPKNSS_LOCK(); + authInfo = authBeast->AUTHauthInfo.zas; + + /* begin the transaction for removing an ACL */ + if (xaction == NULL) + { + zASSERT(!(authBeast->AUTHbstState & BST_STATE_XLOCAL)); + localXaction = COMN_BeginXLocal(authBeast); + } + else + { + localXaction = xaction; + } + if (ZAS_RemoveTrustee(genMsg, authBeast, trusteeID, &rights, + localXaction) != zOK) + { + goto cleanup; + } + + /* + * Remove visibility if the trustee was giving some type of rights. + */ + if (rights) + { + /* + * If this is a hardlink primary beast, we need to add/remove visibility + * for all parents, not just the first parent. + */ + if ((authBeast->AUTHhardLinkZid != zINVALID_ZID) && + !(authBeast->AUTHattributes & zFA_HARDLINK)) + { + for (hlZid = authBeast->AUTHhardLinkZid; hlZid != zINVALID_ZID; ) + { + hlBeast = COMN_LookupByZid(genMsg,authBeast->AUTHvolume,hlZid, + NOTLATCHED,TRUE); + if (hlBeast != NULL) + { + ZAS_RemoveVisibility(genMsg, localXaction, authBeast, + hlBeast->HARDLfirstParentZid, trusteeID, 1, TRUE); + + hlZid = hlBeast->HARDLhardLinkZid; + COMN_Release(&hlBeast); + } + else + { + zASSERT("Broken hard link chain"==NULL); + hlZid = zINVALID_ZID; + } + } + } + else + { + zASSERT(!(authBeast->AUTHattributes & zFA_HARDLINK)); + + ZAS_RemoveVisibility(genMsg, localXaction, authBeast, + authBeast->AUTHfirstParentZid, trusteeID, 1, TRUE); + } + } + + if (!(authBeast->AUTHattributes & zFA_SUBDIRECTORY) || + authBeast->AUTHcomnOps.BST_isDirectoryEmpty(genMsg, &authBeast->AUTHnamed, zNTYPE_FILE)) + { /* this object has no objects below it */ + authInfo->p.cacheIndex = INVALID_EACL_CACHE_INDEX; /* invalidate the cache pointer */ + } + else + { + ZAS_InvalidateEACLCacheEntries(genMsg, trusteeID, TRUE); + } + authInfo->flags |= ZAS_ALLOW_FORCED_WRITE; + VOL_insertEFLEntry(genMsg, &authBeast->AUTHroot, + EFL_FILE_STATE_MODIFY_METADATA, NULL, localXaction); + authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE; + + if (xaction == NULL) + { + COMN_EndXLocal(authBeast, &localXaction); + } + return zOK; + +cleanup: + if (xaction == NULL) + { + COMN_EndXLocal(authBeast, &localXaction); + } + return zFAILURE; +} + +/**************************************************************************** + * + * This routine will remove trustee and rights from a file system object + * + ****************************************************************************/ +STATUS ZAS_RemoveACLEntry( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + UserID_t *trusteeID, + NINT purgedFileFlag) + /* FixFixFix6 -- + * need to do the right thing when files are going to salvage */ +{ + ZASAuthorizeInfo_s *authInfo; + STATUS status = zFAILURE; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_RemoveACLEntry); + + /* Defect #306666. We can't allow unlicensed connection access */ + if (!ConnectionIsLoggedIn(genMsg->pssConn.id)) + { + /* They are not logged in (LICENCED), so limit their access */ + SetErrno(genMsg, zERR_NO_TRUSTEE_CHANGE_PRIVILEGE); + goto cleanupError; + } + + if (authBeast->AUTHvolume->VOLenabledAttributes & zATTR_READONLY) + { + SetErrno(genMsg, zERR_VOLUME_READ_ONLY); + return zFAILURE; + } + + authInfo = authBeast->AUTHauthInfo.zas; + X_LATCH(&authInfo->authLatch); + + status = ZAS_RemoveLatchedACLEntry(genMsg, authBeast, trusteeID, + purgedFileFlag, NULL); + + UNX_LATCH(&authInfo->authLatch); + +cleanupError: + RTN_STATUS(status); +} + +/**************************************************************************** + * This routine will return the effective rights for a beast using the + * IDs in the connection structure. + ****************************************************************************/ +STATUS ZAS_GetEffectiveRights( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZID, + NINT *effectiveRights) +{ + NSSConnection_s *pssConn; + STATUS status; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_GetEffectiveRights); + + if ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) == NULL) + RTN_STATUS(zFAILURE); + +// Removed because supervisor should not be able to see directories that are +// marked for connection zero only +// +// if (pssConn->privileges & SUPERVISOR) +// { /* if the connection has supervisor privilege allow all rights */ +// *effectiveRights = -1; +// RTN_STATUS(zOK); +// } + + /* + * NDS can call back into the file system while it is resolving a + * connection. In this case the authListLatch is already held and we + * will deadlock. To avoid this we check to see we are on connection + * zero and if the condition exist that would indicate we are trying + * to resolve this connection. If so we give it rights to continue. + */ + if ((genMsg->pssConn.id == zSYS_CONNECTION) && + IS_XLATCHED(&pssConn->authInfo.authListLatch) && + (CNCT_LatchingConnection == zSYS_CONNECTION)) + { + *effectiveRights = zVALID_TRUSTEE_RIGHTS; + RTN_STATUS(zOK); + } + S_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + status = ZAS_GetEffectiveRightsByIDs(genMsg, authBeast, parentZID, + (genMsg->pssConn.ptr->flags & CNCTFL_SECURE_ACCESS) ? TRUE : FALSE, + IsSupervisor(genMsg->pssConn.id), + genMsg->pssConn.ptr->authInfo.numAuthenticatedIDs, + &genMsg->pssConn.ptr->authInfo.authenticatedIDs[0], + effectiveRights); + UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + RTN_STATUS(status); +} + + +/**************************************************************************** + * Re-create the visibility lists + ****************************************************************************/ +void ZAS_RebuildVisibilityLists( + GeneralMsg_s *genMsg, + Volume_s *vol, + Zid_t *zidArray, + NINT numArrayEntries, + VisRebuildStats_s *stats, + unicode_t *name) +{ + Zid_t startingZid = 0; + NINT numReturnedZids; + RootBeast_s *beast; + NINT index; + QUAD totalBeasts; + STATUS status; + Zid_t hlZid; + HardLinkBeast_s *hlBeast; + + /* + * Go through the entire beast tree and re-add all trustees + */ + aprintf(YELLOW, + MSG("Visbility rebuild: Rebuilding visiblity information on %U\n", 206), + name); + totalBeasts = 0; + vol->VOLzidInProcess = 0; + vol->v_statusFlag |= VOL_SF_CLEAN_VIS_REBUILD; + do + { + /* + * Check to see if someone is wanting to deactivate the volume. + * If so we stop our thread so the volume can be deactivated. + */ + if (vol->v_statusFlag & VOL_SF_LEAVING_ACTIVE_STATE_CLEANUP) + { + aprintf(LRED, + MSG("STOPPING VISIBILITY REBUILD ON %U BECAUSE OF VOLUME DEACTIVATE\n", 241), + name); + goto exit; + } + + if (vol->VOLcomnVolOps.VOL_browseBeastsInVolume(genMsg, + vol, SELECT_BEASTS_ALL, numArrayEntries, &startingZid, zidArray, + &numReturnedZids) != zOK) + { + aprintf(LRED, MSG("Visibility rebuild on volume %U:\n" + "Error %d getting object list while adding visibility.\n", 244), + name, GetErrno(genMsg)); + goto exit; + } + + /* Process each entry */ + for (index = 0; index < numReturnedZids; index++) + { + totalBeasts++; + if (!(totalBeasts % 10000)) + { + aprintf(LGREEN, + "(%U) Visibility rebuild pass 2: %Ld objects processed\n", + name, totalBeasts); + } + vol->VOLzidInProcess = zidArray[index]; + if ((beast = COMN_LookupByZid(genMsg, vol, + zidArray[index], SLATCHED, TRUE)) == NULL) + { +zASSERT(GetErrno(genMsg) != 20000); + /* + * Only report an error if it not one of errors we know + * can happen because of timing with beast delete. + */ + if (GetErrno(genMsg) != zERR_INVALID_BEAST_ID && + GetErrno(genMsg) != zERR_INVALID_BEAST_ID) + { + aprintf(LRED, MSG("Visibility rebuild on volume %U:\n" + "Error %d looking up an object. ZID[%d]=%Ld\n", 247), + name, GetErrno(genMsg), index, zidArray[index]); + } + ClearErrno(genMsg); + continue; + } + + /* + * If this is a normal file/dir then processes any trustees + */ + if ((COMN_IsDerivedFrom(beast, zFTYPE_FILE)) && + (!(((File_s *)beast)->FILEattributes & zFA_HARDLINK))) + { + /* + * If this is a hardlink primary beast, we need to add/remove visibility + * for all parents, not just the first parent. + */ + if (((File_s *)beast)->FILEhardLinkZid != zINVALID_ZID) + { + for (hlZid = ((File_s *)beast)->FILEhardLinkZid; hlZid != zINVALID_ZID; ) + { + hlBeast = COMN_LookupByZid(genMsg,beast->ROOTvolume, + hlZid,NOTLATCHED,TRUE); + if (hlBeast != NULL) + { + if ((status = ZAS_AddBeastVisibility(genMsg, + (AuthBeast_s *)beast, ((File_s *)hlBeast)->FILEfirstParentZid, + FALSE, stats, FALSE)) != zOK) + { + aprintf(LRED, MSG("Visibility rebuild on volume %U:\n" + "Error %d looking up an object while adding visibility.\n",249), + name, GetErrno(genMsg)); + + } + + hlZid = hlBeast->HARDLhardLinkZid; + COMN_Release(&hlBeast); + } + else + { + zASSERT("Broken hard link chain"==NULL); + hlZid = zINVALID_ZID; + } + } + } + else + { + if ((status = ZAS_AddBeastVisibility(genMsg, + (AuthBeast_s *)beast, ((File_s *)beast)->FILEfirstParentZid, + FALSE, stats, FALSE)) != zOK) + { + aprintf(LRED, MSG("Visibility rebuild on volume %U:\n" + "Error %d looking up an object while adding visibility.\n", 249), + name, GetErrno(genMsg)); + } + } + } + COMN_UnlatchAndRelease(&beast, SLATCHED); + } + } while (numReturnedZids > 0); + +exit: + vol->v_statusFlag &= ~VOL_SF_CLEAN_VIS_REBUILD; + ClearErrno(genMsg); + return; +} + + +/**************************************************************************** + * The thread to rebuild the visibility list for the given volume + ****************************************************************************/ +void ZAS_VisibilityRebuildThread( + FsmLite_s *fsm, + VisRebParms_s *parms) +{ + enum + { + NUM_REQUESTED_ZIDS = 100 + }; + + GeneralMsg_s genMsg; + Zid_t startingZid = 0; + Zid_t *zidArray; + NINT numReturnedZids; + RootBeast_s *beast; + NINT index; + Xaction_s *xaction; + ZASAuthorizeInfo_s *authInfo; + VisRebuildStats_s stats; + QUAD totalBeasts; + Volume_s *vol = parms->vol; + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + COMN_LockVolumeActive(&genMsg, vol, FALSE); + zidArray = malloc(NUM_REQUESTED_ZIDS * sizeof(Zid_t)); + if (zidArray == NULL) + { + aprintf(LRED, + MSG("Visibility rebuild on volume %U:\n" + "Unable to get enough memory to complete the rebuild.\n", 250), + parms->name); + goto exit; + } + + stats.VisNumBeasts = 0; + stats.VisNumOverflowRemoved = 0; + stats.VisNumFilesCleaned = 0; + stats.VisNumTrusteesProcessed = 0; + + /* + * Go through the entire beast tree and remove all visibility information. + */ + aprintf(YELLOW, + MSG("Visibility rebuild: Removing visiblity information from %U\n", 251), + parms->name); + totalBeasts = 0; + do + { + /* + * Check to see if someone is wanting to deactivate the volume. + * If so we stop our thread so that the volume can be deactivated. + */ + if (vol->v_statusFlag & VOL_SF_LEAVING_ACTIVE_STATE_CLEANUP) + { + aprintf(LRED, + MSG("STOPPING VISIBILITY REBUILD ON %U BECAUSE OF VOLUME DEACTIVATE\n", 252), + parms->name); + goto exitStats; + } + if (vol->VOLcomnVolOps.VOL_browseBeastsInVolume(&genMsg, + vol, SELECT_BEASTS_ALL, NUM_REQUESTED_ZIDS, + &startingZid, zidArray, &numReturnedZids) != zOK) + { + aprintf(LRED, + MSG("Visibility rebuild on volume %U:\n" + "Error %d getting object list.\n", 253), parms->name, + GetErrno(&genMsg)); + goto exitFreeMem; + } + /* Process each entry */ + for (index = 0; index < numReturnedZids; index++) + { + totalBeasts++; + if (!(totalBeasts % 10000)) + { + aprintf(LGREEN, + "(%U) Visibility rebuild pass 1: %Ld objects processed\n", + parms->name, totalBeasts); + } + if ((beast = COMN_LookupByZid(&genMsg, vol, + zidArray[index], XLATCHED, TRUE)) == NULL) + { +zASSERT(GetErrno(&genMsg) != 20000); + aprintf(LRED, MSG("Visibility rebuild on volume %U:\n" + "Error %d looking up an object. ZID[%d]=%Ld\n", 254), + parms->name, GetErrno(&genMsg), index, zidArray[index]); + ClearErrno(&genMsg); + continue; + } + + stats.VisNumBeasts++; + + /* + * If this is a visibility overflow beast then just get rid of it. + */ + if (beast->ROOTbeastClass->classID == zFTYPE_ZAS_VIS_OVERFLOW) + { + xaction = COMN_BeginXLocal(beast); + if (BST_delete(&genMsg, NULL, beast, NULL, NULL, xaction, + FALSE, TRUE) != zOK) + { + ClearErrno(&genMsg); + zASSERT("Failed to delete trustee overflow beast"==NULL); + } + COMN_EndXLocal(beast, &xaction); + COMN_UnlatchAndRelease(&beast, XLATCHED); + stats.VisNumOverflowRemoved++; + continue; + } + + /* + * If this is a normal file/dir then get rid of the visibility + * information. + */ + if (COMN_IsDerivedFrom(beast, zFTYPE_FILE)) + { + authInfo = ((AuthBeast_s *)beast)->AUTHauthInfo.zas; + /* If there are visibility entries then clear them */ + if (authInfo->p.numVisibilityTrusteesAssigned || + authInfo->p.visibilityOverflow) + { + zASSERT(!authInfo->p.visibilityOverflow || + authInfo->p.numVisibilityTrusteesAssigned == 4); + authInfo->p.numVisibilityTrusteesAssigned = 0; + authInfo->p.visibilityOverflow = zINVALID_ZID; + xaction = COMN_BeginXLocal(beast); + COMN_MARK_BEAST_XLOCAL(beast, xaction); + COMN_ForceBeastWrite(&genMsg, beast, xaction); + COMN_EndXLocal(beast, &xaction); + stats.VisNumFilesCleaned++; + } + } + COMN_UnlatchAndRelease(&beast, XLATCHED); + } + } while (numReturnedZids > 0); + + /* Rebuild the visibility lists */ + ZAS_RebuildVisibilityLists(&genMsg, vol, zidArray, NUM_REQUESTED_ZIDS, + &stats, parms->name); + +exitStats: + aprintf(LCYAN, MSG( "Visibility rebuild finished on volume %U\n" + "Objects examined: %Ld\n" + "Objects cleaned: %Ld\n" + "Overflow objects removed: %Ld\n" + "Trustees re-added: %Ld\n", 255), + parms->name, + stats.VisNumBeasts, + stats.VisNumFilesCleaned, + stats.VisNumOverflowRemoved, + stats.VisNumTrusteesProcessed); + +exitFreeMem: + free(zidArray); +exit: + vol->v_statusFlag &= ~VOL_SF_CLEAN_VIS_SCHEDULED; + COMN_UnlockVolumeActive(vol, FALSE); + free(parms); + free(fsm); + return; +} + + +/**************************************************************************** + * Rebuild the visibility list for the given volume + ****************************************************************************/ +void ZAS_VisibilityRebuild( + GeneralMsg_s *genMsg, + Volume_s *vol, + unicode_t *name) +{ + VisRebParms_s *parms; + FsmLite_s *fsm; +#if NSS_DEBUG IS_ENABLED + STATIC NINT fsmInstance = 0; +#endif + + + if (vol->state != zVOLSTATE_ACTIVE) + { + aprintf(LRED, MSG("Volume %U must be active to " + "rebuild visibility.\n", 297), name); + goto exit; + } + + /* Check to see if thes volume has the ZAS auth model running on it */ + + if (vol->p.authModelID != zFTYPE_ZAS_AUTH_MODEL) + { + aprintf(LRED, MSG("Volume %U does not use visibility lists\n", 298), + name); + goto exit; + } + + /* Check to see if it is already running */ + if (vol->VOLv_statusFlag & VOL_SF_CLEAN_VIS_SCHEDULED) + { /* There is already one running */ + aprintf(LRED, MSG("Volume %U is already rebuilding visibility.\n", 299), + name); + goto exit; + } + vol->v_statusFlag |= VOL_SF_CLEAN_VIS_SCHEDULED; + + /* Start up a seperate thread to do the processing */ + fsm = malloc(sizeof(FsmLite_s)); + if (fsm == NULL) + { + aprintf(LRED, MSG("Not enough memory to start visibility rebuild\n", + 300)); + vol->v_statusFlag &= ~VOL_SF_CLEAN_VIS_SCHEDULED; + goto exit; + } + + /* Setup parameters for thread */ + parms = malloc(sizeof(VisRebParms_s)); + if (parms == NULL) + { + aprintf(LRED, MSG("Not enough memory to start visibility rebuild\n", + 301)); + vol->v_statusFlag &= ~VOL_SF_CLEAN_VIS_SCHEDULED; + free(fsm); + goto exit; + } + + parms->vol = vol; + unicpy(parms->name, name); + + FSMLITE_INIT(fsm, "FSM for visibility rebuild ", ++fsmInstance); + WORK_Schedule(fsm, ZAS_VisibilityRebuildThread, (ADDR)parms); + aprintf(WHITE, + MSG("Visibility rebuild started on volume \"%U\".\n",302), name); + +exit: + ClearErrno(genMsg); + return; +} + +/**************************************************************************** + * Process command line to start rebuilding of a volumes visibility list. + ****************************************************************************/ +void ZAS_VisibilityRebuildByName( + GeneralMsg_s *genMsg, + unicode_t *name) +{ + Volume_s *vol; + Volume_s *adminVol; + typedef struct Stack_s { + unicode_t volName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + adminVol = COMN_GetAdminVolume(); + /* + * See if doing ALL volumes + */ + if (uniicmp(name, MSGNot(L"all")) == 0) + { + DQ_FOREACH(&NSSMasterVolumeList, vol, Volume_s, masterVolLink) + { + if (vol != adminVol) /* skip the ADMIN volume */ + { + COMN_GetVolumeName(genMsg, vol, aStack->volName, sizeof(aStack->volName)); + COMN_USE_BEAST(&vol->VOLroot); + (void)ZAS_VisibilityRebuild(genMsg, vol, aStack->volName); + BST_UNUSE_BEAST(&vol->VOLroot); + } + } + } + else + { + /* + * Change the given volume + */ + vol = COMN_VolumeNameLookup(genMsg, name, FALSE, NULL); + if (vol == NULL) + { + errPrintf(WHERE, Module, 0, + MSG("Volume %U not found. Check your spelling and type NSS /volumes.\n", 303), name); + STACK_FREE(); + return; + } + + + if (vol == adminVol) + { + BST_UNUSE_BEAST(&vol->VOLroot); + STACK_FREE(); + return; + } + + ZAS_VisibilityRebuild(genMsg, vol, name); + BST_UNUSE_BEAST(&vol->VOLroot); /* remove useCount added by lookup*/ + } + STACK_FREE(); + return; +} + +/**************************************************************************** + * This routine will return the effective rights for a beast using the + * IDs in the connection structure. + ****************************************************************************/ +STATUS ZAS_GetParentsEffectiveRights( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZID, + NINT *effectiveRights) +{ + NSSConnection_s *pssConn; + AuthBeast_s *parentBeast; + STATUS status; + + ENTER(TAUTH, ZAS_GetEffectiveRights); + + if ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) == NULL) + { + RTN_STATUS(zFAILURE); + } + +// Removed because supervisor should not be able to see directories that are +// marked for connection zero only +// +// if ( IsSupervisor(genMsg->pssConn.id) +// { /* if the connection has supervisor privilege allow all rights */ +// *effectiveRights = -1; +// RTN_STATUS(zOK); +// } + + /* Open the parent */ + if (parentZID != zINVALID_ZID) + { + parentBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, + authBeast->AUTHvolume, parentZID, NOTLATCHED); + if (parentBeast == NULL) + { + RTN_STATUS(zFAILURE); + } + } + else + { /* at the root */ + effectiveRights = 0; /* the root's parent has no rights */ + RTN_STATUS(zOK); + } + parentZID = parentBeast->AUTHfirstParentZid; + + /* + * NDS can call back into the file system while it is resolving a + * connection. In this case the authListLatch is already held and we + * will deadlock. To avoid this we check to see we are on connection + * zero and if the condition exist that would indicate we are trying + * to resolve this connection. If so we give it rights to continue. + */ + + if ((genMsg->pssConn.id == zSYS_CONNECTION) && + IS_XLATCHED(&pssConn->authInfo.authListLatch) && + (CNCT_LatchingConnection == zSYS_CONNECTION)) + { + *effectiveRights = zVALID_TRUSTEE_RIGHTS; + RTN_STATUS(zOK); + } + S_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + status = ZAS_GetEffectiveRightsByIDs(genMsg, parentBeast, parentZID, + (genMsg->pssConn.ptr->flags & CNCTFL_SECURE_ACCESS) ? TRUE : FALSE, + IsSupervisor(genMsg->pssConn.id), + genMsg->pssConn.ptr->authInfo.numAuthenticatedIDs, + &genMsg->pssConn.ptr->authInfo.authenticatedIDs[0], + effectiveRights); + UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + COMN_Release(&parentBeast); + RTN_STATUS(status); +} + +/**************************************************************************** + * This routine will return all the effective rights for a beast. If it is + * successful it returns a malloc'ed structure that must be freed by the caller. + ****************************************************************************/ +STATUS ZAS_GetEffectiveACL( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZID, + AuthCacheNode_s **effectiveACL, + BOOL canBlock, + BOOL *freeEACL) +{ + AuthCacheNode_s *computedEACL; + AuthCacheNode_s *newEACL; + AuthCacheNode_s *newerEACL; + AuthBeast_s *beastMemory[BEAST_STACK_ALLOC_SIZE]; + AuthBeast_s *(*beastStack)[]; + STATUS status; + AuthBeast_s *parentBeast; + AuthBeast_s *originalBeast; + NINT stackPtr = 0; + NINT tempStackPtr; + NINT sequence; + UserID_t trusteeID; + NINT rights; + NINT attributes; + NINT index; + NINT numACLs; + NINT numACLslots; + NINT maxStackEntries = BEAST_STACK_ALLOC_SIZE; + NINT originalResetCount = 999; + BOOL freeEACLFlag = FALSE; + BOOL cacheLatched = FALSE; + + ASSERT_MPKNSS_LOCK(); + +#if NSS_DEBUG IS_ENABLED +AuthERRequests++; +#endif + + *effectiveACL = NULL; + *freeEACL = FALSE; + + /* + * If this beast comes from the persistent admin volume but its zid + * is too low then we are getting its parent from the regular admin + * volume. Change the parent to the first parent of the beast. + */ + + if ((authBeast->AUTHvolume == PersistAdminVolume) && (parentZID < + AVOL_FIRST_PERSISTENT_ZID)) + { + parentZID = authBeast->AUTHfirstParentZid; + } + + /* + * The beast must be latched when coming into this routine. It may be + * uplatched during part of the routine, but it will be returned to the + * same latch state it started at. + */ + + beastStack = &beastMemory; + + COMN_USE_BEAST(&authBeast->AUTHroot); + + originalBeast = authBeast; + + /* + * Search the full path (backwards) for the first beast with a valid + * effective ACL. If there is no effective ACL in a beast then push + * its ZID on the stack and keep looking. + */ + + for(;;) + { + //X_LATCH(&authBeast->AUTHauthInfo.zas->authLatch); + X_LATCH(&AuthCache.latch); + originalResetCount = AuthCache.resetCount; + + /* + * As a performance enhancement we first check if the + * beast's restartCount is still valid. If the Beast + * does not match the the activation count then the + * beast is 'old' and must not be in the cache. + */ + + if ( authBeast->AUTHvolume->v_restartCount == + authBeast->AUTHauthInfo.zas->p.restartCount ) + { /* Beast is at correct activation count so see if auth info is + * in the cache. */ + computedEACL = ZAS_GetEACLCacheEntry( + authBeast->AUTHauthInfo.zas->p.cacheIndex, + authBeast->AUTHauthInfo.zas->p.signature); + } + else + { /* Must init because this is used twice more */ + computedEACL = NULL; + } + + if (computedEACL != NULL) + { /* found an effective ACL */ +#if NSS_DEBUG IS_ENABLED +AuthERHits++; +#endif + //UNX_LATCH(&authBeast->AUTHauthInfo.zas->authLatch); + /* + * We can avoid doing this latch as long as we can be sure that + * we will not block while using computedEACL. Since the code + * that requires the latch is in the loop for processing + * stack entries, we should be able to avoid the latch if we are + * not going into that loop. + */ + // if (stackPtr > 0) + // { + // X_LATCH(&AuthCache.latch); + // cacheLatched = TRUE; + // } + COMN_Release(&authBeast); + cacheLatched = TRUE; + break; /* exit the loop */ + } + UNX_LATCH(&AuthCache.latch); + //X_LATCH(&authBeast->AUTHauthInfo.zas->authLatch); + + /* no EACL in the cache -- add to the stack */ + ZAS_PUSH_BEAST(status, errorSet, authBeast, stackPtr, maxStackEntries, + beastMemory, beastStack); + + if (parentZID != zINVALID_ZID) + { + parentBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, + authBeast->AUTHvolume, parentZID, NOTLATCHED); + if (parentBeast == NULL) + { + status = zERR_UNABLE_TO_OPEN_BEAST; + goto errorSet; + } + } + else + { /* at the root */ + zASSERT(authBeast->AUTHfirstParentZid == zINVALID_ZID || + COMN_IsDerivedFrom(&authBeast->AUTHroot, zFTYPE_VOLUME)); + break; + } + authBeast = parentBeast; + parentZID = authBeast->AUTHfirstParentZid; + } + + /* compute effective ACLs for each beast on the stack and put them in + * the cache. */ + + tempStackPtr = stackPtr; + while (tempStackPtr > 0) + { /* while there are entries on the ZID stack */ + authBeast = (*beastStack)[--tempStackPtr]; + numACLs = 0; + + /* allocate a buffer for a new cache entry */ + if (computedEACL == NULL) + { /* did not find EACL -- don't put anything in the new one */ + newEACL = malloc(sizeof(AuthCacheNode_s)); + if (newEACL == NULL) + { /* out of memory */ + status = zERR_NO_MEMORY; + goto errorSet; + } + numACLslots = 1; + } + else + { + numACLslots = computedEACL->EACL.numEntries; + newEACL = (AuthCacheNode_s *)malloc(EACL_SIZE(numACLslots)); + if (newEACL == NULL) + { /* out of memory */ + status = zERR_NO_MEMORY; + goto errorSet; + } + memcpy(newEACL, computedEACL, sizeof(AuthCacheNode_s) - sizeof(EffectiveACL_s)); + + /* apply the inherited rights mask and inheritance flags*/ + for (index = 0; index < computedEACL->EACL.numEntries; index++) + { + if (computedEACL->EACL.entry[index].attributes & + zAUTHORIZE_INHERIT_DOWN) + { + newEACL->EACL.entry[numACLs].rights = + (computedEACL->EACL.entry[index].rights & + authBeast->AUTHauthInfo.zas->p.inheritedRightsMask) & + zVALID_TRUSTEE_RIGHTS; /* strip off special rights as well*/ + if (newEACL->EACL.entry[numACLs].rights != 0) + { /* if there are rights assigned */ + newEACL->EACL.entry[numACLs].trusteeID = + computedEACL->EACL.entry[index].trusteeID; + newEACL->EACL.entry[numACLs].attributes = + computedEACL->EACL.entry[index].attributes; + numACLs++; + } + } + } + } + + if (freeEACLFlag) + { /* if the computed EACL has not been assigned to the cache then free it */ + free(computedEACL); + freeEACLFlag = FALSE; + } + + if (cacheLatched) + { + UNX_LATCH(&AuthCache.latch); + cacheLatched = FALSE; + } + + newEACL->EACL.numEntries = numACLs; + /* FixFixFix6 -- check on multi-domain NDS considerations */ + newEACL->domainID = 0; + + /* merge in the ACLs from this beast */ + /* FixFixFix6 -- have not considered negative ACLs */ + sequence = 0; + while (sequence != -1) + { /* while there are still ACL entries */ + if (ZAS_GetAnACL(genMsg, authBeast, &sequence, &trusteeID, &rights, + &attributes) != zOK) + { + status = GetErrno(genMsg); + goto errorSet; + } + if (sequence == -1) + { /* no more entries */ + break; + } + /* + * If this is the special secure user then setup special rights. + */ + if (LB_GUIDCompare(&trusteeID, &zSECURE_CONNECTION_USERID) == 0) + { + rights |= (zAUTHORIZE_ACCESS_CONTROL | zAUTHORIZE_SECURE); + free(newEACL); + newEACL = malloc(sizeof(AuthCacheNode_s)); + if (newEACL == NULL) + { /* out of memory */ + status = zERR_NO_MEMORY; + goto errorSet; + } + numACLs = 0; + index = 0; + numACLslots = 1; + sequence = -1; /* don't do any more */ + } + else + { + for (index = 0; index < numACLs; index++) + { /* search the current EACL entries */ + if (LB_GUIDCompare(&newEACL->EACL.entry[index].trusteeID, &trusteeID) == 0) + { /* The trustee is already in the effective ACL */ + /* Don't lose supervisor rights */ + newEACL->EACL.entry[index].rights &= zAUTHORIZE_SUPERVISOR; + newEACL->EACL.entry[index].rights |= rights; + newEACL->EACL.entry[index].attributes = attributes; + goto nextEntry; + } + else if (LB_GUIDCompare(&newEACL->EACL.entry[index].trusteeID, &trusteeID) > 0) + { /* need to insert a new entry */ + break; + } + } + } + + /**/ + /* insert a new entry */ + /**/ + + /* make more room to insert a new entry -- if we need to */ + if (numACLs == numACLslots) + { + newerEACL = realloc(newEACL, + EACL_SIZE(numACLs + EACL_GROW_AMOUNT)); + if (newerEACL == NULL) + { + free(newEACL); + status = zERR_NO_MEMORY; + goto errorSet; + } + newEACL = newerEACL; + numACLslots = numACLs + EACL_GROW_AMOUNT; + } + + /* keep in sorted order */ + if (index < numACLs) + { /* need to insert, so shift the entries up by one */ + memmove(&newEACL->EACL.entry[index+1], + &newEACL->EACL.entry[index], + sizeof(ACLEntry_s)*(numACLs-index)); + } + newEACL->EACL.entry[index].trusteeID = trusteeID; + newEACL->EACL.entry[index].rights = rights; + newEACL->EACL.entry[index].attributes = attributes; + numACLs++; +nextEntry: + continue; + } + + + if (numACLs < numACLslots) + { + if (numACLs > 0) + { /* if there are still some EACL entries */ + /* resize the EACL to the needed size */ + newerEACL = realloc(newEACL, EACL_SIZE(numACLs)); + if (newerEACL == 0) + { + status = zERR_NO_MEMORY; + goto errorSet; + } + newEACL = newerEACL; + } + } + newEACL->EACL.numEntries = numACLs; + + X_LATCH(&AuthCache.latch); + cacheLatched = TRUE; + if ((newerEACL = ZAS_AddEACLCacheEntry(newEACL, originalResetCount, + &authBeast->AUTHauthInfo.zas->p.cacheIndex)) != NULL) + { + authBeast->AUTHauthInfo.zas->p.signature = newerEACL->signature; + authBeast->AUTHauthInfo.zas->p.restartCount = + authBeast->AUTHvolume->v_restartCount; + freeEACLFlag = FALSE; + computedEACL = newerEACL; + } + else + { + authBeast->AUTHauthInfo.zas->p.cacheIndex = INVALID_EACL_CACHE_INDEX; + freeEACLFlag = TRUE; + computedEACL = newEACL; + } + } + if (cacheLatched) + { +#if NSS_DEBUG IS_ENABLED +AuthERImmediateHits++; +#endif + UNX_LATCH(&AuthCache.latch); + cacheLatched = FALSE; + } + + /* + * If the computed EACL has not been assigned to cache then pass it + * back to the caller. If it is assigned to the cache and the caller + * can block before using it then we need to make a copy because it can + * be released from the cache as soon as we yield. + */ + if (freeEACLFlag) + { + *effectiveACL = computedEACL; + *freeEACL = TRUE; + freeEACLFlag = FALSE; + } + else + { /* It has been assigned to the cache */ + if (canBlock) + { + int size = EACL_SIZE(computedEACL->EACL.numEntries); + *effectiveACL = malloc(size); + if (*effectiveACL == NULL) + { /* out of memory */ + status = zERR_NO_MEMORY; + goto errorSet; + } + memcpy(*effectiveACL, computedEACL, size); + *freeEACL = TRUE; + } + else + { + *effectiveACL = computedEACL; + *freeEACL = FALSE; + } + } + status = zOK; + +exit: + ZAS_CLEANUP_BEAST_STACK(stackPtr, maxStackEntries, beastStack); + if (freeEACLFlag) + { /* if the computed EACL has not been assigned to the cache or is + * not being returned to the caller then free it */ + free(computedEACL); + } + if (cacheLatched) + { + UNX_LATCH(&AuthCache.latch); + cacheLatched = FALSE; + } + return status; + +errorSet: + SetErrno(genMsg, status); + status = zFAILURE; + goto exit; +} + +/**************************************************************************** + * This routine will return the effective rights for a beast given an array + * of authenticated IDs. + ****************************************************************************/ +STATUS ZAS_GetEffectiveRightsByIDs( + GeneralMsg_s *genMsg, + AuthBeast_s *authBeast, + Zid_t parentZID, + BOOL secureAccess, + BOOL supervisor, + NINT numIDs, + UserID_t *IDs, + NINT *effectiveRights) +{ + AuthCacheNode_s *computedEACL; + NINT numEntries; + NINT index; + NINT connectIndex; + SNINT compare; + BOOL freeEACL; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_GetEffectiveRightsByIDs); + + /* + * IMPORTANT: Do not block after calling this function. The returned + * computed EACL can be in the cache and the cache is not latched at this + * point in time. + */ + if (ZAS_GetEffectiveACL(genMsg, authBeast, parentZID, &computedEACL, FALSE, + &freeEACL) != zOK) + { + goto error; + } + numEntries = computedEACL->EACL.numEntries; + + if (supervisor) + { + *effectiveRights = zVALID_TRUSTEE_RIGHTS; + } + else + { + *effectiveRights = 0; + } + if (numEntries > 0) + { /* if there are any entries in the effective ACL */ + + /* + * If the first entry in the EACL is the special connection zero + * trustee then it takes precedence over all other entries. It + * means only connection zero access is allowed and given the + * specified rights. + */ + if (LB_GUIDCompare(&computedEACL->EACL.entry[0].trusteeID, + &zSECURE_CONNECTION_USERID) == 0) + { + if (secureAccess || (genMsg->flags & ALLOW_SECURE_ACCESS)) + { + *effectiveRights = computedEACL->EACL.entry[0].rights; + } + else + { + *effectiveRights = 0; + } + } + else + { + /* + * Compute rights in the normal case + */ + for (connectIndex = 0; connectIndex < numIDs; connectIndex++) + { /* for each entry in the connection structure */ + for (index = 0; index < numEntries; + index++) + { /* for each entry in the effective ACL */ + compare = LB_GUIDCompare( + &computedEACL->EACL.entry[index].trusteeID, + &IDs[connectIndex]); + if (compare == 0) + { + /* FixFixFix6 -- not checking for negative rights */ + *effectiveRights |= + computedEACL->EACL.entry[index].rights; + break; + } + else if (compare > 0) + { /* already past possible match */ + break; + } + } + } + } + } + if (*effectiveRights & zAUTHORIZE_SUPERVISOR) + { + *effectiveRights |= zVALID_TRUSTEE_RIGHTS; + } + if (computedEACL && freeEACL) + { + free(computedEACL); + } + + RTN_STATUS(zOK); + +error: + RTN_STATUS(zFAILURE); +} + +/*=========================================================================== + *=========================================================================== + *=========================================================================== + * + * ZAS ACL OVERFLOW BEAST + * + *=========================================================================== + *=========================================================================== + *===========================================================================*/ + +/*************************************************************************** + * This routine is called when an overflow beast is allocated in memory + ***************************************************************************/ +STATUS ACLO_ConstructBeast( + GeneralMsg_s *genMsg, + void *overflowBeast_LX) +{ + ZasAclOverflowBeast_s *overflowBeast = + (ZasAclOverflowBeast_s *) overflowBeast_LX; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ACLO_ConstructBeast); + overflowBeast->acl = malloc(OVERFLOW_ALLOC_UNIT * sizeof(ACLEntry_s)); + if (overflowBeast->acl == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + RTN_STATUS(zFAILURE); + } + overflowBeast->numAlloced = OVERFLOW_ALLOC_UNIT; + overflowBeast->p.nextOverflowZid = zINVALID_ZID; + overflowBeast->p.numEntries = 0; + RTN_STATUS(zOK); +} + +/*************************************************************************** + * This routine is called when an overflow beast is freed from memory + ***************************************************************************/ +void ACLO_DestructBeast( + void *overflowBeast_LX) +{ + ZasAclOverflowBeast_s *overflowBeast = + (ZasAclOverflowBeast_s *) overflowBeast_LX; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ACLO_DestructBeast); + if (overflowBeast->acl != NULL) + { + free(overflowBeast->acl); + } + RTN_VOID(); +} + +/**************************************************************************** + * ZAS OVERFLOW BEAST COMMON OPERATIONS definition + *****************************************************************************/ + +CommonBeastOps_s ACLO_ComnBeastOps = +{ + ACLO_ConstructBeast, /* construct */ + ACLO_DestructBeast, /* destruct */ + +// cnt NULL, /* BST_getNameUniquifier */ + NULL, /* BST_setupNameTypeSpecificInfo */ + NULL, /* BST_lookupByNameInDirectory*/ + NULL, /* BST_isDirectoryEmpty*/ + NULL, /* BST_addNameToDirectory*/ + NULL, /* BST_removeNameFromDirectory*/ + NULL, /* BST_modifyNameSpaceMaskInDirectory*/ + NULL, /* BST_setMatchAttributesInDirectory*/ + NULL, /* BST_wildcardLookup*/ + + NULL, /* BST_truncateFile*/ + NULL, /* BST_getStorageInfo*/ + NULL, /* BST_getExtentList*/ + NULL, /* BST_getPhysicalExtent*/ + NULL, /* BST_isBlockInBeast*/ + + NULL, /* BST_asyncReadFileBlk*/ + NULL, /* BST_getFileBlk*/ + NULL, /* BST_dfsReadUnits*/ + NULL, /* BST_dfsWriteUnits*/ + + NULL, /* BST_getZID*/ + NULL, /* BST_beastNotify*/ + NULL, /* BST_getInfo*/ + NULL, /* BST_modifyInfo*/ + NULL, /* BST_getInfoXML*/ + NULL /* BST_modifyInfoXML*/ +}; + +///*************************************************************************** +// * This routine is called when an overflow beast is written to storage +// ***************************************************************************/ +//NINT ACLO_PackedSize( +// ZasAclOverflowBeast_s *overflowBeast) +//{ +// ENTER(TAUTH, ACLO_PackedSize); +// RTN_NINT (sizeof(PersistentZasAclOverflowBeast_s) + +// (overflowBeast->p.numEntries * sizeof(ACLEntry_s))); +//} +// +///*************************************************************************** +// * This routine is called when an overflow beast is written to storage +// ***************************************************************************/ +//BYTE *ACLO_PackBeast( +// ZasAclOverflowBeast_s *overflowBeast, +// BYTE *storeBuffer) +//{ +// NINT len; +// +// ENTER(TAUTH, ACLO_PackBeast); +// len = overflowBeast->p.numEntries * sizeof(ACLEntry_s); +// memcpy(storeBuffer, &overflowBeast->p, sizeof(PersistentZasAclOverflowBeast_s)); +// storeBuffer += sizeof(PersistentZasAclOverflowBeast_s); +// zASSERT(overflowBeast->acl != NULL); +// memcpy(storeBuffer, overflowBeast->acl, len); +// RTN_PTR(storeBuffer + len); +//} +// +///*************************************************************************** +// * This routine is called when an overflow beast is read from storage +// ***************************************************************************/ +//BYTE *ACLO_UnpackBeast( +// GeneralMsg_s *genMsg, +// ZasAclOverflowBeast_s *overflowBeast, +// BYTE *storeBuffer) +//{ +// NINT len; +// +// ENTER(TAUTH, ACLO_UnpackBeast); +// memcpy(&overflowBeast->p, storeBuffer, sizeof(PersistentZasAclOverflowBeast_s)); +// storeBuffer += sizeof(PersistentZasAclOverflowBeast_s); +// len = overflowBeast->p.numEntries * sizeof(ACLEntry_s); +// zASSERT(len != 0); +// overflowBeast->acl = realloc(overflowBeast->acl, len); +// overflowBeast->numAlloced = overflowBeast->p.numEntries; +// if (overflowBeast->acl == NULL) +// { +// SetErrno(genMsg, zERR_NO_MEMORY); +// RTN_PTR(NULL); +// } +// memcpy(overflowBeast->acl, storeBuffer, len); +// RTN_PTR(storeBuffer + len); +//} +// +///*--------------------------------------------------------------------------- +// * beast STORAGE ops definition +// *---------------------------------------------------------------------------*/ +//StoragePoolBeastOps_s ACLO_StoragePoolOps[] = +//{ +// {zFTYPE_ZFS_POOL, ACLO_PackedSize, ACLO_PackBeast, ACLO_UnpackBeast}, +// /*{zFTYPE_ZFS_MEMPOOL, ACLO_PackedSize, ACLO_PackBeast, ACLO_UnpackBeast},*/ +// {zFTYPE_INVALID} +//}; + + +/*=========================================================================== + *=========================================================================== + *=========================================================================== + * + * ZAS VISIBILITY OVERFLOW BEAST + * + *=========================================================================== + *=========================================================================== + *===========================================================================*/ + +/*************************************************************************** + * This routine is called when an overflow beast is allocated in memory + ***************************************************************************/ +STATUS VISO_ConstructBeast( + GeneralMsg_s *genMsg, + void *overflowBeast_LX) +{ + ZasVisOverflowBeast_s *overflowBeast = + (ZasVisOverflowBeast_s *) overflowBeast_LX; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VISO_ConstructBeast); + overflowBeast->vis = malloc(OVERFLOW_ALLOC_UNIT * sizeof(VisEntry_s)); + if (overflowBeast->vis == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + RTN_STATUS(zFAILURE); + } + overflowBeast->numAlloced = OVERFLOW_ALLOC_UNIT; + overflowBeast->p.nextOverflowZid = zINVALID_ZID; + overflowBeast->p.numEntries = 0; + RTN_STATUS(zOK); +} + +/*************************************************************************** + * This routine is called when an overflow beast is freed from memory + ***************************************************************************/ +void VISO_DestructBeast( + void *overflowBeast_LX) +{ + ZasVisOverflowBeast_s *overflowBeast = + (ZasVisOverflowBeast_s *) overflowBeast_LX; + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VISO_DestructBeast); + if (overflowBeast->vis != NULL) + { + free(overflowBeast->vis); + } + RTN_VOID(); +} + +/**************************************************************************** + * ZAS OVERFLOW BEAST COMMON OPERATIONS definition + *****************************************************************************/ + +CommonBeastOps_s VISO_ComnBeastOps = +{ + VISO_ConstructBeast, /* construct */ + VISO_DestructBeast, /* destruct */ + +// cnt NULL, /* BST_getNameUniquifier */ + NULL, /* BST_setupNameTypeSpecificInfo */ + NULL, /* BST_lookupByNameInDirectory*/ + NULL, /* BST_isDirectoryEmpty*/ + NULL, /* BST_addNameToDirectory*/ + NULL, /* BST_removeNameFromDirectory*/ + NULL, /* BST_modifyNameSpaceMaskInDirectory*/ + NULL, /* BST_setMatchAttributesInDirectory*/ + NULL, /* BST_wildcardLookup*/ + + NULL, /* BST_truncateFile*/ + NULL, /* BST_getStorageInfo*/ + NULL, /* BST_getExtentList*/ + NULL, /* BST_isBlockInBeast*/ + + NULL, /* BST_asyncReadFileBlk*/ + NULL, /* BST_getFileBlk*/ + NULL, /* BST_dfsReadUnits*/ + NULL, /* BST_dfsWriteUnits*/ + + NULL, /* BST_getZID*/ + NULL, /* BST_beastNotify*/ + NULL, /* BST_getInfo*/ + NULL, /* BST_getInfoXML*/ + NULL, /* BST_modifyInfo*/ + NULL /* BST_modifyInfoXML*/ +}; + +///*************************************************************************** +// * This routine is called when an overflow beast is written to storage +// ***************************************************************************/ +//NINT VISO_PackedSize( +// ZasVisOverflowBeast_s *overflowBeast) +//{ +// ENTER(TAUTH, VISO_PackedSize); +// RTN_NINT(sizeof(PersistentZasVisOverflowBeast_s) + +// (overflowBeast->p.numEntries * sizeof(VisEntry_s))); +//} +// +///*************************************************************************** +// * This routine is called when an overflow beast is written to storage +// ***************************************************************************/ +//BYTE *VISO_PackBeast( +// ZasVisOverflowBeast_s *overflowBeast, +// BYTE *storeBuffer) +//{ +// NINT len; +// +// ENTER(TAUTH, VISO_PackBeast); +// len = overflowBeast->p.numEntries * sizeof(VisEntry_s); +// memcpy(storeBuffer, &overflowBeast->p, sizeof(PersistentZasVisOverflowBeast_s)); +// storeBuffer += sizeof(PersistentZasVisOverflowBeast_s); +// zASSERT(overflowBeast->vis != NULL); +// memcpy(storeBuffer, overflowBeast->vis, len); +// RTN_PTR(storeBuffer + len); +//} +// +///*************************************************************************** +// * This routine is called when an overflow beast is read from storage +// ***************************************************************************/ +//BYTE *VISO_UnpackBeast( +// GeneralMsg_s *genMsg, +// ZasVisOverflowBeast_s *overflowBeast, +// BYTE *storeBuffer) +//{ +// NINT len; +// +// ENTER(TAUTH, VISO_UnpackBeast); +// memcpy(&overflowBeast->p, storeBuffer, sizeof(PersistentZasVisOverflowBeast_s)); +// storeBuffer += sizeof(PersistentZasVisOverflowBeast_s); +// len = overflowBeast->p.numEntries * sizeof(VisEntry_s); +// overflowBeast->vis = realloc(overflowBeast->vis, len); +// overflowBeast->numAlloced = overflowBeast->p.numEntries; +// if (overflowBeast->vis == NULL) +// { +// SetErrno(genMsg, zERR_NO_MEMORY); +// RTN_PTR(NULL); +// } +// memcpy(overflowBeast->vis, storeBuffer, len); +// RTN_PTR(storeBuffer + len); +//} +// +///*--------------------------------------------------------------------------- +// * beast STORAGE ops definition +// *---------------------------------------------------------------------------*/ +//StoragePoolBeastOps_s VISO_StoragePoolOps[] = +//{ +// {zFTYPE_ZFS_POOL, VISO_PackedSize, VISO_PackBeast, VISO_UnpackBeast}, +// /*{zFTYPE_ZFS_MEMPOOL, VISO_PackedSize, VISO_PackBeast, VISO_UnpackBeast},*/ +// {zFTYPE_INVALID} +//}; diff --git a/src/nwnss/comn/authsys/zasAuthSpace.c b/src/nwnss/comn/authsys/zasAuthSpace.c new file mode 100644 index 0000000..bb7ba32 --- /dev/null +++ b/src/nwnss/comn/authsys/zasAuthSpace.c @@ -0,0 +1,1743 @@ +/**************************************************************************** + | + | (C) Copyright 1993-2005 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: randys $ + | $Date: 2007-02-28 22:35:11 +0530 (Wed, 28 Feb 2007) $ + | + | $RCSfile$ + | $Revision: 1896 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | These are the model support authorization routines (methods on the + | auth info). They are also registered as the PSS default auth space + | routines. + +-------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include /* NSS Library */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "comnPublics.h" +#include "zParams.h" +#include "msgGen.h" +#include "msgName.h" +#include "comnAuthorize.h" +#include "volume.h" +#include "zasAuthSpace.h" +#include "zasAuthModel.h" +#include "zasAuthCache.h" +#include "pssConnection.h" +#include "comnBeasts.h" +#include "searchMap.h" +#include "eventSys.h" +#include "nssFSHooks.h" +#include "unixAuthModel.h" +#include "unixAuthSpace.h" +#include "comnAudit.h" + +BOOL ZAS_CheckDirectory( + NamingMsg_s *nameMsg, + void *trusteeVector, + NINT trusteeCount); + +NINT TotalVisibilityProcesses = 0; + +static inline BOOL NSSLAF_GenerateAuditLog (GeneralMsg_s *genMsg, STATUS status) +{ + if ( NSSLAF_AuditEnabled && (status == zOK) && + !(genMsg->flags & DO_NOT_SEND_EVENTS) ) + { + return TRUE; + } + return FALSE; +} +/**************************************************************************** + * This routine will add a new trustee and rights to the given beast + ****************************************************************************/ +STATIC STATUS VAUTH_AddACLEntry( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *trusteeID, + NINT rights, + NINT attributes) +{ + AuthBeast_s *authBeast; + STATUS status; + STATUS tempStatus; + LONG id; + NINT latchType; +#if zNETWARE + STATUS error; + LONG nwID; +#endif + + typedef struct Stack_s { + struct EventBlock evBlk; + EventAddTrusteeEnter_s enter; + EventAddTrusteeExit_s exit; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_AddACLEntry); + +/*--------------------------------------------------------------------------- + * Resolve the name message to a beast + *---------------------------------------------------------------------------*/ + if (COMN_Lookup(genMsg,nameMsg) != zOK) + { + status = zFAILURE; + goto justReturn; + } + INIT_EVENT_ID_STATUS(id, aStack->exit.enterRetStatus); + if (!(genMsg->flags & DO_NOT_SEND_EVENTS) && + (NEBEventInfo[EVENT_AddTrustee_Enter].consumers)) + { + COMN_UNLATCH_NAMEMSG_BEASTS(nameMsg, &latchType); + INIT_ENTER_EVENT(genMsg, nameMsg, aStack->evBlk, EVENT_AddTrustee_Enter, + aStack->enter, id); + INIT_ADD_TRUSTEE_ENTER_EVENT(aStack->enter, *trusteeID, rights, attributes); + ZOS_ProduceEvent(status, &aStack->evBlk); + CHECK_ENTER_RETURN(genMsg, status, aStack->evBlk, aStack->exit, justReturnLatch); + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + } + authBeast = (AuthBeast_s *)nameMsg->curFile; +// ASSERT_XLATCH(&authInfo->p.authLatch); + + if (authBeast->AUTHmayIDoThis(genMsg, authBeast, + nameMsg->hlFile ? nameMsg->hlParentZid : nameMsg->fileParentZid, + MAY_I_CHANGE_ACCESS_RIGHTS) != zOK) + { + SetErrno(genMsg, zERR_NO_SET_PRIVILEGE); + status = zFAILURE; + goto sendExitEvent; + } + + if (TotalVisibilityProcesses > MAX_VISIB_PROCESSES) + { + NINT count = 0; + COMN_UNLATCH_NAMEMSG_BEASTS(nameMsg, &latchType); + while (TotalVisibilityProcesses > MIN_VISIB_PROCESSES) + { + LB_delay(100); + if (++count > 20) + break; + } + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + } + + status = ZAS_AddACLEntry(genMsg, authBeast, trusteeID, rights, attributes); + + if (NSSLAF_GenerateAuditLog(genMsg, status)) + { + NSSLAF_LogTrusteeChange(genMsg, nameMsg, + NSSLAF_MODE_ADD_TRUSTEE, trusteeID, rights, attributes, 0); + } + +sendExitEvent: + if (!(genMsg->flags & DO_NOT_SEND_EVENTS) && + (NEBEventInfo[EVENT_AddTrustee_Exit].consumers)) + { + COMN_UNLATCH_NAMEMSG_BEASTS(nameMsg, &latchType); + INIT_EXIT_EVENT(status, genMsg, aStack->evBlk, + EVENT_AddTrustee_Exit, aStack->exit, id); + ZOS_ProduceEvent(tempStatus, &aStack->evBlk); + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + } + +justReturn: + STACK_FREE(); + RTN_STATUS(status); + +justReturnLatch: + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + STACK_FREE(); + RTN_STATUS(status); +} + +/**************************************************************************** + * This routine will remove trustee and rights from a file system object + * + ****************************************************************************/ +STATIC STATUS VAUTH_RemoveACLEntry( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *trusteeID, + NINT purgedFileFlag) +{ + AuthBeast_s *authBeast; + STATUS status; + STATUS tempStatus; + LONG id; + NINT latchType; +#if zNETWARE + STATUS error; + LONG nwID; +#endif + + typedef struct Stack_s { + struct EventBlock evBlk; + EventRemoveTrusteeEnter_s enter; + EventRemoveTrusteeExit_s exit; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_RemoveACLEntry); + +/*--------------------------------------------------------------------------- + * Resolve the name message to a beast + *---------------------------------------------------------------------------*/ + if (COMN_Lookup(genMsg,nameMsg) != zOK) + { + status = zFAILURE; + goto justReturn; + } + INIT_EVENT_ID_STATUS(id, aStack->exit.enterRetStatus); + if (!(genMsg->flags & DO_NOT_SEND_EVENTS) && + (NEBEventInfo[EVENT_RemoveTrustee_Enter].consumers)) + { + COMN_UNLATCH_NAMEMSG_BEASTS(nameMsg, &latchType); + INIT_ENTER_EVENT(genMsg, nameMsg, aStack->evBlk, EVENT_RemoveTrustee_Enter, + aStack->enter, id); + INIT_REMOVE_TRUSTEE_ENTER_EVENT(aStack->enter, *trusteeID, purgedFileFlag); + ZOS_ProduceEvent(status, &aStack->evBlk); + CHECK_ENTER_RETURN(genMsg, status, aStack->evBlk, aStack->exit, justReturnLatch); + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + } + + authBeast = (AuthBeast_s *)nameMsg->curFile; + ASSERT_XLATCH(&authBeast->AUTHbeastLatch); + + if (authBeast->AUTHmayIDoThis(genMsg, authBeast, + nameMsg->hlFile ? nameMsg->hlParentZid : nameMsg->fileParentZid, + MAY_I_CHANGE_ACCESS_RIGHTS) != zOK) + { + SetErrno(genMsg, zERR_NO_TRUSTEE_CHANGE_PRIVILEGE); + status = zFAILURE; + goto sendExitEvent; + } + + if (TotalVisibilityProcesses > MAX_VISIB_PROCESSES) + { + NINT count = 0; + COMN_UNLATCH_NAMEMSG_BEASTS(nameMsg, &latchType); + while (TotalVisibilityProcesses > MIN_VISIB_PROCESSES) + { + LB_delay(100); + if (++count > 20) + break; + } + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + } + + status = ZAS_RemoveACLEntry(genMsg, authBeast, trusteeID, purgedFileFlag); + + if (NSSLAF_GenerateAuditLog(genMsg, status)) + { + NSSLAF_LogTrusteeChange(genMsg, nameMsg, + NSSLAF_MODE_REMOVE_TRUSTEE, trusteeID, 0, 0, 0); + } + +sendExitEvent: + if (!(genMsg->flags & DO_NOT_SEND_EVENTS) && + (NEBEventInfo[EVENT_RemoveTrustee_Exit].consumers)) + { + COMN_UNLATCH_NAMEMSG_BEASTS(nameMsg, &latchType); + INIT_EXIT_EVENT(status, genMsg, aStack->evBlk, + EVENT_RemoveTrustee_Exit, aStack->exit, id); + ZOS_ProduceEvent(tempStatus, &aStack->evBlk); + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + } + +justReturn: + STACK_FREE(); + RTN_STATUS(status); + +justReturnLatch: + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + STACK_FREE(); + RTN_STATUS(status); +} + +/**************************************************************************** + * This routine will get an ACL entry for a file. If the sequence number is + * -1 or 0 then it gets the first entry, otherwise it gets the next one in + * the sequence. A returned sequence number of -1 means there are no more + * entries + ****************************************************************************/ +STATIC STATUS VAUTH_GetACLEntry( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT *sequence, + UserID_t *trusteeID, + NINT *rights, + NINT *attributes) +{ + NINT SeeAllTrustees; + NSSConnection_s *pssConn; + AuthBeast_s *authBeast; + NINT index; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_GetACLEntry); +/*--------------------------------------------------------------------------- + * Resolve the name message to a beast + *---------------------------------------------------------------------------*/ + if (COMN_Lookup(genMsg, nameMsg) != zOK) + RTN_STATUS(zFAILURE); + authBeast = (AuthBeast_s *)nameMsg->curFile; + + if (authBeast->AUTHmayIDoThis(genMsg, authBeast, + nameMsg->hlFile ? nameMsg->hlParentZid : nameMsg->fileParentZid, + MAY_I_CHANGE_ACCESS_RIGHTS) == zOK) + { + SeeAllTrustees = 1; + } + else + { + SeeAllTrustees = 0; + if ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) == NULL) + { + RTN_STATUS(zFAILURE); + } + } + /* + * Only show trustees to a user that has access control privileges or + * who is in the connection structure. + */ + S_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + S_LATCH(&authBeast->AUTHauthInfo.zas->authLatch); + for (;;) + { + if (ZAS_GetAnACL(genMsg, authBeast, sequence, trusteeID, rights, + attributes) != zOK) + { + UNS_LATCH(&authBeast->AUTHauthInfo.zas->authLatch); + UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + RTN_STATUS(zFAILURE); + } + zASSERT(*sequence != 0xffff); /* See if this happens */ + if (*sequence == -1) + { + break; + } + if (!SeeAllTrustees) + { + /* + * Search the connection structure for a match. If none are found + * then don't return this entry and keep looking + */ + for (index = 0; index < genMsg->pssConn.ptr->authInfo.numAuthenticatedIDs; + index++) + { + if (LB_GUIDCompare(&genMsg->pssConn.ptr->authInfo.authenticatedIDs[index], + trusteeID) == 0) + { + break; + } + } + if (index >= genMsg->pssConn.ptr->authInfo.numAuthenticatedIDs) + { /* not found */ + continue; + } + } + break; + } + UNS_LATCH(&authBeast->AUTHauthInfo.zas->authLatch); + UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + RTN_STATUS(zOK); +} + +/**************************************************************************** + * This routine will return the effective rights for a beast pointed to by a + * name message. It requires that the General Message structure have valid + * connection information about privileges. + ****************************************************************************/ +STATIC STATUS VAUTH_GetEffectiveRights( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT *effectiveRights) +{ + NSSConnection_s *pssConn; + STATUS status; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_GetEffectiveRights); +/*--------------------------------------------------------------------------- + * Resolve the name message to a beast + *---------------------------------------------------------------------------*/ + if (COMN_Lookup(genMsg,nameMsg) != zOK) + { + RTN_STATUS(zFAILURE); + } + + if ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) == NULL) + { + RTN_STATUS(zFAILURE); + } + + S_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + status = ZAS_GetEffectiveRightsByIDs(genMsg, (AuthBeast_s *)nameMsg->curFile, + nameMsg->fileParentZid, + (genMsg->pssConn.ptr->flags & CNCTFL_SECURE_ACCESS) ? TRUE : FALSE, + IsSupervisor(genMsg->pssConn.id), + genMsg->pssConn.ptr->authInfo.numAuthenticatedIDs, + &genMsg->pssConn.ptr->authInfo.authenticatedIDs[0], + effectiveRights); + UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + RTN_STATUS(status); +} + + +/**************************************************************************** + * This routine will return the effective rights for a beast pointed to by a + * name message. It requires that the General Message structure have valid + * connection information about privileges. + ****************************************************************************/ +STATIC STATUS VAUTH_GetEffectiveRightsByID( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *userGUID, + NINT *effectiveRights) +{ +#define UE_LIST_LEN 256 + LONG UserEquivalentIDsCount; + STATUS status; + BOOL isSupervisor; + struct { + UserID_t UserEquivalentGUIDs[UE_LIST_LEN]; + } *buf = NULL; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_GetEffectiveRightsByID); + + buf = malloc(sizeof(*buf)); + if (!buf) + { + status = zFAILURE; + goto exit; + } + + memcpy(&buf->UserEquivalentGUIDs[0], userGUID, sizeof(NDSid_t)); + + status = COMN_GetSecurityEquivalenceList(userGUID, UE_LIST_LEN - 1, + &buf->UserEquivalentGUIDs[1], &UserEquivalentIDsCount, &isSupervisor); + if (status != 0) + { /* if there is an error */ + if (status == ERR_NO_SUCH_OBJECT) + { + SetErrno(genMsg, zERR_NO_SUCH_OBJECT); + status = zFAILURE; + goto exit; + } + else if (status == zERR_BUFFER_TOO_SMALL) + { + UserEquivalentIDsCount = UE_LIST_LEN; + } + else + { + UserEquivalentIDsCount = 1; + } + } + else + { + UserEquivalentIDsCount += 1; /* Add in the first ID */ + } + + +/*--------------------------------------------------------------------------- + * Resolve the name message to a beast + *---------------------------------------------------------------------------*/ + if (COMN_Lookup(genMsg, nameMsg) != zOK) + { + status = zFAILURE; + goto exit; + } + + if (CNCT_RESOLVE_CONNECTION(genMsg) == NULL) + { + status = zFAILURE; + goto exit; + } + + S_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + status = ZAS_GetEffectiveRightsByIDs(genMsg, + (AuthBeast_s *)nameMsg->curFile, nameMsg->fileParentZid, FALSE, + isSupervisor, + UserEquivalentIDsCount, buf->UserEquivalentGUIDs, + effectiveRights); + UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); +exit: + free(buf); + RTN_STATUS(status); +} + + +/**************************************************************************** + * This routine will return the inherited rights for a beast + ****************************************************************************/ +STATIC STATUS VAUTH_GetInheritedRightsMask( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT *inheritedRights) +{ + ZASAuthorizeInfo_s *authInfo; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_GetInheritedRightsMask); + /* + * Resolve the name message to a beast + */ + if (COMN_Lookup(genMsg,nameMsg) != zOK) + RTN_STATUS(zFAILURE); + + authInfo = ((AuthBeast_s *)nameMsg->curFile)->AUTHauthInfo.zas; + S_LATCH(&authInfo->authLatch); + *inheritedRights = authInfo->p.inheritedRightsMask; + UNS_LATCH(&authInfo->authLatch); + RTN_STATUS(zOK); +} + +/**************************************************************************** + * This routine will set the inherited rights for a beast + ****************************************************************************/ +STATIC STATUS VAUTH_SetInheritedRightsMask( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT inheritedRights, + BOOL modifyFlag) +{ + ZASAuthorizeInfo_s *authInfo; + AuthBeast_s *authBeast; +#if _FSHOOKS IS_ENABLED + ModifyInfo mInfo; +#endif + STATUS status; + STATUS tempStatus; + LONG id = 0; + NINT latchType; + BOOL sendAudit = FALSE; + + typedef struct Stack_s { + FSHooks_F3ModifyInfo_s parms; + struct EventBlock evBlk; + EventSetInheritedRightsEnter_s enter; + EventSetInheritedRightsExit_s exit; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_SetInheritedRightsMask); + + /* + * Resolve the name message to a beast + */ + if (COMN_Lookup(genMsg,nameMsg) != zOK) + { + status = zFAILURE; + goto justReturn; + } + if (FSHOOKS_OR_EVENTS(F3ModifyInfo_Hook, EVENT_SetInheritedRights_Enter)) + { + COMN_UNLATCH_NAMEMSG_BEASTS(nameMsg, &latchType); + + CHECK_FSHOOKS_MODIFY_RIGHTS_ENTER(F3ModifyInfo_Hook, &aStack->parms, status, + justReturnLatch, genMsg, nameMsg, inheritedRights, &mInfo); + + INIT_EVENT_ID_STATUS(id, aStack->exit.enterRetStatus); + if (!(genMsg->flags & DO_NOT_SEND_EVENTS) && + (NEBEventInfo[EVENT_SetInheritedRights_Enter].consumers)) + { + INIT_ENTER_EVENT(genMsg, nameMsg, aStack->evBlk, + EVENT_SetInheritedRights_Enter, aStack->enter, id); + INIT_SET_RIGHTS_ENTER_EVENT(aStack->enter, inheritedRights, modifyFlag); + ZOS_ProduceEvent(status,&aStack->evBlk); + CHECK_ENTER_RETURN(genMsg, status, aStack->evBlk, aStack->exit, justReturnLatch); + } + + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + } + + /* Don't allow changes if the file is exclusive locked */ + if ((nameMsg->curDataStream->NAMEDdenyReaderCount != 0) || + (nameMsg->curDataStream->NAMEDdenyWriterCount != 0)) + { + if (COMN_IsDenyReaderWriterNotMe(genMsg,nameMsg->curDataStream)) + { + SetErrno(genMsg,zERR_ALL_FILES_IN_USE); + status = zFAILURE; + goto sendExitEvent; + } + } + + authBeast = (AuthBeast_s *)nameMsg->curFile; +// ASSERT_XLATCH(&authBeast->AUTHbeastLatch); + + if (modifyFlag && (authBeast->AUTHmayIDoThis(genMsg, authBeast, + nameMsg->hlFile ? nameMsg->hlParentZid : nameMsg->fileParentZid, + MAY_I_CHANGE_ACCESS_RIGHTS) != zOK)) + { + SetErrno(genMsg, zERR_NO_TRUSTEE_CHANGE_PRIVILEGE); + status = zFAILURE; + goto sendExitEvent; + } + authInfo = authBeast->AUTHauthInfo.zas; + X_LATCH(&authInfo->authLatch); + inheritedRights |= zAUTHORIZE_SUPERVISOR; + if (authInfo->p.inheritedRightsMask != inheritedRights) + { + authInfo->p.inheritedRightsMask = inheritedRights; + BST_MarkDirty(&authBeast->AUTHroot); + + /* Set the state so the EFL will be updated */ + authBeast->AUTHbstState |= BST_STATE_METADATA_CHANGED; + + + if (modifyFlag) + { + if (!(authBeast->AUTHattributes & zFA_SUBDIRECTORY) || + authBeast->AUTHcomnOps.BST_isDirectoryEmpty(genMsg, &authBeast->AUTHnamed, zNTYPE_FILE)) + { /* this object has no object below it */ + authInfo->p.cacheIndex = INVALID_EACL_CACHE_INDEX; /* invalidate the cache pointer */ + } + else + { + if (ZAS_InvalidateEntireEACLCache(genMsg, TRUE) != zOK) + { + UNX_LATCH(&authInfo->authLatch); + status = zFAILURE; + goto sendExitEvent; + } + } + } + sendAudit = TRUE; + } + UNX_LATCH(&authInfo->authLatch); + status = zOK; + if (sendAudit && NSSLAF_GenerateAuditLog(genMsg, status)) + { + NSSLAF_LogTrusteeChange(genMsg, nameMsg, + NSSLAF_MODE_SET_INHERITED_RIGHTS, NULL, + 0, 0, inheritedRights); + } + +sendExitEvent: + if (FSHOOKS_OR_EVENTS(F3ModifyInfo_Hook, EVENT_SetInheritedRights_Exit)) + { + COMN_UNLATCH_NAMEMSG_BEASTS(nameMsg, &latchType); + + CHECK_FSHOOKS_MODIFY_RIGHTS_EXIT(F3ModifyInfo_Hook, &aStack->parms, + genMsg, nameMsg, inheritedRights, &mInfo); + + if (!(genMsg->flags & DO_NOT_SEND_EVENTS) && + (NEBEventInfo[EVENT_SetInheritedRights_Exit].consumers)) + { + INIT_EXIT_EVENT(status, genMsg, aStack->evBlk, + EVENT_SetInheritedRights_Exit, aStack->exit, id); + ZOS_ProduceEvent(tempStatus, &aStack->evBlk); + } + + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + } + +justReturn: + STACK_FREE(); + RTN_STATUS(status); + +justReturnLatch: + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, latchType); + STACK_FREE(); + RTN_STATUS(status); +} + +/**************************************************************************** + * + * This routine will check a beast for a given trustee ID and return OK or + * FAILURE + * + ****************************************************************************/ +STATIC STATUS ZAS_FindACLEntryInBeast( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *desiredTrusteeID, + NINT *rights, + NINT *attributes) +{ + NINT sequence; + UserID_t trusteeID; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, ZAS_FindACLEntryInBeast); + + sequence = 0; + for(;;) + { + if (VAUTH_GetACLEntry(genMsg, nameMsg, + &sequence, &trusteeID, rights, attributes) != zOK) + { + RTN_STATUS(zFAILURE); + } + + if (sequence == -1) + { /* end of list */ + RTN_STATUS(zFAILURE); + } + + if (LB_GUIDCompare(desiredTrusteeID, &trusteeID) == 0) + { /* found the desired trustee */ + RTN_STATUS(zOK); + } + } +} + +/**************************************************************************** + * + * This routine will find the next node in a directory tree that has the + * passed in trustee assigned to the node. + * + ****************************************************************************/ +STATIC STATUS VAUTH_FindACLEntryInTree( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *searchMsg, + GetNameMsg_s *gfnMsg, + UserID_t *desiredTrusteeID, + NINT *rights, + NINT *attributes) +{ + STATUS status; + SearchMap_s *smap; + + ENTER(TAUTH, VAUTH_FindACLEntryInTree); + ASSERT_MPKNSS_LOCK(); + + COMN_SET_NAMING_MSG_PARSEMODE(nameMsg,NAMPMODE_DoNotResolveLeafName); + COMN_SET_SEARCH_CHECK_FUNC(searchMsg, ZAS_CheckDirectory, + desiredTrusteeID, 1); + zASSERT(searchMsg->srchMap.id != 0xffff); /* See if this happens */ + if ((searchMsg->srchMap.id == -1) || (searchMsg->srchMap.id == 0)) + { /* This is the first time in -- set up the searchmap */ + if (COMN_WildOpen(genMsg, nameMsg, searchMsg) != zOK) + { + goto cleanup; + } + else + { /* check the first directory for trustees */ + if ((status = ZAS_FindACLEntryInBeast(genMsg, nameMsg, + desiredTrusteeID, rights, attributes)) == zOK) + { /* found a trustee -- return the trustee info */ + goto getName; + } + } + } + if ((smap = SMAP_RESOLVE_SEARCHMAP(genMsg, &searchMsg->srchMap, + searchMsg->srchOpt)) == NULL) + { + goto cleanup; + } + if (smap->dirZid == zROOTDIR_ZID) + { + if (ZAS_CheckDirectory(nameMsg, desiredTrusteeID, 1) == FALSE) + { + /** The trustees have no visibility in the tree, so no need + ** to continue searching further + **/ + SetErrno(genMsg, zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto cleanup; + } + } + /* search for an entry with the needed trustee */ + do + { /* while we have not found a trustee */ + genMsg->flags |= DO_NOT_SEND_FSHOOKS; + if (COMN_WildRead(genMsg, nameMsg, searchMsg) != zOK) + { + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + goto cleanup; + } + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + + status = ZAS_FindACLEntryInBeast(genMsg, nameMsg, + desiredTrusteeID, rights, attributes); + } while (status != zOK); + +getName: + if (COMN_GetName(genMsg, nameMsg, gfnMsg) == zOK) + { + RTN_STATUS(zOK); + } +cleanup: + RTN_STATUS(zFAILURE); +} + +/**************************************************************************** + * + * This routine is called from the wild card search to see if a subdirectory + * should be pushed for searching in the future. We check to see if any of + * trustees in the trustee vector are in the visibility list. If they are + * not then there is no reason to search down this sub-tree. + * + ****************************************************************************/ +BOOL ZAS_CheckDirectory( + NamingMsg_s *nameMsg, + void *trusteeVector_LX, + NINT trusteeCount) +{ + UserID_t *trusteeVector = (UserID_t *) trusteeVector_LX; + NINT i; + NINT entryIndex; + UserID_t trusteeID; + GeneralMsg_s genMsg; + ZasVisOverflowBeast_s *beast; + Zid_t parentZid; + ZASAuthorizeInfo_s *authInfo; + VisEntry_s *entry; + + ASSERT_MPKNSS_LOCK(); + COMN_STRUCT_INIT(genMsg); + COMN_SETUP_GENERAL_MSG(&genMsg, zSYS_CONNECTION, zNSS_TASK, zSAGENT_NETWARE); + + authInfo = ((AuthBeast_s *)nameMsg->curFile)->AUTHauthInfo.zas; + S_LATCH(&authInfo->authLatch); + + if ((authInfo->p.numVisibilityTrusteesAssigned > 0) || + (authInfo->p.visibilityOverflow != zINVALID_ZID)) + { /* if there are visibility trustees assigned */ + for (i = 0; i < trusteeCount; i++) + { /* check to see if there is a visbility trustee */ + trusteeID = trusteeVector[i]; + if (ZAS_FindVisibilityTrustee(&genMsg, + (AuthBeast_s *)nameMsg->curFile, NULL, &trusteeID, SLATCHED, + &entry, &entryIndex, &beast, &parentZid) != zOK) + { + goto error; + } + if (beast != NULL) + { + COMN_UnlatchAndRelease(&beast, SLATCHED); + } + if (entry != NULL) + { + UNS_LATCH(&authInfo->authLatch); + return TRUE; + } + } + } + /* nothing matched */ +error: + UNS_LATCH(&authInfo->authLatch); + return FALSE; +} + +/**************************************************************************** + * + * This routine will remove the list of trustees from all files/dirs. + * + ****************************************************************************/ +STATUS VAUTH_PurgeACLEntriesFromTree( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *trusteeVector, + NINT trusteeCount) +{ + SearchMsg_s searchMsg; + NINT i; + + ASSERT_MPKNSS_LOCK(); + ENTER(TAUTH, VAUTH_PurgeACLEntriesFromTree); + + COMN_STRUCT_INIT(searchMsg); + COMN_SETUP_SEARCH_MSG (&searchMsg, 0, + SMAPOPT_32BitMode | SMAPOPT_searchAllDirs | SMAPOPT_matchAllEntries, + zNTYPE_FILE); + COMN_SET_SEARCH_CHECK_FUNC(&searchMsg, ZAS_CheckDirectory, trusteeVector, + trusteeCount); + + COMN_SET_NAMING_MSG_PARSEMODE(nameMsg, NAMPMODE_DoNotResolveLeafName); + if (COMN_WildOpen(genMsg, nameMsg, &searchMsg) != zOK) + { + goto cleanup; + } + + if (((AuthBeast_s *)nameMsg->curFile)-> + authInfo.zas->p.numTrusteesAssigned > 0) + { /* if there are trustees assigned */ + for (i = 0; i < trusteeCount; i++) + { /* remove each trustee in the trusteeVector */ + ZAS_RemoveACLEntry(genMsg, (AuthBeast_s *)nameMsg->curFile, + &trusteeVector[i], TRUE); + } + } + /** Ignoring error from remove acl entry **/ + ClearErrno(genMsg); + if (ZAS_CheckDirectory(nameMsg, trusteeVector, trusteeCount) == FALSE) + { + /** The trustees have no visibility in the tree, so no need + ** to continue searching further + **/ + COMN_WildClose(genMsg, &searchMsg); + RTN_STATUS(zOK); + } + /* search for all entry with the needed trustee */ + for(;;) + { /* look at each file in the system */ + genMsg->flags |= DO_NOT_SEND_FSHOOKS; + if (COMN_WildRead(genMsg, nameMsg, &searchMsg) != zOK) + { + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + if (GetErrno(genMsg) == zERR_NAME_NOT_FOUND_IN_DIRECTORY) + { /* normal end */ + ClearErrno(genMsg); + COMN_WildClose(genMsg, &searchMsg); + RTN_STATUS(zOK); + } + goto cleanupClose; + } + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + if (((AuthBeast_s *)nameMsg->curFile)-> + authInfo.zas->p.numTrusteesAssigned > 0) + { /* if there are trustees assigned */ + for (i = 0; i < trusteeCount; i++) + { /* remove each trustee in the trusteeVector */ + ZAS_RemoveACLEntry(genMsg, (AuthBeast_s *)nameMsg->curFile, + &trusteeVector[i], TRUE); + } + } + /** Ignoring error from remove acl entry **/ + ClearErrno(genMsg); + } + +cleanupClose: + COMN_WildClose(genMsg, &searchMsg); +cleanup: + RTN_STATUS(zFAILURE); +} + +/**************************************************************************** + * + * Return the count of visibility TrusteeIDs on the specified beast. + * + ****************************************************************************/ +STATUS VAUTH_GetVisibilityCount( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT *numTrustees) +{ + STATUS status = zOK; + NINT count; + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *overflowBeast; + ZasAclOverflowBeast_s *aclOverflowBeast; + Zid_t overflowZid; + AuthBeast_s *authBeast; + + ASSERT_MPKNSS_LOCK(); + authBeast = (AuthBeast_s *)nameMsg->curFile; + + authInfo = authBeast->AUTHauthInfo.zas; + + count = authInfo->p.numTrusteesAssigned; + overflowZid = authInfo->p.trusteeOverflow; + while (overflowZid != zINVALID_ZID) + { + aclOverflowBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, FALSE); + if (aclOverflowBeast == NULL) + { + status = zFAILURE; + break; + } + count += aclOverflowBeast->p.numEntries; + overflowZid = aclOverflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&aclOverflowBeast, SLATCHED); + } + + count += authInfo->p.numVisibilityTrusteesAssigned; + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + overflowBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, FALSE); + if (overflowBeast == NULL) + { + status = zFAILURE; + break; + } + count += overflowBeast->p.numEntries; + overflowZid = overflowBeast->p.nextOverflowZid; + zASSERT((overflowZid == zINVALID_ZID) || + (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES)); + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + *numTrustees = count; + return status; +} + +/**************************************************************************** + * Do a binary search + * returns TRUE if the trusteeID is not in the trusteeVector list + * FALSE if it finds the trusteeID within count entries. + * It also increments the count for that trustee in the + * trusteeVector. + ****************************************************************************/ +BOOL notInVisibilityList( + UserID_t *trusteeID, + VisEntry_s *trusteeVector, + NINT count) +{ + UserID_t midID; + NINT start, end, mid; + + ASSERT_MPKNSS_LOCK(); + start = 0; + end = count; + do + { + mid = (start + end) / 2; + midID = trusteeVector[mid].trusteeID; + if (LB_GUIDCompare(trusteeID, &midID) <= 0) + { + if (LB_GUIDCompare(trusteeID, &midID) == 0) + { + trusteeVector[mid].count++; + return FALSE; + } + end = mid; + } + else + { + start = mid + 1; + } + } while (start < end); + + return TRUE; +} + + +/**************************************************************************** + * + * Fill the trusteeVector with trusteeCount number of trusteeIDs + * + ****************************************************************************/ +STATUS VAUTH_GetVisibilityList( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + VisEntry_s *trusteeVector, + NINT *numTrustees) +{ + STATUS status = zOK; + NINT entry; + NINT count, tmpCount; + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *overflowBeast; + ZasAclOverflowBeast_s *aclOverflowBeast; + Zid_t overflowZid; + AuthBeast_s *authBeast; + UserID_t trusteeID; + + ASSERT_MPKNSS_LOCK(); + authBeast = (AuthBeast_s *)nameMsg->curFile; + + authInfo = authBeast->AUTHauthInfo.zas; + + for (entry = 0, count = 0; + (entry < authInfo->p.numVisibilityTrusteesAssigned) && + (count < *numTrustees); + entry++, count++) + { + trusteeVector[count].trusteeID = authInfo->p.visibilityList[entry].trusteeID; + trusteeVector[count].count = authInfo->p.visibilityList[entry].count; + } + + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + overflowBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, FALSE); + if (overflowBeast == NULL) + { + status = zFAILURE; + break; + } + for (entry = 0; + (entry < overflowBeast->p.numEntries) && (count < *numTrustees); + entry++, count++) + { + trusteeVector[count].trusteeID = overflowBeast->vis[entry].trusteeID; + trusteeVector[count].count = overflowBeast->vis[entry].count; + } + overflowZid = overflowBeast->p.nextOverflowZid; + zASSERT((overflowZid == zINVALID_ZID) || + (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES)); + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + tmpCount = count; + + for (entry = 0; + (entry < authInfo->p.numTrusteesAssigned) && (count < *numTrustees); + entry++) + { + trusteeID = authInfo->p.ACL[entry].trusteeID; + if (notInVisibilityList(&trusteeID, trusteeVector, tmpCount)) + { + trusteeVector[count].trusteeID = trusteeID; + trusteeVector[count].count = 1; + count++; + } + } + + overflowZid = authInfo->p.trusteeOverflow; + while (overflowZid != zINVALID_ZID) + { + aclOverflowBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, FALSE); + if (aclOverflowBeast == NULL) + { + status = zFAILURE; + break; + } + for (entry = 0; + (entry < aclOverflowBeast->p.numEntries) && + (count < *numTrustees); + entry++) + { + trusteeID = aclOverflowBeast->acl[entry].trusteeID; + if (notInVisibilityList(&trusteeID, trusteeVector, tmpCount)) + { + trusteeVector[count].trusteeID = trusteeID; + trusteeVector[count].count = 1; + count++; + } + } + overflowZid = aclOverflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&aclOverflowBeast, SLATCHED); + } + + *numTrustees = count; + return status; +} + +/************************************************************************** + * Find the lowest valued GUID in a list of visibility entries + ***************************************************************************/ + +void findSmallestVisEntry( + VisEntry_s *array, + LONG *count, + VisEntry_s *retEntry) +{ + NINT i, index = 0; + + if (*count == 0) + { + retEntry->trusteeID = zINVALID_USERID; + retEntry->count = 0; + return; + } + + *retEntry = array[0]; + + for (i = 1; i < *count; i++) + { + if (LB_GUIDCompare(&array[i].trusteeID, &retEntry->trusteeID) < 0) + { + *retEntry = array[i]; + index = i; + } + } + (*count)--; + array[index] = array[*count]; + array[*count].trusteeID = zINVALID_USERID; + + return; + +} + +/************************************************************************** + * Switch the trustees on a beast from old IDs to new IDs + ***************************************************************************/ + +STATUS VAUTH_SwitchTrusteeIDs( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + void *hashTable) +{ + STATUS status = zOK; + NINT entry; + ZASAuthorizeInfo_s *authInfo; + ZasVisOverflowBeast_s *overflowBeast; + ZasAclOverflowBeast_s *aclOverflowBeast; + Zid_t overflowZid; + AuthBeast_s *authBeast; + LONG visibilityCount = 0; + VisEntry_s *array, *tmpArray; + + ASSERT_MPKNSS_LOCK(); + authBeast = (AuthBeast_s *)nameMsg->curFile; + authInfo = authBeast->AUTHauthInfo.zas; + +#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3) +#error "Check to see if the beastVersion code below is still needed." +#endif + /* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */ + X_LATCH(&authInfo->authLatch); + if (ZAS_ConvertVisFromVersionOne(genMsg, NULL, authBeast) != zOK) + { + UNX_LATCH(&authInfo->authLatch); + RTN_STATUS(zFAILURE); + } + UNX_LATCH(&authInfo->authLatch); + /* END OF BEAST VERSION ONE CONVERSION CODE */ + + /** Replace the visibility list with the new IDS **/ + for (entry = 0; entry < authInfo->p.numVisibilityTrusteesAssigned; entry++) + { + authInfo->p.visibilityList[entry].trusteeID = findId( + hashTable, authInfo->p.visibilityList[entry].trusteeID); + } + visibilityCount = authInfo->p.numVisibilityTrusteesAssigned; + + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + overflowBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, FALSE); + if (overflowBeast == NULL) + { + status = zFAILURE; + break; + } + for (entry = 0; entry < overflowBeast->p.numEntries; entry++) + { + overflowBeast->vis[entry].trusteeID = findId( + hashTable, overflowBeast->vis[entry].trusteeID); + } + visibilityCount += overflowBeast->p.numEntries; + overflowZid = overflowBeast->p.nextOverflowZid; + zASSERT((overflowZid == zINVALID_ZID) || + (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES)); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + + /** Visibility list is kept sorted, so sort the list, by first copying + ** the values to a temp array, and then reinserting them in a + ** sorted manner + **/ + if (visibilityCount > 0) + { + array = tmpArray = zalloc(visibilityCount * sizeof(VisEntry_s)); + if (array == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + return zFAILURE; + } + for (entry=0;entry < authInfo->p.numVisibilityTrusteesAssigned;entry++) + { + *tmpArray++ = authInfo->p.visibilityList[entry]; + } + + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + overflowBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + overflowZid, SLATCHED, FALSE); + if (overflowBeast == NULL) + { + status = zFAILURE; + break; + } + for (entry = 0; entry < overflowBeast->p.numEntries; entry++) + { + *tmpArray++ = overflowBeast->vis[entry]; + } + overflowZid = overflowBeast->p.nextOverflowZid; + zASSERT((overflowZid == zINVALID_ZID) || + (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES)); + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + + tmpArray = array; + for (entry=0;entry < authInfo->p.numVisibilityTrusteesAssigned;entry++) + { + findSmallestVisEntry(tmpArray, &visibilityCount, + &authInfo->p.visibilityList[entry]); + COMN_MARK_BEAST_DIRTY(&authBeast->AUTHroot); + } + + overflowZid = authInfo->p.visibilityOverflow; + while (overflowZid != zINVALID_ZID) + { + overflowBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, FALSE); + if (overflowBeast == NULL) + { + status = zFAILURE; + break; + } + for (entry = 0; entry < overflowBeast->p.numEntries; entry++) + { + findSmallestVisEntry(tmpArray, &visibilityCount, + &overflowBeast->vis[entry]); + } + overflowZid = overflowBeast->p.nextOverflowZid; + zASSERT((overflowZid == zINVALID_ZID) || + (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES)); + COMN_MARK_BEAST_DIRTY(&overflowBeast->VISOroot); + COMN_UnlatchAndRelease(&overflowBeast, XLATCHED); + } + zASSERT(LB_GUIDCompare(&tmpArray[0].trusteeID, &zINVALID_USERID) == 0); + zASSERT(visibilityCount == 0); + free(tmpArray); + } + + /** Replace the ACL list with the new ids **/ + for (entry = 0; entry < authInfo->p.numTrusteesAssigned; entry++) + { + authInfo->p.ACL[entry].trusteeID = findId( + hashTable, authInfo->p.ACL[entry].trusteeID); + COMN_MARK_BEAST_DIRTY(&authBeast->AUTHroot); + } + + overflowZid = authInfo->p.trusteeOverflow; + while (overflowZid != zINVALID_ZID) + { + aclOverflowBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume, + overflowZid, XLATCHED, FALSE); + if (aclOverflowBeast == NULL) + { + status = zFAILURE; + break; + } + for (entry = 0; entry < aclOverflowBeast->p.numEntries; entry++) + { + aclOverflowBeast->acl[entry].trusteeID = findId( + hashTable, aclOverflowBeast->acl[entry].trusteeID); + } + overflowZid = aclOverflowBeast->p.nextOverflowZid; + COMN_MARK_BEAST_DIRTY(&aclOverflowBeast->ACLOroot); + COMN_UnlatchAndRelease(&aclOverflowBeast, XLATCHED); + } + return status; +} + + +/************************************************************************** + * Get a list of visibility entries + ***************************************************************************/ + +STATUS VAUTH_GetVisibilityEntries( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT numEntries, + VisEntry_s *visEntries, + NINT *numReturned) +{ + ENTER(TAUTH, VAUTH_GetVisibilityEntries); + + if (COMN_Lookup(genMsg, nameMsg) != zOK) + { + RTN_STATUS(zFAILURE); + } + RTN_STATUS(ZAS_GetVisibilityEntries(genMsg, (AuthBeast_s *)nameMsg->curFile, + numEntries, visEntries, numReturned)); +} + +/************************************************************************** + * Get the effective (not actual) list of ACLs assigned to this file/dir. + * If the status is zOK and the number of returned entries is greater than + * zero then the caller must free the returned structure. + ***************************************************************************/ + +STATUS VAUTH_GetEffectiveACL( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + ACLEntry_s **aclEntries, + NINT *numReturnedEntries) +{ + STATUS status; + AuthCacheNode_s *effectiveACL; + BOOL freeEACL; + + + if (COMN_Lookup(genMsg, nameMsg) != zOK) + { + return zFAILURE; + } + + if (CNCT_RESOLVE_CONNECTION(genMsg) == NULL) + { + return zFAILURE; + } + + S_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + status = ZAS_GetEffectiveACL(genMsg, (AuthBeast_s *)nameMsg->curFile, + nameMsg->fileParentZid, &effectiveACL, TRUE, &freeEACL); + UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch); + if (status == zOK) + { + NINT size; + + *numReturnedEntries = effectiveACL->EACL.numEntries; + if (*numReturnedEntries == 0) + { + *aclEntries = NULL; + return zOK; + } + size = *numReturnedEntries * sizeof(ACLEntry_s); + *aclEntries = malloc(size); + if (*aclEntries == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + status = zFAILURE; + *numReturnedEntries = 0; + } + else + { + memcpy(*aclEntries, effectiveACL->EACL.entry, size); + } + if (freeEACL) + { + free(effectiveACL); + } + } + else + { + *numReturnedEntries = 0; + *aclEntries = NULL; + } + return status; +} + +/**************************************************************************** + **************************************************************************** + + UNIX to NETWARE Authorization space functions + + **************************************************************************** + ****************************************************************************/ + +STATIC STATUS NW2UX_AddACLEntry( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *trusteeID, + NINT rights, + NINT attributes) +{ + SetErrno(genMsg, zERR_AUTH_SPACE_NOT_IMPLEMENTED); + return zFAILURE; +} + +STATIC STATUS NW2UX_RemoveACLEntry( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *trusteeID, + NINT purgedFileFlag) +{ + SetErrno(genMsg, zERR_AUTH_SPACE_NOT_IMPLEMENTED); + return zFAILURE; +} + +NINT translateUnixRightsToNetWare( + NINT mode) +{ + NINT rights = 0; + + if (mode & UX_IR) + { + rights |= zAUTHORIZE_READ_CONTENTS | zAUTHORIZE_SEE_FILES; + } + if (mode & UX_IW) + { + rights |= zAUTHORIZE_WRITE_CONTENTS | zAUTHORIZE_CREATE_ENTRY | + zAUTHORIZE_DELETE_ENTRY | zAUTHORIZE_MODIFY_METADATA | + zAUTHORIZE_SALVAGE; + } + return rights; +} + +STATIC STATUS NW2UX_GetACLEntry( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT *sequence, + UserID_t *trusteeID, + NINT *rights, + NINT *attributes) +{ + AuthBeast_s *authBeast; + UserID_t ownerID; + UserID_t groupID; + NINT mode; + + ASSERT_MPKNSS_LOCK(); + + if (UX_statAuth(genMsg, nameMsg, &ownerID, &groupID, &mode) != zOK) + { + return zFAILURE; + } + authBeast = (AuthBeast_s *)nameMsg->curFile; + + if (*sequence == -1 || *sequence == 0) + { + /* Return owner as first trustee */ + *trusteeID = ownerID; + mode &= UX_IRWXU; + mode >>= UX_IMU; + } + else if (*sequence == 1) + { + /* Return group as second trustee */ + *trusteeID = groupID; + mode &= UX_IRWXG; + mode >>= UX_IMG; + } + else if (*sequence == 2) + { + /* Return world rights as third trustee */ + *trusteeID = zANYONE_USERID; + mode &= UX_IRWXO; + mode >>= UX_IMO; + } + else + { + *sequence = -1; + return zOK; + } + + *rights = translateUnixRightsToNetWare(mode); + *attributes = 0; + (*sequence)++; + return zOK; +} + +STATIC STATUS NW2UX_GetEffectiveRights( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT *effectiveRights) +{ + NINT mode; + AuthBeast_s *authBeast; + NINT ownerRights; + NINT groupRights; + NINT otherRights; + + ASSERT_MPKNSS_LOCK(); + +/*--------------------------------------------------------------------------- + * Resolve the name message to a beast + *---------------------------------------------------------------------------*/ + if (COMN_Lookup(genMsg, nameMsg) != zOK) + { + return zFAILURE; + } + + authBeast = (AuthBeast_s *)nameMsg->curFile; + UX_GetEffectivePermissions(authBeast, + &genMsg->pssConn.ptr->authInfo.authenticatedIDs[0], + genMsg->pssConn.ptr->authInfo.numAuthenticatedIDs, + &mode); + ownerRights = translateUnixRightsToNetWare((mode & UX_IRWXU) >> UX_IMU); + groupRights = translateUnixRightsToNetWare((mode & UX_IRWXG) >> UX_IMG); + otherRights = translateUnixRightsToNetWare((mode & UX_IRWXO) >> UX_IMO); + + *effectiveRights = ownerRights | groupRights | otherRights; + return zOK; +} + +STATIC STATUS NW2UX_GetEffectiveRightsByID( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *userGUID, + NINT *effectiveRights) +{ + NINT mode; + AuthBeast_s *authBeast; + NINT ownerRights; + NINT groupRights; + NINT otherRights; + + ASSERT_MPKNSS_LOCK(); + +/*--------------------------------------------------------------------------- + * Resolve the name message to a beast + *---------------------------------------------------------------------------*/ + if (COMN_Lookup(genMsg, nameMsg) != zOK) + { + return zFAILURE; + } + + authBeast = (AuthBeast_s *)nameMsg->curFile; + UX_GetEffectivePermissions(authBeast, userGUID, 1, &mode); + ownerRights = translateUnixRightsToNetWare((mode & UX_IRWXU) >> UX_IMU); + groupRights = translateUnixRightsToNetWare((mode & UX_IRWXG) >> UX_IMG); + otherRights = translateUnixRightsToNetWare((mode & UX_IRWXO) >> UX_IMO); + + *effectiveRights = ownerRights | groupRights | otherRights; + return zOK; +} + +STATIC STATUS NW2UX_GetInheritedRightsMask( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT *inheritedRights) +{ + *inheritedRights = 0; + return zOK; +} + +STATIC STATUS NW2UX_SetInheritedRightsMask( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT inheritedRights, + BOOL modifyFlag) +{ + return zOK; +} + +STATIC STATUS NW2UX_FindACLEntryInTree( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *searchMsg, + GetNameMsg_s *gfnMsg, + UserID_t *desiredTrusteeID, + NINT *rights, + NINT *attributes) +{ + SetErrno(genMsg, zERR_AUTH_SPACE_NOT_IMPLEMENTED); + return zFAILURE; +} + +STATUS NW2UX_PurgeACLEntriesFromTree( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + UserID_t *trusteeVector, + NINT trusteeCount) +{ + SetErrno(genMsg, zERR_AUTH_SPACE_NOT_IMPLEMENTED); + return zFAILURE; +} + +STATUS NW2UX_GetVisibilityCount( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT *numTrustees) +{ + *numTrustees = 0; + return zOK; +} + +STATUS NW2UX_GetVisibilityList( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + VisEntry_s *trusteeVector, + NINT *numTrustees) +{ + *numTrustees = 0; + return zOK; +} + +STATUS NW2UX_SwitchTrusteeIDs( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + void *hashTable) +{ + SetErrno(genMsg, zERR_AUTH_SPACE_NOT_IMPLEMENTED); + return zFAILURE; +} + +STATUS NW2UX_GetVisibilityEntries( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NINT numEntries, + VisEntry_s *visEntries, + NINT *numReturned) +{ + *numReturned = 0; + return zOK; +} + +STATUS NW2UX_GetEffectiveACL( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + ACLEntry_s **aclEntries, + NINT *numReturnedEntries) +{ + SetErrno(genMsg, zERR_AUTH_SPACE_NOT_IMPLEMENTED); + return zFAILURE; +} + +/***************************************************************************/ + +struct ZASAuthSpaceOps_s ZASAuthorizeSpaceOps = +{ + VAUTH_AddACLEntry, + VAUTH_RemoveACLEntry, + VAUTH_GetACLEntry, + VAUTH_GetEffectiveRights, + VAUTH_GetEffectiveRightsByID, + VAUTH_GetInheritedRightsMask, + VAUTH_SetInheritedRightsMask, + VAUTH_FindACLEntryInTree, + VAUTH_PurgeACLEntriesFromTree, + VAUTH_GetVisibilityCount, + VAUTH_GetVisibilityList, + VAUTH_SwitchTrusteeIDs, + VAUTH_GetVisibilityEntries, + VAUTH_GetEffectiveACL, +}; + +struct ZASAuthSpaceOps_s NetWareToUnixAuthorizeSpaceOps = +{ + NW2UX_AddACLEntry, + NW2UX_RemoveACLEntry, + NW2UX_GetACLEntry, + NW2UX_GetEffectiveRights, + NW2UX_GetEffectiveRightsByID, + NW2UX_GetInheritedRightsMask, + NW2UX_SetInheritedRightsMask, + NW2UX_FindACLEntryInTree, + NW2UX_PurgeACLEntriesFromTree, + NW2UX_GetVisibilityCount, + NW2UX_GetVisibilityList, + NW2UX_SwitchTrusteeIDs, + NW2UX_GetVisibilityEntries, + NW2UX_GetEffectiveACL, +}; diff --git a/src/nwnss/comn/common/cSA.c b/src/nwnss/comn/common/cSA.c new file mode 100644 index 0000000..a828f9c --- /dev/null +++ b/src/nwnss/comn/common/cSA.c @@ -0,0 +1,1392 @@ +/**************************************************************************** + | + | (C) Copyright 2002 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) Initialization module + | + |--------------------------------------------------------------------------- + | + | $Author: blarsen $ + | $Date: 2006-02-09 05:04:41 +0530 (Thu, 09 Feb 2006) $ + | + | $RCSfile$ + | $Revision: 1325 $ + | + |--------------------------------------------------------------------------- + +-------------------------------------------------------------------------*/ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "csa.h" +#include "csaLease.h" +#include "xMsg.h" + +NINT XLSSArrayIndex; +#if NSS_DEBUG IS_ENABLED + /* Our xMsg_s must not be bigger than a Msg_s */ +char xMSGSize[ sizeof(xMsg_s) <= sizeof(Msg_s) ]; +#endif +//char xMSG_Debug_Char = 0; /* Variable to init local xMsg_s for testing */ + +/** These globals define a worktodo that is scheduled to cleanup searchmaps + ** created on the master for XLSS searchMaps. We need to schedule a Work + ** because otherwise we may deadlock while trying to get the SM latch + **/ +typedef struct SearchMapCleanupWork_s +{ + FsmLite_s SMCW_fsm; + BOOL SMCW_workScheduled; +} SearchMapCleanupWork_s; + +SearchMapCleanupWork_s SMapCleanupWork; + +CIRhead_t SMapCleanupIDList = NULL; + +ObjCache_s CSASearchMapCleanupList; + + +/***************************************************************************** + * + ****************************************************************************/ +STATUS CSA_MsgRecv( + GeneralMsg_s *genMsg, + XLSS_GeneralMsg_s *xGenMsg, + xMsg_s *msg, + Zid_t zid, + RootBeast_s **beast, + NINT latchType) +{ + Volume_s *volume; + + CSA_REMOTE_GENMSG_TO_LOCAL_GENMSG(xGenMsg, genMsg); + + volume = ((CsaVolumeDoor_s *)msg->sys.door)->volume; + + if (volume == NULL) + { + SetErrno(genMsg, zERR_VOLUME_NOT_FOUND); + return zFAILURE; + } + COMN_USE_BEAST(&volume->VOLroot); + + if (COMN_LockVolumeActive(genMsg, volume, FALSE) != zOK) + { + COMN_Release(&volume); + return zFAILURE; + } + + *beast = BEASTHASH_LookupByZid(genMsg, volume, zid, latchType); + if (*beast == NULL) + { + COMN_UnlockVolumeActive(volume, FALSE); + COMN_Release(&volume); + return zFAILURE; + } + return zOK; +} + +void CSA_MsgRecvCleanup(RootBeast_s **beast, NINT latchType) +{ + Volume_s *volume = ((RootBeast_s *)(*beast))->ROOTvolume; + + COMN_UnlatchAndRelease(beast, latchType); + COMN_UnlockVolumeActive(volume, FALSE); + COMN_Release(&volume); +} + +/***************************************************************************** + * + ****************************************************************************/ +STATUS CSA_VOL_GetBeastFromVolume( + GeneralMsg_s *genMsg, + RootBeast_s *zlssBeast, + void *xlssPackedBeast, + NINT *xlssPackedSize) +{ + NINT realPackedSize; + + realPackedSize = BST_getPackedSizeIndex(zlssBeast, XLSSArrayIndex); + zASSERT(realPackedSize != 0); + + zASSERT(realPackedSize <= *xlssPackedSize); + if (realPackedSize > *xlssPackedSize) + { + *xlssPackedSize = 0; + BST_noPackCleanupIndex(zlssBeast, XLSSArrayIndex); + SetErrno(genMsg, zERR_BAD_LENGTH_UNPACKING_BEAST); + return zFAILURE; + } +// xlssPackedBeast->XPR_length = realPackedSize; + *xlssPackedSize = realPackedSize; + + BST_doPackIndex(zlssBeast, xlssPackedBeast, realPackedSize, XLSSArrayIndex); + + return zOK; +} + + +void CSA_VOL_GetBeastFromVolumeMsg( + xMsg_s *msg) /* Input and Output */ +{ + CSALeaseID_t beastLeaseID; + GeneralMsg_s genMsg; + RootBeast_s *zlssBeast; + STATUS status; + XLSS_GetBeastMsg_s *xlssPacket = &msg->body.getBeast.xlssPacket; /* Input */ + CSA_GetBeastMsg_s *csaPacket = &msg->body.getBeast.csaPacket; /* Output */ + + status = CSA_MsgRecv( &genMsg, &xlssPacket->XGBM_genMsg, msg, + xlssPacket->XGBM_zid, &zlssBeast, XLATCHED ); + if (status != zOK) + { + goto exitReturn; + } + + beastLeaseID = CSA_BeastLeaseAcquire( &genMsg, (CsaVolumeDoor_s *)msg->sys.door, zlssBeast ); + if ( beastLeaseID == INVALID_BEAST_LEASE_ID ) + { + status = zFAILURE; + goto exitCleanupReturn; + } + csaPacket->CGBM_beastLeaseID = beastLeaseID; + csaPacket->CGBM_dataSeqNum = zlssBeast->csaBeast->CB_dataSeqNum; + + status = CSA_VOL_GetBeastFromVolume(&genMsg, zlssBeast, + msg->sys.data[0].start, + &msg->sys.data[0].length); + if (status != zOK) + { + CSA_BeastLeaseToss( &genMsg, (CsaVolumeDoor_s *)msg->sys.door, + xlssPacket->XGBM_zid, beastLeaseID); + } +exitCleanupReturn: + CSA_MsgRecvCleanup(&zlssBeast, XLATCHED); + +exitReturn: + CSA_LOCAL_GENMSG_TO_REMOTE_GENMSG(status, &genMsg, &csaPacket->CGBM_genMsg); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +Zid_t CSA_VOL_LookupByNameInDirectory( + GeneralMsg_s *genMsg, + File_s *directory, + NameSpace_s *nameSpace, + NINT nameType, + unicode_t *name, +// cnt NINT nameUniquifier, /* passes zFNU_UNDEFINED if unknown */ +// cnt NINT *retNameUniquifier, + FullDirectoryInfo_s *retInfo) +{ + return directory->FILEcomnOps.BST_lookupByNameInDirectory(genMsg, + &directory->FILEnamed, nameSpace, nameType, name,/* cnt nameUniquifier, + retNameUniquifier,*/ retInfo); +} + +void CSA_VOL_LookupByNameInDirectoryMsg( + xMsg_s *msg) +{ + GeneralMsg_s genMsg; + STATUS status; + RootBeast_s *directory; + NameSpace_s *nameSpace; + XLSS_LookupByNameMsg_s *xlssPacket = &msg->body.lookupName.xlssPacket; + CSA_LookupByNameMsg_s *csaPacket = &msg->body.lookupName.csaPacket; +// cnt NINT nameUniquifier; + + status = CSA_MsgRecv( &genMsg, &xlssPacket->XLBM_genMsg, msg, + xlssPacket->XLBM_directoryZid, &directory, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + nameSpace = COMN_NameSpaceIDLookup(&genMsg, xlssPacket->XLBM_nSpaceID); + if (nameSpace == NULL) + { + status = zFAILURE; + goto exitNameSpaceLookupFailed; + } + + csaPacket->CLBM_zid = CSA_VOL_LookupByNameInDirectory(&genMsg, + (File_s *)directory, nameSpace, + xlssPacket->XLBM_nameType, + (unicode_t *)msg->sys.data[0].start, /* name */ +// cnt xlssPacket->XLBM_nameUniquifier, +// cnt &nameUniquifier, + (msg->sys.numDataAreas == 2 ? msg->sys.data[1].start : NULL)); + +// cnt csaPacket->CLBM_nameUniquifier = nameUniquifier; + + if (csaPacket->CLBM_zid == zINVALID_ZID) + { + status = zFAILURE; + } + + COMN_Release(&nameSpace); + +exitNameSpaceLookupFailed: + CSA_MsgRecvCleanup(&directory, SLATCHED); + +exitReturn: + CSA_LOCAL_GENMSG_TO_REMOTE_GENMSG(status, &genMsg, &csaPacket->CLBM_genMsg); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +STATUS CSA_VOL_GetStorageInfo( + GeneralMsg_s *genMsg, + RootBeast_s *beast, + GetStorageInfo_s *getStorageInfo) +{ + return COMN_GetStorageInfo(genMsg, beast, getStorageInfo); +} + +void CSA_VOL_GetStorageInfoMsg(xMsg_s *msg) +{ + GeneralMsg_s genMsg; + STATUS status; + RootBeast_s *beast; + XLSS_GetStorageInfoMsg_s *xlssPacket = &msg->body.getStorageInfo.xlssPacket; + CSA_GetStorageInfoMsg_s *csaPacket = &msg->body.getStorageInfo.csaPacket; + + status = CSA_MsgRecv( &genMsg, &xlssPacket->XGSM_genMsg, msg, + xlssPacket->XGSM_zid, &beast, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + status = CSA_VOL_GetStorageInfo(&genMsg, beast, + &csaPacket->CGSM_storageInfo); + + CSA_MsgRecvCleanup(&beast, SLATCHED); + +exitReturn: + CSA_LOCAL_GENMSG_TO_REMOTE_GENMSG(status, &genMsg, &csaPacket->CGSM_genMsg); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +BOOL CSA_VOL_IsBlockInBeast( + RootBeast_s *beast, + Blknum_t blkNum) +{ + return beast->ROOTcomnOps.BST_isBlockInBeast(beast, blkNum); +} + +void CSA_VOL_IsBlockInBeastMsg( + xMsg_s *msg) +{ + GeneralMsg_s genMsg; + STATUS status; + RootBeast_s *beast; + XLSS_IsBlockInBeastMsg_s *xlssPacket = &msg->body.isBlockInBeast.xlssPacket; + CSA_IsBlockInBeastMsg_s *csaPacket = &msg->body.isBlockInBeast.csaPacket; + + status = CSA_MsgRecv( &genMsg, NULL, msg, + xlssPacket->XIBM_zid, &beast, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + csaPacket->CIBM_retReply = CSA_VOL_IsBlockInBeast(beast, + xlssPacket->XIBM_block); + CSA_MsgRecvCleanup(&beast, SLATCHED); + +exitReturn: + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +Buffer_s *CSA_VOL_GetFileBlk( + GeneralMsg_s *genMsg, + IoMsg_s *ioMsg) +{ + return COMN_GetFileBlk(genMsg, ioMsg); +} + +void CSA_VOL_GetFileBlkMsg( + xMsg_s *msg) +{ + GeneralMsg_s genMsg; + STATUS status; + RootBeast_s *beast; + Buffer_s *buffer; + IoMsg_s ioMsg; + XLSS_GetFileBlkMsg_s *xlssPacket = &msg->body.getFileBlk.xlssPacket; + CSA_GetFileBlkMsg_s *csaPacket = &msg->body.getFileBlk.csaPacket; + + status = CSA_MsgRecv( &genMsg, &xlssPacket->XGFM_genMsg, msg, + xlssPacket->XGFM_zid, &beast, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + FILEBLK_IO_MSG(ioMsg, beast, xlssPacket->XGFM_fileBlk, 0, CACHE_READ); + buffer = CSA_VOL_GetFileBlk(&genMsg, &ioMsg); + if (buffer == NULL) + { + status = zFAILURE; + goto exitGetBlkFailed; + } + + csaPacket->CGFM_volBlk = buffer->volBlk; + zASSERT(msg->sys.data[0].length == PAGE_SIZE); + mapBufferPage(buffer); + memcpy(msg->sys.data[0].start, buffer->pBuf.data, msg->sys.data[0].length); + unmapBufferPage(buffer); + + CACHE_RELEASE(buffer); + +exitGetBlkFailed: + CSA_MsgRecvCleanup(&beast, SLATCHED); + +exitReturn: + CSA_LOCAL_GENMSG_TO_REMOTE_GENMSG(status, &genMsg, &csaPacket->CGFM_genMsg); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +Buffer_s *CSA_VOL_AsyncReadFileBlk( + GeneralMsg_s *genMsg, + IoMsg_s *ioMsg) +{ + STATUS status; + RootBeast_s *beast = ioMsg->beast; + BOOL done = FALSE; + QUAD offset; + QUAD numBytes; + NINT shift; +//FixFixFix(ACCESS LEASE) need to send the grantedRights from the XLSS side over here. + NINT grantedRights = 0; + + if ((beast->ROOTvariableData) && + ((*beast->ROOTvariableData)[RVD_COMP_META_DATA] != NULL)) + { + shift = beast->blkSizeShift; + offset = ((QUAD)ioMsg->fileBlk) << shift; + numBytes = ((QUAD)1) << shift; + + do + { + status = CM_uncompressFileRange(genMsg, beast, offset, numBytes, + CACHE_READ, SLATCHED, NULL, &grantedRights, TRUE, &done); + if (status != zOK) + { + return NULL; + } + } while (!done); + } + + return COMN_GetFileBlk(genMsg, ioMsg); +} + +void CSA_VOL_AsyncReadFileBlkMsg( + xMsg_s *msg) +{ + GeneralMsg_s genMsg; + RootBeast_s *beast; + IoMsg_s ioMsg; + STATUS status; + Buffer_s *buffer; + XLSS_AsyncReadMsg_s *xlssPacket = &msg->body.asyncReadBlk.xlssPacket; + CSA_AsyncReadMsg_s *csaPacket = &msg->body.asyncReadBlk.csaPacket; + + status = CSA_MsgRecv( &genMsg, NULL, msg, + xlssPacket->XARM_zid, &beast, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + FILEBLK_IO_MSG(ioMsg, beast, xlssPacket->XARM_fileBlk, 0, CACHE_READ); + buffer = CSA_VOL_AsyncReadFileBlk(&genMsg, &ioMsg); + if (buffer == NULL) + { + status = zFAILURE; + goto exitGetBlkFailed; + } + + csaPacket->CARM_volBlk = buffer->volBlk; + zASSERT(msg->sys.data[0].length == PAGE_SIZE); + mapBufferPage(buffer); + memcpy(msg->sys.data[0].start, buffer->pBuf.data, msg->sys.data[0].length); + unmapBufferPage(buffer); + + CACHE_RELEASE(buffer); + +exitGetBlkFailed: + CSA_MsgRecvCleanup(&beast, SLATCHED); + +exitReturn: + csaPacket->CARM_status = GetErrno(&genMsg); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +STATUS CSA_VOL_GetExtentList( + GeneralMsg_s *genMsg, + RootBeast_s *beast, + Blknum_t startingBlock, + NINT extentListSize, + Blknum_t extentList[], + NINT *retNumExtents, + Blknum_t *retNextBlock) +{ + return beast->ROOTcomnOps.BST_getExtentList(genMsg, beast, startingBlock, + extentListSize, extentList, retNumExtents, retNextBlock); +} + +void CSA_VOL_GetExtentListMsg( + xMsg_s *msg) +{ + STATUS status; + GeneralMsg_s genMsg; + RootBeast_s *beast; + NINT retNumExtents; + XLSS_GetExtentListMsg_s *xlssPacket = &msg->body.getExtentList.xlssPacket; + CSA_GetExtentListMsg_s *csaPacket = &msg->body.getExtentList.csaPacket; + + status = CSA_MsgRecv( &genMsg, &xlssPacket->XGEM_genMsg, msg, + xlssPacket->XGEM_zid, &beast, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + status = CSA_VOL_GetExtentList(&genMsg, beast, + xlssPacket->XGEM_startingBlk, + msg->sys.data[0].length / sizeof(Blknum_t), + (Blknum_t *)msg->sys.data[0].start, + &retNumExtents, + &csaPacket->CGEM_retNextBlock); + + csaPacket->CGEM_retNumExtents = retNumExtents; + + CSA_MsgRecvCleanup(&beast, SLATCHED); + +exitReturn: + CSA_LOCAL_GENMSG_TO_REMOTE_GENMSG(status, &genMsg, &csaPacket->CGEM_genMsg); + + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +BOOL CSA_VOL_IsDirectoryEmpty( + GeneralMsg_s *genMsg, + File_s *directory, + NINT nameType) +{ + return directory->FILEcomnOps.BST_isDirectoryEmpty(genMsg, + &directory->FILEnamed, nameType); +} + +void CSA_VOL_IsDirectoryEmptyMsg( + xMsg_s *msg) +{ + GeneralMsg_s genMsg; + STATUS status; + RootBeast_s *directory; + XLSS_IsDirectoryEmptyMsg_s *xlssPacket = &msg->body.isDirEmpty.xlssPacket; + CSA_IsDirectoryEmptyMsg_s *csaPacket = &msg->body.isDirEmpty.csaPacket; + + status = CSA_MsgRecv( &genMsg, &xlssPacket->XIDM_genMsg, msg, + xlssPacket->XIDM_dirZid, &directory, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + csaPacket->CIDM_retValue = CSA_VOL_IsDirectoryEmpty(&genMsg, + (File_s *)directory, xlssPacket->XIDM_nameType); + status = GetErrno(&genMsg); + + CSA_MsgRecvCleanup(&directory, SLATCHED); + +exitReturn: + CSA_LOCAL_GENMSG_TO_REMOTE_GENMSG(status, &genMsg, &csaPacket->CIDM_genMsg); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +STATUS CSA_VOL_GetPhysicalExtent( + zNSSMsg_s *msg, + RootBeast_s *beast) +{ + return beast->ROOTcomnOps.BST_getPhysicalExtent(msg, beast); +} + +void CSA_VOL_GetPhysicalExtentMsg( + xMsg_s *xMsg) +{ + STATUS status; + GeneralMsg_s genMsg; + RootBeast_s *beast; + zNSSMsg_s zMsg; + XLSS_GetPhysicalExtentMsg_s *xlssPacket=&xMsg->body.getPhyExtent.xlssPacket; + CSA_GetPhysicalExtentMsg_s *csaPacket = &xMsg->body.getPhyExtent.csaPacket; + + status = CSA_MsgRecv( &genMsg, NULL, xMsg, xlssPacket->XGPM_zid, + &beast, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + zMsg.sys.status = zOK; + zMsg.sys.owner = NULL; + zMsg.sys.door = NULL; + zMsg.sys.numDataAreas = 1; + zMsg.sys.data[MAP_DATA].start = xMsg->sys.data[MAP_DATA].start; + zMsg.sys.data[MAP_DATA].length = xMsg->sys.data[MAP_DATA].length; + zMsg.body.id.xid = 0; + zMsg.body.id.internalFlags = 0; + zMsg.body.id.externalFlags = 0; + zMsg.body.map.offset = xlssPacket->XGPM_startOffset; + zMsg.body.map.extentListFormat = zFILEMAP_PHYSICAL; + + status = CSA_VOL_GetPhysicalExtent(&zMsg, beast); + if (status == zOK) + { + csaPacket->CGPM_retNumExtents = zMsg.body.map.retExtentListCount; + csaPacket->CGPM_retOffset = zMsg.body.map.retEndingOffset; + } + + CSA_MsgRecvCleanup(&beast, SLATCHED); + +exitReturn: + csaPacket->CGPM_status = GetStatus(&zMsg); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +STATUS CSA_VOL_DioReadUnits( + zNSSMsg_s *msg, + RootBeast_s *beast) +{ + return beast->ROOTcomnOps.BST_dioReadUnits(msg, beast); +} + +void CSA_VOL_DioReadUnitsMsg( + xMsg_s *xmsg) +{ + STATUS status; + GeneralMsg_s genMsg; + Volume_s *volume; + RootBeast_s *beast; + zNSSMsg_s msg; + XLSS_DioReadUnitsMsg_s *xlssPacket = &xmsg->body.dioRead.xlssPacket; + CSA_DioReadUnitsMsg_s *csaPacket = &xmsg->body.dioRead.csaPacket; + + COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE(&genMsg); + + volume = COMN_VolumeIDLookup(&genMsg, &xlssPacket->XDRM_volumeID, TRUE); + + if (volume == NULL) + { + status = zFAILURE; + goto exitVolumeLookupFailed; + } + + if (COMN_LockVolumeActive(&genMsg, volume, FALSE) != zOK) + { + status = zFAILURE; + goto exitVolumeLockFailed; + } + + beast = BEASTHASH_LookupByZid(&genMsg, volume, + xlssPacket->XDRM_zid, SLATCHED); + if (beast == NULL) + { + status = zFAILURE; + goto exitBeastLookupFailed; + } + + msg.sys.status = zOK; + msg.sys.owner = NULL; + msg.sys.door = NULL; + msg.sys.numDataAreas = 1; +// msg.sys.data[DIO_DATA].start = csaPacket->CDRM_retData; + msg.sys.data[DIO_DATA].length = xlssPacket->XDRM_length; + msg.sys.callback = NULL; + msg.body.id.sa = xlssPacket->XDRM_saID; + msg.body.dio.unitOffset = xlssPacket->XDRM_startSector; + + status = CSA_VOL_DioReadUnits(&msg, beast); + if (status != zOK) + { + SetErrnoFromStatus(&genMsg, &msg); + } + + COMN_UnlatchAndRelease(&beast, SLATCHED); + +exitBeastLookupFailed: + COMN_UnlockVolumeActive(volume, FALSE); + +exitVolumeLockFailed: + COMN_Release(&volume); + +exitVolumeLookupFailed: + csaPacket->CDRM_status = GetErrno(&genMsg); + + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +Zid_t CSA_VOL_WildcardLookup( + GeneralMsg_s *genMsg, + File_s *directory, + NameSpace_s *nameSpace, + NINT nameType, + unicode_t *pattern, + SearchMap_s *smap, +// cnt NINT *retNameUniquifier, + FullDirectoryInfo_s *retInfo) +{ + return directory->FILEcomnOps.BST_wildcardLookup(genMsg, + &directory->FILEnamed, nameSpace, nameType, pattern, smap, + /* cnt retNameUniquifier,*/ retInfo); +} + +void CSA_VOL_WildcardLookupMsg( + xMsg_s *msg) +{ + GeneralMsg_s genMsg; + STATUS status; + RootBeast_s *directory; + NameSpace_s *nameSpace; + SearchMap_s *smap = NULL; + NSSConnection_s *pssConn; +// cnt NINT retNameUniquifier; + XLSS_WildcardLookupMsg_s *xlssPacket = &msg->body.wildLookup.xlssPacket; + CSA_WildcardLookupMsg_s *csaPacket = &msg->body.wildLookup.csaPacket; + + status = CSA_MsgRecv( &genMsg, &xlssPacket->XWLM_genMsg, msg, + xlssPacket->XWLM_directoryZid, &directory, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + nameSpace = COMN_NameSpaceIDLookup(&genMsg, xlssPacket->XWLM_nSpaceID); + if (nameSpace == NULL) + { + status = zFAILURE; + goto exitNameSpaceLookupFailed; + } + + if ((pssConn = CNCT_RESOLVE_CONNECTION(&genMsg)) == NULL) + { + status = zFAILURE; + goto exitConnectionResolveFailed; + } + + pssConn->connUseCount++; + X_LATCH(&pssConn->searchMaps.smLatch); + + if (xlssPacket->XWLM_smapID == 0) + { + smap = objCacheAlloc( &SearchMapObjCache); + if (smap == NULL) + { + SetErrno(&genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exitSmapSetupFailed; + } + bzero(smap, sizeof(*smap)); + smap->options = SMAPOPT_notReusable | SMAPOPT_32BitMode; + smap->mapID = pssConn->searchMaps.nextMapID--; + smap->useCount = 1; + smap->volumeID = directory->ROOTvolume->volumeID; + smap->taskID = genMsg.taskID; + smap->semanticAgentID = genMsg.saID; + smap->pssConn = pssConn; + DQ_PUSH(&pssConn->searchMaps.inuseList, smap, link); + DQ_ENQ(&((CsaVolumeDoor_s *)msg->sys.door)->smapHead, smap, croLink); + } + else + { + smap = SMAP_FindSearchMapByID(&pssConn->searchMaps, + xlssPacket->XWLM_smapID, SMAPOPT_notReusable); + if (smap == NULL) + { + SetErrno(&genMsg, zERR_BAD_SEARCHMAP_ID); + status = zFAILURE; + goto exitSmapSetupFailed; + } + } + smap->options |= xlssPacket->XWLM_smapOptions; + csaPacket->CWLM_smapID = smap->mapID; + + csaPacket->CWLM_zid = CSA_VOL_WildcardLookup(&genMsg, + (File_s *)directory, nameSpace, + xlssPacket->XWLM_nameType, + (unicode_t *)msg->sys.data[0].start, /* pattern */ + smap, +// cnt &retNameUniquifier, + (msg->sys.numDataAreas == 2 ? msg->sys.data[1].start : NULL)); + + if (csaPacket->CWLM_zid == zINVALID_ZID) + { + status = zFAILURE; + } +// cnt csaPacket->CWLM_nameUniquifier = retNameUniquifier; + + csaPacket->CWLM_smapOptions = (smap->options & XLSS_SMAPOPT_MASK); + +exitSmapSetupFailed: + UNX_LATCH(&pssConn->searchMaps.smLatch); + pssConn->connUseCount--; + +exitConnectionResolveFailed: + COMN_Release(&nameSpace); + +exitNameSpaceLookupFailed: + CSA_MsgRecvCleanup(&directory, SLATCHED); + +exitReturn: + CSA_LOCAL_GENMSG_TO_REMOTE_GENMSG(status, &genMsg, &csaPacket->CWLM_genMsg); + return; +} + + +/***************************************************************************** + * + * This is the WorkToDo that will release all SearchMaps that have been + * added to a global linked list. This is to avoid deadlocks while trying + * to get the SM latch. + * + ****************************************************************************/ +void CSA_SearchMapCleanupMsgWork( + FsmLite_s *fsm) +{ + GeneralMsg_s genMsg; + SearchMap_s *smap = NULL; + NSSConnection_s *pssConn; + SearchMapCleanupIDList_s *smapIDList; + + COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE(&genMsg); + + if ((pssConn = CNCT_RESOLVE_CONNECTION(&genMsg)) == NULL) + { + goto exitConnectionResolveFailed; + } + + pssConn->connUseCount++; + X_LATCH(&pssConn->searchMaps.smLatch); + + for (;;) + { + CIR_DEQ(SMapCleanupIDList, smapIDList, + SearchMapCleanupIDList_s, SMCIL_link); + + if (smapIDList == NULL) + { + break; + } + smap = SMAP_FindSearchMapByID( &pssConn->searchMaps, + smapIDList->SMCIL_smapID, + SMAPOPT_notReusable); + if (smap != NULL) + { + SMAP_ReleaseSearchMap(smap); + } + objCacheFree(smapIDList); + } + + UNX_LATCH(&pssConn->searchMaps.smLatch); + pssConn->connUseCount--; + +exitConnectionResolveFailed: + SMapCleanupWork.SMCW_workScheduled = FALSE; + return; +} + +/***************************************************************************** + * + * Request from the XLSS to cleanup a particular SM + * + ****************************************************************************/ +void CSA_SearchMapCleanupMsg( + xMsg_s *msg) +{ + XLSS_SearchMapCleanupMsg_s *xlssPacket = &msg->body.smapCleanup.xlssPacket; + SearchMapCleanupIDList_s *smapIDList; + + smapIDList = objCacheAlloc( &CSASearchMapCleanupList); + if (smapIDList == NULL) + { + return; + } + smapIDList->SMCIL_smapID = xlssPacket->XSMM_smapID; + smapIDList->SMCIL_link = NULL; + + CIR_ENQ(SMapCleanupIDList, smapIDList, SMCIL_link); + + if (!SMapCleanupWork.SMCW_workScheduled) + { + SMapCleanupWork.SMCW_workScheduled = TRUE; + FSMLITE_INIT(&SMapCleanupWork.SMCW_fsm, MSGNot("SmapCleanupWork"), 0); + WORK_Schedule( &SMapCleanupWork.SMCW_fsm, + CSA_SearchMapCleanupMsgWork, NULL); + } + return; +} + + +/***************************************************************************** + * + * Request from the XLSS to cleanup all SMs that were created for this + * slave. + * + * I get the IDs and put them on the list (instead of directly releasing them) + * because the SM latch needs to be held to release them. Getting the latch + * at this point can cause a deadlock. + * + ****************************************************************************/ +void CSA_SearchMapCleanupAll( + CsaVolumeDoor_s *volObject) +{ + SearchMapCleanupIDList_s *smapIDList; + SearchMap_s *smap; + + for (;;) + { + DQ_DEQ(&volObject->smapHead, smap, SearchMap_s, croLink); + + if (smap == NULL) + { + break; + } + smapIDList = objCacheAlloc( &CSASearchMapCleanupList); + if (smapIDList == NULL) + { + return; + } + smapIDList->SMCIL_smapID = smap->mapID; + smapIDList->SMCIL_link = NULL; + + CIR_ENQ(SMapCleanupIDList, smapIDList, SMCIL_link); + + if (!SMapCleanupWork.SMCW_workScheduled) + { + SMapCleanupWork.SMCW_workScheduled = TRUE; + FSMLITE_INIT(&SMapCleanupWork.SMCW_fsm, MSGNot("SmapCleanupWork"), 0); + WORK_Schedule( &SMapCleanupWork.SMCW_fsm, + CSA_SearchMapCleanupMsgWork, NULL); + } + PERIODIC_YIELD(); + } + return; +} + +void CSA_SearchMapCleanupAllMsg( + xMsg_s *msg) +{ + CSA_SearchMapCleanupAll((CsaVolumeDoor_s *)msg->sys.door); + return; +} + +/***************************************************************************** + * + ****************************************************************************/ +Zid_t CSA_SearchMapReestablish( + GeneralMsg_s *genMsg, + File_s *directory, + NameSpace_s *nameSpace, + NINT nameType, + unicode_t *pattern, + SearchMap_s *smap) +{ +// cnt NINT retNameUniquifier; + + return directory->FILEcomnOps.BST_wildcardLookup(genMsg, + &directory->FILEnamed, nameSpace, nameType, pattern, smap, + /* cnt &retNameUniquifier,*/ NULL); +} + +void CSA_SearchMapReestablishMsg( + xMsg_s *msg) +{ + GeneralMsg_s genMsg; + STATUS status; + File_s *file; + RootBeast_s *directory; + NameSpace_s *nameSpace; + SearchMap_s *smap = NULL; + NSSConnection_s *pssConn; + typedef struct Stack_s { + unicode_t name[zMAX_COMPONENT_NAME]; + } Stack_s; + Stack_s *aStack; + + XLSS_SearchMapReestablishMsg_s *xlssPacket = + &msg->body.reestablishSmap.xlssPacket; + CSA_SearchMapReestablishMsg_s *csaPacket = + &msg->body.reestablishSmap.csaPacket; + + STACK_ALLOC_NO_ASTACK(); + + status = CSA_MsgRecv( &genMsg, &xlssPacket->XSRM_genMsg, msg, + xlssPacket->XSRM_directoryZid, &directory, SLATCHED); + if (status != zOK) + { + goto exitReturn; + } + + nameSpace = COMN_NameSpaceIDLookup(&genMsg, xlssPacket->XSRM_nSpaceID); + if (nameSpace == NULL) + { + status = zFAILURE; + goto exitNameSpaceLookupFailed; + } + + if ((pssConn = CNCT_RESOLVE_CONNECTION(&genMsg)) == NULL) + { + status = zFAILURE; + goto exitConnectionResolveFailed; + } + + /** Get the name corresponding to the zid where we want to set our + ** search map to + **/ + if ((file = BEASTHASH_LookupByZid(&genMsg, directory->ROOTvolume, + xlssPacket->XSRM_zid, SLATCHED)) == NULL) + { + status = zFAILURE; + goto exitLookupFailed; + } + if (COMN_GetNameFromBeast(&genMsg, file, /* cnt zFNU_FIRST_PARENT, */ + xlssPacket->XSRM_nSpaceID, zMAX_COMPONENT_NAME, + aStack->name, NULL) != zOK) + { + COMN_UnlatchAndRelease(&file, SLATCHED); + status = zFAILURE; + goto exitGetNameFailed; + } + COMN_UnlatchAndRelease(&file, SLATCHED); + + pssConn->connUseCount++; + X_LATCH(&pssConn->searchMaps.smLatch); + + smap = objCacheAlloc( &SearchMapObjCache); + if (smap == NULL) + { + SetErrno(&genMsg, zERR_NO_MEMORY); + status = zFAILURE; + goto exitSmapSetupFailed; + } + bzero(smap, sizeof(*smap)); + smap->options = SMAPOPT_notReusable | SMAPOPT_32BitMode; + smap->mapID = pssConn->searchMaps.nextMapID--; + smap->useCount = 1; + smap->volumeID = directory->ROOTvolume->volumeID; + smap->taskID = genMsg.taskID; + smap->semanticAgentID = genMsg.saID; + smap->pssConn = pssConn; + DQ_PUSH(&pssConn->searchMaps.inuseList, smap, link); + DQ_ENQ(&((CsaVolumeDoor_s *)msg->sys.door)->smapHead, smap, croLink); + + smap->options |= xlssPacket->XSRM_smapOptions; + csaPacket->CSRM_smapID = smap->mapID; + + csaPacket->CSRM_zid = CSA_SearchMapReestablish(&genMsg, + (File_s *)directory, nameSpace, + xlssPacket->XSRM_nameType, + aStack->name, /* pattern */ + smap); + + if (csaPacket->CSRM_zid == zINVALID_ZID) + { + status = zFAILURE; + } + csaPacket->CSRM_smapOptions = (smap->options & XLSS_SMAPOPT_MASK); + +exitSmapSetupFailed: + UNX_LATCH(&pssConn->searchMaps.smLatch); + pssConn->connUseCount--; + +exitLookupFailed: +exitGetNameFailed: +exitConnectionResolveFailed: + COMN_Release(&nameSpace); + +exitNameSpaceLookupFailed: + CSA_MsgRecvCleanup(&directory, SLATCHED); + +exitReturn: + CSA_LOCAL_GENMSG_TO_REMOTE_GENMSG(status, &genMsg, &csaPacket->CSRM_genMsg); + STACK_FREE(); + return; +} + +/***************************************************************************** + * CSA_SendVolumeStats + * + * Runs on a timer to send updates VolumeStats to the slaves, if the stats + * have changed. + ****************************************************************************/ +void CSA_SendVolumeStats( + FsmLite_s *fsm, + Volume_s *volume) +{ + CsaVolumeInfo_s *csaVolInfo = volume->v_csaVolInfo; + xMsg_s msg; + CSA_SendVolumeStatsMsg_s *csaPacket = &msg.body.sendVolStats.csaPacket; + + if (csaVolInfo->CVI_volume == NULL) + { + csaVolInfo->CVI_scheduled = FALSE; + COMN_Release(&volume); + return; + } + zASSERT(volume == csaVolInfo->CVI_volume); + if (!CSA_SLAVE_VOLUMES_FOUND(volume)) + { + csaVolInfo->CVI_scheduled = FALSE; + COMN_Release(&volume); + return; + } + + CSAVOL_FillMasterVolInfo(volume, &csaVolInfo->CVI_volStatsLastSent); + + xMSG_INIT( &msg ); + CSAVOL_FillMasterVolInfo(volume, &csaPacket->CVSM_volInfo) + + CSA_MsgSendAll(volume, &msg, XLSS_SEND_VOLUME_STATS); + + secOneShot( &csaVolInfo->CVI_volumeStatsUpdateTimer, + CFS_UPDATE_VOL_STATS_SECS, + CSA_SendVolumeStatsCheck); + + COMN_Release(&volume); + return; +} + + +/* + * This routine cannot block because it is called by a timer + */ +void CSA_SendVolumeStatsCheck( + OneShot_s *timer) +{ + CsaVolumeInfo_s *csaVolInfo = STRUCT(timer, CsaVolumeInfo_s, + CVI_volumeStatsUpdateTimer); + Volume_s *volume = csaVolInfo->CVI_volume; + XlssMasterVolumeInfo_s volInfo; + + if (volume == NULL) + { + csaVolInfo->CVI_scheduled = FALSE; + return; + } + if (!CSA_SLAVE_VOLUMES_FOUND(volume)) + { + csaVolInfo->CVI_scheduled = FALSE; + return; + } + + CSAVOL_FillMasterVolInfo(volume, &volInfo); + + if (memcmp(&volInfo, &csaVolInfo->CVI_volStatsLastSent, + sizeof(volInfo)) != 0) + { + COMN_USE_BEAST(&volume->VOLroot); + WORK_Schedule(&csaVolInfo->CVI_fsm, CSA_SendVolumeStats, (ADDR)volume); + } + else + { + secOneShot( &csaVolInfo->CVI_volumeStatsUpdateTimer, + CFS_UPDATE_VOL_STATS_SECS, + CSA_SendVolumeStatsCheck); + } + return; + +} + +/***************************************************************************** + * + * This routine is called when the slave first starts communicating with + * the master. When the slave who has demanded gets its callback routine + * called, it will call this routine to create a communication link with + * a set of keys being exchanged. + * This routine is called with the volume active if we are not in reconnect + * mode. + ****************************************************************************/ +void CSA_VolNotifyMsg( + xMsg_s *msg) +{ + GeneralMsg_s genMsg; + Volume_s *volume; + XLSS_VolNotifyMsg_s *xlssPacket = &msg->body.volNotify.xlssPacket; + Key_t xlssVolKey; + Key_t csaVolKey; + CsaVolumeDoor_s *csaVolObject; + STATUS status; + BOOL lockedActive = FALSE; + typedef struct Stack_s { + xMsg_s reconnectMsg; + xMsg_s xMsg; + } Stack_s; + STACK_ALLOC(); + + COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE(&genMsg); + + volume = ((CsaMsgDoor_s *)msg->sys.door)->volume; + if (volume == NULL) + { + goto exitReturn; + } + xlssVolKey = msg->sys.passedKey; + + COMN_USE_BEAST(&volume->VOLroot); + + if (!(volume->v_statusFlag & VOL_SF_RECONNECT)) + { + if (COMN_LockVolumeActive(&genMsg, volume, FALSE) != zOK) + { + goto exitLockVolumeFailed; + } + else + { + lockedActive = TRUE; + } + } + else + { + ASSERT_XLATCH( &volume->stateLatch); + } + + switch (xlssPacket->XVNM_volState) + { + case zVOLSTATE_ACTIVE: + { + if (!(volume->v_statusFlag & VOL_SF_RECONNECT) && + (xlssPacket->XVNM_reconnectState != + CRO_RECONNECT_STATE_IN_SYNC)) + { + goto exitBadState; + } + if (volume->v_csaVolInfo == NULL) + { + if (CSABeastHash == NULL) + { + STATUS status; + + status = CSA_CSABeastHashInit(); + if (status != zOK) + { + goto exitBadState; + } + } + volume->v_csaVolInfo = (CsaVolumeInfo_s *) + zalloc(sizeof(CsaVolumeInfo_s)); + if (volume->v_csaVolInfo == NULL) + { + goto exitBadState; + } + COMN_USE_BEAST(&volume->VOLroot); + volume->v_csaVolInfo->CVI_volume = volume; + DQ_INIT(&volume->v_csaVolInfo->CVI_csaVolumeDoorHead); + DQ_INIT(&volume->v_csaVolInfo->CVI_csaBeastHead); + INIT_ONESHOT(volume->v_csaVolInfo->CVI_volumeStatsUpdateTimer); + FSMLITE_INIT(&volume->v_csaVolInfo->CVI_fsm, + MSGNot("CFS Volume Stats"), 0); + volume->v_csaVolInfo->CVI_scheduled = FALSE; + } + csaVolObject = MSG_CreateDoor(&CsaVolumeType.hdr, + CsaMsgMgr.mgr, 0, &csaVolKey); + if (csaVolObject == NULL) + { + goto exitBadState; + } + + xMSG_INIT(&aStack->xMsg); + aStack->xMsg.sys.passedKey = csaVolKey; + + status = MSG_SendKey(xlssVolKey, XLSS_VOL_KEY, (Msg_s *)&aStack->xMsg); + if (status != zOK) + { + goto exitBadState; + } + + csaVolObject->xlssVolumeKey = xlssVolKey; + COMN_USE_BEAST(&volume->VOLroot); + csaVolObject->volume = volume; + csaVolObject->reconnectState = xlssPacket->XVNM_reconnectState; + NULLIFY(&csaVolObject->csaVolumeDoorLink); + DQ_ENQ( &volume->v_csaVolInfo->CVI_csaVolumeDoorHead, + csaVolObject, csaVolumeDoorLink); + DQ_INIT(&csaVolObject->smapHead); + if (csaVolObject->reconnectState == CRO_RECONNECT_STATE_IN_SYNC) + { + if (!(volume->v_statusFlag & VOL_SF_RECONNECT)) + { + xMSG_INIT(&aStack->reconnectMsg); + MSG_Send(csaVolObject->xlssVolumeKey, + XLSS_ALL_SLAVES_SYNCD, (Msg_s *)&aStack->reconnectMsg); + } + } + if (!volume->v_csaVolInfo->CVI_scheduled) + { + volume->v_csaVolInfo->CVI_scheduled = TRUE; + secOneShot( &volume->v_csaVolInfo->CVI_volumeStatsUpdateTimer, + CFS_UPDATE_VOL_STATS_SECS, + CSA_SendVolumeStatsCheck); + } + break; + } + default: + { + goto exitBadState; + } + } + +exitBadState: + if (lockedActive) + { + COMN_UnlockVolumeActive(volume, FALSE); + } + +exitLockVolumeFailed: + COMN_Release(&volume); + +exitReturn: + STACK_FREE(); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +void CSA_ReconnectNotifyMsg( + xMsg_s *msg) +{ + XLSS_ReconnectNotifyMsg_s *xlssPacket = &msg->body.reconNotify.xlssPacket; + CsaVolumeDoor_s *csaVolObject; + + csaVolObject = (CsaVolumeDoor_s *)msg->sys.door; + csaVolObject->reconnectState = xlssPacket->XRNM_reconnectState; +} + + +/***************************************************************************** + * + ****************************************************************************/ +void CSA_VolGetAuthModelIDMsg( + xMsg_s *msg) +{ + Volume_s *volume; + CSA_VolGetAuthModelIDMsg_s *csaPacket = &msg->body.getAuthID.csaPacket; + + volume = ((CsaMsgDoor_s *)msg->sys.door)->volume; + zASSERT( volume != NULL ); + + csaPacket->CCGM_authModelID = volume->VOLauthModelID; + CSAVOL_FillMasterVolInfo(volume, &csaPacket->CGCM_volInfo); + + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +void CSA_Clean_UI() +{ + CSA_CSABeastNotInUseTossAll(); +} /* End of CSA_Clean_UI() */ + + +void CSA_StatsDisplay_UI() +{ + + aprintf(LGREEN,"CSABeasts:\n"); + aprintf(CYAN," Size %u\n", sizeof( CSABeast_s ) ); + aprintf(CYAN," Current %Lu\n", CSAStats.CS_csaBeastCurrent ); + aprintf(CYAN," NotInUse %Lu\n", CSAStats.CS_csaBeastNotInUse ); + aprintf(CYAN," Constructed %Lu\n", CSAStats.CS_csaBeastConstructed ); + aprintf(CYAN," Destructed %Lu\n", CSAStats.CS_csaBeastDestructed ); + aprintf(LRED," Constructed(F) %Lu\n", CSAStats.CS_csaBeastConstructFailed ); + aprintf(CYAN," Reserved %Lu\n", CSAStats.CS_csaBeastReserved ); + + aprintf(LGREEN,"Beast Leases:\n"); + aprintf(CYAN," Size %u\n", sizeof( CSABeastLease_s ) ); + aprintf(CYAN," Current %Lu\n", CSAStats.CS_beastLeaseCurrent ); + aprintf(CYAN," Constructed %Lu\n", CSAStats.CS_beastLeaseConstructed ); + aprintf(CYAN," Destructed %Lu\n", CSAStats.CS_beastLeaseDestructed ); + aprintf(LRED," Constructed(F) %Lu\n", CSAStats.CS_beastLeaseConstructFailed ); + aprintf(CYAN," Tossed %Lu\n", CSAStats.CS_beastLeaseToss ); + aprintf(LRED," Tossed(F) %Lu\n", CSAStats.CS_beastLeaseTossFailed ); + aprintf(CYAN," Cleaned(Hit) %Lu\n", CSAStats.CS_beastLeaseCleanup ); + aprintf(CYAN," Cleaned(Miss) %Lu\n", CSAStats.CS_beastLeaseCleanupMissing ); + aprintf(CYAN," Deleted %Lu\n", CSAStats.CS_beastLeaseDeleted ); + +} /* End of CSA_StatsDisplay_UI() */ diff --git a/src/nwnss/comn/common/cmdLineRecovery.c b/src/nwnss/comn/common/cmdLineRecovery.c new file mode 100644 index 0000000..358eff6 --- /dev/null +++ b/src/nwnss/comn/common/cmdLineRecovery.c @@ -0,0 +1,1494 @@ +/**************************************************************************** + | + | (C) Copyright 2002 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | Novell Storage Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: taysom $ + | $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $ + | + | $RCSfile$ + | $Revision: 465 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Recover SYS volume if it was renamed or if you need to expand it. + +-------------------------------------------------------------------------*/ +#include + +#include +#include +#include +#include "zPublics.h" + +#include "xmlNSS.h" +#include "xmlTags.h" + + +/* Global variables */ + +NINT SYSHotFixSize = 100; // Global variable for allowing a hotfix value to be set + // for when we do an expandsys from the command line. + +// prototypes for this module +utf8_t * ReadReply(Key_t fileKey); + +#define BUFFERSIZE 500 +#define PARTITIONBUFFERSIZE 64 +#define REPLYBUFFERSIZE 2047 +#define POOLSTATESIZE 30 + +/* Function Pre-Declaration(s) */ +STATUS WriteBuffer(utf8_t *requestBuffer, Key_t fileKey, NINT size); +STATUS InitializeCommandFile(Key_t *fileKey, Key_t *rootKey); + +/**************************************************************************** +** Function: CovertFromSectors +** +** Given the number of sectors, convert it to either MB or GB depending on +** its size. partitionSize points to the string. +** Returns: Nothing +****************************************************************************/ + +void CovertFromSectors(char size[], utf8_t* partitionSize) +{ + QUAD capacity; + LONG rSize, modSize; + QUAD mSize; + + capacity = LB_atoq(size); + if ((capacity / 2048) <= 9999) // use MB up to 9999 MB + { + capacity = capacity / 2048; // divide by 2048 to get MB + LB_sprintf(partitionSize, "%Lu MB", capacity); + } + else + { + capacity *= 100; // after that convert to GB + mSize = capacity / 2097152; + modSize = mSize % 100; + rSize = mSize / 100; + LB_sprintf(partitionSize, "%u.%02u GB", rSize, modSize); + } + return; +} + +/**************************************************************************** +** Function: DisplayFreePartitions +** +** List all Type "0" partitions and any NSS partitions that aren't part of +** a pool +** Returns: Status +****************************************************************************/ + +STATUS DisplayFreePartitions() +{ + char partitionID[24]; + char partitionName[128]; + char partitionType[24]; + char numSectors[64]; + char poolName[20]; + utf8_t *requestBuffer; + utf8_t *replyBuffer; + utf8_t *partitionSize; + + XML_ElementInfo_s elementInfo; + utf8_t *startOfData; + utf8_t *endOfData; + utf8_t *savstartOfData; + utf8_t *savendOfData; + Key_t rootKey; + Key_t fileKey; + + // get space for request buffer + // if we couldn't get memory abort + requestBuffer = (utf8_t *)malloc(BUFFERSIZE); + if (requestBuffer == NULL) + { + aprintf( LRED, "Error out of memory" ); + return(zFAILURE); + } + + strcpy(requestBuffer, ""); + // initialize command file + // abort if error on initializing command file. + if (InitializeCommandFile(&fileKey, &rootKey) != zOK) + { + free(requestBuffer); + return(zFAILURE); + } + // request partition information + // abort if error on writing to command file. + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); + return(zFAILURE); + } + // get reply + // abort if error on read + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); + return(zFAILURE); + } + + // Close manage.cmd + zClose(fileKey); + zClose(rootKey); + + // get space for partitionSize buffer + // if we couldn't get memory abort + partitionSize = (utf8_t *)malloc(PARTITIONBUFFERSIZE); + if (partitionSize == NULL) + { + aprintf( LRED, "Memory allocation error.\n" ); + free(requestBuffer); + free(replyBuffer); + return(zFAILURE); + } + + // setup pointers to start and end of buffer. + startOfData = replyBuffer; + endOfData = startOfData + strlen(replyBuffer); + aprintf( LBLUE, "PartitionID\t Size\t\tPartition Name\n" ); + while (1) + { + if (XML_GetTagElement(TAG_PARTITIONINFO, startOfData, endOfData, &elementInfo) == zOK) + { + // parse to partitionInfo tag + // save pointers to the begin partitionInfo tag and the end + // partitionInfo tag + savstartOfData = elementInfo.dataStart; + savendOfData = elementInfo.dataEnd; + if (XML_GetTagElement(TAG_PARTITIONNAME, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // get partitionName and save it for later + memcpy(partitionName, elementInfo.dataStart, elementInfo.dataLen); + partitionName[elementInfo.dataLen] = '\0'; + // restore saved position + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_PARTITIONTYPE, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // get partitionType and save it for later + memcpy(partitionType, elementInfo.dataStart, elementInfo.dataLen); + partitionType[elementInfo.dataLen] = '\0'; + // restore saved position + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_PARTITIONID, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // get partitionID and save it for later + memcpy(partitionID, elementInfo.dataStart, elementInfo.dataLen); + partitionID[elementInfo.dataLen] = '\0'; + + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; // restore saved position + if (XML_GetTagElement(TAG_NUMSECTORS, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // get numSectors + memcpy(numSectors, elementInfo.dataStart, elementInfo.dataLen); + numSectors[elementInfo.dataLen] = '\0'; + // restore saved position + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_POOLNAME, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // get poolName and save it for later + memcpy(poolName, elementInfo.dataStart, elementInfo.dataLen); + poolName[elementInfo.dataLen] = '\0'; + } + else + { + // if partition isn't part of pool make sure poolName is "" + poolName[0] = '\0'; + } + if (strcmp(partitionType, "0") == 0) + { + // if partition type is Free and greater then 1 MB then output + if ((LB_atoq(numSectors) / 2048) > 1) + { + CovertFromSectors(numSectors, partitionSize); + aprintf( LGREEN, " %-7s%12s %s\n", partitionID, partitionSize, partitionName ); + } + } + else + { + // else if partition type is NSS see if it's part of a pool + if (strcmp(partitionType, "105") == 0) + { + if (strcmp( poolName,"") == 0) + { + // if its not part of a pool then output + CovertFromSectors(numSectors, partitionSize); + aprintf( LGREEN, " %-7s%12s %s\n", partitionID, partitionSize, partitionName ); + } + } + } + } + } + } + } + } + else + { + // no more partitions so free up memory and return zOK + free(requestBuffer); + free(replyBuffer); + free(partitionSize); + return zOK; + } + // ajust start position so we get the next partitionInfo tag + startOfData = savendOfData; + } +} + +/**************************************************************************** +** Function: SalvageSys +** +** Salvage SYS +** +** Returns: Status +****************************************************************************/ + +STATUS SalvageSys() +{ + +#define SALVAGESYSFORMATSTRING "%-17s%-15s%-45s\n" + + char UndeleteVolume[] = ""; + char UndeleteVolume1[] = ""; + char UndeleteVolume2[] = ""; + char UndeleteVolume3[] = ""; + char RequestDeletedVolumeInfoCommand[] = ""; + char RequestDeletedVolumeInfoCommand1[] = ""; + char RequestVolumeInfo[] = ""; + char RequestVolumeInfo1[] = ""; + char RequestPoolCommand[] = ""; + + char resultValue[25]; + char description[128]; + char poolState[POOLSTATESIZE]; + + utf8_t **internalVolNamePtr = NULL; + utf8_t **ptr; + utf8_t **poolNameptr; + utf8_t **pPtr; + utf8_t *requestBuffer; + utf8_t *replyBuffer; + utf8_t *savendOfData; + utf8_t *startOfData; + utf8_t *endOfData; + + XML_ElementInfo_s elementInfo; + Key_t rootKey; + Key_t fileKey; + NINT count = 0; + NINT i,j,pCount; + + // get space for request buffer + // if we couldn't get memory abort + requestBuffer = (utf8_t *)malloc(BUFFERSIZE); + if (requestBuffer == NULL) + { + aprintf( LRED, "Memory allocation error. SalvageSys failed.\n" ); + return(zFAILURE); + } + + // initialize command file + // abort if error on initializing command file. + if (InitializeCommandFile(&fileKey, &rootKey) != zOK) + { + free(requestBuffer); + aprintf( LRED, "Error initializing command file. SalvageSys failed.\n" ); + return(zFAILURE); + } + + strcpy(requestBuffer, RequestPoolCommand); + + // request list of all pools so we can check each one to see which one contains deleted + // SYS volume. + // abort if error on writing to command file. + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + aprintf( LRED, "Error getting pool information. SalvageSys failed.\n" ); + goto CleanUpFailure; + } + + // get reply + // abort if error on read + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + aprintf( LRED, "Error getting pool information. SalvageSys failed.\n" ); + goto CleanUpFailure; + } + startOfData = replyBuffer; + endOfData = startOfData + strlen(replyBuffer); + + pCount = 0; + // get space for pointer to pools + // if we couldn't get memory abort + if ((poolNameptr = malloc(sizeof(poolNameptr))) == NULL) + { + aprintf( LRED, "Memory allocation error. SalvageSys failed.\n" ); + goto CleanupFailureWithReply; + } + + // parse to listPools tag + if (XML_GetTagElement(TAG_LISTPOOLS, startOfData, + endOfData, &elementInfo) == zOK) + { + while (1) + { + // save listPools end tag position + savendOfData = elementInfo.dataEnd; + // keep looking for poolInfo tags until we get a list of all pools + if (XML_GetTagElement(TAG_POOLINFO, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // get poolName + if (XML_GetTagElement(TAG_POOLNAME, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + poolNameptr[pCount] = malloc(elementInfo.dataLen +1); + memcpy(poolNameptr[pCount], elementInfo.dataStart, + elementInfo.dataLen); + poolNameptr[pCount][elementInfo.dataLen] = '\0'; + pCount++; + // allocate another position in array for the next pointer + // abort on error getting memory + if ((pPtr = realloc(poolNameptr, + (pCount+1) * sizeof(poolNameptr))) == NULL) + { + aprintf( LRED, "Memory allocation error. SalvageSys failed.\n" ); + goto CleanUpFailureWithPoolPtr; + } + poolNameptr = pPtr; + } + } + else + { + // if we didn't find any pools abort, they have bigger problems. + if (pCount == 0) + { + aprintf( LRED, "Error: Unable to find any pools on this server. SalvageSys failed.\n" ); + goto CleanUpFailureWithPoolPtr; + } + // we found all the pools + break; + } + // increment count and reposition start and end of data so we can look + // for next poolInfo tag. + elementInfo.dataStart = elementInfo.dataEnd; + elementInfo.dataEnd = savendOfData; + } + } + else + { + // didn't find sys volumes information + aprintf( LRED, "Error: Unable to find any pools on this server. SalvageSys failed.\n" ); + goto CleanUpFailureWithPoolPtr; + } + + // give some feedback so user doesn't get to nervous + aprintf( LGREEN, "Have list of pools, now checking to see which pool contains the SYS volume\n\n" ); + aprintf( LGREEN, "Pool Name\t State\t\tSYS Volume Found\n"); + for (j = 0; j < pCount; j++) + { + + // request information on all deleted volumes on pool + strcpy(requestBuffer, RequestDeletedVolumeInfoCommand); + strcat(requestBuffer, poolNameptr[j]); + strcat(requestBuffer, RequestDeletedVolumeInfoCommand1); + + // request pool information so we can get SYS's internal Name + // abort if error on writing to command file. + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + aprintf( LRED, "Error getting deleted volume information. SalvageSys failed.\n" ); + goto CleanUpFailureWithPoolPtr; + } + + // get reply + // abort if error on read + free(replyBuffer); + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + aprintf( LRED, "Error getting deleted volume information. SalvageSys failed.\n" ); + goto CleanUpFailureWithPoolPtr; + } + + count = 0; + + // get space for pointer to deletedVolumes + // if we couldn't get memory abort + if ((internalVolNamePtr = malloc(sizeof(internalVolNamePtr))) == NULL) + { + aprintf( LRED, "Memory allocation error. SalvageSys failed.\n" ); + goto CleanUpFailureWithPoolPtr; + } + + startOfData = replyBuffer; + endOfData = startOfData + strlen(replyBuffer); + + // Get the state of the pool. + if (XML_GetTagElement(TAG_POOLSTATE, startOfData, endOfData, &elementInfo) == zOK) + { + memcpy(poolState, elementInfo.dataStart, + elementInfo.dataLen); + poolState[elementInfo.dataLen] = '\0'; + } + else + { + strcpy (poolState, "Unknown"); + } + + // parse to deletedVolume tag + if (XML_GetTagElement(TAG_DELETEDVOLUMEINFO, startOfData, + endOfData, &elementInfo) == zOK) + { + // save deletedVolume end tag position + savendOfData = elementInfo.dataEnd; + while (1) + { + // keep looking for volumeName tags until we get all of the deleted + // volumes internal names saved. + if (XML_GetTagElement(TAG_VOLUMENAME, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + internalVolNamePtr[count] = malloc(elementInfo.dataLen +1); + memcpy(internalVolNamePtr[count], elementInfo.dataStart, + elementInfo.dataLen); + internalVolNamePtr[count][elementInfo.dataLen] = '\0'; + count++; + // allocate another position in array for the next pointer + // abort on error getting memory + if ((ptr = realloc(internalVolNamePtr, + (count+1) * sizeof(internalVolNamePtr))) == NULL) + { + aprintf( LRED, "Memory allocation error. SalvageSys failed.\n" ); + goto CleanUpFailureWithVolPtr; + } + internalVolNamePtr = ptr; + } + else + { + // if we didn't find any deleted volumes on this pool check next pool. + break; + } + // increment count and reposition start and end of data so we can look + // for next volumeName. + elementInfo.dataStart = elementInfo.dataEnd; + elementInfo.dataEnd = savendOfData; + } + } + else + { + // didn't find sys volumes information + if (strcmp( poolState, "active") == 0) + { + aprintf( LGREEN, SALVAGESYSFORMATSTRING, poolNameptr[j], poolState, "No" ); + } + else + { + aprintf( LGREEN, SALVAGESYSFORMATSTRING, poolNameptr[j], poolState, "Couldn't check because pool is not active" ); + } + continue; + } + // need to request volumeInfo on each deleted volume to see which one is SYS + for (i = 0; i < count; i++) + { + strcpy(requestBuffer,RequestVolumeInfo); + strcat(requestBuffer,internalVolNamePtr[i]); + strcat(requestBuffer,RequestVolumeInfo1); + + // request volume information for each saved internal volume name until + // we find SYS. + // abort if error on writing to command file. + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + aprintf( LRED, "Error getting volume information. SavageSys failed.\n" ); + goto CleanUpFailureWithVolPtr; + } + // get reply + // abort if error on read + free(replyBuffer); + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + aprintf( LRED, "Error getting volume information. SavageSys failed.\n" ); + goto CleanUpFailureWithVolPtr; + } + startOfData = replyBuffer; + endOfData = startOfData + strlen(replyBuffer); + // parse to deletedVolumeInfo tag + if (XML_GetTagElement(TAG_DELETEDVOLUMEINFO, startOfData, + endOfData, &elementInfo) == zOK) + { + // parse to deletedVolumeInfo tag + if (XML_GetTagElement(TAG_ORIGINALVOLUMENAME, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + if (strncmp(elementInfo.dataStart, "SYS", elementInfo.dataLen) == 0) + { + aprintf( LGREEN, SALVAGESYSFORMATSTRING, poolNameptr[j], poolState, "Yes" ); + strcpy(requestBuffer, UndeleteVolume); + strcat(requestBuffer, internalVolNamePtr[i]); + strcat(requestBuffer, UndeleteVolume1); + strcat(requestBuffer, "SYS"); + strcat(requestBuffer, UndeleteVolume2); + strcat(requestBuffer, poolNameptr[j]); + strcat(requestBuffer, UndeleteVolume3); + // try and undelete the SYS volume. + // abort if error on writing to command file. + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + aprintf( LRED, "Error undeleting SYS volume. SavageSys failed.\n" ); + goto CleanUpFailureWithVolPtr; + } + // get reply + // abort if error on read + free(replyBuffer); + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + aprintf( LRED, "Error undeleting SYS volume. SavageSys failed.\n" ); + goto CleanUpFailureWithVolPtr; + } + startOfData = replyBuffer; + endOfData = startOfData + strlen(replyBuffer); + if (XML_GetTagElement(TAG_RESULT, startOfData, + endOfData, &elementInfo) == zOK) + { + if (XML_GetTagAttribute(TAG_VALUE, &elementInfo) == zOK) + { + // if value is not zOK get error value and description and + // output to screen + memcpy(resultValue, elementInfo.attributeValueStart, elementInfo.attributeValueLen); + resultValue[elementInfo.attributeValueLen] = '\0'; + if (strcmp(resultValue, "0") != 0) + { + + if (XML_GetTagElement(TAG_DESCRIPTION, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(description, elementInfo.dataStart, elementInfo.dataLen); + description[elementInfo.dataLen] = '\0'; + aprintf( LRED, "Error %s %s.\n", resultValue, description ); + goto CleanUpFailureWithVolPtr; + } + else + { + aprintf( LRED, "Error %s Salvaging SYS.\n", resultValue ); + goto CleanUpFailureWithVolPtr; + } + } + else + { + aprintf( LGREEN, "SYS volume was successfully salvaged. Please restart server.\n" ); + goto CleanUpOk; + } + } + else + { + aprintf( LRED, "Unable to salvage SYS volume. SalvageSys failed.\n" ); + goto CleanUpFailureWithVolPtr; + } + } + else + { + aprintf( LRED, "Unable to salvage SYS volume. SalvageSys failed.\n" ); + goto CleanUpFailureWithVolPtr; + } + } + } + } + } + if (strcmp( poolState, "active") == 0) + { + aprintf( LGREEN, SALVAGESYSFORMATSTRING, poolNameptr[j], poolState, "No" ); + } + else + { + aprintf( LGREEN, SALVAGESYSFORMATSTRING, poolNameptr[j], poolState, "Couldn't check because pool is not active" ); + } + } + aprintf( LRED, "Unable to find SYS volumes undelete information. SalvageSys failed.\n" ); + +CleanUpOk: + for (i = 0; i < count; i++) + { + free(internalVolNamePtr[i]); + } + free (internalVolNamePtr); + for (i = 0; i < pCount; i++) + { + free(poolNameptr[i]); + } + free (poolNameptr); + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + return (zOK); + +CleanUpFailureWithVolPtr: + for (i = 0; i < count; i++) + { + free(internalVolNamePtr[i]); + } + free (internalVolNamePtr); +CleanUpFailureWithPoolPtr: + for (i = 0; i < pCount; i++) + { + free(poolNameptr[i]); + } + free (poolNameptr); +CleanupFailureWithReply: + free (replyBuffer); +CleanUpFailure: + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + return (zFAILURE); +} + + +/**************************************************************************** +** Function: ChangeSysQuota +** +** Change SYS quota +** +** Returns: Status +****************************************************************************/ + +STATUS ChangeSysQuota(utf8_t quota[]) +{ + char resultValue[25]; + char description[128]; + utf8_t *replyBuffer; + utf8_t *requestBuffer; + + XML_ElementInfo_s elementInfo; + utf8_t *startOfData; + utf8_t *endOfData; + QUAD rQuota; + Key_t rootKey; + Key_t fileKey; + + // get space for request buffer + requestBuffer = (utf8_t *)malloc(BUFFERSIZE); + if (requestBuffer == NULL) + { + aprintf( LRED, "Error out of memory" ); + return(zFAILURE); // if we couldn't get memory abort + } + // initialize command file + if (InitializeCommandFile(&fileKey, &rootKey) != zOK) + { + aprintf( LRED, "Error setting quota to \"%s\" MB.\n", quota ); + free(requestBuffer); + return(zFAILURE); // if we couldn't open command file return failure + } + strcpy(requestBuffer,"<"TAG_NSSREQUEST">"); // build request buffer + strcat(requestBuffer,"<"TAG_VOLUME">"); + strcat(requestBuffer,"<"TAG_MODIFYVOLUMEINFO">"); + strcat(requestBuffer,"<"TAG_VOLUMENAME">"); + strcat(requestBuffer,"SYS"); + strcat(requestBuffer,""); + + // make sure quota is greater then 0 + if (LB_atoi (quota) > 0) + { + rQuota = LB_atoq(quota); // convert to quad + rQuota *= (QUAD)1048576; // quota needs to be in bytes + LB_sprintf(description, "%Lu", rQuota); + strcat(requestBuffer,""); + } + else + { + strcat(requestBuffer,""); + } + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + // write command to command file + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + aprintf( LRED, "Error setting quota to \"%s\" MB.\n", quota ); + return(zFAILURE); + } + + if ((replyBuffer = ReadReply(fileKey)) == NULL) // get reply + { + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + aprintf( LRED, "Error setting quota to \"%s\" MB.\n", quota ); + return(zFAILURE); + } + + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + // setup pointers to start and end of buffer + startOfData = replyBuffer; + endOfData = startOfData + strlen(replyBuffer); + if (XML_GetTagElement(TAG_MODIFYVOLUMEINFO, startOfData, endOfData, &elementInfo) == zOK) + { + if (XML_GetTagElement(TAG_RESULT, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + if (XML_GetTagAttribute(TAG_VALUE, &elementInfo) == zOK) + { + memcpy(resultValue, elementInfo.attributeValueStart, elementInfo.attributeValueLen); + resultValue[elementInfo.attributeValueLen] = '\0'; + if (strcmp(resultValue, "0") == 0) // Check for error + { + if (strcmp(quota, "0") == 0) + { + // if quota was set to zero output None + aprintf( LGREEN, "SYS volume quota was successfully changed to \"None\".\n" ); + } + else + { + // otherwise let them now what the new quota is. + aprintf( LGREEN, "SYS volume quota was successfully changed to \"%s\" MB.\n", quota ); + } + free(requestBuffer); + free(replyBuffer); + return (zOK); + } + else + { + // if we got an error output error number and description + if (XML_GetTagElement(TAG_DESCRIPTION, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(description, elementInfo.dataStart, elementInfo.dataLen); + description[elementInfo.dataLen] = '\0'; + aprintf( LRED, "Error %s %s.\n", resultValue, description ); + free(requestBuffer); + free(replyBuffer); + return (zFAILURE); + } + else + { + // if we can't find the description just output simple error + aprintf( LRED, "Error setting quota to \"%s\" MB.\n", quota ); + free(requestBuffer); + free(replyBuffer); + return (zFAILURE); + } + } + } + } + } + // something didn't work so let them know and cleanup before leaving + aprintf( LRED, "Error setting quota to \"%s\" MB.\n", quota ); + free(requestBuffer); + free(replyBuffer); + return (zFAILURE); +} + +/**************************************************************************** +** Function: ExpandSys +** +** Expands the Pool that SYS volume is on. If needed will create a partition +** +** Returns: Status +****************************************************************************/ + +STATUS ExpandSys(utf8_t passedPartitionID[]) +{ + char partitionID[24]; + char logicalPartitionID[24]; + char partitionType[24]; + char poolName[20]; + char deviceID[24]; + char startingSector[64]; + char numSectors[64]; + char hotFixSize[64]; + char resultValue[25]; + char description[256]; + char sysPoolName[20]; + char sysInfoFileName[] = "_ADMIN:\\Manage_NSS\\Volume\\SYS\\VolumeInfo.xml"; + + XML_ElementInfo_s elementInfo; + utf8_t *savstartOfData; + utf8_t *savendOfData; + utf8_t *startOfData; + utf8_t *endOfData; + utf8_t *requestBuffer; + utf8_t *replyBuffer; + Key_t rootKey; + Key_t fileKey; + Key_t sysInfoKey; + STATUS status; + NINT iBytesRead; + + // get space for request buffer + requestBuffer = (utf8_t *)malloc(BUFFERSIZE); + if (requestBuffer == NULL) + { + aprintf( LRED, "Error out of memory" ); + return(zFAILURE); // if we couldn't get memory abort + } + + // initialize command file + if (InitializeCommandFile(&fileKey, &rootKey) != zOK) + { + aprintf( LRED, "Error Expanding SYS\n" ); + free(requestBuffer); + return(zFAILURE); // if we couldn't open command file return failure + } + + // need to get pool that SYS is on. + // Open _admin:\Manage_NSS\Volume\SYS\VolumeInfo.xml it contains the SYS volumes poolname + if((status = zOpen( + rootKey, /* Root Key */ + 0, /* Task ID, Need to use zero because we need admin rights */ + zNSPACE_LONG | zMODE_UTF8, /* Long NS with UTF8 characters */ + sysInfoFileName, /* VolumeInfo.xml */ + zRR_READ_ACCESS, /* Need Read access*/ + &sysInfoKey))!=zOK) /* Key (handle) to object returned in last argument */ + { + aprintf( LRED, "File (%s) open failed. err = %d\n", sysInfoFileName, status ); + goto CleanUpFailure; + } + + // read enough of the file to get the poolName + // use request buffer because its available. + if ((status = zRead(sysInfoKey, zNILXID, 0, BUFFERSIZE - 1, requestBuffer, &iBytesRead)) != zOK) + { + aprintf( LRED, "ERROR: zRead = %d\n", status ); + zClose(sysInfoKey); + goto CleanUpFailure; + } + requestBuffer[iBytesRead] = '\0'; + // setup pointers to start and end of buffer + elementInfo.dataStart = requestBuffer; + elementInfo.dataEnd = requestBuffer + iBytesRead; + + if (XML_GetTagElement(TAG_POOLNAME, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(sysPoolName, elementInfo.dataStart, elementInfo.dataLen); + sysPoolName[elementInfo.dataLen] = '\0'; // save poolname for later. + } + else + { + // if we can't find pool we must abort. + zClose(sysInfoKey); + aprintf( LRED, "Error Expanding SYS\n" ); + goto CleanUpFailure; + } + zClose(sysInfoKey); // close VolumeInfo.xml + + strcpy(requestBuffer, ""); + aprintf( LGREEN, "Gathering partition information.\n" ); + // write request for partition information + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + aprintf( LRED, "Error Expanding SYS\n" ); + goto CleanUpFailure; + } + + // get the reply + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + aprintf( LRED, "Error Expanding SYS\n" ); + goto CleanUpFailure; + } + // setup pointers to start and end of buffer + startOfData = replyBuffer; + endOfData = startOfData + strlen(replyBuffer); + while (1) + { + if (XML_GetTagElement(TAG_PARTITIONINFO, startOfData, + endOfData, &elementInfo) == zOK) + { + // check each partition in the list to find the one with the passed in + // partitionID + // save this spot + savstartOfData = elementInfo.dataStart; + savendOfData = elementInfo.dataEnd; + if (XML_GetTagElement(TAG_PARTITIONID, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // get partitionID so we can check to see if its the right one + memcpy(partitionID, elementInfo.dataStart, elementInfo.dataLen); + partitionID[elementInfo.dataLen] = '\0'; + if (strcmp(partitionID, passedPartitionID) == 0) + { + // we have a match, now check to see if its OK + // restore saved position and get poolName + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_POOLNAME, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // see if partition contains pool, if so we can't use it. + memcpy(poolName, elementInfo.dataStart, elementInfo.dataLen); + poolName[elementInfo.dataLen] = '\0'; + aprintf( LRED, "Error: Partition is already part of a pool \"%s\", ExpandSYS failed\n", poolName ); + goto CleanUpReplyFailure; + } + else + { + // restore saved position and get partitionType + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_PARTITIONTYPE, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // get partitionType and make sure its type is "0" free + memcpy(partitionType, elementInfo.dataStart, elementInfo.dataLen); + partitionType[elementInfo.dataLen] = '\0'; + if ((strcmp(partitionType, "105") == 0) || (strcmp(partitionType, "0") == 0)) + { + break; // this ones OK. + } + else + { + // partition doesn't meet criteria. + aprintf( LRED, "Error: Partition is NOT a free partition, ExpandSYS failed\n" ); + goto CleanUpReplyFailure; + } + } + } + } + } + } + else + { + // looked at all of the free partitions and couldn't fine the one + // they specified + aprintf( LRED, "Error: Partition not found, ExpandSYS failed\n" ); + goto CleanUpReplyFailure; + } + startOfData = savendOfData; + } + // ajust start position so we get the rest of the information we need to create + // a partition + // restore saved position and get deviceID + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_DEVICEID, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(deviceID, elementInfo.dataStart, elementInfo.dataLen); + deviceID[elementInfo.dataLen] = '\0'; + // restore saved position + // and get startingSector + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_STARTINGSECTOR, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(startingSector, elementInfo.dataStart, elementInfo.dataLen); + startingSector[elementInfo.dataLen] = '\0'; + // restore saved position + // and get numSectors + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_NUMSECTORS, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(numSectors, elementInfo.dataStart, elementInfo.dataLen); + numSectors[elementInfo.dataLen] = '\0'; + + // if partition is not a free partition get the logicalPartitionID + // and then proceed to expand the sys pool. + // otherwise go ahead and create the partition. + if (strcmp(partitionType, "0") != 0) + { + // restore saved position + // and get logicalPartitionID + elementInfo.dataStart = savstartOfData; + elementInfo.dataEnd = savendOfData; + if (XML_GetTagElement(TAG_LOGICALPARTITIONID, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(logicalPartitionID, elementInfo.dataStart, elementInfo.dataLen); + logicalPartitionID[elementInfo.dataLen] = '\0'; + } + else // if we don't find a logicalPartitionID we have a problem + // do an ASSERT and then abort. + { + zASSERT("Couldn't find logicalPartitionID" == NULL); + aprintf( LRED, "Error Expanding SYS. Couldn't find logicalPartitionID.\n" ); + goto CleanUpReplyFailure; + } + } + else // create an NSS partition. + { + aprintf( LGREEN, "Creating partition.\n" ); + strcpy(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,deviceID); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,"105"); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,startingSector); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,numSectors); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,partitionID); + strcat(requestBuffer,""); + if (SYSHotFixSize != 0) + { + // if they want hotfix then give them mirror too + // hotfix must be at least 100kb + if (SYSHotFixSize < 100) + { + SYSHotFixSize = 100; + } + LB_sprintf(hotFixSize, "%d", SYSHotFixSize * 2); + strcat(requestBuffer,""); + strcat(requestBuffer, hotFixSize); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer, "0"); + strcat(requestBuffer,""); + } + else + { + strcat(requestBuffer,""); + strcat(requestBuffer, "0"); + strcat(requestBuffer,""); + } + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + // write command to command file + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + aprintf( LRED, "Error Expanding SYS\n" ); + goto CleanUpReplyFailure; + } + // get results + free(replyBuffer); + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + aprintf( LRED, "Error Expanding SYS\n" ); + goto CleanUpReplyFailure; + } + // setup pointers to start and end of buffer + // and parse reply to see if partition was created or if we got + // an error + elementInfo.dataStart = replyBuffer; + elementInfo.dataEnd = replyBuffer + strlen(replyBuffer); + if (XML_GetTagElement(TAG_RESULT, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + if (XML_GetTagAttribute(TAG_VALUE, &elementInfo) == zOK) + { + // if value is not zOK get error value and description and + // output to screen + memcpy(resultValue, elementInfo.attributeValueStart, elementInfo.attributeValueLen); + resultValue[elementInfo.attributeValueLen] = '\0'; + if (strcmp(resultValue, "0") != 0) + { + + if (XML_GetTagElement(TAG_DESCRIPTION, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(description, elementInfo.dataStart, elementInfo.dataLen); + description[elementInfo.dataLen] = '\0'; + aprintf( LRED, "Error %s %s.\n", resultValue, description ); + goto CleanUpReplyFailure; + } + else + { + aprintf( LRED, "Error %s Expanding SYS.\n", resultValue ); + goto CleanUpReplyFailure; + } + } + } + } + // partition was created OK and we are now going to expand SYS + aprintf( LGREEN, "Partition successfully created. Proceeding to expand pool \"%s\".\n", sysPoolName ); + elementInfo.dataStart = replyBuffer; + elementInfo.dataEnd = replyBuffer + strlen(replyBuffer); + if (XML_GetTagElement(TAG_LOGICALPARTITIONID, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + // look for logicalPartitionID + memcpy(logicalPartitionID, elementInfo.dataStart, elementInfo.dataLen); + logicalPartitionID[elementInfo.dataLen] = '\0'; + } + else + { + // if we don't find a logicalPartitionID we have a problem so + // do an ASSERT and then abort. + + zASSERT("Couldn't find logicalPartitionID" == NULL); + aprintf( LRED, "Error Expanding SYS. Couldn't find logicalPartitionID of the new partition.\n" ); + goto CleanUpReplyFailure; + } + } + aprintf( LGREEN, "Expanding pool \"%s\".\n", sysPoolName ); + strcpy(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,sysPoolName); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,logicalPartitionID); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + aprintf( LRED, "Error Expanding SYS\n" ); + goto CleanUpReplyFailure; + } + + free(replyBuffer); + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + aprintf( LRED, "Error Expanding SYS\n" ); + goto CleanUpReplyFailure; + } + // setup pointers to start and end of buffer + // parse reply to see if we got an error. + elementInfo.dataStart = replyBuffer; + elementInfo.dataEnd = replyBuffer + strlen(replyBuffer); + if (XML_GetTagElement(TAG_RESULT, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + if (XML_GetTagAttribute(TAG_VALUE, &elementInfo) == zOK) + { + memcpy(resultValue, elementInfo.attributeValueStart, elementInfo.attributeValueLen); + resultValue[elementInfo.attributeValueLen] = '\0'; + if (strcmp(resultValue, "0") != 0) + { + // if result value is not 0 then get description and output to + // screen + if (XML_GetTagElement(TAG_DESCRIPTION, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(description, elementInfo.dataStart, elementInfo.dataLen); + description[elementInfo.dataLen] = '\0'; + aprintf( LRED, "Error %s %s.\n", resultValue, description ); + goto CleanUpReplyFailure; + } + else + { + aprintf( LRED, "Error %s Expanding SYS.\n", resultValue ); + goto CleanUpReplyFailure; + } + } + } + } + } + } + } + // expand worked so give them feedback and then cleanup buffers + aprintf( LGREEN, "Pool \"%s\" was successfully expanded.\n", sysPoolName ); + + free(requestBuffer); + free(replyBuffer); // free buffers + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + return zOK; + +CleanUpReplyFailure: + free(replyBuffer); +CleanUpFailure: + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + return (zFAILURE); +} + +/**************************************************************************** +** Function: RenameToSys +** +** Renames a volume to SYS. If the SYS volume was rename for some reason +** this command line function will rename it back to SYS. +** Returns: Status +****************************************************************************/ + +STATUS RenameToSys(utf8_t volumeName[]) +{ + char resultValue[25]; + char description[256]; + XML_ElementInfo_s elementInfo; + utf8_t *startOfData; + utf8_t *endOfData; + utf8_t *requestBuffer; + utf8_t *replyBuffer; + Key_t rootKey; + Key_t fileKey; + + // get space for request buffer + requestBuffer = (utf8_t *)malloc(BUFFERSIZE); + if (requestBuffer == NULL) + { + aprintf( LRED, "Error out of memory" ); + return(zFAILURE); // if we couldn't get memory abort + } + // initialize command file + if (InitializeCommandFile(&fileKey, &rootKey) != zOK) + { + aprintf( LRED, "Error renaming \"%s\".\n", volumeName ); + free(requestBuffer); + return(zFAILURE); // if we couldn't open command file return failure + } + strcpy(requestBuffer,"<"TAG_NSSREQUEST">"); // rename volume to SYS + strcat(requestBuffer,"<"TAG_VOLUME">"); + strcat(requestBuffer,"<"TAG_RENAMEVOLUME">"); + strcat(requestBuffer,"<"TAG_VOLUMENAME">"); + strcat(requestBuffer,volumeName); + strcat(requestBuffer,""); + strcat(requestBuffer,"<"TAG_NEWVOLUMENAME">"); + strcat(requestBuffer,"SYS"); + strcat(requestBuffer,""); + strcat(requestBuffer,"<"TAG_DONTRENAMENDSOBJECT"/>"); // don't worry about NDS being up + strcat(requestBuffer,""); + strcat(requestBuffer,""); + strcat(requestBuffer,""); + + if (WriteBuffer(requestBuffer, fileKey, strlen(requestBuffer)) != zOK) + { + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + aprintf( LRED, "Error renaming \"%s\".\n", volumeName ); + return(zFAILURE); + } + + if ((replyBuffer = ReadReply(fileKey)) == NULL) + { + free(requestBuffer); + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + aprintf( LRED, "Error renaming \"%s\".\n", volumeName ); + return(zFAILURE); + } + + zClose(fileKey); + zClose(rootKey); // Close manage.cmd + + startOfData = replyBuffer; + endOfData = startOfData + strlen(replyBuffer); + if (XML_GetTagElement(TAG_RENAMEVOLUME, startOfData, endOfData, &elementInfo) == zOK) + { + if (XML_GetTagElement(TAG_RESULT, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + if (XML_GetTagAttribute(TAG_VALUE, &elementInfo) == zOK) + { + memcpy(resultValue, elementInfo.attributeValueStart, elementInfo.attributeValueLen); + resultValue[elementInfo.attributeValueLen] = '\0'; + if (strcmp(resultValue, "0") == 0) + { + aprintf( LGREEN, "Volume \"%s\" was successfully renamed to \"SYS\".\n", volumeName ); + free(requestBuffer); + free(replyBuffer); // free buffers + return (zOK); + } + else + { + + if (XML_GetTagElement(TAG_DESCRIPTION, elementInfo.dataStart, + elementInfo.dataEnd, &elementInfo) == zOK) + { + memcpy(description, elementInfo.dataStart, elementInfo.dataLen); + description[elementInfo.dataLen] = '\0'; + aprintf( LRED, "Error %s %s.\n", resultValue, description ); + free(requestBuffer); + free(replyBuffer); // free buffers + return (zFAILURE); + } + else + { + aprintf( LRED, "Error %s renaming \"%s\".\n", resultValue, volumeName ); + free(requestBuffer); + free(replyBuffer); // free buffers + return (zFAILURE); + } + } + } + } + } + aprintf( LRED, "Error renaming \"%s\".\n", volumeName ); + free(requestBuffer); + free(replyBuffer); // free buffers + return (zFAILURE); +} + +/**************************************************************************** +** Function: WriteBuffer +** +** Write contents of the buffer pointed to by requestBuffer to the file who's +** Key is fileKey +** Returns: STATUS +****************************************************************************/ + +STATUS WriteBuffer(utf8_t *requestBuffer, Key_t fileKey, NINT size) +{ + NINT numWritten; + STATUS status; + + if ((status = zWrite(fileKey, zNILXID, 0, size, requestBuffer, &numWritten)) != zOK) + { + aprintf( LRED, "ERROR: write = %d\n", numWritten ); + return(zFAILURE); + } + return zOK; +} + +/**************************************************************************** +** Function: ReadReply +** +** Read into a buffer pointed to by replyBuffer the contents of the command +** file +** Returns: utf8_t pointer to the buffer which contains the file +** or NULL if error +****************************************************************************/ + +utf8_t * ReadReply(Key_t fileKey) +{ + STATUS status; + NINT iBytesRead,bytesRead; + utf8_t *replyBuffer; + utf8_t *rPtr; + + // start with a 2k buffer and have replyBuffer point to it. + // bytesRead is a running total of how many bytes have been read from the command file. + + if ((rPtr = (utf8_t *)malloc(REPLYBUFFERSIZE + 1)) == NULL) + { + aprintf( LRED, "Error allocating memory.\n" ); + return(NULL); + } + bytesRead = 0; + replyBuffer = rPtr; + // keep reading until we get all of the reply. + while (1) + { + // read 2k chunks until we have all of the file. + if ((status = zRead(fileKey, zNILXID, (QUAD)bytesRead, REPLYBUFFERSIZE, &replyBuffer[bytesRead], &iBytesRead)) != zOK) + { + aprintf( LRED, "ERROR: zRead = %d\n", status ); + free(replyBuffer); + return(NULL); + } + // update our running total of bytes read and put a NULL at the end + // for the realloc + bytesRead = bytesRead + iBytesRead; + rPtr[bytesRead] = '\0'; + // if we read less then 2k were done + if (iBytesRead < REPLYBUFFERSIZE) + { + return (replyBuffer); + } + else + { + // else make the buffer bigger by 2k and continue. + if ((rPtr = realloc(replyBuffer, bytesRead + REPLYBUFFERSIZE + 1)) == NULL) + { + aprintf( LRED, "Error allocating memory.\n" ); + free (replyBuffer); + return(NULL); + } + replyBuffer = rPtr; + } + } +} + +/**************************************************************************** +** Function: InitializeCommandFile +** +** Opens _ADMIN:\\Manage_NSS\\manage.cmd and writes initialize command +** +** Returns: STATUS +****************************************************************************/ + +STATUS InitializeCommandFile(Key_t *fileKey, Key_t *rootKey) +{ + char name[] = "_ADMIN:\\Manage_NSS\\manage.cmd"; + char command[] = ""; + STATUS status; + NINT numWritten; + + /* Get Root Key */ + if ((status = zRootKey(0, rootKey)) != zOK) + { + aprintf( LRED, "ERROR: Getting zRootKey = %d\n", status ); + return(zFAILURE); + } + + /* Open _admin:\Manage_NSS\Manage.cmd */ + if((status = zOpen( + *rootKey, /* Root Key */ + 0, /* Task ID, Need to use zero because we need admin rights */ + zNSPACE_LONG | zMODE_UTF8, /* Long NS with UTF8 characters */ + name, /* Manage.cmd */ + zRR_READ_ACCESS | zRR_WRITE_ACCESS, /* Need Read and Write access */ + fileKey))!=zOK) /* Key (handle) to object returned in last argument */ + { + aprintf( LRED, "File (%s) opened failed. err = %d\n", name, status ); + zClose(*rootKey); + return(zFAILURE); + } + + /* + * Write Command String to Manage.cmd + */ + if ((status = zWrite(*fileKey, zNILXID, 0, sizeof(command), command, &numWritten)) != zOK) + { + aprintf( LRED, "ERROR: zWrite = %d\n", status ); + zClose(*fileKey); + zClose(*rootKey); + return(zFAILURE); + } + + return zOK; +} diff --git a/src/nwnss/comn/common/comnStartup.c b/src/nwnss/comn/common/comnStartup.c new file mode 100644 index 0000000..757ec4c --- /dev/null +++ b/src/nwnss/comn/common/comnStartup.c @@ -0,0 +1,367 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996, 2004 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: blarsen $ + | $Date: 2007-09-12 22:29:07 +0530 (Wed, 12 Sep 2007) $ + | + | $RCSfile$ + | $Revision: 2203 $ + | + |--------------------------------------------------------------------------- + | This module is used to initialize the common layer + | + +-------------------------------------------------------------------------*/ +#include + +#include +#include +#include +#include +#include +#define _NSS_ENCP_H_ /* flag we have included ENCP.H already*/ +#include + +#include +#include +#include +#include +#include + +#include "pssConnection.h" +#include "nameScan.h" +#include "nssFSHooks.h" +#include "eventSys.h" +#include "volume.h" +#include "adminVolume.h" +#include "pssStartup.h" +#include "objectIDStore.h" +#include "purgeDir.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if _FSHOOKS IS_ENABLED +FSHookParms_s FSHooksList[MAX_NUMBER_FSHOOKS]; +statusfunc_t FSHooksCall[MAX_NUMBER_FSHOOKS]; +#endif + +STATUS NSSUT_MediaFormatTestAllSizes(void); +statusfunc_t LegacyEventReport[NUM_LEGACY_EVENTS]; + +/**************************************************************************** + * COMN_FSHOOKS_Startup + *****************************************************************************/ +void COMN_FSHOOKS_Startup() +{ +#if _FSHOOKS IS_ENABLED + LONG retList; + struct InternalPublicDefinitionStructure *symRec; + LONG result; + + ASSERT_MPKNSS_LOCK(); + + ZOS_FindPublicRecordStructure(result, MSGNot("\x10""FSHookParmsArray"), 0, + &retList, (LONG *)&symRec) + if (result != 0) + { + return; + } + memcpy(&FSHooksList, symRec->IPDActualAddress, + sizeof(FSHookParms_s) * MAX_NUMBER_FSHOOKS); +#endif + return; +} + + +/**************************************************************************** + * COMN_Startup + *****************************************************************************/ +#if zNETWARE +extern STATUS nfsStartup(); +extern void nfsShutdown(); +#endif +extern STATUS CSA_Startup(void); +extern void CSA_Shutdown(void); + +STATUS COMN_Startup( + GeneralMsg_s *genMsg) +{ + STATUS rc; + + ASSERT_MPKNSS_LOCK(); + + rc = NSSUT_MediaFormatTestAllSizes(); + if ( rc != zOK ) + { + SetErrno(genMsg, rc); + return zFAILURE; + } +#if zNETWARE + if ((rc = nfsStartup()) != zOK) + { + SetErrno(genMsg, rc); + return zFAILURE; + } +#endif + COMN_FSHOOKS_Startup(); + if (OID_Startup() != zOK) + { +#if zNETWARE + nfsShutdown(); +#endif + return zFAILURE; + } + + if (ADMINVOL_StartupPhase2(genMsg) != zOK) + { + OID_Shutdown(); +#if zNETWARE + nfsShutdown(); +#endif + return zFAILURE; + } + if ((rc = CSA_Startup()) != zOK) + { + OID_Shutdown(); +#if zNETWARE + nfsShutdown(); +#endif + return zFAILURE; + } + + INIT_LATCH(&PurgeDirLatch); + + return zOK; +} + +/**************************************************************************** + * COMN_Shutdown + *****************************************************************************/ +void COMN_Shutdown() +{ + extern unicode_t *ZIDToFileNameVolumeName; + + ASSERT_MPKNSS_LOCK(); + CSA_Shutdown(); + NMSG_ShutdownWorkBufferMemory(); + free(ZIDToFileNameVolumeName); + ZIDToFileNameVolumeName = NULL; + OID_Shutdown(); +#if zNETWARE + nfsShutdown(); +#endif +} + + +typedef struct NSSPersistentItems_s { + char *NPI_Name; + int NPI_Size; + char *NPI_LastItemName; + int NPI_LastItem; + int NPI_SizePacked; + int NPI_LastItemPacked; +} NSSPersistentItems_s; + + + +NSSPersistentItems_s NPIList[] = { + // cmCompFile.h + { "CompChunkHdr_s", sizeof(CompChunkHdr_s), "algoVersion", offsetof(CompChunkHdr_s,algoVersion), 10, 9 }, + { "CompFileLayoutID_s", sizeof(CompFileLayoutID_s), "unused", offsetof(CompFileLayoutID_s,unused), 4, 3 }, + { "CompFileHdr_s", sizeof(CompFileHdr_s), "chunkStateVector[DIRECT_CHUNK_VECTOR_BYTES]", offsetof(CompFileHdr_s,chunkStateVector[DIRECT_CHUNK_VECTOR_BYTES]), 22, 22 }, + // cmControl.h + { "VolumeCompAttr_s", sizeof(VolumeCompAttr_s), "algorithms_used", offsetof(VolumeCompAttr_s,algorithms_used), 24, 16 }, + // comnBeasts.h + { "PersistentNameEntry_s", sizeof(PersistentNameEntry_s), "name[0]", offsetof(PersistentNameEntry_s,name[0]), +#if NSS_DEBUG IS_ENABLED + 262, +#else + 6, +#endif + 6 }, + { "PersistentParentEntry_s", sizeof(PersistentParentEntry_s), "zid", offsetof(PersistentParentEntry_s,zid), 20, 12 }, + { "DeletedPersistentParentEntry_s", sizeof(DeletedPersistentParentEntry_s), "ID", offsetof(DeletedPersistentParentEntry_s,ID), 20, 4 }, + { "V1_DeletedPersistentParentEntry_s", sizeof(V1_DeletedPersistentParentEntry_s), "ID", offsetof(V1_DeletedPersistentParentEntry_s,ID), 8, 4 }, + { "TypeSpecificPersistentParentEntry_s", sizeof(TypeSpecificPersistentParentEntry_s), "u.deleted.ID", offsetof(TypeSpecificPersistentParentEntry_s,u.deleted.ID), 20, 4 }, + { "PersistentNamed2_s", sizeof(PersistentNamed2_s), "reserved", offsetof(PersistentNamed2_s,reserved), 20, 18 }, + { "PersistentNamed3_s", sizeof(PersistentNamed3_s), "hardLinkZid", offsetof(PersistentNamed3_s,hardLinkZid), 28, 20 }, + { "V1_PersistentAuthBeast_s", sizeof(V1_PersistentAuthBeast_s), "ownerID", offsetof(V1_PersistentAuthBeast_s,ownerID), 16, 0 }, + { "PersistentFile_s", sizeof(PersistentFile_s), "archiverID", offsetof(PersistentFile_s,archiverID), 68, 52 }, + { "V1_PersistentFile_s", sizeof(V1_PersistentFile_s), "archiverID", offsetof(V1_PersistentFile_s,archiverID), 32, 28 }, + { "MFLKey_s", sizeof(MFLKey_s), "zid", offsetof(MFLKey_s,zid), 8, 0 }, + { "MFLValue_s", sizeof(MFLValue_s), "reserved", offsetof(MFLValue_s,reserved), 8, 4 }, + { "MFLEntry_s", sizeof(MFLEntry_s), "value", offsetof(MFLEntry_s,value), 16, 8 }, + { "PersistentComp_s", sizeof(PersistentComp_s), "unused[4]", offsetof(PersistentComp_s,unused[4]), 24, 24 }, + // compCompress.h + { "PersistentCompressInfo_s", sizeof(PersistentCompressInfo_s), "action", offsetof(PersistentCompressInfo_s,action), 28, 27 }, + { "PackedCompInfo_s", sizeof(PackedCompInfo_s), "cmInfo", offsetof(PackedCompInfo_s,cmInfo), 32, 4 }, + // comnZAS.h: + { "ACLEntry_s", sizeof(ACLEntry_s), "attributes", offsetof(ACLEntry_s,attributes), 20, 18 }, + { "VisEntry_s", sizeof(VisEntry_s), "count", offsetof(VisEntry_s,count), 20, 16 }, + { "V1_ACLEntry_s", sizeof(V1_ACLEntry_s), "attributes", offsetof(V1_ACLEntry_s,attributes), 8, 6 }, + { "V1_VisEntry_s", sizeof(V1_VisEntry_s), "count", offsetof(V1_VisEntry_s,count), 8, 4 }, + { "PersistentZasAclOverflowBeast_s", sizeof(PersistentZasAclOverflowBeast_s), "numEntries", offsetof(PersistentZasAclOverflowBeast_s,numEntries), 12, 8 }, + { "PersistentZasVisOverflowBeast_s", sizeof(PersistentZasVisOverflowBeast_s), "numEntries", offsetof(PersistentZasVisOverflowBeast_s,numEntries), 12, 8 }, + // evs.h + { "PersistentVolumeCrypt_s", sizeof(PersistentVolumeCrypt_s), "macLen", offsetof(PersistentVolumeCrypt_s,macLen), 128, 124 }, + // extAttrBeast.h + { "PersistentExtAttrBeast_s", sizeof(PersistentExtAttrBeast_s), "extAttrUserFlags", offsetof(PersistentExtAttrBeast_s,extAttrUserFlags), 4, 0 }, + // hardLinkBeast.h + { "PersistentHardLink_s", sizeof(PersistentHardLink_s), "reserved2", offsetof(PersistentHardLink_s,reserved2), 44, 12 }, + // macNSpace.h + { "PackedMacInfo_s", sizeof(PackedMacInfo_s), "macInfo.dirRightsMask", offsetof(PackedMacInfo_s,macInfo.dirRightsMask), 48, 44 }, + // volume.h + { "LoggedPersistentVolume_s", sizeof(LoggedPersistentVolume_s), "LPV_reserved[32-30]", offsetof(LoggedPersistentVolume_s,LPV_reserved[32-30]), 128, 128 }, + { "VolInfoLog_s", sizeof(VolInfoLog_s), "VIL_value", offsetof(VolInfoLog_s,VIL_value), 16, 8 }, + { "PersistentVolume_s", sizeof(PersistentVolume_s), "PV_reserved3[18]", offsetof(PersistentVolume_s,PV_reserved3[18]), 256, 256 }, + { "PersistentPool_s", sizeof(PersistentPool_s), "PP_reserved[64-22-4]", offsetof(PersistentPool_s,PP_reserved[64-22-4]), 256, 256 }, + { "LoggedPersistentPool_s", sizeof(LoggedPersistentPool_s), "LPP_reserved[64-8]", offsetof(LoggedPersistentPool_s,LPP_reserved[64-8]), 256, 256 }, + // unixAuthModel.h + { "UXASPersistentAuthInfo_s", sizeof(UXASPersistentAuthInfo_s), "unused[8]", offsetof(UXASPersistentAuthInfo_s,unused[8]), 56, 56 }, + // unixNSpace.h: + { "zUnixInfo_Layout1_s", sizeof(zUnixInfo_Layout1_s), "filler[2]", offsetof(zUnixInfo_Layout1_s,filler[2]), 24, 24 }, + { "PackedUnixInfo_Layout1_s", sizeof(PackedUnixInfo_Layout1_s), "reserved", offsetof(PackedUnixInfo_Layout1_s,reserved), 32, 28 }, + { "PackedUnixInfo_s", sizeof(PackedUnixInfo_s), "unixInfo.variableSize", offsetof(PackedUnixInfo_s,unixInfo.variableSize), 52, 50 }, + // uxaction.h + { "UserXactionLogRec_s", sizeof(UserXactionLogRec_s), "type", offsetof(UserXactionLogRec_s,type), 48, 44 }, + { "UserXactionLogBuffer_s", sizeof(UserXactionLogBuffer_s), "time", offsetof(UserXactionLogBuffer_s,time), 16, 12 }, + // zasAuthModel.h + { "ZASPersistentAuthInfo_s ", sizeof(ZASPersistentAuthInfo_s ), "visibilityList[MAX_VISIBILITY_TRUSTEES_IN_BEAST]", offsetof(ZASPersistentAuthInfo_s ,visibilityList[MAX_VISIBILITY_TRUSTEES_IN_BEAST]), 204, 204 }, + { "V1_ZASPersistentAuthInfo_s", sizeof(V1_ZASPersistentAuthInfo_s), "numVisibilityTrusteesAssigned", offsetof(V1_ZASPersistentAuthInfo_s,numVisibilityTrusteesAssigned), 40, 38 }, + // zOmni.h + { "GUID_t", sizeof(GUID_t), "node[6]", offsetof(GUID_t,node[6]), 16, 16 }, + // zParams.h + { "zMacInfo_s", sizeof(zMacInfo_s), "dirRightsMask", offsetof(zMacInfo_s,dirRightsMask), 44, 40 }, + { "zUnixInfo_s", sizeof(zUnixInfo_s), "variableSize", offsetof(zUnixInfo_s,variableSize), 48, 46 }, +}; + + +#if MEDIA_FORMAT_DISPLAY_SIZES +STATUS ZLOG_ssprintf( + NINT bufferLength, + BYTE **bufferAddress, + NINT *retLen, + const char *format, + ...) +{ + va_list args; + int added; /* Does not include the NULL */ + + va_start( args, format ); + added = LB_vsnprintf( *bufferAddress + *retLen, + bufferLength - *retLen, format, args ); + if ( added < 0 ) + { /* Encoding error in format string */ + return( zERR_BAD_PARAMETER_VALUE ); + } + if ( added >= (bufferLength - *retLen) ) + { /* Could do a re-alloc here and then error on out of memory */ + *retLen = bufferLength; /* Say we are using whole buffer so + * that next call to us returns no + * space left. This way callers can call + * us many times in a row and only need + * to check for an error after the last + * call. + */ + return( zERR_BUFFER_TOO_SMALL ); + } + *retLen += added; + return( zOK ); + +} /* End of ZLOG_ssprintf() */ +#endif + +#if MEDIA_FORMAT_DISPLAY_SIZES +void NSSUT_DisplayAll( + NINT bufferLength, + BYTE **bufferAddress, + NINT *retLen ) /* This indicates how much of buffer is + * already filled in. We must update + * as we fill things in. + */ +{ + int i; + + ZLOG_ssprintf(bufferLength, bufferAddress, retLen, "\n"); + for ( i = 0; i < NELEMS(NPIList); ++i ) + { +#if 1 // XML + ZLOG_ssprintf(bufferLength, bufferAddress, retLen, "\n", + NPIList[i].NPI_Name, NPIList[i].NPI_Size, NPIList[i].NPI_LastItem); +#else // In format to place into "NSSPersistentItems_s NPIList[]" + ZLOG_ssprintf(bufferLength, bufferAddress, retLen, "\t{ \"%s\", sizeof(%s), \"%s\", offsetof(%s,%s), %u, %u },\n", + NPIList[i].NPI_Name, NSSZPI[i].NPI_Name, + NPIList[i].NPI_LastItemName, NPIList[i].NPI_Name, NPIList[i].NPI_LastItemName, + NPIList[i].NPI_Size, NPIList[i].NPI_LastItem); +#endif + if ( NPIList[i].NPI_Size != NPIList[i].NPI_SizePacked ) + { + zASSERT("Persistent structure size is not correct"==NULL); + } + if ( NPIList[i].NPI_LastItem != NPIList[i].NPI_LastItemPacked ) + { + zASSERT("Persistent structure offsetof is not correct"==NULL); + } + } + ZLOG_ssprintf(bufferLength, bufferAddress, retLen, "\n"); +} +#else +void NSSUT_DisplayAll( NINT bufferLength, BYTE **bufferAddress, NINT *retLen ) {} /* Keep NetWare linker happy */ +#endif + + +STATUS NSSUT_MediaFormatTestAllSizes( ) +{ + int i; + STATUS status = zOK; + + for ( i = 0; i < NELEMS(NPIList); ++i ) + { + if ( NPIList[i].NPI_Size != NPIList[i].NPI_SizePacked ) + { + printf("sizeof %d. %s\n", i, NPIList[i].NPI_Name); + zASSERT("Persistent structure size is not correct"==NULL); + status = zERR_MEDIA_CORRUPTED; + } + if ( NPIList[i].NPI_LastItem != NPIList[i].NPI_LastItemPacked ) + { + printf("offsetof %d. %s\n", i, NPIList[i].NPI_Name); + zASSERT("Persistent structure offsetof is not correct"==NULL); + status = zERR_MEDIA_CORRUPTED; + } + } + return status; +} diff --git a/src/nwnss/comn/common/hmc.c b/src/nwnss/comn/common/hmc.c new file mode 100644 index 0000000..4072c95 --- /dev/null +++ b/src/nwnss/comn/common/hmc.c @@ -0,0 +1,1355 @@ +/**************************************************************************** + | + | (C) Copyright 2006 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2006-11-08 11:00:42 -0700 (Wed, 08 Nov 2006) $ + | + | $RCSfile$ + | $Revision: 1620 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Implements the Linux himem I/O caching layer. + +-------------------------------------------------------------------------*/ +//#include +//#include +//#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inst.h" +#include "fsm.h" +#include "pssDebug.h" +#include "latch.h" +#include "pssmpk.h" +#include "bitmap.h" + +#include "pssConfig.h" +#include "cacheControl.h" + +#include "nssDebug.h" + + + +/* + Oct 2006 + Changed NSS to store its meta-data blocks in high memory. Prior to + this NSS was limited to only using low memory for its meta-data block + cache. User blocks had the low memory restriction removed by changes + made for SP1(long ago). Change only needed for Linux Servers with + limited amount of low memory (I.E. most 32 bit Linux servers). + The design used was selected because it required limited changes to + NSS. This change was done as a patch and therefore we wanted to reduce + the chances of introducing bugs. The cost of this is that the design + does not fully integrate NSS with the Linux cache system. + The himem meta-data cache design is modeled after the NetWare ESM + cache. We treat the himem cache as a secondary cache that is only + referenced in NSS's physical I/O paths. This gives us very defined + points in the code to make changes. It allows us to forgo having a + Buffer_s for each himem page we are using. This saves low memory for + other uses (each Buffer_s requires ~160 bytes). + The two main drawbacks of this design are hits on performance and + cache usage. Performance takes a hit in that EVERY time a meta-data + block is written to disk it must first be copied to the himem cache. + A copy to himem is also required when we read a meta-data block from + disk. Because the himem meta-data cache is treated as a secondary cache + it contains a duplicate block for every block in the primary + (traditional) NSS Buffer_s cache. Although, newly allocated meta-data + blocks do not have a duplicate until they are written. + Any NSS meta-data block may be stored in the himem cache except for + journal blocks. Journal blocks are excluded from the cache because + journal blocks are never read after they are written. I.E. there is no + performance reason to cache them. By not caching them we have more + room for meta-data blocks that may be re-accessed. + + A single inode per pool is used to track all of the himem meta-data + blocks associated with the pool. This is done by using the standard + Linux page API. This allows Linux to toss our himem pages whenever + there is memory pressure within the server. The tracking method used + by Linux, a radix tree, is not optimal in tracking NSS meta-data blocks. + The radix tree is designed to be space efficient for non sparse keys. + E.G. A file's logical block offset. Unfortunately, NSS meta-data keys + are the blocks physical block number. Because of this space issue we + choose not to have an inode per system object. + + The NSS Buffer_s cache is keyed by a block number and pool mycache. It + would have been nice to key the himem cache with a block number and the + specific inode. We choose not to do this because it would have greatly + increased the amount of memory needed for the radix trees. I.E. we would + have had sparser trees since there would have been fewer block mappings in + each tree. A possible solution to this issue would be to use a key + other than the physical block number. We punted on this due to time + and simplicity requirements of the patch. + + We currently invalidate all of a pool's himem cache whenever we do + a pool change state. This is required when going deactive in a cluster. + Plus it makes us feel better when going from/to Maintenance and Active + state because of all the games verify/rebuild perform into doing their + tasks. + + Nov 2006 + It appears that Linux freely tosses 'cached' blocks from memory. It + also appears that Linux does not allow the FS to specify that some blocks + are much more costly to re-read than others. In the case of NSS, user + blocks are cheap and meta-data blocks are very expensive to re-read. + Therefore, we have added an option "/nss PrivateCacheSizeInBlocks" that + allows the admin to dedicate a specific number of pages to NSS meta-data + caching. Our private meta-data cache uses alloc_page and therefore + by-passes Linux's cache tossing logic. + + */ + + +/* + We use the Linux slab allocator for our PageBuffer_s that we allocate. + This way we show up in /proc/slabinfo. We do not have any handlers to + release memory when the kernel has memory pressure. + Generally, NSS does not use the Linux Slab allocators because it would + require us to release our spinlock. For PageBuffer_s I get around this by + allocating all of the items I need upfront. I place them on the NSS + Cache.freePageBuffers list so that I can 'allocate' without releasing our + spinlock. +*/ +kmem_cache_t *NSSPageBufferCache; + + + + +static inline void lruPageBufferENQ( PageBuffer_s *pb ) +{ + DQ_ENQ( &Cache.lruQMetadataPage, pb, PB_LruLink); + return; +} + + +static inline void lruPageBufferPUSH( PageBuffer_s *pb ) +{ + DQ_PUSH( &Cache.lruQMetadataPage, pb, PB_LruLink); + return; +} + + +static inline void lruPageBufferRMV( PageBuffer_s *pb ) +{ + if ( QMEMBER( &pb->PB_LruLink ) ) + { + DQ_RMV( pb, PB_LruLink); + } + return; +} + + +/* + Take the oldest PageBuffer from the LRU. + + Returns NULL if no PageBuffer_s are available. +*/ +static inline PageBuffer_s *lruPageBufferDEQ( void ) +{ + PageBuffer_s *pb; + + DQ_DEQ( &Cache.lruQMetadataPage, pb, PageBuffer_s, PB_LruLink ); + return pb; +} + + +/* + lruPageBufferNewest() - + Make the PageBuffer_s the newest item in the LRU. PB must + already be on the LRU. +*/ +static inline void lruPageBufferNewest( PageBuffer_s *pb ) +{ + lruPageBufferRMV( pb ); + lruPageBufferENQ( pb ); + return; +} + + +/* + lruPageBufferOldest() - + Make the PageBuffer_s the newest item in the LRU. PB must + already be on the LRU. +*/ +static inline void lruPageBufferOldest( PageBuffer_s *pb ) +{ + lruPageBufferRMV( pb ); + lruPageBufferPUSH( pb ); + return; +} + + +/* + Places a PageBuffer_s on the NSS free list. PBs on this list + must NEVER have a PB_Page pointer. +*/ +static inline void putPageBuffer( PageBuffer_s *pb ) +{ + zASSERT( pb->PB_Page == NULL ); + STK_PUSH(Cache.freePageBuffers, pb, PB_LruLink); + ++Inst.cache.numFreePageBuffers; + return; +} + +/* + Returns a free PageBuffer_s. + + Returns + NULL if no PageBuffer_s on NSS free list. +*/ +static inline PageBuffer_s *getPageBuffer( void ) +{ + PageBuffer_s *pb; + + STK_POP(Cache.freePageBuffers, pb, PageBuffer_s, PB_LruLink); + if ( pb ) { + zASSERT( pb->PB_Page == NULL ); + --Inst.cache.numFreePageBuffers; + } + return pb; +} + + +/* + Returns + NULL if we do not have a PageBuffer_s cached in himem for the + requested item. + + Notes - + Modeled after cacheFind(). +*/ +static PageBuffer_s *cacheFindPageBuffer( + ADDR keyPart, + Blknum_t fileBlk ) +{ + NINT hashKey; + PageBuffer_s *pb; + DQhead_t *head; + + ASSERT_MPKNSS_LOCK(); + hashKey = (((ADDR)keyPart >> 3) ^ fileBlk) & Config.cache.privateHashMask; + head = &Cache.bucketPageBuffer[hashKey]; + DQ_FOREACH(head, pb, PageBuffer_s, PB_HashLink) + { + if ( (pb->PB_KeyPart == keyPart) && (pb->PB_FileBlk == fileBlk) ) + { + lruPageBufferNewest( pb ); + return pb; + } + } + return NULL; +} + + +/* + cachePushPageBuffer() - + Places a PageBuffer_s into our hash table so we can quickly + look it up. + + Notes - + Modeled after cachePush(). +*/ +static void cachePushPageBuffer( + PageBuffer_s *pb ) +{ + NINT hashKey; + DQhead_t *head; + + ASSERT_MPKNSS_LOCK(); + hashKey = (pb->PB_FileBlk ^ ((ADDR)pb->PB_KeyPart >> 3)) & Config.cache.privateHashMask; + head = &Cache.bucketPageBuffer[hashKey]; + DQ_PUSH(head, pb, PB_HashLink); + return; +} + + +static inline void cachePageBufferRMV( PageBuffer_s *pb ) +{ + if ( QMEMBER( &pb->PB_HashLink ) ) + { + DQ_RMV( pb, PB_HashLink); + } + return; +} + + +/* + cachePushPageBuffer() - + Places a PageBuffer_s into our Pool so we can quickly toss + when we 'deactivate' the pool. + +*/ +static void poolPushPageBuffer( + DQhead_t *head, + PageBuffer_s *pb ) +{ + + DQ_PUSH(head, pb, PB_PoolLink); + return; +} + + +static inline void poolPageBufferRMV( PageBuffer_s *pb ) +{ + if ( QMEMBER( &pb->PB_PoolLink ) ) + { + DQ_RMV( pb, PB_PoolLink); + } + return; +} + + +/* + Invalidate all of the meta-data himem pages that are associated + with a pool. Must not cache blocks when not ACTIVE. Required for + Novell Clustering Services (NCS) and a good idea anyway. +*/ +void HMC_InvalidatePoolHimemPages( Pool_s *pool ) +{ + PageBuffer_s *pb; + + S_LATCH( &Cache.CC_HMCCacheTypeLatch ); + if ( Config.cache.hmcCacheType == HMC_CT_PRIVATE ) { + printk("<3>NSS: Clearing the NSS private cache for a pool\n"); + DQ_DEQ( &pool->P_MDHimemList, pb, PageBuffer_s, PB_PoolLink ); + while (pb) { + cachePageBufferRMV(pb); + lruPageBufferOldest(pb); + PERIODIC_YIELD(); + DQ_DEQ( &pool->P_MDHimemList, pb, PageBuffer_s, PB_PoolLink ); + } + } + else if ( Config.cache.hmcCacheType == HMC_CT_LINUX ) { + printk("<3>NSS: Clearing the NSS Linux cache for a pool\n"); + if (pool->P_Inode) + { + MPKNSS_UNLOCK(); + invalidate_inode_pages(pool->P_Inode->i_mapping); + MPKNSS_LOCK(); + } + else + { + printk("<1>NSS: Unable to clear NSS Linux cache due to null inode\n"); + } + } + UNS_LATCH( &Cache.CC_HMCCacheTypeLatch ); + return; +} +EXPORT_SYMBOL(HMC_InvalidatePoolHimemPages); + + +/* + + Warnings - + Releases NSS spinlock. + */ +static PageBuffer_s *zallocPageBuffer( void ) +{ + PageBuffer_s *pb; + + MPKNSS_UNLOCK(); + pb = kmem_cache_alloc(NSSPageBufferCache, SLAB_KERNEL); + MPKNSS_LOCK(); + if ( pb ) { + ++Config.cache.privateCachePageBuffers; + // Note that /proc/slabinfo also tracks usage + memset( pb, 0, sizeof( PageBuffer_s ) ); + } + return pb; +} + + +/* + + Warnings - + Releases NSS spinlock. + */ +static void freePageBuffer( PageBuffer_s *pb ) +{ + if ( !pb ) { + return; + } + /* Note that /proc/slabinfo also tracks usage */ + --Config.cache.privateCachePageBuffers; + MPKNSS_UNLOCK(); + kmem_cache_free(NSSPageBufferCache, pb); + pb = NULL; + MPKNSS_LOCK(); + return; +} + + +/* + allocPageBufferGroup() - + Allocates PageBuffer_s items from Linux. Places the items on + our free list (i.e. Cache.freePageBuffers). This is done so that + we can get + + Warnings - + Releases NSS spinlock. + + Return - + Number of PageBuffer_s allocated. + */ +static unsigned int allocPageBufferGroup( unsigned int numberToAllocate ) +{ + PageBuffer_s *pb; + unsigned int items; + + for (items = 0; items < numberToAllocate; ++items) + { + pb = zallocPageBuffer(); + if ( !pb ) { + return items; + } + putPageBuffer( pb ); + pb = NULL; + PERIODIC_YIELD(); + } + return numberToAllocate; +} + + +/* + Reduces the memory used by the Himem Metadata Page Buffer + system. Does this by freeing the Himem page associated with + the oldest page buffer on the cache.lruQMetadataPage. Places + this PageBuffer_s on the list of re-useable PageBuffer_s. + + Returns true if we reduced memory usage else false. +*/ +#if 0 +BOOL removePageBuffer( void ) +{ + PageBuffer_s *pb; + + pb = lruPageBufferDEQ(); + if ( pb == NULL ) { + return FALSE; + } + remove from all lists + + removeAPage( pb ); + movePageBuffer( &pb ); + return TRUE; +} +#endif + +/* + addAPage() - + Adds a Linux Himem page to a PageBuffer_s. This PB must + not already have a page associated with it. This routine + will add a low memory page if that is what the kernel returns:-( + */ +STATUS addAPage( PageBuffer_s *pb ) +{ + MPKNSS_UNLOCK(); + pb->PB_Page = alloc_page(GFP_HIGHUSER); + MPKNSS_LOCK(); + if (pb->PB_Page == NULL) + { + ++Inst.cache.numMetadataHimemPagesAllocFailures; + printk("<2>NSS: Error return from addAPage\n"); + return zFAILURE; + } + if ( !PageHighMem(pb->PB_Page) ) { + ++Inst.cache.numMetadataHimemPagesInLowMemory; +// printk("<2>NSS: addAPage is using a low memory page\n"); + } + ++Config.cache.privateCachePages; + return zOK; +} + + +/* + removeAPage() - + Frees a Linux Himem page associated with a PageBuffer_s. This PB must + already have a page associated with it. + + Return + On return the PageBuffer_s will no longer have a page associated + with it. In addition PB_Page will be NULL. + */ +void removeAPage( PageBuffer_s *pb ) +{ + struct page *page; + + zASSERT( pb != NULL ); + page = pb->PB_Page; + pb->PB_Page = NULL; + --Config.cache.privateCachePages; + if ( !PageHighMem(page) ) { + --Inst.cache.numMetadataHimemPagesInLowMemory; + } + MPKNSS_UNLOCK(); + __free_page((struct page *)page); + MPKNSS_LOCK(); + return; +} + +void RemovePageBufferFromAllLists( PageBuffer_s *pb ) +{ + lruPageBufferRMV(pb); + cachePageBufferRMV(pb); + poolPageBufferRMV(pb); + return; +} + +unsigned int freePageBufferGroup(unsigned int numToFree) +{ + unsigned int i; + PageBuffer_s *pb; + + for (i = 0; i < numToFree; i++) + { + pb = getPageBuffer( ); + if ( !pb ) + { + pb = lruPageBufferDEQ(); + if (!pb) + { + break; + } + RemovePageBufferFromAllLists(pb); + removeAPage(pb); + } + freePageBuffer( pb ); + pb = NULL; + PERIODIC_YIELD(); + } + return i; +} + + +/* + Warnings - + Must be callable from HMC_PrivateAllocate in error paths to clean up + partially allocated items. + */ +static void HMC_PrivateFree() +{ + unsigned int itemsProcessed; + unsigned int totalFreed = 0; + unsigned int itemsRemaining = Config.cache.privateCachePageBuffers; + + printk("<3>NSS: Freeing the NSS private cache.\n"); + do + { + itemsProcessed = freePageBufferGroup(itemsRemaining); + itemsRemaining = itemsRemaining - itemsProcessed; + totalFreed += itemsProcessed; + } while (itemsRemaining && itemsProcessed ); + + printk("<1>NSS: Freed %u PageBuffers\n", totalFreed ); + if (NSSPageBufferCache) + { + MPKNSS_UNLOCK(); + kmem_cache_destroy(NSSPageBufferCache); + MPKNSS_LOCK(); + NSSPageBufferCache = NULL; + } + free(Cache.bucketPageBuffer); + Cache.bucketPageBuffer = NULL; + return; +} + + +STATUS HMC_PrivateSizeSetUIValidate(NINT *newBlockTotal) +{ + struct sysinfo si; + + si_meminfo(&si); + if (*newBlockTotal > si.totalhigh) + { + *newBlockTotal = si.totalhigh; + } + if ( ((*newBlockTotal)/2) < Config.cache.numBuffers ) + { /* Since the Private cache has a copy of all the blocks in + the NSS cache we require that the private cache is + twice the size of the NSS Cache. */ + return zERR_HMC_LESS_THAN_TWICE_NSS_CACHE; + } + return zOK; +} + + +/* + Attempts to change the current number of page buffers (i.e. + Inst.cache.numPageBuffers) to Config.cache.privateCacheSizeRequest. + + */ +static void HMC_PrivateSizeSet() +{ + int changeAmount; + unsigned int itemsProcessed; + + changeAmount = Config.cache.privateCacheSizeRequest - + Config.cache.privateCachePageBuffers; + if (changeAmount > 0) + { + itemsProcessed = allocPageBufferGroup( changeAmount ); + printk("<2>NSS: Allocated %u PageBuffers\n", itemsProcessed ); + } + else + { + changeAmount = -changeAmount; + itemsProcessed = freePageBufferGroup( changeAmount ); + printk("<2>NSS: Freed %u PageBuffers.\n", itemsProcessed ); + } + printk("<2>NSS: Private Cache target blocks is %u.\n", + Config.cache.privateCacheSizeRequest ); + printk("<2>NSS: Private cache has %u page buffers.\n", + Config.cache.privateCachePageBuffers ); + return; +} + + +/* + Pre-allocates all of the PageBuffer_s that we may need. They + are placed on our free list so that we can use without releasing + our spinlock. Does NOT allocate that pages that need to be + associated with the PageBuffer_s. This is done when we need the + pages. +*/ +#if defined(__i386__) +static STATUS HMC_PrivateAllocate() +{ + STATUS status; + NINT i; + NINT temp; + + MPKNSS_UNLOCK(); + NSSPageBufferCache = kmem_cache_create("nss_private_cache", + sizeof(PageBuffer_s), 0, 0, NULL, NULL); + MPKNSS_LOCK(); + if ( !NSSPageBufferCache ) + { + HMC_PrivateFree(); + return zERR_NO_MEMORY; + } + + HMC_PrivateSizeSet(); + /* Verify that we were able to allocate at least the minimum + required. We may be short of slab space OR the calculated + number for Config.cache.privateCacheSizeRequest may be too small + to effectively use the Private cache. + */ + temp = Config.cache.privateCachePageBuffers; + status = HMC_PrivateSizeSetUIValidate( &temp ); + if ( status != zOK ) { + HMC_PrivateFree(); + return status; + } + /* The hash size is based on the number of private cache items when + the private cache is turned on. Therefore, if you grow private + cache size we are stuck with the old hash size. This may + be an issue if you go from a SMALL number of private caches + to a much greater number of them. Our hash chains will get + much larger:-( We do not re-size hash during private + cache re-size because the hash table is being used at that + time AND many DQs point into it. + */ + Config.cache.privateHashSize = 1 << (findHighBit(Config.cache.privateCachePageBuffers) + 1); + Config.cache.privateHashMask = Config.cache.privateHashSize - 1; + + /* By allocating private hash here we do not waste memory + when the server is not using a private cache:-) + */ + Cache.bucketPageBuffer = zalloc(Config.cache.privateHashSize * sizeof(DQhead_t)); + if (Cache.bucketPageBuffer == NULL) + { + HMC_PrivateFree(); + return zERR_NO_MEMORY; + } + for (i = 0; i < Config.cache.privateHashSize; ++i) + { + DQ_INIT(&Cache.bucketPageBuffer[i]); + PERIODIC_YIELD(); + } + return zOK; +} +#endif + + +/* + HMC_PrivateSizeSetUI() - + Verifies that the new private block total is logical. If so + will set the new total. + + Notes - + If requested blocks is more than high memory then we change + request to high memory total. + If requested blocks <= number of meta-data Buffer_s blocks then + we return an error. + */ +STATUS HMC_PrivateSizeSetUI(NINT newBlockTotal) +{ + STATUS status; + + status = HMC_PrivateSizeSetUIValidate( &newBlockTotal ); + if (status != zOK) { + return status; + } + Config.cache.privateCacheSizeRequest = newBlockTotal; + if ( !Cache.isInitialized ) { + Config.cache.privateCacheSizeRequestStartup = TRUE; + return zOK; + } + S_LATCH( &Cache.CC_HMCCacheTypeLatch ); + if ( Config.cache.hmcCacheType == HMC_CT_PRIVATE ) + { + HMC_PrivateSizeSet(); + } + UNS_LATCH( &Cache.CC_HMCCacheTypeLatch ); + return zOK; +} + + +void HMC_LinuxAllocate( void ) +{ + return; +} + + +static void HMC_LinuxFree() +{ + Pool_s *pool; + + printk("<3>NSS: Invalidating the NSS Linux cache\n"); + SET_FOREACHBLOCKING(&NSSMasterPoolList, pool, Pool_s, masterPoolLink) + { + COMN_USE_BEAST( &pool->POOLroot ); + X_LATCH( &pool->cvsLatch ); + if (pool->P_Inode) + { + MPKNSS_UNLOCK(); + invalidate_inode_pages(pool->P_Inode->i_mapping); + MPKNSS_LOCK(); + } + UNX_LATCH( &pool->cvsLatch ); + COMN_Release( &pool ); + SET_FOREACHBLOCKINGEND(&NSSMasterPoolList, pool, Pool_s, masterPoolLink) + } + return; +} + + +/* + + Warning - + To continue with the cache tradition of hard to maintain code, the page + we return is only protected via our NSS spinlock:-( + */ +static struct page *HMC_grab_cache_page( + DQhead_t *head, /* Pool head to use */ + ADDR keyPart, + Blknum_t fileBlk ) +{ + STATUS status; + PageBuffer_s *pb; + + pb = cacheFindPageBuffer(keyPart,fileBlk); + if (pb) + { /* Its in our private cache so just return the page */ + return pb->PB_Page; + } + pb = getPageBuffer( ); + if ( pb ) + { /* Found a never used pb so hook to a 4k page and then use this pb */ + /* Can block, but no race beause Buffer_s latch is held. */ + status = addAPage(pb); /* pb->PB_Page */ + if (status != zOK ) { + putPageBuffer(pb); + pb = NULL; + } + } + if ( !pb ) + { /* Maxed out on Meta-data himem cache so we have to re-use our oldest one:-( */ + pb = lruPageBufferDEQ(); + if ( pb == NULL ) { + ++Inst.cache.numLRUPageBufferDEQFailures; + return NULL; + } + cachePageBufferRMV(pb); + poolPageBufferRMV(pb); + } + pb->PB_FileBlk = fileBlk; /* pb->PB_FileBlk */ + pb->PB_KeyPart = keyPart; /* pb->PB_KeyPart */ + lruPageBufferENQ(pb); /* pb->PB_LruLink */ + cachePushPageBuffer(pb); /* pb->PB_HashLink */ + poolPushPageBuffer(head, pb); /* pb->PB_PoolLink */ + return pb->PB_Page; +} + + +/* + + Warning - + To continue with the cache tradition of hard to maintain code, the page + we return is only protected via our NSS spinlock:-( + */ + +static struct page *HMC_find_get_page( + ADDR keyPart, + Blknum_t fileBlk) +{ + PageBuffer_s *pb; + + pb = cacheFindPageBuffer(keyPart,fileBlk); + if (!pb) { + return NULL; + } + return pb->PB_Page; +} + + +/* + HMC_MarkNewestIfCached() - + Marks specified cache as the newest on the LRU. If no cache entry + for specified volBlk then nothing is done. + Returns TRUE if found in Cache, else returns FALSE + */ +BOOL HMC_MarkNewestIfCached( + struct inode *inode, + Blknum_t volBlk ) +{ + BOOL found = FALSE; + + S_LATCH( &Cache.CC_HMCCacheTypeLatch ); + if ( Config.cache.hmcCacheType == HMC_CT_PRIVATE ) + { + if (cacheFindPageBuffer((ADDR)inode,volBlk)) + { + /* cacheFindPageBuffer() does lruPageBufferNewest() if found */ + found = TRUE; + } + } + else if ( (Config.cache.hmcCacheType == HMC_CT_LINUX) && inode ) + { + struct page *page; + + page = find_get_page(inode->i_mapping, volBlk); + if (page) + { + mark_page_accessed(page); + page_cache_release(page); + found = TRUE; + } + } + UNS_LATCH( &Cache.CC_HMCCacheTypeLatch ); + return found; +} +EXPORT_SYMBOL(HMC_MarkNewestIfCached); + + +/* + Warning - + Must only be called if HMC_UseHimem returned TRUE. + Must not be called to store user blocks (caller must perform + required checks). User blocks are sometimes stored in the NSS meta-data + cache (see the two functions in this file that jump to the label + useNSScache). When user data is stored in our NSS meta-data cache we + must not place (or look) for the blocks in himem. If we did and the + block does not ALWAYS use the NSS meta-data cache then we + could end up getting a stale copy from himem. Long term, we should not + use NSS meta-data cache for user data. +*/ +static BOOL HMC_CopyDataToLinuxCache( + Buffer_s *buffer, + struct inode *inode) +{ + struct page *page; + char *data; + + if ( Config.cache.hmcCacheType != HMC_CT_LINUX ) + { + return FALSE; + } + MPKNSS_UNLOCK(); + page = grab_cache_page(inode->i_mapping, buffer->volBlk); + if (!page) + { + MPKNSS_LOCK(); + return FALSE; + } + unlock_page(page); + data = kmap_atomic(page, KM_USER0); + memcpy(data, buffer->pBuf.data, PAGE_SIZE); + kunmap_atomic(data, KM_USER0); + mark_page_accessed(page); + page_cache_release(page); + MPKNSS_LOCK(); + return TRUE; +} + + +/* + Returns - + This will return TRUE if we did find in himem and successfully + copied the data to buffer. + + Warning - + Must only be called if HMC_UseHimem returned TRUE. + */ +static BOOL HMC_CopyDataFromLinuxCache( + Buffer_s *buffer, + struct inode *inode) +{ + struct page *page; + char *data; + + if ( Config.cache.hmcCacheType != HMC_CT_LINUX ) + { + return FALSE; + } + page = find_get_page(inode->i_mapping, buffer->volBlk); + if (!page) + { + return FALSE; + } + data = kmap_atomic(page, KM_USER0); + memcpy(buffer->pBuf.data, data, PAGE_SIZE); + kunmap_atomic(data, KM_USER0); + mark_page_accessed(page); + page_cache_release(page); +/// cacheLinuxStatsUpdate((buffer->state & CACHE_USER_BUFFER), CACHE_READ, !found); + return TRUE; +} + + +/* + Warning - + Must only be called if HMC_UseHimem returned TRUE. + Must not be called to store user blocks (caller must perform + required checks). User blocks are sometimes stored in the NSS meta-data + cache (see the two functions in this file that jump to the label + useNSScache). When user data is stored in our NSS meta-data cache we + must not place (or look) for the blocks in himem. If we did and the + block does not ALWAYS use the NSS meta-data cache then we + could end up getting a stale copy from himem. Long term, we should not + use NSS meta-data cache for user data. + + Returns - + TRUE if we copied into our private cache. +*/ +static BOOL HMC_CopyDataToPrivateCache( + DQhead_t *poolHead, + Buffer_s *buffer, + struct inode *inode) +{ + struct page *page; + char *data; + + if ( Config.cache.hmcCacheType != HMC_CT_PRIVATE ) + { + return FALSE; + } + page = HMC_grab_cache_page(poolHead, (ADDR)inode, buffer->pBuf.fileBlk); + if (!page) + { + return FALSE; + } + data = kmap_atomic(page, KM_USER0); + memcpy(data, buffer->pBuf.data, PAGE_SIZE); + kunmap_atomic(data, KM_USER0); + return TRUE; +} + + +/* + Returns - + This will return TRUE if we found in our private cache and successfully + copied the data to the Buffer_s. + + Warning - + Must only be called if HMC_UseHimem returned TRUE. + */ +static BOOL HMC_CopyDataFromPrivateCache( + Buffer_s *buffer, + struct inode *inode) +{ + struct page *page; + char *data; + BOOL found = FALSE; + + if ( Config.cache.hmcCacheType != HMC_CT_PRIVATE ) + { + return FALSE; + } + page = HMC_find_get_page((ADDR)inode, buffer->pBuf.fileBlk); + if (page) + { + data = kmap_atomic(page, KM_USER0); + memcpy(buffer->pBuf.data, data, PAGE_SIZE); + kunmap_atomic(data, KM_USER0); + found = TRUE; + } +/// cacheLinuxStatsUpdate((buffer->state & CACHE_USER_BUFFER), CACHE_READ, !found); + return found; +} + + +/* + Warning - + Must only be called if HMC_UseHimem returned TRUE. + Must not be called to store user blocks (caller must perform + required checks). User blocks are sometimes stored in the NSS meta-data + cache (see the two functions in this file that jump to the label + useNSScache). When user data is stored in our NSS meta-data cache we + must not place (or look) for the blocks in himem. If we did and the + block does not ALWAYS use the NSS meta-data cache then we + could end up getting a stale copy from himem. Long term, we should not + use NSS meta-data cache for user data. +*/ +BOOL HMC_CopyDataToHimem( + DQhead_t *poolHead, + Buffer_s *buffer, + struct inode *inode) +{ + BOOL copied; + + S_LATCH( &Cache.CC_HMCCacheTypeLatch ); + copied = HMC_CopyDataToPrivateCache(poolHead,buffer,inode); + if ( !copied ) { + copied = HMC_CopyDataToLinuxCache(buffer,inode); + } + UNS_LATCH( &Cache.CC_HMCCacheTypeLatch ); + return copied; +} +EXPORT_SYMBOL(HMC_CopyDataToHimem); + + +/* + Returns - + This will return TRUE if we did find in himem and successfully + copied the data to buffer. + + Warning - + Must only be called if HMC_UseHimem returned TRUE. + */ +BOOL HMC_CopyDataFromHimem( + Buffer_s *buffer, + struct inode *inode) +{ + BOOL found; + + S_LATCH( &Cache.CC_HMCCacheTypeLatch ); + found = HMC_CopyDataFromPrivateCache(buffer,inode); + if ( !found ) { + found = HMC_CopyDataFromLinuxCache(buffer,inode); + } + UNS_LATCH( &Cache.CC_HMCCacheTypeLatch ); + CACHE_LinuxStatsUpdate((buffer->state & CACHE_USER_BUFFER), CACHE_READ, !found); + return found; +} +EXPORT_SYMBOL(HMC_CopyDataFromHimem); + + +/* + HMC_UseHimem() - + Determines if a Buffer_s data can be placed into himem. + + Returns - + TRUE if we can place Buffer_s data into himem. + + Warning - + Caller must ensure that the buffer does not contain user data before + calling the HMC_CopyData... routines. See the routines for details. + The buffer checks are done to make Vandana happy. Since we must + not be called with user blocks they SHOULD not be needed. +*/ +BOOL HMC_UseHimem(const Buffer_s *buffer) +{ + if ( (Config.cache.hmcCacheType == HMC_CT_NONE) || + (!(buffer->b_page) || (buffer->state & CACHE_HAS_LINUX_PAGE)) ) + { + return FALSE; + } + return TRUE; +} +EXPORT_SYMBOL(HMC_UseHimem); + + +#if defined(__i386__) +STATUS HMC_TypeSetPrivate( void ) +{ + STATUS status; + + ASSERT_XLATCH( &Cache.CC_HMCCacheTypeLatch ); + if ( Config.cache.hmcCacheType == HMC_CT_PRIVATE ) { + return zOK; + } + if ( Config.cache.hmcCacheType == HMC_CT_LINUX ) { + Config.cache.hmcCacheType = HMC_CT_PRIVATE; + /* Optimal code would 'copy' the blocks from the + Linux Cache to the Private Cache. We punted + as we do not think the user will change the + cache the server uses very often. + */ + HMC_LinuxFree(); + status = HMC_PrivateAllocate(); + if ( status != zOK ) { + printk("<1>NSS: Unable to switch to using private cache\n"); + Config.cache.hmcCacheType = HMC_CT_LINUX; + HMC_LinuxAllocate(); + return status; + } + return zOK; + } + Config.cache.hmcCacheType = HMC_CT_PRIVATE; + status = HMC_PrivateAllocate(); + if ( status != zOK ) { + printk("<1>NSS: Unable to switch to using private cache\n"); + Config.cache.hmcCacheType = HMC_CT_NONE; + return status; + } + return zOK; +} +#endif + +#if defined(__x86_64__) +STATUS HMC_TypeSetPrivate( void ) +{ + return zERR_HMC_USE_MINBUFFERCACHESIZE; +} +#endif + + +#if defined(__i386__) +STATUS HMC_TypeSetLinux( void ) +{ + struct sysinfo si; + + ASSERT_XLATCH( &Cache.CC_HMCCacheTypeLatch ); + if ( Config.cache.hmcCacheType == HMC_CT_LINUX ) { + return zOK; + } + if ( Config.cache.hmcCacheType == HMC_CT_PRIVATE ) { + Config.cache.hmcCacheType = HMC_CT_LINUX; + HMC_PrivateFree(); + HMC_LinuxAllocate(); + return zOK; + } + /* Going from 'none' to 'linux' */ + si_meminfo(&si); + if ( (si.totalhigh/2) < Config.cache.numBuffers ) { + return zERR_HMC_HIGH_MEMORY_LESS_THAN_TWICE_NSS_CACHE; + } + Config.cache.hmcCacheType = HMC_CT_LINUX; + HMC_LinuxAllocate(); + return zOK; +} +#endif + +#if defined(__x86_64__) +STATUS HMC_TypeSetLinux( void ) +{ + return zERR_HMC_USE_MINBUFFERCACHESIZE; // TODO: let them use Linux cache!!! +} +#endif + + +STATUS HMC_TypeSetNone( void ) +{ + ASSERT_XLATCH( &Cache.CC_HMCCacheTypeLatch ); + if ( Config.cache.hmcCacheType == HMC_CT_LINUX ) { + Config.cache.hmcCacheType = HMC_CT_NONE; + HMC_LinuxFree(); + } + else if ( Config.cache.hmcCacheType == HMC_CT_PRIVATE ) { + Config.cache.hmcCacheType = HMC_CT_NONE; + HMC_PrivateFree(); + } + return zOK; +} + + +/* + HMC_TypeSet() - + Sets the cache type to private, Linux or none. + */ +static STATUS HMC_TypeSet( NINT cacheType ) +{ + STATUS status; + + X_LATCH( &Cache.CC_HMCCacheTypeLatch ); + switch ( cacheType ) { + case HMC_CT_NONE: + status = HMC_TypeSetNone(); + break; + case HMC_CT_LINUX: + status = HMC_TypeSetLinux(); + break; + case HMC_CT_PRIVATE: + status = HMC_TypeSetPrivate(); + break; + default: + status = zERR_BAD_PARAMETER_VALUE; + break; + } + UNX_LATCH( &Cache.CC_HMCCacheTypeLatch ); + return status; +} + + +#if defined(__i386__) +STATUS HMC_TypeSetUIValidate( NINT cacheType ) +{ + switch ( cacheType ) { + case HMC_CT_PRIVATE: + case HMC_CT_LINUX: + case HMC_CT_NONE: + return zOK; + default: + return zERR_BAD_PARAMETER_VALUE; + } +} +#endif + + +#if defined(__x86_64__) +STATUS HMC_TypeSetUIValidate( NINT cacheType ) +{ + switch ( cacheType ) { + case HMC_CT_NONE: + return zOK; + case HMC_CT_LINUX: + case HMC_CT_PRIVATE: + return zERR_HMC_USE_MINBUFFERCACHESIZE; + default: + return zERR_BAD_PARAMETER_VALUE; + } +} +#endif + + +/* + HMC_TypeSetUI() - + Sets the cache type to private, Linux or none. Since a UI + routine does not trust the input value. + */ +STATUS HMC_TypeSetUI( NINT cacheType ) +{ + STATUS status; + + status = HMC_TypeSetUIValidate( cacheType ); + if (status != zOK) { + return status; + } + if ( !Cache.isInitialized ) { + Config.cache.hmcCacheType = cacheType; + return zOK; + } + status = HMC_TypeSet(cacheType); + return status; +} +EXPORT_SYMBOL(HMC_TypeSetUI); + +const char *HMC_CacheName() +{ + switch (Config.cache.hmcCacheType) + { + case HMC_CT_NONE: + return "none"; + case HMC_CT_PRIVATE: + return "private"; + case HMC_CT_LINUX: + return "linux"; + default: + return "unknown"; + } +} + +STATUS HMC_Startup( void ) +{ + STATUS status; + struct sysinfo si; + + si_meminfo(&si); + if ( !Config.cache.privateCacheSizeRequestStartup ) + { /* User did not set in parse startup so lets come up with + a value based on the amount of memory the server has. */ + Config.cache.privateCacheSizeRequest = si.totalhigh/5; + status = HMC_PrivateSizeSetUIValidate(&Config.cache.privateCacheSizeRequest); + if ( (status != zOK) && (Config.cache.hmcCacheType == HMC_CT_PRIVATE) ) { + printk("<2>NSS: Default private cache size is too small, switching to Linux cache.\n"); + Config.cache.hmcCacheType = HMC_CT_LINUX; + } + } + if ( Config.cache.hmcCacheType != HMC_CT_NONE ) + { + if ( (si.totalhigh/2) < Config.cache.numBuffers ) + { + printk("<2>NSS: Limited high memory - disabling high memory cache feature.\n"); + (void)HMC_TypeSet( HMC_CT_NONE ); + } else { + if ( Config.cache.hmcCacheType == HMC_CT_PRIVATE ) { + /* Set to HMC_CT_NONE 1st so that when we set to + HMC_CT_PRIVATE it will do HMC_PrivateAllocate. + We force set HMC_CT_NONE to match the state + that we have not allocated anything. */ + Config.cache.hmcCacheType = HMC_CT_NONE; + (void)HMC_TypeSet( HMC_CT_PRIVATE ); + } + else if ( Config.cache.hmcCacheType == HMC_CT_LINUX ) { + Config.cache.hmcCacheType = HMC_CT_NONE; + (void)HMC_TypeSet( HMC_CT_LINUX ); + } + } + } + return zOK; +} + + +STATUS HMC_Shutdown( void ) +{ + STATUS status; + + status = HMC_TypeSet( HMC_CT_NONE ); + return status; +} diff --git a/src/nwnss/comn/common/repair.c b/src/nwnss/comn/common/repair.c new file mode 100644 index 0000000..186071c --- /dev/null +++ b/src/nwnss/comn/common/repair.c @@ -0,0 +1,2619 @@ +/* + | (C) Copyright 1995-1998, 2003 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Service + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2006-12-30 03:27:16 +0530 (Sat, 30 Dec 2006) $ + | + | $RCSfile$ + | $Revision: 1799 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | + +-------------------------------------------------------------------------*/ +#if zLINUX +#define EXPORT_SYMTAB +#include +#else +#define EXPORT_SYMBOL(_fun) +#endif + +#include +#include +#include "nssOSAPIs.h" +#include /* NSS Library Includes*/ +#include +#include +#include +#include +#include +#include +#include "schedule.h" +#include "nssOSAPIs.h" +#include +#include "repair.h" +#include "sysimp.h" + +#include "mgmt.h" +#include "xmlNSS.h" +#include "xmlTags.h" +#include "manage.h" + + +#include "nCache.h" +#include "comnPublics.h" +#include "xUnicode.h" +#include "eventSys.h" +#include "pssStartup.h" +#include "guid.h" +#include "parse.h" +#include "maintenance.h" +#include "adminVolume.h" +#include "zPool.h" +#include "virtualIO.h" +#include "repairRAVUser.h" + +#ifndef NEB_STATUS +#define NEB_STATUS int +#endif + +#undef WHERE +#define WHERE "repair.c" "[" MAKE_STRING(__LINE__) "]" + +#define STATIC_INIT_LATCH(_latch) { 0, IDLE_LATCH_STATE, 0 } + +#if NSS_DEBUG IS_ENABLED +#if zNETWARE +//#define HERE_WE_ARE() aprintf( LRED, WHERE "\n" ) +#define HERE_WE_ARE() +#else +//#define HERE_WE_ARE() printk(KERN_ALERT WHERE "\n") +#define HERE_WE_ARE() +#endif +#else +#define HERE_WE_ARE() +#endif + + +Latch_s VP_RepairProcessListLatch = STATIC_INIT_LATCH(VP_RepairProcessListLatch); + /* Latch used to walk the VP_RepairProcessList list. Latch must only be owned + * while walking list. + */ +DQhead_t VP_RepairProcessList = DQ_STATIC_INIT(VP_RepairProcessList); + /* List of all current and saved VPV_Status_s items. These items track + * the status of pool verify operations. Used by verify thread and XML + * interfaces, and CPS NEB event code. + */ +Latch_s VP_RepairProcessListNoItem; + /* Latched used to implement ZSH_FLAG_WAIT. We always have an X_LATCH on latch + * if there are NO items on the VP_RepairProcessList. + */ +STATIC ADDR REPAIR_ConsumerIDVolEnter; +STATIC ADDR REPAIR_ConsumerIDPoolEnter; +STATIC BYTE *CheckModName = {(BYTE *)MSGNot("NSS Maintenance")}; + + +// each of the menu items below can be 'extern' but they will be loaded after +// this modules is loaded +//gLONG MENU_WinHandle; // this needs to be filled in for the menu +//gBYTE MENU_DisplayBuffer[200]; // this is needed for the menu +//gVolumeID_t MENU_PoolVolElementList[500]; // this is needed for the menu +//gBYTE ToDoListProcessFlag = 0; +//gLONG REPAIR_ConsumerIDVolExit; +//gLONG REPAIR_ConsumerIDPoolExit; + +/*- local to this modules only -*/ +//gNINT updatingPoolsToDoList = LIST_UNLOCKED; +//gNINT updatingProcessList = LIST_UNLOCKED; +//gDQhead_t PoolsToDoList = DQ_STATIC_INIT(PoolsToDoList); +//gDQhead_t RepairProcessList = DQ_STATIC_INIT(RepairProcessList); +//gNINT processCount = 0; +//gNINT toDoCount = 0; +//gNINT CPListIsUp = FALSE; +//gLONG CPWinHandle; +//gLONG MenuWinHandle = 0; +//LONG CPMenuProcessID; +//THREAD CPMenuProcessID; +//gBYTE *CPMenuProcessStack = NULL; + +BOOL COMN_PoolCorrectType( Pool_s *pool, NINT includeType ); +STATUS VP_PoolAction( GeneralMsg_s *genMsg, const unicode_t *poolName, Pool_s *pool, + QUAD *key, BOOL crossValidation, QUAD debugLevel, QUAD uiOptions ); +STATUS VP_PoolAction2( const unicode_t *poolName ); +STATUS CPUnInitGlobals(); +void VP_PoolInfoDestroy( VP_Status_s *pInfo ); +STATUS VP_PA_ReverseNameLookup( ZVS_ReverseNameLookup_s *rnl ); +STATUS VP_PA_RAVSetWithKey( ZVS_Set_s *set ); +STATUS VP_PA_RAVStatus( const unicode_t *poolName ); +STATUS VP_PA_RAVRemoveWithKey( const QUAD *userKey ); +STATUS VP_PA_RAVStatusWithKey( const QUAD *userKey ); +STATUS VP_PA_RAVItemRemoveWithKey( ZVS_ItemRemoveWithKey_s *removeItem ); +STATUS VP_PoolAction21( GeneralMsg_s *genMsg, const unicode_t *poolName, Pool_s *pool, + QUAD *key, Zid_t rezidThreshold, BOOL purge, BOOL uiPruneWait, + ZSR_LossLimits_s limits, QUAD debugLevel, QUAD uiOptions ); + + + +VPV_Status_s *VP_GetVPV( VP_Status_s *pComn ) +{ + + if ( pComn == NULL ) + { + return NULL; + } + if ( pComn->VPS_Type != NSS_TYPE_VERIFY ) + { + return NULL; + } + return( (VPV_Status_s *)pComn ); + +} /* End of VP_GetVPV() */ + + +VPR_Status_s *VP_GetVPR( VP_Status_s *pComn ) +{ + if ( pComn == NULL ) + { + return NULL; + } + if ( pComn->VPS_Type != NSS_TYPE_REBUILD ) + { + return NULL; + } + return( (VPR_Status_s *)pComn ); + +} /* End of VP_GetVPR() */ + + +void VP_PoolInfoGet( VP_Status_s *pInfo ) +{ + zASSERT( pInfo->VPS_UseCount != 0 ); + ++pInfo->VPS_UseCount; + return; + +} + + +/* + Mark object has going into the salvage system when it is deleted. + */ +//void VP_PoolInfoKeep( VPV_Status_s *pInfo ) +//{ +// +// pInfo->VPVS_State |= VPS_STATE_KEEP; +// return; +// +//} + + +void VP_PoolInfoRelease( VP_Status_s *pInfo ) +{ + zASSERT( pInfo->VPS_UseCount != 0 ); + --pInfo->VPS_UseCount; + if ( pInfo->VPS_UseCount == 0 ) + { + VP_PoolInfoDestroy( pInfo ); + } + return; + +} + + +void VP_ThreadInfoDestroy( VP_Status_s *pInfo ) +{ + VP_ThreadInfo_s *tInfo; + + tInfo = pInfo->VPS_threadInfo; + if ( tInfo == NULL ) + { + return; + } + pInfo->VPS_threadInfo = NULL; + + if ( tInfo->VPTI_ownershipKey != NULL ) + { + (void)xPoolOwnershipRelease( tInfo->VPTI_ownershipKey, WHERE ); + tInfo->VPTI_ownershipKey = NULL; + } + if ( tInfo->VPTI_poolVol != NULL ) + { + COMN_Release( &tInfo->VPTI_poolVol ); // Release the count that we got when we inited this pointer. + zASSERT( tInfo->VPTI_poolVol == NULL ); + } + + free( tInfo ); + return; + +} /* End of VP_ThreadInfoDestroy() */ + + +//STATIC void VP_PoolInfoDestroyDelay( VPV_Status_s *pInfo ) +//{ +// +// if ( pInfo->VPS_threadInfo != NULL ) +// { +// VP_ThreadInfoDestroy( pInfo ); +// } +// ++pInfo->VPS_UseCount; // Since we left on list we need to ensure that user count is 1 +// // Need to implement FixFixFix(ZVPDone,3,4) - i.e. where is the call to VP_PoolInfoDestroy Need UI also - purge... (4 hours) +//} + + +void VP_LSSCleanup( VP_Status_s *pInfo ) +{ + GeneralMsg_s genMsg; + Pool_s *pool; + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + pool = (Pool_s *)COMN_PoolNameLookup(&genMsg, pInfo->VPS_PoolName, FALSE, NULL); + if ( pool != NULL ) + { + (void)pool->POOLroot.beastClass->comnVolOps.VOL_volumeMaintenance( &genMsg, pool, + VOLMAINTCMD_FREE_RESOURCES, 0, &pInfo->VPS_UserKey ); + COMN_Release( &pool ); + } + return; +} + + +STATUS VP_LSSCleanupPartial( VP_Status_s *pInfo, ZVS_ItemRemoveWithKey_s *removeItem ) +{ + STATUS status; + GeneralMsg_s genMsg; + Pool_s *pool; + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + pool = (Pool_s *)COMN_PoolNameLookup(&genMsg, pInfo->VPS_PoolName, FALSE, NULL); + if ( pool == NULL ) + { + status = GetErrno( &genMsg ); + } + else + { + status = pool->POOLroot.beastClass->comnVolOps.VOL_volumeMaintenance( &genMsg, pool, + VOLMAINTCMD_FREE_RESOURCES_PARTIAL, 0, removeItem ); + COMN_Release( &pool ); + } + return status; +} + + +void VP_PoolInfoDestroy( VP_Status_s *pInfo ) +{ + + if ( pInfo == NULL ) + { + return; + } + if ( !(pInfo->VPS_State & VPS_STATE_DELETING) ) + { + zASSERT("We have a use count issue with pInfo"==NULL); + return; + } +// if ( pInfo->VPS_State & VPS_STATE_KEEP ) +// { +// VP_PoolInfoDestroyDelay( pInfo ); +// return; +// } + +// X_LATCH( &VP_RepairProcessListLatch ); +// if ( QMEMBER( &pInfo->VPS_link ) ) +// { +// DQ_RMV( pInfo, VPS_link); +// NULLIFY( &pInfo->VPS_link ); +// } +// UNX_LATCH( &VP_RepairProcessListLatch ); + + VP_LSSCleanup( pInfo ); + VP_ThreadInfoDestroy( pInfo ); + free( pInfo ); + +} /* End of VP_PoolInfoDestroy() */ + + +/* + VP_PoolInfoDelete() - + Called to logically delete the VPV_Status_s. + + To detect that someone did an extra release we have a specific + function that is called when we are 'done' with a VPV_Status_s. + + This also enables to indentify the code that is responsible for + deleting an VPV_Status_s. + + Warnings - + Caller must not own VP_RepairProcessListLatch. + */ +void VP_PoolInfoDelete( VP_Status_s *pComn ) +{ + zASSERT( pComn != NULL ); + zASSERT( pComn->VPS_UseCount >= 1 ); + if ( pComn->VPS_State & VPS_STATE_DELETING ) + { + return; + } +// pComn->VPS_UTCVerifyEnd = GetUTCTime(); +// pComn->VPS_Status = zERR_RAV_COMPLETED; + // Caller must have a use count and the 'VP_RepairProcessList' count must still be present + zASSERT( pComn->VPS_UseCount >= 2 ); + pComn->VPS_State |= VPS_STATE_DELETING; + // Remove from list so no one can find anymore. + X_LATCH( &VP_RepairProcessListLatch ); + if ( QMEMBER( &pComn->VPS_link ) ) + { + DQ_RMV( pComn, VPS_link); + NULLIFY( &pComn->VPS_link ); + if ( DQ_EMPTY(&VP_RepairProcessList) ) + { + X_LATCH( &VP_RepairProcessListNoItem ); + } + VP_PoolInfoRelease( pComn ); // Release the 'VP_RepairProcessList' use count. + } + UNX_LATCH( &VP_RepairProcessListLatch ); + +} /* End of VP_PoolInfoDelete() */ + + + // Key used to uniquily identify different verify/rebuild statuses. We ensure + // that rebuild and verify keys to not match so that underlying code can + // assume keys are unique. +QUAD ZVP_StatusUserKey = UI64_CONST(0)-UI64_CONST(1); + +void VP_Status_Construct( + VP_Status_s *pComn, + NINT type, + const unicode_t *poolName, + VolumeID_t *poolVolID, + NINT cmd, + NINT vmFlag, + QUAD debugLevel, + QUAD uiOptions ) +{ + pComn->VPS_Type = type; + NULLIFY( &pComn->VPS_link ); + pComn->VPS_UseCount = 1; // One for creator + pComn->VPS_State = VPS_STATE_DEFAULT; + pComn->VPS_UserKey = --ZVP_StatusUserKey; + pComn->VPS_Terminate = FALSE; + pComn->VPS_UTCStart = GetUTCTime(); + pComn->VPS_UTCEnd = 0; + pComn->VPS_Status = zERR_RAV_WORKING; + pComn->VPS_threadInfo = NULL; + pComn->VPS_vmFlag = vmFlag; + pComn->VPS_cmd = cmd; + pComn->VPS_poolVolID = *poolVolID; + pComn->VPS_DebugLevel = debugLevel; + pComn->VPS_UIOptions = uiOptions; + unincpy( pComn->VPS_PoolName, poolName, NELEMS(pComn->VPS_PoolName) ); +} + +void VP_Status_Insert( VP_Status_s *pComn ) +{ + BOOL firstItem; // FixFixFix(ZVPSkipped,1,1) - remove wait code as admin broken. I believe + // 'admin broken' means that the wait logic does not work via + // admin because the admin owns resources when it calls with + // ZSH_FLAG_WAIT. Not removing as works for zPoolVerify (just + // not via ADMIN). Code that calls via ADMIN will not use tag. + + // Once we get on this list then other threads can find us and put their + // own UseCount on the pInfo object. + X_LATCH( &VP_RepairProcessListLatch ); + VP_PoolInfoGet( pComn ); // This is the 'VP_RepairProcessList' count. Is released + // in VP_PoolInfoDelete when removed from 'VP_RepairProcessList'. + // Very important to put at head of list as status routines assume newest verify is first + firstItem = DQ_EMPTY( &VP_RepairProcessList ); + DQ_PUSH( &VP_RepairProcessList, pComn, VPS_link); + if ( firstItem ) + { + UNX_LATCH( &VP_RepairProcessListNoItem ); + } + UNX_LATCH( &VP_RepairProcessListLatch ); + return; + +} /* End of VP_Status_Insert() */ + + +/* + VPV_PoolInfoCreate + Creates a VPV_Status_s which is used by COMN to track a verify + operation. This structure is passed to the thread that does the verify + which passes it to the LSS. The LSS then fills in specific fields so + that the user may obtain the progress of the verify operation. + + */ +VPV_Status_s *VPV_PoolInfoCreate( + GeneralMsg_s *genMsg, + Pool_s *pool, + const unicode_t *poolName, + VolumeID_t *poolVolID, + NINT cmd, + NINT vmFlag, + BOOL crossValidation, + QUAD debugLevel, + QUAD uiOptions ) +{ + VPV_Status_s *pInfo; + VP_Status_s *pComn; + + if ( unilen(poolName) >= NELEMS(pInfo->VPVS_Common.VPS_PoolName) ) + { + SetErrno( genMsg, zERR_BAD_PARAMETER_VALUE ); + return NULL; + } + + pInfo = (VPV_Status_s *)zalloc(sizeof(VPV_Status_s)); + if ( pInfo == NULL ) + { + SetErrno( genMsg, zERR_NO_MEMORY ); + return NULL; + } + pComn = &pInfo->VPVS_Common; + VP_Status_Construct( pComn, NSS_TYPE_VERIFY, poolName, poolVolID, cmd, vmFlag, debugLevel, uiOptions ); + pInfo->VPVS_CrossValidation = crossValidation; +//g unicpy( pInfo->VPVS_SavedFileName, L"" ); + VP_Status_Insert( pComn ); + return pInfo; + +} /* End of VP_PoolInfoCreate() */ + + +/* + VPR_PoolInfoCreate + Creates a VP_RebuildStatus_s which is used by COMN to track a rebuild + operation. This structure is passed to the thread that does the rebuild + which passes it to the LSS. The LSS then fills in specific fields so + that the user may obtain the progress of the rebuild operation. + + */ +VPR_Status_s *VPR_PoolInfoCreate( + GeneralMsg_s *genMsg, + Pool_s *pool, + const unicode_t *poolName, + VolumeID_t *poolVolID, + NINT cmd, + NINT vmFlag, + Zid_t rezidThreshold, + BOOL purge, + BOOL uiPruneWait, + ZSR_LossLimits_s limits, + QUAD debugLevel, + QUAD uiOptions ) +{ + VP_Status_s *pComn; + VPR_Status_s *pInfo; + + if ( unilen(poolName) >= NELEMS(pInfo->VPRS_Common.VPS_PoolName) ) + { + SetErrno( genMsg, zERR_BAD_PARAMETER_VALUE ); + return NULL; + } + pInfo = (VPR_Status_s *)zalloc(sizeof(VPR_Status_s)); + if ( pInfo == NULL ) + { + SetErrno( genMsg, zERR_NO_MEMORY ); + return NULL; + } + pComn = &pInfo->VPRS_Common; + VP_Status_Construct( pComn, NSS_TYPE_REBUILD, poolName, poolVolID, cmd, vmFlag, debugLevel, uiOptions ); + pInfo->VPRS_RezidThreshold = rezidThreshold; + pInfo->VPRS_Purge = purge; + pInfo->VPRS_UIPruneWait = uiPruneWait; + pInfo->VPRS_LimitStart = limits; // Struct copy +//ggg pInfo->VPRS_LimitPost = limits; // Struct copy - any items not set by Post set will get start values. + pInfo->VPRS_UIPruneStatus = zERR_RAV_FINAL_NOT_SET; + pInfo->VPRS_UIPruneSet = FALSE; // User has not set, we have set default values. + VP_Status_Insert( pComn ); + return pInfo; + +} /* End of VPR_PoolInfoCreate() */ + + +STATUS VP_ThreadInfoCreate( + VP_Status_s *pInfo, + Pool_s *pool ) +{ + VP_ThreadInfo_s *tInfo; + + tInfo = (VP_ThreadInfo_s *)zalloc(sizeof(VP_ThreadInfo_s)); + if ( tInfo == NULL ) + { + return zERR_NO_MEMORY; + } + + tInfo->VPTI_processID = 0; + COMN_USE_BEAST( &pool->POOLroot ); // This is for the VPTI_poolVol pointer that we keep around + tInfo->VPTI_poolVol = pool; + tInfo->VPTI_ownershipKey = NULL; +// memset( &tInfo->VPTI_processStack[0], 0xcc, sizeof(tInfo->VPTI_processStack) ); + + pInfo->VPS_threadInfo = tInfo; + return zOK; + +} /* End of VP_ThreadInfoCreate() */ + + +void VP_TruncateLeft( char *dest, const char *where, size_t destSize ) +{ + size_t len; + const char *whereRight; + + if ( (where == NULL) || (dest == NULL) || (destSize <= 0) ) + { + return; + } + len = strlen( where ); + if ( len < destSize ) + { + whereRight = where; + } + else + { + whereRight = where + ( len - destSize + 1 ); + } + strcpy( dest, whereRight ); + return; +} + + +void VP_FinalStatus( VP_Status_s *pComn, GeneralMsg_s *finalGenMsg, STATUS finalStatus ) +{ + + if ( finalStatus != zOK ) + { + pComn->VPS_FinalStatus = GetErrno(finalGenMsg); + } + else + { + pComn->VPS_FinalStatus = zOK; + } + VP_TruncateLeft( pComn->VPS_FinalStatusSetter, GetErrnoSetter(finalGenMsg), sizeof(pComn->VPS_FinalStatusSetter) ); + pComn->VPS_UTCEnd = GetUTCTime(); + pComn->VPS_Status = zERR_RAV_COMPLETED; + return; +} + +/* + VP_PoolRAVThread() - + Main routine of a thread that will verify OR rebuild a pool. +*/ + // Pools ONLY +void *VP_PoolRAVThread(THREAD notused1, void *info) +{ + VP_Status_s *pComn = (VP_Status_s *)info; +// VPV_Status_s *pInfo = (VPV_Status_s *)info; +// VP_Status_s *pComn = &pInfo->VPVS_Common; + Pool_s *pool; + STATUS finalStatus; + GeneralMsg_s finalGenMsg; + MaintenanceRetInfo_s retInfo; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&finalGenMsg); + zASSERT( pComn->VPS_threadInfo != NULL ); // When the thread is running this must be TRUE. + + bzero( &retInfo, sizeof( retInfo ) ); +//g retInfo.MRI_status = MAINTRETINFO_STATUS_OK; /* Default so LSS does not have to set */ + VP_PoolInfoGet( pComn ); // For PTR in retInfo + retInfo.MRI_StatusDetails = pComn; + + pool = pComn->VPS_threadInfo->VPTI_poolVol; + pool->maintenanceTime = GetUTCTime(); + zASSERT( (pool->maintenanceStatus & VOLMAINTSTATUS_STATE) == 0 ); + pool->maintenanceStatus &= ~VOLMAINTSTATUS_STATE; + if ( pComn->VPS_cmd == VOLMAINTCMD_CHECK ) + { + pool->maintenanceStatus |= VOLMAINTSTATUS_CHECKING; + } + else + { + pool->maintenanceStatus |= VOLMAINTSTATUS_REPAIRING; + } + finalStatus = pool->POOLroot.beastClass->comnVolOps.VOL_volumeMaintenance( &finalGenMsg, pool, pComn->VPS_cmd, pComn->VPS_vmFlag, &retInfo ); + /* We must write the data in the mycache because it contains the PersistentVolume_s information. */ + X_LATCH(&pool->VOLbeastLatch); + cacheFlushMyCacheBufs(&pool->VOLroot.mycache); + UNX_LATCH(&pool->VOLbeastLatch); + defaultFlushWait(&pool->VOLroot.mycache.agent); + cacheTossAll(&pool->VOLroot.mycache); + pool->maintenanceStatus &= ~VOLMAINTSTATUS_STATE; // turns off VOLMAINTSTATUS_CHECKING and VOLMAINTSTATUS_REPAIRING for pool + VP_PoolInfoRelease( pComn ); // For PTR in retInfo which is about to go out of scope + retInfo.MRI_StatusDetails = NULL; +//g VP_PoolInfoKeep( pComn ); // Indicate we wish to 'keep' status around for a while. New design is that Daemon is in charge of freeing (we must do if we unload) + VP_ThreadInfoDestroy( pComn ); // We are done with thread specific resource +//g VP_PoolInfoDelete( pComn ); // Indicate that we are done with none 'status' portion. + VP_FinalStatus( pComn, &finalGenMsg, finalStatus ); + VP_PoolInfoRelease( pComn ); // For pComn that was passed to us (VP_ThreadStart got this use count for us) + MPKNSS_UNLOCK(); + return NULL; + +} /* End of VP_PoolRAVThread() */ + + +/* + + Warnings - + We ignore the VOLMAINTSTATUS_CAN_RUN_ACTIVE flag in NSS 4.x as we no + longer change states for the caller. + */ +STATUS VP_IsLegalOperation( + GeneralMsg_s *genMsg, + Pool_s *pool, + const unicode_t *poolName, + VolumeID_t *poolVolID, + NINT cmd, + NINT vmFlag ) +{ + + if ( !(vmFlag & VOLMAINTFLAG_POOL) ) + { + SetErrno( genMsg, zERR_NOT_SUPPORTED ); + return( zFAILURE ); + } + switch ( cmd ) + { + case VOLMAINTCMD_REPAIR: +//g case VOLMAINTCMD_REZID: +//g case VOLMAINTCMD_REBUILD_PURGE: + if ( !(pool->POOLsupportedFeatures & zPOOL_FEATURE_REBUILD) ) + { +//g aprintf( LRED, MSG("%U does not support Rebuild\n",145), poolName ); + SetErrno( genMsg, zERR_NOT_SUPPORTED ); + return(zFAILURE); + } + break; + case VOLMAINTCMD_CHECK: + if ( !(pool->POOLsupportedFeatures & zPOOL_FEATURE_VERIFY) ) + { +//g aprintf( LRED, MSG("%U does not support Verify\n",146), poolName ); + SetErrno( genMsg, zERR_NOT_SUPPORTED ); + return(zFAILURE); + } + break; + default: + SetErrno( genMsg, zERR_NOT_SUPPORTED ); + return(zFAILURE); + } + + return( zOK ); + +} /* End of VP_IsLegalOperation() */ + + +/* + Warnings - + CVS callbacks must be aware of verify or they will not prevent or tell us to terminate + so this check needs to come late. + +*/ +STATUS VP_IsPoolStateCorrect( + VP_Status_s *pComn, + Pool_s *pool ) +{ + zASSERT( QMEMBER( &pComn->VPS_link ) ); // Must be on this list for CVS code to work + + if ( pool->maintenanceStatus & VOLMAINTSTATUS_CAN_RUN_ACTIVE ) + { + if ( (pool->state != zVOLSTATE_ACTIVE) && (pool->state != zVOLSTATE_MAINTENANCE) ) + { + return zERR_RAV_STATE_ACTIVE_OR_MAINTENANCE_REQUIRED; + } + } + else + { + if ( pool->state != zVOLSTATE_MAINTENANCE ) + { + return zERR_RAV_STATE_MAINTENANCE_REQUIRED; + } + } + return zOK; + +} /* End of VP_IsPoolStateCorrect() */ + + +/* + VP_ThreadStart() - + Starts up a thread to do a pool verify or rebuild. + */ +STATUS VP_ThreadStart(VP_Status_s *pComn) +{ + VP_ThreadInfo_s *tInfo; + + zASSERT( pComn->VPS_threadInfo != NULL ); // When the thread is running this must be TRUE. + tInfo = pComn->VPS_threadInfo; + +//g DQ_ENQ(&RepairProcessList, CProcessPtr, link); + VP_PoolInfoGet( pComn ); // Count for our thread that we are going to create. The thread will release. +#if zNETWARE + // By using the CMN_ModuleHandle we take ownership of thread + // so that NetWare will not ABEND if the user thread that started + // this process terminates. + ZOS_StartThreadWithModuleHandle( tInfo->VPTI_processID, CheckModName, VP_PoolRAVThread, + NULL, CHECK_STACKSIZE, pComn, (LONG)CMN_ModuleHandle ); +#else + ZOS_StartThread( tInfo->VPTI_processID, CheckModName, VP_PoolRAVThread, + NULL, CHECK_STACKSIZE, pComn ); +#endif + if ( tInfo->VPTI_processID == 0 ) + { // Thread unable to start + VP_PoolInfoRelease( pComn ); +//g DQ_RMV(CProcessPtr, link); +//g errPrintf(WHERE, Module, 634, MSG("Error starting maintenance process.", 160)); + return zERR_CANNOT_START_THREAD; + } + return zOK; + +} /* End of VP_ThreadStart() */ + + +// ChangeStateExitCallBack - Not used in new rebuild/verify +void ChangeStateExitCallBack(struct EventBlock *evBlk, NINT producerFlag) +{ + EventChangeVolStateExit_s *data; + + zASSERT(evBlk != NULL); + zASSERT( (((ADDR)evBlk->EBUserParameter) == EVENT_ChangeVolState_Exit) || (((ADDR)evBlk->EBUserParameter) == EVENT_ChangePoolState_Exit) ); + + if(producerFlag == VOLUME_EVENT) + { + data = (EventChangeVolStateExit_s *)evBlk->EBEventData; + } + else + { + data = (EventChangeVolStateExit_s *)evBlk->EBEventData; + } + if ( data->newState < zVOLSTATE_MAINTENANCE ) + { + return; + } + return; +} + +// ChangePoolStateExitCallBack - Not used in new rebuild/verify +LONG ChangePoolStateExitCallBack(struct EventBlock *evBlk) +{ + ChangeStateExitCallBack(evBlk, POOL_EVENT); + return 0; +} + +/*- (FUNCTION) ----- ChangeStateEnterCallBack() ------------------------------------------ + | + | + +-------------------------------------------------------------------------*/ +LONG ChangeStateEnterCallBack(struct EventBlock *evBlk) +{ + VP_Status_s *pComn; + NINT count; + NINT mode; + WORD oldState; + WORD newState; + STATUS retCode; + VolumeID_t *objectID; + + MPKNSS_LOCK(); + zASSERT( evBlk != NULL ); + zASSERT( (((ADDR)evBlk->EBUserParameter) == EVENT_ChangeVolState_Enter) || (((ADDR)evBlk->EBUserParameter) == EVENT_ChangePoolState_Enter) ); + if ( ((ADDR)evBlk->EBUserParameter) == EVENT_ChangeVolState_Enter ) + { + EventChangeVolStateEnter_s *data; + + data = (EventChangeVolStateEnter_s *)evBlk->EBEventData; + newState = data->newState; + oldState = data->oldState; + mode = data->mode; + objectID = &data->volID; + retCode = zERR_VOLUME_CONSUMER_PREVENTED; + } + else if ( ((ADDR)evBlk->EBUserParameter) == EVENT_ChangePoolState_Enter ) + { + EventChangePoolStateEnter_s *data; + + data = (EventChangePoolStateEnter_s *)evBlk->EBEventData; + newState = data->newState; + oldState = data->oldState; + mode = data->mode; + objectID = &data->poolID; + retCode = zERR_POOL_CONSUMER_PREVENTED; + } + else + { + MPKNSS_UNLOCK(); + return(SUCCESS); + } + if ( newState == oldState ) + { /* Ignore switches to current state */ + MPKNSS_UNLOCK(); + return(SUCCESS); + } + if ( newState == zVOLSTATE_MAINTENANCE ) + { /* Ignore switches to maintenance state */ + MPKNSS_UNLOCK(); + return(SUCCESS); + } + +ZCCBCheckPoolForLiveProcesses: + count = 0; + X_LATCH( &VP_RepairProcessListLatch ); + // While we own the VP_RepairProcessListLatch we are ensured that + // any pComn we pull from the list already has a use count of + // at least 1 (I.E. the 'VP_RepairProcessList' count). We also + // know the item will not disappear on us because of our latch. + // I.E. we do not need our own use count!!! + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { +// VP_PoolInfoGet( pComn ); + if ( (pComn->VPS_threadInfo) && + ( LB_GUIDCompare( &pComn->VPS_poolVolID, objectID ) == 0 ) ) + { + if ( mode & VOLMODE_USER_ABORTABLE ) + { /* We are allowed to abort request so we do. We do not use + * zERR_VOLUME_STATE_CHANGE_ABORTED because it is handled special by + * NSS's Change Pool State. It causes no error to be displayed to the user. + */ + evBlk->EBParm1 = (void*)(ADDR)retCode; + UNX_LATCH( &VP_RepairProcessListLatch ); + MPKNSS_UNLOCK(); + return(USER_DEFINABLE); /* Any of these bits indicates operation denied - we + * must be registered as a CHECK_CONSUMER. + */ + } + // notify the process to clean up and die + pComn->VPS_Terminate = TRUE; + count++; + } +// VP_PoolInfoRelease( pComn ); + } + UNX_LATCH( &VP_RepairProcessListLatch ); + + if ( count == 0 ) + { // No live processes on this pool to clean up + MPKNSS_UNLOCK(); + return(SUCCESS); + } // no, safe to return + LB_delay(500); // allow the processes to clean up a bit + goto ZCCBCheckPoolForLiveProcesses; // go check for process in this pool again +} + +/*- (FUNCTION) ----- ChangePoolStateEnterCallBack() ------------------------------------------ + | + | call back routine for "CHANGE_POOL_STATE_ENTER" event + | + +-------------------------------------------------------------------------*/ +NEB_STATUS ChangePoolStateEnterCallBack(struct EventBlock *evBlk) +{ + return( ChangeStateEnterCallBack(evBlk) ); +} + +/*- (FUNCTION) ----- ChangeVolStateEnterCallBack() ------------------------------------------ + | + | call back routine for "CHANGE_VOLUME_STATE_ENTER" event + | + +-------------------------------------------------------------------------*/ +NEB_STATUS ChangeVolStateEnterCallBack(struct EventBlock *evBlk) +{ + return( ChangeStateEnterCallBack(evBlk) ); +} + + +/*- (FUNCTION) ----- ZCheckerESR() ------------------------------------------ + | + | event service routine + | + +-------------------------------------------------------------------------*/ +LONG ZCheckerESR(struct EventBlock *evBlk) +{ + zASSERT(evBlk != NULL); + return 0; +} + +#if 0 +LONG ZCheckerXESR(struct EventBlock *evBlk) +{ + zASSERT(evBlk != NULL); + return 0; +} +#endif + + + +/*- (FUNCTION) ----- REPAIR_Startup() ------------------------------------------ + | + | Startup code + | + +-------------------------------------------------------------------------*/ +void REPAIR_Startup() +{ +//#ifndef __linux__ // LINUX_Rebuild + struct ConsumerRegistrationInfo consumerRegInfo; + + ASSERT_MPKNSS_LOCK(); + +//g VP_DaemonSetInit(); + INIT_X_LATCH( &VP_RepairProcessListNoItem ); +// X_LATCH( &VP_RepairProcessListNoItem ); + + /* register for EVENT_ChangeVolState_Enter */ + consumerRegInfo.CRIVersion = NEB_CONSUMER_VERSION1; + consumerRegInfo.CRIConsumerName = MSGNot("NSS.VolumeMaintenance"); + + consumerRegInfo.CRIEventFlags = 0; + consumerRegInfo.CRIOwnerID = CMN_ModuleHandle; + consumerRegInfo.CRIConsumerESR = NULL; // ZCheckerESR; + consumerRegInfo.CRISecurityToken = 0; + consumerRegInfo.CRIConsumerFlags = 0; + consumerRegInfo.CRIFilterName = 0; + consumerRegInfo.CRIFilterDataLength = 0; + consumerRegInfo.CRIFilterData = 0; + consumerRegInfo.CRIConsumerCallback = ChangeVolStateEnterCallBack; + consumerRegInfo.CRIOrder = 0; + consumerRegInfo.CRIConsumerType = CHECK_CONSUMER; + + consumerRegInfo.CRIEventName = MSGNot("NSS.ChangeVolState.Enter"); + consumerRegInfo.CRIUserParameter = (void *)EVENT_ChangeVolState_Enter; + ZOS_RegisterConsumer(&consumerRegInfo); + REPAIR_ConsumerIDVolEnter = (ADDR)consumerRegInfo.CRIConsumerID; + +#if 0 + /* register for EVENT_ChangeVolState_Exit */ + consumerRegInfo.CRIVersion = NEB_CONSUMER_VERSION1; + consumerRegInfo.CRIConsumerName = MSGNot("NSS.VolumeMaintenance"); + + consumerRegInfo.CRIEventFlags = 0; + consumerRegInfo.CRIOwnerID = CMN_ModuleHandle; + consumerRegInfo.CRIConsumerESR = ZCheckerXESR; + consumerRegInfo.CRISecurityToken = 0; + consumerRegInfo.CRIConsumerFlags = 0; + consumerRegInfo.CRIFilterName = 0; + consumerRegInfo.CRIFilterDataLength = 0; + consumerRegInfo.CRIFilterData = 0; + consumerRegInfo.CRIConsumerCallback = ChangeVolStateExitCallBack; + consumerRegInfo.CRIOrder = 0; + consumerRegInfo.CRIConsumerType = SYNCHRONOUS_CONSUMER; + + consumerRegInfo.CRIEventName = MSGNot("NSS.ChangeVolState.Exit"); + consumerRegInfo.CRIUserParameter = (void *)EVENT_ChangeVolState_Exit; + ZOS_RegisterConsumer(&consumerRegInfo); + REPAIR_ConsumerIDVolExit = (LONG)consumerRegInfo.CRIConsumerID; +#endif + + /* register for EVENT_ChangePoolState_Enter */ + consumerRegInfo.CRIVersion = NEB_CONSUMER_VERSION1; + consumerRegInfo.CRIConsumerName = MSGNot("NSS.PoolMaintenance"); + + consumerRegInfo.CRIEventFlags = 0; + consumerRegInfo.CRIOwnerID = CMN_ModuleHandle; + consumerRegInfo.CRIConsumerESR = NULL; //ZCheckerESR; + consumerRegInfo.CRISecurityToken = 0; + consumerRegInfo.CRIConsumerFlags = 0; + consumerRegInfo.CRIFilterName = 0; + consumerRegInfo.CRIFilterDataLength = 0; + consumerRegInfo.CRIFilterData = 0; + consumerRegInfo.CRIConsumerCallback = ChangePoolStateEnterCallBack; + consumerRegInfo.CRIOrder = 0; + consumerRegInfo.CRIConsumerType = CHECK_CONSUMER; + + consumerRegInfo.CRIEventName = MSGNot("NSS.ChangePoolState.Enter"); + consumerRegInfo.CRIUserParameter = (void *)EVENT_ChangePoolState_Enter; + ZOS_RegisterConsumer(&consumerRegInfo); + REPAIR_ConsumerIDPoolEnter = (ADDR)consumerRegInfo.CRIConsumerID; + +#if 0 + /* register for EVENT_ChangePoolState_Exit */ + consumerRegInfo.CRIVersion = NEB_CONSUMER_VERSION1; + consumerRegInfo.CRIConsumerName = MSGNot("NSS.PoolMaintenance"); + + consumerRegInfo.CRIEventFlags = 0; + consumerRegInfo.CRIOwnerID = CMN_ModuleHandle; + consumerRegInfo.CRIConsumerESR = ZCheckerXESR; + consumerRegInfo.CRISecurityToken = 0; + consumerRegInfo.CRIConsumerFlags = 0; + consumerRegInfo.CRIFilterName = 0; + consumerRegInfo.CRIFilterDataLength = 0; + consumerRegInfo.CRIFilterData = 0; + consumerRegInfo.CRIConsumerCallback = ChangePoolStateExitCallBack; + consumerRegInfo.CRIOrder = 0; + consumerRegInfo.CRIConsumerType = SYNCHRONOUS_CONSUMER; + + consumerRegInfo.CRIEventName = MSGNot("NSS.ChangePoolState.Exit"); + consumerRegInfo.CRIUserParameter = (void *)EVENT_ChangePoolState_Exit; + ZOS_RegisterConsumer(&consumerRegInfo); + REPAIR_ConsumerIDPoolExit = (LONG)consumerRegInfo.CRIConsumerID; +#endif + +//#endif + return; +} + +/*- (FUNCTION) ----- REPAIR_Shutdown() ------------------------------------------ + | + | Shutdown code + | + +-------------------------------------------------------------------------*/ +void REPAIR_Shutdown() +{ +#ifndef __linux__// LINUX_Rebuild +//g CheckProcess_s *CProcessPtr; + +//g ToDoListProcessFlag = 1; /* flag that we are unloading so we can clean up */ + // this should never happen since the process is destroyed in "processToDoList" +//g while(updatingProcessList == LIST_LOCKED) //wait for semaphore to clear +//g Yield(); +//g updatingProcessList = LIST_LOCKED; +//g DQ_FOREACH(&RepairProcessList, CProcessPtr, CheckProcess_s, link) +//g { +//g CProcessPtr->flag = CP_FLAG_CLEANUP; +//g } +//g updatingProcessList = LIST_UNLOCKED; + +//g REPAIR_CleanUpCheckProcessesList(&RepairProcessList); + + ZOS_UnRegisterConsumer((void *)REPAIR_ConsumerIDVolEnter, (void *)EVENT_ChangeVolState_Enter); +//g ZOS_UnRegisterConsumer((void *)REPAIR_ConsumerIDVolExit, (void *)EVENT_ChangeVolState_Exit); + ZOS_UnRegisterConsumer((void *)REPAIR_ConsumerIDPoolEnter, (void *)EVENT_ChangePoolState_Enter); +//g ZOS_UnRegisterConsumer((void *)REPAIR_ConsumerIDPoolExit, (void *)EVENT_ChangePoolState_Exit); +#endif + return; +} + +/*- (FUNCTION) ----- CPInitGlobals() ------------------------------------------ + | + | set up all of the nlms global operations and vari. + | + +-------------------------------------------------------------------------*/ +STATUS CPInitGlobals() +{ +//g char subver[2]; +//g LONG languageID; // added 08/12/98 by sks +//g char help_CommandLine[16]; // added 08/12/98 by sks +//g LONG result; + + /*- init default values for nlm vari. -*/ +//g CPWinHandle = 0; +//g CPMenuProcessID = 0; +//g CPListIsUp = TRUE; + + + return(zOK); +} + +/*- (FUNCTION) ----- CPUnInitGlobals() ---------------------------------------- + | + | return all vari. that are set in the InitGlobals function + | + +-------------------------------------------------------------------------*/ +STATUS CPUnInitGlobals() +{ + + return(zOK); +} + + + + +/* -------------------------------------------------------------------------- + StartUpList + + This routine is called either by CPStartUpList() or RPStartUpList() in + either case the routine is required to exit by killing the process. + -------------------------------------------------------------------------- */ + + +/* -------------------------------------------------------------------------- + getNextNameFromCmdLineString + in - namePtr -> unicode string containing names seperated by commas + name -> place to copy the next name from input string + + out- zOK + name contains the next name from the string + input pointer updated to next name in the string + + zFAILURE + no more names in string (done) + -------------------------------------------------------------------------- */ +STATUS getNextNameFromCmdLineString(unicode_t *name, NINT size, unicode_t **namePtr) +{ + unicode_t c; + NINT length; + + + length = size / (sizeof(unicode_t)); + + //null terminate the name buffer + *name = 0; + + //if no more names, return zFAILURE + if ( (**namePtr == 0) || (length == 0) ) + return (zFAILURE); + + //skip white space + while((c = **namePtr)) + { + //copy chars until comma or zero + if(c == L',' || c == 0 || c == L' ') + break; //done with this name + *name = c; + ++name; + ++*namePtr; + --length; + if ( length == 0 ) + { /* Buffer not big enough to hold another unicode (we + * have a NULL at least left to put in). + */ + return( zFAILURE ); + } + } + + //terminate name, skip to next name in string + *name = 0; + while(c == L' ' || c == L',') + { + ++*namePtr; + c = **namePtr; + } + + return (zOK); +} + + + + + +// Caller must own X_LATCH on VP_RepairProcessListLatch +STATUS VP_VerifyStatusFill( ZVP_StatusHeader_s *zVS, VPV_Status_s *pInfo ) +{ + ZVP_StatusEntry_s *cEntry; + ZVP_VerifyStatusEntry_s *entry; + VP_Status_s *pComn = &pInfo->VPVS_Common; + + if ( zVS->ZSH_ResultsReturned >= zVS->ZSH_ResultsNeeded ) + { + return zERR_BUFFER_TOO_SMALL; + } + cEntry = &zVS->ZSH_Entry[zVS->ZSH_ResultsReturned]; + entry = (ZVP_VerifyStatusEntry_s *)cEntry; + cEntry->ZSE_Key = pComn->VPS_UserKey; + unicpy( cEntry->ZSE_PoolName, pComn->VPS_PoolName ); + cEntry->ZSE_poolVolID = pComn->VPS_poolVolID; + cEntry->ZSE_Status = pComn->VPS_Status; + cEntry->ZSE_FinalStatus = pComn->VPS_FinalStatus; + strcpy( cEntry->ZSE_FinalStatusSetter, pComn->VPS_FinalStatusSetter ); + cEntry->ZSE_UTCStart = pComn->VPS_UTCStart; + cEntry->ZSE_UTCEnd = pComn->VPS_UTCEnd; + cEntry->ZSE_State = pComn->VPS_State; + cEntry->ZSE_UIOptions = pComn->VPS_UIOptions; + cEntry->ZSE_DebugLevel = pComn->VPS_DebugLevel; + cEntry->ZSE_Terminate = pComn->VPS_Terminate; + cEntry->ZSE_vmFlag = pComn->VPS_vmFlag; + cEntry->ZSE_cmd = pComn->VPS_cmd; + +//g unicpy( entry->ZVSE_SavedFileName, pInfo->VPVS_SavedFileName ); + entry->ZVSE_CrossValidation = pInfo->VPVS_CrossValidation; + + ++zVS->ZSH_ResultsReturned; + return zOK; + +} + + +// Caller must own X_LATCH on VP_RepairProcessListLatch +STATUS VP_RebuildStatusFill( ZVP_StatusHeader_s *zVS, VPR_Status_s *pInfo ) +{ + ZVP_StatusEntry_s *cEntry; + ZVP_RebuildStatusEntry_s *entry; + VP_Status_s *pComn = &pInfo->VPRS_Common; + + if ( zVS->ZSH_ResultsReturned >= zVS->ZSH_ResultsNeeded ) + { + return zERR_BUFFER_TOO_SMALL; + } + cEntry = &zVS->ZSH_Entry[zVS->ZSH_ResultsReturned]; + entry = (ZVP_RebuildStatusEntry_s *)cEntry; + + cEntry->ZSE_Key = pComn->VPS_UserKey; + unicpy( cEntry->ZSE_PoolName, pComn->VPS_PoolName ); + cEntry->ZSE_poolVolID = pComn->VPS_poolVolID; + cEntry->ZSE_Status = pComn->VPS_Status; + cEntry->ZSE_FinalStatus = pComn->VPS_FinalStatus; + strcpy( cEntry->ZSE_FinalStatusSetter, pComn->VPS_FinalStatusSetter ); + cEntry->ZSE_UTCStart = pComn->VPS_UTCStart; + cEntry->ZSE_UTCEnd = pComn->VPS_UTCEnd; + cEntry->ZSE_State = pComn->VPS_State; + cEntry->ZSE_UIOptions = pComn->VPS_UIOptions; + cEntry->ZSE_DebugLevel = pComn->VPS_DebugLevel; + cEntry->ZSE_Terminate = pComn->VPS_Terminate; + cEntry->ZSE_vmFlag = pComn->VPS_vmFlag; + cEntry->ZSE_cmd = pComn->VPS_cmd; + + entry->ZRSE_RezidThreshold = pInfo->VPRS_RezidThreshold; + entry->ZRSE_Purge = pInfo->VPRS_Purge; + entry->ZRSE_UIPruneWait = pInfo->VPRS_UIPruneWait; + entry->ZRSE_LimitStart = pInfo->VPRS_LimitStart; // Struct copy + entry->ZRSE_UIPruneStatus = pInfo->VPRS_UIPruneStatus; + entry->ZRSE_UIPruneSet = pInfo->VPRS_UIPruneSet; + + + ++zVS->ZSH_ResultsReturned; + return zOK; + +} /* End of VP_RebuildStatusFill() */ + + +// +// Returns - +// error if unable to gather information. E.G. buffer too small. +// Does not return an error because the specific item was not found. +// +// Caller must own X_LATCH on VP_RepairProcessListLatch +STATUS VP_VerifyStatusSpecific( ZVP_StatusHeader_s *zVS ) +{ +// STATUS status = zERR_RAV_NO_STATUS_FOUND; + STATUS status = zOK; + VP_Status_s *pComn; + + zVS->ZSH_NextKey = zVS->ZSH_SearchKey; + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { +// VP_PoolInfoGet( pComn ); + if ( zVS->ZSH_SearchKey == pComn->VPS_UserKey ) + { // A Match + VPV_Status_s *pInfo; + + pInfo = VP_GetVPV( pComn ); + if ( pInfo == NULL ) + { +// VP_PoolInfoRelease( pComn ); + return zERR_RAV_KEY_MISMATCH; + } + status = VP_VerifyStatusFill( zVS, pInfo ); + if ( status != zOK ) + { +// VP_PoolInfoRelease( pComn ); + return status; + } + if ( zVS->ZSH_ResultsReturned == zVS->ZSH_ResultsNeeded ) + { +// VP_PoolInfoRelease( pComn ); + return zOK; + } + } +// VP_PoolInfoRelease( pComn ); + } + return status; + +} /* End of VP_VerifyStatusSpecific() */ + + +// +// Returns - +// error if unable to gather information. E.G. buffer too small. +// Does not return an error because the specific item was not found. +// +// Caller must own X_LATCH on VP_RepairProcessListLatch +STATUS VP_RebuildStatusSpecific( ZVP_StatusHeader_s *zVS ) +{ +// STATUS status = zERR_RAV_NO_STATUS_FOUND; + STATUS status = zOK; + VP_Status_s *pComn; + + zVS->ZSH_NextKey = zVS->ZSH_SearchKey; + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { +// VP_PoolInfoGet( pComn ); + if ( zVS->ZSH_SearchKey == pComn->VPS_UserKey ) + { // A Match + VPR_Status_s *pInfo; + + pInfo = VP_GetVPR( pComn ); + if ( pInfo == NULL ) + { +// VP_PoolInfoRelease( pComn ); + return zERR_RAV_KEY_MISMATCH; + } + status = VP_RebuildStatusFill( zVS, pInfo ); + if ( status != zOK ) + { +// VP_PoolInfoRelease( pComn ); + return status; + } + if ( zVS->ZSH_ResultsReturned == zVS->ZSH_ResultsNeeded ) + { +// VP_PoolInfoRelease( pComn ); + return zOK; + } + } +// VP_PoolInfoRelease( pComn ); + } + return status; + +} /* End of VP_RebuildStatusSpecific() */ + + +// Returns - +// error if unable to gather information. E.G. buffer too small. +// Does not return an error because the no items were found. +// +// Caller must own X_LATCH on VP_RepairProcessListLatch +STATUS VP_RebuildStatusMultiple( ZVP_StatusHeader_s *zVS ) +{ +// STATUS status = zERR_RAV_NO_Rebuild_STATUS_FOUND; + STATUS status = zOK; + VP_Status_s *pComn; + + zVS->ZSH_NextKey = zVS->ZSH_SearchKey; + ++zVS->ZSH_NextKey; + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { +// VP_PoolInfoGet( pComn ); + if ( zVS->ZSH_NextKey <= pComn->VPS_UserKey ) + { // A Match + VPR_Status_s *pInfo; + + pInfo = VP_GetVPR( pComn ); + if ( pInfo != NULL ) + { + status = VP_RebuildStatusFill( zVS, pInfo ); + if ( status != zOK ) + { + // VP_PoolInfoRelease( pComn ); + return status; + } + } + zVS->ZSH_NextKey = pComn->VPS_UserKey; + if ( zVS->ZSH_ResultsReturned == zVS->ZSH_ResultsNeeded ) + { +// VP_PoolInfoRelease( pComn ); + return zOK; + } + } +// VP_PoolInfoRelease( pComn ); + } + return status; + +} /* End of VP_RebuildStatusMultiple() */ + + +// Returns - +// error if unable to gather information. E.G. buffer too small. +// Does not return an error because the no items were found. +// +// Caller must own X_LATCH on VP_RepairProcessListLatch +STATUS VP_VerifyStatusMultiple( ZVP_StatusHeader_s *zVS ) +{ +// STATUS status = zERR_RAV_NO_STATUS_FOUND; + STATUS status = zOK; + VP_Status_s *pComn; + + zVS->ZSH_NextKey = zVS->ZSH_SearchKey; + ++zVS->ZSH_NextKey; + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { +// VP_PoolInfoGet( pComn ); + if ( zVS->ZSH_NextKey <= pComn->VPS_UserKey ) + { // A Match + VPV_Status_s *pInfo; + + pInfo = VP_GetVPV( pComn ); + if ( pInfo != NULL ) + { + status = VP_VerifyStatusFill( zVS, pInfo ); + if ( status != zOK ) + { + // VP_PoolInfoRelease( pComn ); + return status; + } + } + zVS->ZSH_NextKey = pComn->VPS_UserKey; + if ( zVS->ZSH_ResultsReturned == zVS->ZSH_ResultsNeeded ) + { +// VP_PoolInfoRelease( pComn ); + return zOK; + } + } +// VP_PoolInfoRelease( pComn ); + } + return status; + +} /* End of VP_VerifyStatusMultiple() */ + + +// Caller must own X_LATCH on VP_RepairProcessListLatch +unsigned int VP_StatusCount( ZVP_StatusHeader_s *zVS, NINT type ) +{ + unsigned int items = 0; + VP_Status_s *pComn; + + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { +// VP_PoolInfoGet( pComn ); + if ( zVS->ZSH_Flag & ZSH_FLAG_MULTIPLE ) + { + if ( zVS->ZSH_SearchKey < pComn->VPS_UserKey ) + { + if ( pComn->VPS_Type == type ) + { + ++items; + } + } + } + else + { + if ( zVS->ZSH_SearchKey == pComn->VPS_UserKey ) + { + if ( pComn->VPS_Type == type ) + { + ++items; + } + } + } +// VP_PoolInfoRelease( pComn ); + } + return items; + +} /* End of VP_StatusCount() */ + + + + +STATUS VP_PA_RebuildDetailsWithKeyB( ZVP_StatusHeader_s *zVS ) +{ + STATUS status; + +again: + if ( (zVS->ZSH_Flag & ZSH_FLAG_WAIT) && (zVS->ZSH_SearchKey == 0) ) + { + S_LATCH( &VP_RepairProcessListNoItem ); + UNS_LATCH( &VP_RepairProcessListNoItem ); + // Window here - it is closed with 'goto again:' logic. + } + X_LATCH( &VP_RepairProcessListLatch ); + zVS->ZSH_ResultsReturned = 0; + zVS->ZSH_ResultsTotal = VP_StatusCount( zVS, NSS_TYPE_REBUILD ); + if ( zVS->ZSH_Flag & ZSH_FLAG_MULTIPLE ) + { // Get information for all verifies + status = VP_RebuildStatusMultiple( zVS ); + } + else + { // Get information for a SPECIFIC rebuild instance. + status = VP_RebuildStatusSpecific( zVS ); + } + UNX_LATCH( &VP_RepairProcessListLatch ); + if ( (zVS->ZSH_Flag & ZSH_FLAG_WAIT) && (zVS->ZSH_SearchKey == 0) && + (status == zOK) && (zVS->ZSH_ResultsReturned == 0) ) + { + goto again; + } + return status; +} + + +STATUS VP_PoolAction3B( ZVP_StatusHeader_s *zVS ) +{ + STATUS status; + +again: + if ( (zVS->ZSH_Flag & ZSH_FLAG_WAIT) && (zVS->ZSH_SearchKey == 0) ) + { + S_LATCH( &VP_RepairProcessListNoItem ); + UNS_LATCH( &VP_RepairProcessListNoItem ); + // Window here - it is closed with 'goto again:' logic. + } + X_LATCH( &VP_RepairProcessListLatch ); + zVS->ZSH_ResultsReturned = 0; + zVS->ZSH_ResultsTotal = VP_StatusCount( zVS, NSS_TYPE_VERIFY ); + if ( zVS->ZSH_Flag & ZSH_FLAG_MULTIPLE ) + { // Get information for all verifies + status = VP_VerifyStatusMultiple( zVS ); + } + else + { // Get information for a SPECIFIC verify instance. + status = VP_VerifyStatusSpecific( zVS ); + } + UNX_LATCH( &VP_RepairProcessListLatch ); + if ( (zVS->ZSH_Flag & ZSH_FLAG_WAIT) && (zVS->ZSH_SearchKey == 0) && + (status == zOK) && (zVS->ZSH_ResultsReturned == 0) ) + { + goto again; + } + return status; +} + + +/* + VP_PA_RebuildDetailsWithKey() - + Implements zPOOL_REBUILD_DETAILS_WITH_KEY. + + Returns - + Standard errors if unable to perform the request. Does NOT + return an error if no entries found. The user should look at + zVS->ZSH_ResultsReturned to see the number of entries found. +*/ +STATUS VP_PA_RebuildDetailsWithKey( unsigned int bufSize, ZVP_StatusHeader_s *zVS ) +{ + STATUS status; + + if ( bufSize < offsetof(ZVP_StatusHeader_s,ZSH_Entry) ) + { + return zERR_BUFFER_TOO_SMALL; + } + if ( zVS->ZSH_Format != ZVP_VSH_FORMAT ) + { + return zERR_RAV_FORMAT_MISMATCH; + } + if ( !(zVS->ZSH_Flag & ZSH_FLAG_MULTIPLE) && (zVS->ZSH_Flag & ZSH_FLAG_WAIT) ) + { + return zERR_BAD_PARAMETER_VALUE;; + } + if ( zVS->ZSH_ResultsNeeded == 0 ) + { + return zERR_BAD_PARAMETER_VALUE; + } + if ( bufSize < + (offsetof(ZVP_StatusHeader_s,ZSH_Entry) + (sizeof(ZVP_RebuildStatusEntry_s) * zVS->ZSH_ResultsNeeded)) ) + { + return zERR_BUFFER_TOO_SMALL; + } + status = VP_PA_RebuildDetailsWithKeyB( zVS ); + return status; + +} /* End of VP_PA_RebuildDetailsWithKey() */ + + +/* + VP_PA_RAVVersionInformation() - + Implements zPOOL_RAV_VERSION_INFORMATION. + + Returns - + Standard errors if unable to perform the request. +*/ +STATUS VP_PA_RAVVersionInformation( unsigned int bufSize, ZVP_VersionInformation_s *zVI ) +{ + if ( bufSize < sizeof( ZVP_VersionInformation_s ) ) + { + return zERR_BUFFER_TOO_SMALL; + } + zVI->ZVI_VersionMajor = ZVP_VI_VERSION_MAJOR; + zVI->ZVI_VersionMinor = ZVP_VI_VERSION_MINOR; + zVI->ZVI_XMLVersionMajor = RAV_XML_MAJOR_VERSION; + zVI->ZVI_XMLVersionMinor = RAV_XML_MINOR_VERSION; + bzero( &zVI->ZVI_Reserved[0], sizeof( zVI->ZVI_Reserved ) ); + return zOK; +} + + +/* + VP_PoolAction3() - + Implements zPOOL_VERIFY_DETAILS_WITH_KEY. + + Returns - + Standard errors if unable to perform the request. Does NOT + return an error if no entries found. The user should look at + zVS->ZSH_ResultsReturned to see the number of entries found. +*/ +STATUS VP_PoolAction3( unsigned int bufSize, ZVP_StatusHeader_s *zVS ) +{ + STATUS status; + + if ( bufSize < offsetof(ZVP_StatusHeader_s,ZSH_Entry) ) + { + return zERR_BUFFER_TOO_SMALL; + } + if ( zVS->ZSH_Format != ZVP_VSH_FORMAT ) + { + return zERR_RAV_FORMAT_MISMATCH; + } + if ( !(zVS->ZSH_Flag & ZSH_FLAG_MULTIPLE) && (zVS->ZSH_Flag & ZSH_FLAG_WAIT) ) + { + return zERR_BAD_PARAMETER_VALUE;; + } + if ( zVS->ZSH_ResultsNeeded == 0 ) + { + return zERR_BAD_PARAMETER_VALUE; + } + if ( bufSize < + (offsetof(ZVP_StatusHeader_s,ZSH_Entry) + (sizeof(ZVP_VerifyStatusEntry_s) * zVS->ZSH_ResultsNeeded)) ) + { + return zERR_BUFFER_TOO_SMALL; + } + status = VP_PoolAction3B( zVS ); + return status; + +} /* End of VP_PoolAction3() */ + + +/* + zPoolVerify() - + Used by XML interface to actually do work. + + */ +STATUS zPoolVerify( int action, unsigned int bufSize, void *buffer ) +{ + STATUS status; + Pool_s *pool; + GeneralMsg_s dummyGenMsg; + +HERE_WE_ARE(); + COMN_SETUP_GENERAL_MSG_NOSA(&dummyGenMsg); + switch ( action ) + { + case zPOOL_REVERSE_NAME_LOOKUP: + { + ZVS_ReverseNameLookup_s *rnl = buffer; +HERE_WE_ARE(); + status = VP_PA_ReverseNameLookup( rnl ); + return status; + } + case zPOOL_VERIFY_START: + { + ZVS_Start_s *start = buffer; +HERE_WE_ARE(); + + if ( start == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + pool = COMN_PoolNameLookup( &dummyGenMsg, start->ZVSS_PoolName, FALSE, NULL ); + if (pool == NULL) + { + status = GetErrno( &dummyGenMsg ); + return status; + } + status = VP_PoolAction( &dummyGenMsg, start->ZVSS_PoolName, pool, &start->ZVSS_Key, + start->ZVSS_CrossValidation, start->ZVSS_DebugLevel, start->ZVSS_UIOptions ); + if ( status != zOK ) + { + status = GetErrno( &dummyGenMsg ); + } + COMN_Release( &pool ); + return status; + } + case zPOOL_RAV_VERSION_INFORMATION: + { + + status = VP_PA_RAVVersionInformation( bufSize, buffer ); + return status; + } + case zPOOL_RAV_STATUS: + { + const unicode_t *poolName = buffer; + +HERE_WE_ARE(); + status = VP_PA_RAVStatus( poolName ); + return status; + } + case zPOOL_VERIFY_DETAILS_WITH_KEY: + { +HERE_WE_ARE(); + status = VP_PoolAction3( bufSize, buffer ); + return status; + } + case zPOOL_RAV_STATUS_WITH_KEY: + { + const QUAD *userKey = buffer; + +HERE_WE_ARE(); + status = VP_PA_RAVStatusWithKey( userKey ); + return status; + } + case zPOOL_RAV_REMOVE_WITH_KEY: + { + // FixFixFix(ZRPDone,1,.1) - Add back in. Using to force stat files to stay around +#if 1 + const QUAD *userKey = buffer; + status = VP_PA_RAVRemoveWithKey( userKey ); +#else +HERE_WE_ARE(); + status = 126349; +#endif + return status; + } + case zPOOL_RAV_ITEM_REMOVE_WITH_KEY: + { + ZVS_ItemRemoveWithKey_s *itemRemove = buffer; + +HERE_WE_ARE(); + status = VP_PA_RAVItemRemoveWithKey( itemRemove ); + return status; + } +#if 0 + case zPOOL_VERIFY_DAEMON_SAVED_WITH_KEY: + { + ZVS_Saved_s *saved = buffer; + + status = VP_PoolAction6( saved ); + return status; + } +#endif +#if 0 + case zPOOL_VERIFY_DAEMON_SET: + { + ZVS_DaemonSet_s *set = buffer; + status = VP_PoolAction7( set ); + return status; + } +#endif +#if 0 + case zPOOL_VERIFY_DAEMON_GET: + { + ZVS_DaemonGet_s *get = buffer; + status = VP_PoolAction8( get ); + return status; + } +#endif + case zPOOL_REBUILD_START: + { + ZRS_Start_s *start = buffer; + +HERE_WE_ARE(); + if ( start == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + pool = COMN_PoolNameLookup( &dummyGenMsg, start->ZRSS_PoolName, FALSE, NULL ); + if (pool == NULL) + { + status = GetErrno( &dummyGenMsg ); + return status; + } + status = VP_PoolAction21( &dummyGenMsg, start->ZRSS_PoolName, pool, &start->ZRSS_Key, + start->ZRSS_RezidThreshold, start->ZRSS_Purge, start->ZRSS_UIPruneWait, start->ZRSS_Limit, + start->ZRSS_DebugLevel, start->ZRSS_UIOptions ); + if ( status != zOK ) + { + status = GetErrno( &dummyGenMsg ); + } + COMN_Release( &pool ); + return status; + } + case zPOOL_REBUILD_DETAILS_WITH_KEY: + { +HERE_WE_ARE(); + status = VP_PA_RebuildDetailsWithKey( bufSize, buffer ); + return status; + } +#if 0 + case zPOOL_REBUILD_LIMIT_POST_WITH_KEY: + { + ZVS_LimitPost_s *limitPost = buffer; + if ( buffer == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + if ( sizeof(*limitPost) < bufSize ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PA_RebuildLimitPostWithKey( limitPost ); + return status; + } +#endif + case zPOOL_RAV_SET_WITH_KEY: + { + ZVS_Set_s *set = buffer; +HERE_WE_ARE(); + if ( buffer == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + if ( sizeof(*set) < bufSize ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PA_RAVSetWithKey( set ); + return status; + } + + } +HERE_WE_ARE(); + return zERR_BAD_PARAMETER_VALUE; + +} /* End of zPoolVerify() */ +EXPORT_SYMBOL(zPoolVerify); + +STATUS VP_xPoolOwnershipGet( + VP_Status_s *pComn, + const unicode_t *poolName, + char *where ) +{ + STATUS status; + + zASSERT( pComn->VPS_threadInfo != NULL ); + status = xPoolOwnershipGet( (unicode_t *)poolName, where, &pComn->VPS_threadInfo->VPTI_ownershipKey ); + if ( status != zOK ) + { + pComn->VPS_threadInfo->VPTI_ownershipKey = NULL; + } + return status; + +} /* End of VP_xPoolOwnershipGet() */ + + + +#if 0 +/* RAV_VCF_Command - + * This is the function that gets called when writes are done to + * _ADMIN:\Manage_NSS\LSS\ZLSS\Internal.Cmd. The XML commands that are + * placed into this file are general for Novell use only. + * + * Returns - + * Always returns zOK to indicate that the 'write' succeeded. Any + * errors are stored in the 'read' buffer. This is done as clients + * are unable to get a zERR back from a standard NetWare write, but can do + * a read to see how the 'command' fared. + */ +/* VIRTUAL FILE -- WRITE FUNCTION */ +STATUS RAV_VCF_Command( + NINT parmLen, + utf8_t *parm, + NINT dataLen, + BYTE *data, + NINT offset, + VirtInfo_s *virtInfo) +{ + GeneralMsg_s genMsg; + STATUS status; +// XML_ElementInfo_s resultInfo; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA( &genMsg ); + + status = VIRT_AddResultTag( virtInfo, TAG_NSSREPLY, FALSE, TRUE ); // XML head + if ( status != zOK ) + { + SetErrno( &genMsg, status ); + goto exit; + } + +//g ZLSS_XML_Head( virtInfo, &genMsg ); + if ( offset != 0 ) + { + SetErrno( &genMsg, zERR_BAD_OFFSET ); + goto exit; + } +//g status = MNSS_GetSpecificTemplate( "", +//g dataLen, (utf8_t *)data, &resultInfo ); +//g if ( status == zOK ) +//g { + status = RAV_VF_Command( &genMsg, parmLen, parm, dataLen, data, offset, virtInfo ); +//g } +//g else +//g { +//g SetErrno( &genMsg, status ); +//g } +exit: + (void)MGMT_ReturnResultNSSWithSetter( virtInfo, GetErrno( &genMsg ), GetErrnoSetter( &genMsg ) ); + status = VIRT_AddResultTag( virtInfo, TAG_NSSREPLY, TRUE, TRUE ); // XML tail +//g status = ZLSS_XML_Tail( virtInfo, &genMsg ); + MPKNSS_UNLOCK(); + return( status ); + +} /* End of RAV_VCF_Command() */ +#endif + + +STATUS VP_PoolRAVStart( + GeneralMsg_s *genMsg, + VP_Status_s *pComn, + Pool_s *pool, + const unicode_t *poolName, + VolumeID_t poolVolID, + NINT cmd, + NINT vmFlag, + QUAD *key ) +{ + STATUS status; + + status = VP_ThreadInfoCreate( pComn, pool ); + if ( status != zOK ) + { + VP_PoolInfoDelete( pComn ); + VP_PoolInfoRelease( pComn ); // Our count + SetErrno( genMsg, status ); + return zFAILURE; + } + status = VP_IsPoolStateCorrect( pComn, pool ); + if ( status != zOK ) + { + VP_PoolInfoDelete( pComn ); + VP_PoolInfoRelease( pComn ); // Our count + SetErrno( genMsg, status ); + return( status ); + } + // We need to get 'ownership' of the pool so that two 'maintenance' type operations + // are not occuring at the same time. + status = VP_xPoolOwnershipGet( pComn, poolName, WHERE ); + if ( status != zOK ) + { + VP_PoolInfoDelete( pComn ); + VP_PoolInfoRelease( pComn ); + SetErrno( genMsg, status ); + return zFAILURE; + } + // If the thread starts then it will cleanup our resources. tInfo and pool ownership + // will be released when the thread terminates. The pComn information will stay around + // for a while so that UIs can retrieve completion information. + status = VP_ThreadStart( pComn ); + if ( status != zOK ) + { + VP_PoolInfoDelete( pComn ); + VP_PoolInfoRelease( pComn ); // Our count (plus releases any VP_xPoolOwnership) + SetErrno( genMsg, status ); + return zFAILURE; + } + *key = pComn->VPS_UserKey; + VP_PoolInfoRelease( pComn ); // Our count + return( status ); + +} + +// +// zPOOL_REBUILD_START +// +STATUS VP_PoolRebuildStart( + GeneralMsg_s *genMsg, + Pool_s *pool, + const unicode_t *poolName, + VolumeID_t poolVolID, + NINT cmd, + NINT vmFlag, + QUAD *key, + Zid_t rezidThreshold, + BOOL purge, + BOOL uiPruneWait, + ZSR_LossLimits_s limits, + QUAD debugLevel, + QUAD uiOptions ) +{ + STATUS status; + VPR_Status_s *pInfo; + VP_Status_s *pComn; + + status = VP_IsLegalOperation( genMsg, pool, poolName, &pool->POOLvolumeID, cmd, vmFlag ); + if ( status != zOK ) + { + return( status ); + } + pInfo = VPR_PoolInfoCreate( genMsg, pool, poolName, &pool->POOLvolumeID, cmd, + vmFlag, rezidThreshold, purge, uiPruneWait, limits, debugLevel, uiOptions ); + if ( pInfo == NULL ) + { + return( zFAILURE ); + } + pComn = &pInfo->VPRS_Common; + status = VP_PoolRAVStart( genMsg, pComn, pool, poolName, poolVolID, cmd, vmFlag, key ); + return status; + + +} /* End of VP_PoolRebuildStart() */ + + +// +// zPOOL_REBUILD_START +// +STATUS VP_PoolAction21( + GeneralMsg_s *genMsg, + const unicode_t *poolName, + Pool_s *pool, + QUAD *key, + Zid_t rezidThreshold, + BOOL purge, + BOOL uiPruneWait, + ZSR_LossLimits_s limits, + QUAD debugLevel, + QUAD uiOptions ) +{ + + STATUS status; + NINT vmFlag = VOLMAINTFLAG_POOL; + + status = VP_PoolRebuildStart( genMsg, pool, poolName, pool->POOLvolumeID, VOLMAINTCMD_REPAIR, + vmFlag, key, rezidThreshold, purge, uiPruneWait, limits, debugLevel, uiOptions ); + return status; + +} + + +STATUS VP_PoolVerifyStart( + GeneralMsg_s *genMsg, + Pool_s *pool, + const unicode_t *poolName, + VolumeID_t poolVolID, + NINT cmd, + NINT vmFlag, + QUAD *key, + BOOL crossValidation, + QUAD debugLevel, + QUAD uiOptions ) +{ + STATUS status; + VP_Status_s *pComn; + VPV_Status_s *pInfo; + + status = VP_IsLegalOperation( genMsg, pool, poolName, &pool->POOLvolumeID, cmd, vmFlag ); + if ( status != zOK ) + { + return( status ); + } + pInfo = VPV_PoolInfoCreate( genMsg, pool, poolName, &pool->POOLvolumeID, cmd, vmFlag, + crossValidation, debugLevel, uiOptions ); + if ( pInfo == NULL ) + { + return( zFAILURE ); + } + pComn = &pInfo->VPVS_Common; + status = VP_PoolRAVStart( genMsg, pComn, pool, poolName, poolVolID, cmd, vmFlag, key ); + return status; + +} /* End of VP_PoolVerifyStart() */ + + +STATUS VP_PoolAction( + GeneralMsg_s *genMsg, + const unicode_t *poolName, + Pool_s *pool, + QUAD *key, + BOOL crossValidation, + QUAD debugLevel, + QUAD uiOptions ) +{ + STATUS status; + NINT vmFlag = VOLMAINTFLAG_POOL; + + status = VP_PoolVerifyStart( genMsg, pool, poolName, pool->POOLvolumeID, VOLMAINTCMD_CHECK, + vmFlag, key, crossValidation, debugLevel, uiOptions ); + return status; + +} + + +/* + VP_PoolRAVStatus() - + Returns the status of the verify. Legal return values are limited + to the following. + + zERR_RAV_COMPLETED + zERR_RAV_WORKING + zERR_RAV_STATUS_NOT_AVALIABLE + + */ +STATUS VP_PoolRAVStatus( + const unicode_t *poolName ) +{ + STATUS status = zERR_RAV_STATUS_NOT_AVALIABLE; + VP_Status_s *pComn; + + X_LATCH( &VP_RepairProcessListLatch ); + + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { +// VP_PoolInfoGet( pComn ); + if ( uniicmp( poolName, pComn->VPS_PoolName ) == 0 ) + { // A Match + status = pComn->VPS_Status; +// VP_PoolInfoRelease( pComn ); + break; + } +// VP_PoolInfoRelease( pComn ); + } + UNX_LATCH( &VP_RepairProcessListLatch ); + return status; + +} /* End of VP_PoolRAVStatus() */ + + + +VP_Status_s *VP_PoolInfoGetWithKey( QUAD userKey ) +{ + VP_Status_s *pComn; + + X_LATCH( &VP_RepairProcessListLatch ); + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { + if ( userKey == pComn->VPS_UserKey ) + { // A Match + VP_PoolInfoGet( pComn ); + UNX_LATCH( &VP_RepairProcessListLatch ); + return pComn; + } + } + UNX_LATCH( &VP_RepairProcessListLatch ); + return NULL; + +} /* End of VP_PoolInfoGetWithKey() */ + + +/* + VP_PA_RAVSetWithKey() - + Implements zPOOL_RAV_SET_WITH_KEY. + + Returns - +*/ +STATUS VP_PA_RAVSetWithKey( ZVS_Set_s *set ) +{ + VPR_Status_s *pInfo; + VP_Status_s *pComn; + + pComn = VP_PoolInfoGetWithKey( set->ZS_Key ); + if ( pComn == NULL ) + { + return zERR_RAV_ITEM_NOT_FOUND; + } + if ( set->ZS_UIPruneStatusSet ) + { + pInfo = VP_GetVPR( pComn ); + if ( pInfo == NULL ) + { + VP_PoolInfoRelease( pComn ); + return zERR_RAV_REBUILD_SPECIFIC; + } + pInfo->VPRS_UIPruneStatus = set->ZS_UIPruneStatus; + pInfo->VPRS_UIPruneSet = TRUE; + } + + if ( set->ZS_UIOptionsSet ) + { + pComn->VPS_UIOptions = set->ZS_UIOptions; + } + if ( set->ZS_DebugLevelSet ) + { + pComn->VPS_DebugLevel = set->ZS_DebugLevel; + } + + VP_PoolInfoRelease( pComn ); + return zOK; + +} /* End of VP_PA_RAVSetWithKey() */ + + +/* + VP_PA_RebuildLimitPostWithKey() - + Implements zPOOL_REBUILD_LIMIT_POST_WITH_KEY. + + Returns - +*/ +#if 0 +STATUS VP_PA_RebuildLimitPostWithKey( ZVS_LimitPost_s *limitPost ) +{ + VPR_Status_s *pInfo; + VP_Status_s *pComn; + + pComn = VP_PoolInfoGetWithKey( limitPost->ZLP_Key ); + if ( pComn == NULL ) + { + return zERR_RAV_ITEM_NOT_FOUND; + } + pInfo = VP_GetVPR( pComn ); + if ( pInfo == NULL ) + { + VP_PoolInfoRelease( pComn ); + return zERR_RAV_ITEM_NOT_FOUND; + } + + pInfo->VPRS_UIPruneStatus = limitPost->ZLP_LimitsPost; + pInfo->VPRS_UIPruneSet = TRUE; // User has set. + + VP_PoolInfoRelease( pComn ); + return zOK; + +} /* End of VP_PA_RebuildLimitPostWithKey() */ +#endif + + + +/* + VP_PoolVerifySavedWithKey() - + Removes the status of a verify. + + */ +#if 0 +STATUS VP_PoolVerifySavedWithKey( ZVS_Saved_s *saved ) +{ + VPV_Status_s *pInfo; + VP_Status_s *pComn; + + pComn = VP_PoolInfoGetWithKey( saved->ZVSS_Key ); + if ( pComn == NULL ) + { + return zERR_RAV_ITEM_NOT_FOUND; + } + pInfo = VP_GetVPV( pComn ); + if ( pInfo == NULL ) + { + VP_PoolInfoRelease( pComn ); + return zERR_RAV_ITEM_NOT_FOUND; + } + + // FixFixFix(ZVPSkipped,8,.5) - this assumes that caller has passed in a legal null terminated string +//g unicpy( pInfo->VPVS_SavedFileName, saved->ZVSS_FileName ); + pComn->VPS_State |= VPS_STATE_SAVED; + VP_PoolInfoRelease( pComn ); + return zOK; + +} /* End of VP_PoolVerifySavedWithKey() */ +#endif + + + +#if 0 +ZVS_DaemonSet_s VP_DaemonSet; + +void VP_DaemonSetInit() +{ + VP_DaemonSet.ZDS_Reconfigure = FALSE; + VP_DaemonSet.ZDS_Reset = FALSE; +} + +STATUS VP_PoolVerifySet( ZVS_DaemonSet_s *set ) +{ + if ( set->ZDS_Reset ) + { + VP_DaemonSetInit(); + } + VP_DaemonSet.ZDS_Reconfigure = set->ZDS_Reconfigure; + return zOK; +} + +STATUS VP_PoolVerifyGet( ZVS_DaemonGet_s *get ) +{ + get->ZDG_Reconfigure = VP_DaemonSet.ZDS_Reconfigure; + return zOK; +} +#endif + +/* + VP_PoolRemoveWithKey() - + Removes the status of a verify/rebuild. + + */ +STATUS VP_PoolRemoveWithKey( + QUAD userKey ) +{ + STATUS status = zERR_RAV_ITEM_NOT_FOUND; + VP_Status_s *pComn; + + X_LATCH( &VP_RepairProcessListLatch ); + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { + if ( userKey == pComn->VPS_UserKey ) + { // A Match + VP_PoolInfoGet( pComn ); // We must have since next 2 calls release the 'VP_RepairProcessList' count. + UNX_LATCH( &VP_RepairProcessListLatch ); + VP_PoolInfoDelete( pComn ); + VP_PoolInfoRelease( pComn ); // Our count + pComn = NULL; // Not valid to use as no latch or use count + return zOK; + } + } + UNX_LATCH( &VP_RepairProcessListLatch ); + return status; + +} /* End of VP_PoolRemoveWithKey() */ + + +/* + VP_PoolItemRemoveWithKey() - + Removes PARTIAL status of a verify/rebuild. + + */ +STATUS VP_PoolItemRemoveWithKey( ZVS_ItemRemoveWithKey_s *removeItem ) +{ + STATUS status = zERR_RAV_ITEM_NOT_FOUND; + VP_Status_s *pComn; + + X_LATCH( &VP_RepairProcessListLatch ); + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { + if ( removeItem->ZIRWK_Key == pComn->VPS_UserKey ) + { // The Match + VP_PoolInfoGet( pComn ); + UNX_LATCH( &VP_RepairProcessListLatch ); + status = VP_LSSCleanupPartial( pComn, removeItem ); + VP_PoolInfoRelease( pComn ); // Our count + pComn = NULL; // Not valid to use as no latch or use count + return status; + } + } + UNX_LATCH( &VP_RepairProcessListLatch ); + return status; + +} /* End of VP_PoolItemRemoveWithKey() */ + + +/* + VP_PoolRAVStatusWithKey() - + Returns the status of the verify/rebuild. Legal return values are limited + to the following. + + zERR_RAV_COMPLETED + zERR_RAV_WORKING + zERR_RAV_STATUS_NOT_AVALIABLE + + */ +STATUS VP_PoolRAVStatusWithKey( + QUAD userKey ) +{ + STATUS status = zERR_RAV_STATUS_NOT_AVALIABLE; + VP_Status_s *pComn; + + X_LATCH( &VP_RepairProcessListLatch ); + // While we own the VP_RepairProcessListLatch we are ensured that + // any pComn we pull from the list already has a use count of + // at least 1 (I.E. the 'VP_RepairProcessList' count). We also + // know the item will not disappear on us because of our latch. + // I.E. we do not need our own use count!!! + DQ_FOREACH( &VP_RepairProcessList, pComn, VP_Status_s, VPS_link ) + { +// VP_PoolInfoGet( pComn ); + if ( userKey == pComn->VPS_UserKey ) + { // A Match + status = pComn->VPS_Status; +// VP_PoolInfoRelease( pComn ); + break; + } +// VP_PoolInfoRelease( pComn ); + } + UNX_LATCH( &VP_RepairProcessListLatch ); + return status; + +} /* End of VP_PoolRAVStatusWithKey() */ + + +STATUS VP_PA_RAVStatus( const unicode_t *poolName ) +{ + STATUS status; + + if ( poolName == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PoolRAVStatus( poolName ); + return status; + +} + + +STATUS VP_PA_RAVStatusWithKey( const QUAD *userKey ) +{ + STATUS status; + + if ( userKey == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PoolRAVStatusWithKey( *userKey ); + return status; + +} + + +STATUS VP_PA_ReverseNameLookup( ZVS_ReverseNameLookup_s *rnl ) +{ + STATUS status; + GeneralMsg_s dummyGenMsg; + + COMN_SETUP_GENERAL_MSG_NOSA(&dummyGenMsg); + if ( rnl == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + COMN_INCLUDE_INTERNAL_VOLUMES( &dummyGenMsg ); + status = COMN_ReverseNameLookup2( &dummyGenMsg, rnl->ZRNL_Zid, rnl->ZRNL_NameSpace, rnl->ZRNL_NameType, + &rnl->ZRNL_VolumeID, rnl->ZRNL_VolumeName, sizeof(rnl->ZRNL_VolumeName), + rnl->ZRNL_FullName, sizeof(rnl->ZRNL_FullName) ); + COMN_EXCLUDE_INTERNAL_VOLUMES( &dummyGenMsg ); + if ( status != zOK ) + { + return GetErrno(&dummyGenMsg); + } + return status; + +} + + +STATUS VP_PA_RAVItemRemoveWithKey( ZVS_ItemRemoveWithKey_s *removeItem ) +{ + STATUS status; + + if ( removeItem == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PoolItemRemoveWithKey( removeItem ); + return status; + +} /* End of VP_PA_RAVItemRemoveWithKey() */ + + +STATUS VP_PA_RAVRemoveWithKey( const QUAD *userKey ) +{ + STATUS status; + + if ( userKey == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PoolRemoveWithKey( *userKey ); + return status; + +} + + +#if 0 +STATUS VP_PoolAction6( ZVS_Saved_s *saved ) +{ + STATUS status; + + if ( saved == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PoolVerifySavedWithKey( saved ); + return status; + +} +#endif + + +#if 0 +STATUS VP_PoolAction7( ZVS_DaemonSet_s *set ) +{ + STATUS status; + + if ( set == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PoolVerifySet( set ); + return status; + +} +#endif + + +#if 0 +STATUS VP_PoolAction8( ZVS_DaemonGet_s *get ) +{ + STATUS status; + + if ( get == NULL ) + { + return zERR_BAD_PARAMETER_VALUE; + } + status = VP_PoolVerifyGet( get ); + return status; + +} +#endif + +void doRepairSpecificPool( struct PCLSwitchDef_s *switchDef, NINT options, void *userParm) +{ +/*OK*/aprintf(LRED, "This command is no longer supported, use the ravsui utility.\n"); // FixFixFix(ZVPDone,5,.1) - add in command to use here and next 3 messages. + return; +} +void doRepairSelectedPool( struct PCLSwitchDef_s *switchDef, NINT options, void *userParm) +{ +/*OK*/aprintf(LRED, "This command is no longer supported, use the ravsui utility.\n"); + return; +} +void doCheckSpecificPool( struct PCLSwitchDef_s *switchDef, NINT options, void *userParm) +{ +/*OK*/aprintf(LRED, "This command is no longer supported, use the ravsui utility.\n"); + return; +} +void doCheckSelectedPool( struct PCLSwitchDef_s *switchDef, NINT options, void *userParm) +{ +/*OK*/aprintf(LRED, "This command is no longer supported, use the ravsui utility.\n"); + return; +} + + + +void VP_MarkAsChecking( Volume_s *volume ) +{ + + zASSERT( (volume->maintenanceStatus & VOLMAINTSTATUS_STATE) == 0 ); + volume->maintenanceStatus &= ~VOLMAINTSTATUS_STATE; + volume->maintenanceStatus |= VOLMAINTSTATUS_CHECKING; + return; + +} /* End of VP_MarkAsChecking() */ + +void VP_ClearChecking( Volume_s *volume ) +{ + + volume->maintenanceStatus &= ~VOLMAINTSTATUS_CHECKING; + return; + +} /* End of VP_ClearChecking() */ + + +void VP_MarkAsRepairing( Volume_s *volume ) +{ + + zASSERT( (volume->maintenanceStatus & VOLMAINTSTATUS_STATE) == 0 ); + volume->maintenanceStatus &= ~VOLMAINTSTATUS_STATE; + volume->maintenanceStatus |= VOLMAINTSTATUS_REPAIRING; + return; + +} /* End of VP_MarkAsRepairing() */ + + +void VP_ClearRepairing( Volume_s *volume ) +{ + + volume->maintenanceStatus &= ~VOLMAINTSTATUS_REPAIRING; + return; + +} /* End of VP_ClearRepairing() */ + + +STATUS COMN_ReverseNameLookup2( + GeneralMsg_s *genMsg, + Zid_t ztr_PZid, + BYTE ztr_NameSpaceID, /* E.g. zNSPACE_DOS, zNSPACE_MAC, etc */ + WORD ztr_NameType, /* E.g. zNTYPE_FILE, zNTYPE_DELETED_FILE, etc */ + VolumeID_t *ztr_VolumeID, + unicode_t *volumeNameBuffer, + unsigned int volumeNameBufferSizeOf, + unicode_t *fullNameBuffer, + unsigned int fullNameBufferSizeOf ) +{ + STATUS status; + Volume_s *volume; + + volume = COMN_VolumeIDLookup( genMsg, ztr_VolumeID, FALSE ); + if ( volume == NULL ) + { + return zFAILURE; + } + status = COMN_LockVolumeActive( genMsg, volume, FALSE ); + if ( status != zOK ) + { + if ( GetErrno(genMsg) == zERR_VOLUME_NOT_FOUND ) + { // This is a much better return than NOT FOUND!!! + ForceSetErrno( genMsg, zERR_VOLUME_NOT_IN_ACTIVE_STATE ); + } + COMN_Release( &volume ); /* remove useCount added by COMN_VolumeIDLookup */ + return status; + } + status = COMN_GetVolumeName( genMsg, volume, volumeNameBuffer, volumeNameBufferSizeOf/(sizeof(unicode_t)) ); + if ( status != zOK ) + { + COMN_UnlockVolumeActive( volume, FALSE ); + COMN_Release( &volume ); + return status; + } + status = COMN_ReverseNameLookup( genMsg, volumeNameBuffer, + ztr_PZid, ztr_NameSpaceID, ztr_NameType, + fullNameBuffer, fullNameBufferSizeOf ); + if ( status != zOK ) + { + COMN_UnlockVolumeActive( volume, FALSE ); + COMN_Release( &volume ); + return status; + } + COMN_UnlockVolumeActive(volume, FALSE); + COMN_Release( &volume ); + return status; + +} /* End of COMN_ReverseNameLookup2() */ diff --git a/src/nwnss/comn/common/seqUpdater.c b/src/nwnss/comn/common/seqUpdater.c new file mode 100644 index 0000000..0549d1c --- /dev/null +++ b/src/nwnss/comn/common/seqUpdater.c @@ -0,0 +1,257 @@ +/**************************************************************************** + | + | (C) Copyright 2001 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | Novell Storage Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2005-08-10 01:03:51 +0530 (Wed, 10 Aug 2005) $ + | + | $RCSfile$ + | $Revision: 1177 $ + | + |--------------------------------------------------------------------------- + | This module has the routines used to run the background checker. + +-------------------------------------------------------------------------*/ +#include + +#if zLINUX +#include +#include + +#include "comnPublics.h" +#include "pssStartup.h" +#include "pssConfig.h" +#include "pssConnection.h" +#include "seqUpdater.h" + + +/* GLOBALS */ +THREAD SEQ_ThreadID; +BOOL SEQ_ThreadRunning = FALSE; +BOOL SEQ_ShutdownRequest = FALSE; +BOOL SEQ_Sleeping = FALSE; +OneShot_s SEQ_Alarm; + +/*************************************************************************** + * This function is called when the alarm goes off + ***************************************************************************/ +void SEQ_TimedOut( + NINT seconds) +{ + zASSERT(SEQ_Sleeping); + Continue(SEQ_ThreadID); + SEQ_Sleeping = FALSE; +} + +/*************************************************************************** + * This function puts the updater to sleep for the specified number of + * seconds. + ***************************************************************************/ +void SEQ_Sleep( + NINT seconds) +{ + ASSERT_MPKNSS_LOCK(); + + INIT_ONESHOT(SEQ_Alarm); + secOneShot( &SEQ_Alarm, seconds, SEQ_TimedOut); + SEQ_Sleeping = TRUE; + Wait(); +} + +/*************************************************************************** + * This function is called to wake up the updater before the normal time. + ***************************************************************************/ +void SEQ_Wakeup() +{ + if (SEQ_Sleeping) + { + CANCEL_ALARM(SEQ_Alarm); + Continue(SEQ_ThreadID); + SEQ_Sleeping = FALSE; + } +} + +/************************************************************************** + * This function checks to see if we are shutting down the updater. + * It returns TRUE in that case. + ***************************************************************************/ +BOOL SEQ_ShutdownUpdater( void ) +{ + /* + * If updating has been suspended and not forced on then return TRUE. + */ + if ((!Config.SecEquiv.updater && !Config.SecEquiv.forceUpdater) || + SEQ_ShutdownRequest) + { + return TRUE; + } + return FALSE; +} + +/************************************************************************** + * This function is used to update the security equivalence vectors of all + * NSS connections. + * + * This will loop through the PSSConnection list and call all of the + * CNCT_UpdatePSSConnection routine on each connection. + ***************************************************************************/ +void SEQ_UpdateAllPSSConnections( void ) +{ + NSSConnection_s *pssConn; + + ASSERT_MPKNSS_LOCK(); + + /* If we have been told to stop, don't start */ + if (SEQ_ShutdownUpdater()) + { + return; + } + + DQ_FOREACH(&CNCT_PSSConnectionList, pssConn, NSSConnection_s, link) + { + pssConn->connUseCount++; + + COMN_UpdatePSSConnection( pssConn ); + + pssConn->connUseCount--; + + /* If we have been told to stop, stop now */ + if (SEQ_ShutdownUpdater()) + { + return; + } + } +} + +/************************************************************************** + * This function is scheduled as a background thread to update the cached + * security equivalence vectors of the system. + ***************************************************************************/ +void SEQ_UpdaterThread( + THREAD threadID, + void *info) +{ + + MPKNSS_LOCK(); + + SEQ_ThreadRunning = TRUE; + aprintf(YELLOW, "NSS background security equivalence updating scheduled.\n"); + + /* + * Pause at startup to let the server get going without getting in the + * way. + */ + + SEQ_Sleep(Config.SecEquiv.updaterInterval); + if (SEQ_ShutdownRequest) + { + goto exit; + } + + /* Main body of the updater */ + for (;;) + { + if (SEQ_ShutdownRequest) + { + break; + } + + if (Config.SecEquiv.intervalChanged) + { + /* We just changed intervals, go back to sleep for the new interval */ + Config.SecEquiv.intervalChanged = FALSE; + } + else + { + /* + * If updating has not been suspended then go for it... + */ + if ((Config.SecEquiv.updater) || (Config.SecEquiv.forceUpdater)) + { + aprintf(YELLOW, "NSS background security equivalence updater running ...\n"); + + SEQ_UpdateAllPSSConnections(); + + aprintf(YELLOW, "NSS background security equivalence updater completed ...\n"); + } + + /* Reset the force flag if we were forced to update one time */ + Config.SecEquiv.forceUpdater = FALSE; + } + + /* + * Sleep until time to start again. + */ + SEQ_Sleep(Config.SecEquiv.updaterInterval); + } + +exit: + aprintf(YELLOW, "NSS background security equivalence updater shut down.\n"); + SEQ_ThreadRunning = FALSE; + MPKNSS_UNLOCK(); +} + +/************************************************************************** + * This function schedules a background thread to update the + * Security Equivalence Cache. + ***************************************************************************/ +void SEQ_StartProcess() +{ + ZOS_StartThread(SEQ_ThreadID, "NSS Security Equivalence Updater", + (void *(*)(THREAD, void *))SEQ_UpdaterThread, + 0, 0, NULL); + if (SEQ_ThreadID == 0) + { + errPrintf(WHERE, Module, -1, + MSG("Unable to start the background security equivalence updater.\n", 0)); + } + return; +} + +/************************************************************************** + * This function shuts down the background updater thread. + ***************************************************************************/ +void SEQ_StopProcess() +{ + NINT count; + enum + { + SEQ_MAX_SHUTDOWN_SECONDS = 30 + }; + + SEQ_ShutdownRequest = TRUE; + SEQ_Wakeup(); + for (count = 0; count < SEQ_MAX_SHUTDOWN_SECONDS; count++) + { + if (!SEQ_ThreadRunning) + { + return; + } + LB_delay(1000); + } + errPrintf(WHERE, Module, -1, + MSG("Unable to shutdown the background security equivalence updater.\n", 0)); + return; +} +#endif diff --git a/src/nwnss/comn/compression/nwAlgo.c b/src/nwnss/comn/compression/nwAlgo.c new file mode 100644 index 0000000..55210b5 --- /dev/null +++ b/src/nwnss/comn/compression/nwAlgo.c @@ -0,0 +1,417 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996-1998 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) Command Line Support module + | + |--------------------------------------------------------------------------- + | + | $Author: blarsen $ + | $Date: 2006-09-06 03:03:38 +0530 (Wed, 06 Sep 2006) $ + | + | $RCSfile$ + | $Revision: 1522 $ + | + |--------------------------------------------------------------------------- + | Module Description: + | + +-------------------------------------------------------------------------*/ +#include "nwAlgo.h" + +LONG +NSSCCDSetFileSize( + IoHandle_t internalHandle, + LONG fileSize, + LONG internalFileSize) +{ + return ALGOMGR_setStreamSize(CM_STREAM(internalHandle), internalFileSize); +} + +LONG +NSSCCDDecompressBuildFile( IoHandle_t outHandle, LONG offset, LONG size, + LONG prevSize, LONG nextSize ) +{ + /* XXX Determine if there's anything to do here */ + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "buildfile(offset=%ld, size=%ld, psize=%ld, nsize=%ld) called\n", + offset, size, prevSize, nextSize)); + if (offset != 0) + return (LONG)0; + ALGOMGR_setStreamSize(CM_STREAM(outHandle), size); + return (LONG)0; +} + +LONG +NSSCCDGetWriteCacheBlock( IoHandle_t ioHandle, LONG cacheBlockNumber, + LONG noFlushFlag, BYTE **cacheBlock, LONG *cacheHandle ) +{ + STATUS rc; + LONG holeFlag; + LONG size; + + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "---------- getwrite: fseek(offset=%ld) handle=%d\n", + cacheBlockNumber * CD_SYSTEM_CACHE_BUFFER_SIZE, ioHandle->nextfreeIobuf+1)); + ioHandle->iobuf[ioHandle->nextfreeIobuf].offset = + cacheBlockNumber * CD_SYSTEM_CACHE_BUFFER_SIZE; + CD_ASSERT((! ISVALID_HANDLE(ioHandle->iobuf[ioHandle->nextfreeIobuf].cmbuf))); + rc = ALGOMGR_fetchStreamBuf(CM_STREAM(ioHandle), + ioHandle->iobuf[ioHandle->nextfreeIobuf].offset, + &ioHandle->iobuf[ioHandle->nextfreeIobuf].cmbuf, CM_STREAM_MODE_WRITE, + CD_SYSTEM_CACHE_BUFFER_SIZE, cacheBlock, &size, &holeFlag); + if (rc == zOK) + { + *cacheHandle = ioHandle->nextfreeIobuf+1; + ioHandle->nextfreeIobuf = (ioHandle->nextfreeIobuf + 1) % WRITE_CACHE_BUFFER_RANGE; + } + else *cacheHandle = 0; + return rc; +} + +LONG +NSSCCDReturnWriteCacheBlock( LONG cacheHandle, IoHandle_t ioHandle, + LONG numberOfSectors, LONG noFlushFlag ) +{ + STATUS rc; + LONG offset; + + if ((cacheHandle == 0) || (cacheHandle > WRITE_CACHE_BUFFER_RANGE)) + return UNCOMPRESS_ERROR_INVALID_OFFSET; + -- cacheHandle; + offset = ioHandle->iobuf[cacheHandle].offset; + + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "---------- returnwrite: fseek(offset=%ld) handle=%d\n", offset, cacheHandle+1)); + if (offset != ALGOMGR_getStreamPosition(CM_STREAM(ioHandle))) { +#if 0 + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "---------- write_off %ld != %ld\n", offset, + ALGOMGR_getStreamPosition(CM_STREAM(ioHandle)))); +#endif + ALGOMGR_setStreamPosition(CM_STREAM(ioHandle), (QUAD)offset); + } + CD_ASSERT((ISVALID_HANDLE(ioHandle->iobuf[cacheHandle].cmbuf))); + rc = ALGOMGR_releaseStreamBuf(CM_STREAM(ioHandle), + ioHandle->iobuf[cacheHandle].cmbuf, TRUE); + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "---------- wrote (secsize=%d, nsectors=%ld, offset=%ld)\n", + CD_SYSTEM_SECTOR_SIZE, numberOfSectors, offset)); + + INVALIDATE_HANDLE(ioHandle->iobuf[cacheHandle].cmbuf); + return rc; +} + +LONG +NSSCCDGetReadCacheBlock( IoHandle_t ioHandle, LONG cacheBlockNumber, + LONG *realBytesRead, BYTE **cacheBlock, LONG *cacheHandle, + LONG *holeFlag ) +{ + STATUS rc; + CMStream_t stream = CM_STREAM(ioHandle); + + ioHandle->iobuf[ioHandle->nextfreeIobuf].offset = + cacheBlockNumber * CD_SYSTEM_CACHE_BUFFER_SIZE; + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "getread: offset=%d handle=%d\n", + ioHandle->iobuf[ioHandle->nextfreeIobuf].offset, ioHandle->nextfreeIobuf+1)); + *holeFlag = 0; + + if (ioHandle->iobuf[ioHandle->nextfreeIobuf].offset != ALGOMGR_getStreamPosition(stream)) { + rc = ALGOMGR_setStreamPosition(stream, + (QUAD)ioHandle->iobuf[ioHandle->nextfreeIobuf].offset); + if (rc != 0) { + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "fseek(offset=%ld)", + ioHandle->iobuf[ioHandle->nextfreeIobuf].offset)); + return rc; + } + } + *realBytesRead = CD_SYSTEM_CACHE_BUFFER_SIZE; + rc = ALGOMGR_fetchStreamBuf(stream, + ioHandle->iobuf[ioHandle->nextfreeIobuf].offset, + &ioHandle->iobuf[ioHandle->nextfreeIobuf].cmbuf, CM_STREAM_MODE_READ, + *realBytesRead, cacheBlock, realBytesRead, holeFlag); + if ((rc == zOK) && (*holeFlag == 0)) + { + *cacheHandle = ioHandle->nextfreeIobuf+1; + ioHandle->nextfreeIobuf = (ioHandle->nextfreeIobuf + 1) % READ_CACHE_BUFFER_RANGE; + } + else *cacheHandle = 0; + + return rc; +} + +void +NSSCCDReturnReadCacheBlock(IoHandle_t ioHandle, LONG cacheHandle) +{ + if ((cacheHandle == 0) || (cacheHandle > READ_CACHE_BUFFER_RANGE)) + return; + -- cacheHandle; + + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "return_read: offset=%d, handle=%d\n", + ioHandle->iobuf[cacheHandle].offset, cacheHandle+1)); + (void) ALGOMGR_releaseStreamBuf(CM_STREAM(ioHandle), + ioHandle->iobuf[cacheHandle].cmbuf, FALSE); +} + +LONG NSSCCDGetReadAheadBuffer(readCache_tp ra, BYTE **cachePointer, + LONG *validBytes, LONG *holeFlag) +{ + LONG retCode; + LONG nextBufferToBeUsed = ra->CacheNextToBeUsed; // & CD_READ_CACHE_MASK; + + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "read_ahead used=%d, freed=%d: ", + nextBufferToBeUsed, ra->CacheNextToBeFreed)); + if (ra->CacheHandles[nextBufferToBeUsed] != 0) { + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "overreading offset=%d !!\n", + ((IoHandle_s *)ra->CacheReadFileHandle)->iobuf[ + ra->CacheHandles[nextBufferToBeUsed]-1].offset)); + CD_ASSERT((0)); + } + retCode = NSSCCDGetReadCacheBlock(ra->CacheReadFileHandle, +// ra->CacheNextToBeUsed, validBytes, cachePointer, + ra->CacheNextBlockToRead, validBytes, cachePointer, + &ra->CacheHandles[nextBufferToBeUsed], holeFlag); + if (retCode != 0) + return retCode; + + if (! *validBytes) + return CD_ERROR_READ_ZERO_BYTES; + ra->CacheNextBlockToRead++; + if (*holeFlag) + { + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, " ~~~ holeFlag is on\n")); + } + else + { + ra->CacheNextToBeUsed ++; + ra->CacheNextToBeUsed &= CD_READ_CACHE_MASK; + } + return (LONG)0; +} + + +LONG NSSCCDFreeReadAheadBuffer(readCache_tp ra) +{ + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "free_read_ahead used=%d, freed=%d:\n", + ra->CacheNextToBeUsed, ra->CacheNextToBeFreed)); + NSSCCDReturnReadCacheBlock(ra->CacheReadFileHandle, + ra->CacheHandles[ra->CacheNextToBeFreed]); + ra->CacheHandles[ra->CacheNextToBeFreed] = 0; /* Some invalid value */ + + ra->CacheNextToBeFreed++; + ra->CacheNextToBeFreed &= CD_READ_CACHE_MASK; + return (LONG)0; +} + +LONG +NSSCCDPrepareForRead( IoHandle_t ioHandle, LONG fileSize, + readCache_tpp readCacheHandleReturn) +{ + readCache_tp ra; + + if ((ra = (readCache_tp)CD_MALLOC(sizeof(readCache_t))) == NULL) + return( zERR_NO_MEMORY ); + + memset(ra, (LONG)0, sizeof(readCache_t)); + + ra->CacheReadFileHandle = ioHandle; + ioHandle->nextfreeIobuf = 0; + *readCacheHandleReturn = ra; + + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "Preparing to read\n")); + ALGOMGR_setStreamPosition(CM_STREAM(ioHandle), 0); + return((LONG)0); +} + +LONG NSSCCDStopReadAhead(readCache_tp ra) +{ + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "Stopping read\n")); + + while (ra->CacheNextToBeFreed != ra->CacheNextToBeUsed) + { + if (ra->CacheHandles[ra->CacheNextToBeFreed] == 0) + { + NWALGO_DBG_PRINTF((NWALGO_DBG_COLOR, "freeing NULL buffer, used=%d, freed=%d:\n", + ra->CacheNextToBeUsed, ra->CacheNextToBeFreed)); + ++ ra->CacheNextToBeFreed; + ra->CacheNextToBeFreed &= CD_READ_CACHE_MASK; + CD_ASSERT((0)); + } + else { + NSSCCDFreeReadAheadBuffer(ra); + } + } + CD_FREE( ra ); + + return((LONG)0); +} + +STATIC STATUS +NWALGO_init() +{ + return zOK; +} + +STATIC STATUS +NWALGO_compressStream( + BYTE algoVersion, + CMStream_t uncompStream, /* read-only */ + CMStream_t compStream, /* write */ + CMStream_t tempStream, /* write/read + * For NW algorithm use */ + BYTE minPercentGain) +{ + LONG ccode; + QUAD fileSize = ALGOMGR_getStreamSize(uncompStream); + CompressStatus_t compressStatus; + IoHandle_s uncompHandle, compHandle, tempHandle; + ADDR compressHandle; + + memset( &compressStatus, 0, sizeof(compressStatus) ); + + compressStatus.totalInitialBlocks = + (fileSize + CD_SYSTEM_CACHE_BUFFER_SIZE - 1) + >> CD_SYSTEM_CACHE_BUFFER_SHIFT; + + compressStatus.minimumPercentageGain = minPercentGain; + + memset( &uncompHandle, 0, sizeof(uncompHandle) ); + uncompHandle.CM_stream = uncompStream; + uncompHandle.nextfreeIobuf = 0; + + memset( &compHandle, 0, sizeof(compHandle) ); + compHandle.CM_stream = compStream; + compHandle.nextfreeIobuf = 0; + + memset( &tempHandle, 0, sizeof(tempHandle) ); + tempHandle.CM_stream = tempStream; + tempHandle.nextfreeIobuf = 0; + + ccode = CCDCompressFile(&uncompHandle, &compHandle, &tempHandle, + fileSize, 0, &compressHandle, "", &compressStatus); + switch (ccode) { + case 0: + return zOK; + case COMPRESS_ERROR_OUT_OF_RAM: + return zERR_NO_MEMORY; + case COMPRESS_ERROR_READ_ZERO_BYTES: + case COMPRESS_ERROR_READ_BEYOND_EOF: + return zERR_END_OF_FILE; + case COMPRESS_ERROR_ABORTED: + return zERR_CM_ABORTED; + case COMPRESS_ERROR_UNCOMPRESSABLE: + return zERR_CM_CANT_COMPRESS; + case COMPRESS_ERROR_CODE_COUNTS_MISMATCH: + case COMPRESS_ERROR_TOTALS_MISMATCH: + case COMPRESS_ERROR_TREE_TOO_BIG: + case COMPRESS_ERROR_MATCH_SIZE_FAIL: + case COMPRESS_ERROR_TEMP_FILE_ERROR: + return zERR_CM_COMP_ALGO_ERROR; + case COMPRESS_ERROR_NO_RESOURCES: + return zERR_NO_MEMORY; + case COMPRESS_ERROR_HOLE_COUNT_MISMATCH: + case COMPRESS_ERROR_FILE_TOO_BIG: + return zERR_FILE_TOO_LARGE; + case COMPRESS_ERROR_WRITE_TREE_ERROR: + return zERR_CM_COMP_ALGO_ERROR; + case COMPRESS_ERROR_NO_MIN_PERCENT: + case COMPRESS_ERROR_NO_MIN_BYTES: + return zERR_CM_CANT_COMPRESS; + case COMPRESS_ERROR_INVALID_HOLE: + return zERR_CM_COMP_ALGO_ERROR; + case COMPRESS_ERROR_TRY_AGAIN: + return zERR_NO_MEMORY; + default: + return ccode; + } +} + +STATIC STATUS +NWALGO_uncompressStream( + BYTE algoVersion, + CMStream_t compStream, + CMStream_t uncompStream) +{ + LONG ccode; + IoHandle_s compHandle, uncompHandle; + ADDR compressHandle; + + memset( &compHandle, 0, sizeof(compHandle) ); + compHandle.CM_stream = compStream; + compHandle.nextfreeIobuf = 0; + + memset( &uncompHandle, 0, sizeof(uncompHandle) ); + uncompHandle.CM_stream = uncompStream; + uncompHandle.nextfreeIobuf = 0; + + ccode = CCDStartDecompress(&compHandle, &uncompHandle, &compressHandle, + "", 0, 0); + switch (ccode) { + case 0: + return zOK; + case UNCOMPRESS_ERROR_OUT_OF_RAM: + return zERR_NO_MEMORY; + case UNCOMPRESS_ERROR_READ_ZERO_BYTES: + case UNCOMPRESS_ERROR_READ_BEYOND_EOF: + return zERR_END_OF_FILE; + case UNCOMPRESS_ERROR_ABORTED: + return zERR_CM_ABORTED; + case UNCOMPRESS_ERROR_INVALID_DATA_COUNT: + case UNCOMPRESS_ERROR_INVALID_LENGTH_COUNT: + case UNCOMPRESS_ERROR_INVALID_OFFSET_COUNT: + case UNCOMPRESS_ERROR_INVALID_HOLES: + case UNCOMPRESS_ERROR_INVALID_OFFSET: + case UNCOMPRESS_ERROR_INVALID_LENGTH: + case UNCOMPRESS_ERROR_HOLE_COUNT_MISMATCH: + return zERR_CM_CORRUPT_COMPRESSED_FILE; + case UNCOMPRESS_ERROR_UNKNOWN_VERSION: + return zERR_CM_UNKNOWN_COMP_ALGO_VERSION; + case UNCOMPRESS_ERROR_FILE_TOO_SMALL: + return zERR_CM_UNKNOWN_COMP_ALGO_VERSION; + case UNCOMPRESS_ERROR_TREE_TOO_BIG: + return zERR_FILE_TOO_LARGE; + case UNCOMPRESS_ERROR_WRITE_BEYOND_EOF: + return zERR_END_OF_FILE; + case UNCOMPRESS_ERROR_INVALID_HEADER: + return zERR_CM_INVALID_COMP_FILE_HEADER; + case UNCOMPRESS_ERROR_CORRUPT_COMPRESSED_FILE: + return zERR_CM_CORRUPT_COMPRESSED_FILE; + case UNCOMPRESS_ERROR_TRY_AGAIN: + case UNCOMPRESS_ERROR_TRY_AGAIN_FOREVER: + return zERR_NO_MEMORY; + default: ; + return ccode; + } +} + +STATIC void +NWALGO_uninit() +{ +} + +STATIC CompAlgoIF_s NWALGO_ops = { + NWALGO_init, + NWALGO_compressStream, + NWALGO_uncompressStream, + NWALGO_uninit, +}; + +STATUS +NWALGO_startup() +{ + return ALGOMGR_registerCompAlgo(NSS_COMP_ALGO_ID_NETWARE, &NWALGO_ops); +} + +CompAlgoStartupFn_t CM_defaultAlgoStartupFn = NWALGO_startup; diff --git a/src/nwnss/comn/sbs/sbsMgmt.c b/src/nwnss/comn/sbs/sbsMgmt.c new file mode 100644 index 0000000..39d136a --- /dev/null +++ b/src/nwnss/comn/sbs/sbsMgmt.c @@ -0,0 +1,680 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: blarsen $ + | $Date: 2006-01-21 04:09:53 +0530 (Sat, 21 Jan 2006) $ + | + | $RCSfile$ + | $Revision: 1315 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Management volume files + +-------------------------------------------------------------------------*/ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msgGen.h" +#include "msgName.h" +#include "comnPublics.h" +#include "xmlNSS.h" +#include "mgmt.h" +#include "nssPubs.h" +#include "sbsMFL.h" +#include "xmlTags.h" + +typedef struct MFLControlCookie_s +{ +// Volume_s *volume; + NINT currentOp; +#define MFL_OP_NONE 0 +#define MFL_OP_ENUMERATE 1 +#define MFL_OP_GET_STATUS 2 +#define MFL_OP_VERIFY 3 +#define MFL_OP_REPAIR 4 +#define MFL_OP_END 99 + union + { + struct + { + BOOL isDynamic; /* include files modified during enumeration? */ + NINT nameSpaceID; /* use this name space for returning path names */ + NINT pathFormat; /* Character encoding to use for path names */ + MFLCursor_s cursor; + BOOL isMFLincomplete; + BOOL done; /* Is enumeration done? */ + } enumerate; + } s; /* operation's internal state */ + SNINT resultLen; + BYTE resultBuf[2 * zGET_NAME_VARIABLE_DATA_SIZE]; +} MFLControlCookie_s; + +/**************************************************************************** + * Cleanup at file close time + ****************************************************************************/ +void cleanupMFLControlCookie( + VirtInfo_s *virtInfoe) +{ + return; + +// MFLControlCookie_s *mflCookie = +// (MFLControlCookie_s *)virtInfo->memPtr; +// +// if (mflCookie == NULL) +// { +// return; +// } +// /* Unlock the volume */ +// COMN_UnlockVolumeActive(mflCookie->volume, FALSE); +} + +/**************************************************************************** + * Allocate a cookie structure for MFL. + ****************************************************************************/ +STATUS allocateCookie( + VirtInfo_s *virtInfo) +{ + MFLControlCookie_s *mflCookie; + + /* If we have not allocated a cookie then do so. */ + if (virtInfo->memPtr == NULL) + { + mflCookie = zalloc(sizeof(MFLControlCookie_s)); + if (mflCookie == NULL) + { + return zERR_NO_MEMORY; + } + virtInfo->memPtr = mflCookie; + virtInfo->closeFunc = cleanupMFLControlCookie; + mflCookie->currentOp = MFL_OP_NONE; + } + return zOK; +} + +/**************************************************************************** + * Send whatever is in the result buffer. Return TRUE if we filled the + * output buffer. + ****************************************************************************/ +BOOL sendResult( + MFLControlCookie_s *mflCookie, + NINT *bufBytesLeft, + BYTE **outBuf, + NINT *outLen) +{ + NINT retLen; + + if (mflCookie->resultLen > 0) + { + retLen = (*bufBytesLeft < mflCookie->resultLen) + ? *bufBytesLeft : mflCookie->resultLen; + if (retLen > 0) + { + memmove(*outBuf, mflCookie->resultBuf, retLen); + *outBuf += retLen; + *outLen += retLen; + *bufBytesLeft -= retLen; + mflCookie->resultLen -= retLen; + if (mflCookie->resultLen > 0) + { + memmove(mflCookie->resultBuf, (mflCookie->resultBuf + retLen), + mflCookie->resultLen); + } + } + } + return !(*bufBytesLeft); +} + +/**************************************************************************** + * Generate the modified files list for this volume. + * NOTE: This is a cookie type read function. + ****************************************************************************/ +/* VIRTUAL FILE -- READ FUNCTION */ +STATUS SBS_volumeMFLControlReadFunc( + NINT parmLen, + utf8_t *parm, + VirtInfo_s *virtInfo) +{ + STATUS status; + Volume_s *volume; + GeneralMsg_s genMsg; + MFLEntry_s *mflEntries = NULL; + NINT numEntriesRequested, numEntriesObtained, i; + BOOL mflIncompleteFlag; + MFLControlCookie_s *mflCookie; + BYTE *path = NULL; + NINT bufBytesLeft = virtInfo->resultBufferSize; + BYTE *outBuf = virtInfo->resultBuffer; + NINT *retLen = &virtInfo->resultEOF; + + typedef struct Stack_s { + NamingMsg_s nameMsg; + GetNameMsg_s gfnMsg; + zGetName_s nameBuffer; + BYTE volName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + *retLen = 0; + + if ((status = allocateCookie(virtInfo)) != zOK) + { + STACK_FREE(); + return zFAILURE; + } + + mflCookie = (MFLControlCookie_s *)virtInfo->memPtr; + /* + * Send anything that happens to be held in the result buffer. If this + * fills the output buffer then we are done with this request. + */ + if (sendResult(mflCookie, &bufBytesLeft, &outBuf, retLen)) + { + goto done; + } + + /* If no operation pending then make it an enumerate */ + if (mflCookie->currentOp == MFL_OP_NONE) + { + mflCookie->currentOp = MFL_OP_ENUMERATE; + mflCookie->s.enumerate.isDynamic = TRUE; + mflCookie->s.enumerate.nameSpaceID = zNSPACE_LONG; +// mflCookie->s.enumerate.pathFormat = zPFMT_UTF8; + mflCookie->s.enumerate.pathFormat = zPFMT_ASCII; + mflCookie->s.enumerate.cursor.lastZidReturned = zINVALID_ZID; + mflCookie->s.enumerate.isMFLincomplete = FALSE; + mflCookie->s.enumerate.done = FALSE; + + /* send out the start tag */ + strcpy(mflCookie->resultBuf, MSGNot("<"TAG_NSSREPLY">\n<" + TAG_MODIFIEDFILELIST">\n")); + mflCookie->resultLen = strlen(mflCookie->resultBuf); + } + else if ((mflCookie->currentOp != MFL_OP_ENUMERATE) || + ((mflCookie->currentOp == MFL_OP_ENUMERATE) && + mflCookie->s.enumerate.done)) + { + if (mflCookie->resultLen == 0) + { + mflCookie->currentOp = MFL_OP_END; + } + goto done; + } + + /* We reach here only if there is an unfinished MFL enumeration */ + zASSERT((mflCookie->currentOp == MFL_OP_ENUMERATE) && + ! mflCookie->s.enumerate.done); + + /* allocate memory for return data and for path */ + mflEntries = malloc((MAX_MFL_ENTRIES_PER_SCOOP * sizeof(MFLEntry_s)) + + zMAX_FULL_NAME); + if (! mflEntries) + { + status = zERR_NO_MEMORY; + goto sendRetcode; + } + path = (BYTE *)(mflEntries) + (MAX_MFL_ENTRIES_PER_SCOOP * sizeof(MFLEntry_s)); + + /* Obtain the volume ptr */ + memcpy(aStack->volName, parm, parmLen); + aStack->volName[parmLen] = 0; + if ((status = findVolume(aStack->volName, &volume)) != zOK) + { + status = zERR_VOLUME_NOT_FOUND; + goto sendRetcode; + } + if (COMN_LockVolumeActive(&genMsg, volume, FALSE) != zOK) + { + status = GetErrno(&genMsg); + COMN_Release(&volume); + goto sendRetcode; + } + + /* Check if there is an actively maintained MFL for this volume */ + if (! SBS_MFL_ENABLED(volume)) + { + status = zERR_MFL_NOT_ENABLED; + COMN_UnlockVolumeActive(volume, FALSE); + COMN_Release(&volume); + goto sendRetcode; + } + + COMN_USE_BEAST(&volume->VOLroot); + COMN_INIT_NAMING_MSG(&aStack->nameMsg); + COMN_SET_NAMING_MSG_VOLUME(&aStack->nameMsg, volume); + COMN_STRUCT_INIT(aStack->gfnMsg); + COMN_SETUP_GET_NAME_MSG(&aStack->gfnMsg, zGFN_INCLUDE_PATH, 0, + mflCookie->s.enumerate.pathFormat, + mflCookie->s.enumerate.nameSpaceID, &aStack->nameBuffer, + sizeof(zGetName_s)); + + while (bufBytesLeft > 0) + { + numEntriesRequested = MAX_MFL_ENTRIES_PER_SCOOP; + if (volume->VOLcomnVolOps.VOL_enumerateMFL(&genMsg, volume, + (mflCookie->s.enumerate.isDynamic ? + (volume->VOLepoch + 1) : volume->VOLepoch), + numEntriesRequested, + &mflCookie->s.enumerate.cursor.lastZidReturned, + mflEntries, &numEntriesObtained, &mflIncompleteFlag) != zOK) + { + if (GetErrno(&genMsg) != zERR_ZID_NOT_FOUND) + { + status = GetErrno(&genMsg); + goto errorReleaseNameMsg; + } + ClearErrno(&genMsg); + mflCookie->s.enumerate.done = TRUE; + } + + mflCookie->s.enumerate.isMFLincomplete = + mflCookie->s.enumerate.isMFLincomplete || mflIncompleteFlag; + + for (i = 0; i < numEntriesObtained; ++i) + { + COMN_SETUP_NAMING_MSG_VOLUME_ZID( &aStack->nameMsg, volume->volumeID, + /* cnt zFNU_FIRST_PARENT,*/ zINVALID_ZID, mflEntries[i].key.zid, + mflEntries[i].key.zid, SLATCHED, + mflCookie->s.enumerate.nameSpaceID, zNTYPE_FILE, + NULL); + status = COMN_GetName(&genMsg, &aStack->nameMsg, &aStack->gfnMsg); + COMN_UNLATCH_AND_RELEASE_NAMEMSG_BEASTS_KEEP_LATCHTYPE(&aStack->nameMsg); + aStack->nameMsg.parseFlags &= ~NAMPFL_nameMsgFullyResolved; + if ((status != zOK) && (GetErrno(&genMsg) != zERR_ZID_NOT_FOUND)) + { + status = GetErrno(&genMsg); + goto errorReleaseNameMsg; + } + status = zOK; + mflCookie->s.enumerate.cursor.lastZidReturned = mflEntries[i].key.zid; + sprintf(mflCookie->resultBuf + mflCookie->resultLen, + MSGNot("<" TAG_FILE "><" TAG_NAME ">%s<" + TAG_ID ">%Ld\n"), + &aStack->nameBuffer.variableData[0], + mflEntries[i].key.zid); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + if (sendResult(mflCookie, &bufBytesLeft, &outBuf, retLen)) + { + break; + } + } + + /* Normal end of enumeration */ + if ((numEntriesObtained == 0) || mflCookie->s.enumerate.done) + { + mflCookie->s.enumerate.done = TRUE; + sprintf(mflCookie->resultBuf + mflCookie->resultLen, + MSGNot("<" TAG_STATUS " " ATR_COMPLETE "=\"%s\"/>\n\n"), + mflCookie->s.enumerate.isMFLincomplete + ? MSGNot("no") : MSGNot("yes")); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + MGMT_BuildResultNSS(status, + mflCookie->resultBuf + mflCookie->resultLen); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + sprintf(mflCookie->resultBuf + mflCookie->resultLen, + MSGNot("\n")); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + sendResult(mflCookie, &bufBytesLeft, &outBuf, retLen); + break; + } + } + COMN_CleanupNameMsg(&genMsg, &aStack->nameMsg); + COMN_Release(&volume); + free(mflEntries); + +done: + MPKNSS_UNLOCK(); + STACK_FREE(); + return zOK; + +errorReleaseNameMsg: + COMN_CleanupNameMsg(&genMsg, &aStack->nameMsg); + COMN_Release(&volume); + +sendRetcode: + /* send the error code */ + sprintf(mflCookie->resultBuf + mflCookie->resultLen, + MSGNot("\n")); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + MGMT_BuildResultNSS(status, + mflCookie->resultBuf + mflCookie->resultLen); + mflCookie->resultLen += strlen(mflCookie->resultBuf + mflCookie->resultLen); + sprintf(mflCookie->resultBuf + mflCookie->resultLen, + MSGNot("\n")); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + sendResult(mflCookie, &bufBytesLeft, &outBuf, retLen); + + /* Reset state and get ready to perform next operation */ + mflCookie->currentOp = MFL_OP_END; + if (mflEntries) + { + free(mflEntries); + } + MPKNSS_UNLOCK(); + STACK_FREE(); + return zOK; +} + +/**************************************************************************** + * Parse the MFL operation from the XML + ****************************************************************************/ +STATIC STATUS +parseMFLOp( + GeneralMsg_s *genMsg, + XML_ElementInfo_s *element, + MFLControlCookie_s *mflCookie) +{ + XML_ElementInfo_s elementInfo; + utf8_t *tagName; + NINT tagLen; + + if (XML_GetNextTag(element->dataStart, element->dataEnd, &elementInfo, + &tagName, &tagLen) != zOK) + { + goto badFormat; + } + if (memcmp(tagName, MSGNot(TAG_LISTMFL), tagLen) == 0) + { + /* Initialize the cookie */ + mflCookie->currentOp = MFL_OP_ENUMERATE; + mflCookie->s.enumerate.isDynamic = TRUE; + mflCookie->s.enumerate.nameSpaceID = zNSPACE_LONG; + mflCookie->s.enumerate.pathFormat = zPFMT_ASCII; + mflCookie->s.enumerate.cursor.lastZidReturned = zINVALID_ZID; + mflCookie->s.enumerate.isMFLincomplete = FALSE; + mflCookie->s.enumerate.done = FALSE; + if (XML_GetTagAttribute(MSGNot(ATR_NAMESPACE), &elementInfo) == zOK) + { + if (memcmp(MSGNot("zNSPACE_DOS"), elementInfo.attributeValueStart, + elementInfo.attributeValueEnd - + elementInfo.attributeValueStart + 1) == 0) + { + mflCookie->s.enumerate.nameSpaceID = zNSPACE_DOS; + } + else if (memcmp(MSGNot("zNSPACE_MAC"), elementInfo.attributeValueStart, + elementInfo.attributeValueEnd - + elementInfo.attributeValueStart + 1) == 0) + { + mflCookie->s.enumerate.nameSpaceID = zNSPACE_MAC; + } + else if (memcmp(MSGNot("zNSPACE_UNIX"), elementInfo.attributeValueStart, + elementInfo.attributeValueEnd - + elementInfo.attributeValueStart + 1) == 0) + { + mflCookie->s.enumerate.nameSpaceID = zNSPACE_UNIX; + } + else if (memcmp(MSGNot("zNSPACE_LONG"), elementInfo.attributeValueStart, + elementInfo.attributeValueEnd - + elementInfo.attributeValueStart + 1) == 0) + { + mflCookie->s.enumerate.nameSpaceID = zNSPACE_LONG; + } + else + { + goto badFormat; + } + } +// if (XML_GetTagAttribute(MSGNot("pathFormat"), &elementInfo) == zOK) +// { +// if (memcmp(MSGNot("zPFMT_ASCII"), elementInfo.attributeValueStart, +// elementInfo.attributeValueEnd - +// elementInfo.attributeValueStart + 1) == 0) +// { +// mflCookie->s.enumerate.pathFormat = zPFMT_ASCII; +// } +// else if (memcmp(MSGNot("zPFMT_UTF8"), elementInfo.attributeValueStart, +// elementInfo.attributeValueEnd - +// elementInfo.attributeValueStart + 1) == 0) +// { +// mflCookie->s.enumerate.pathFormat = zPFMT_UTF8; +// } +// else if (memcmp(MSGNot("zPFMT_UNICODE"), elementInfo.attributeValueStart, +// elementInfo.attributeValueEnd - +// elementInfo.attributeValueStart + 1) == 0) +// { +// mflCookie->s.enumerate.pathFormat = zPFMT_UNICODE; +// } +// else +// { +// goto badFormat; +// } +// } +// if (XML_GetTagAttribute(MSGNot("isDynamic"), &elementInfo) == zOK) +// { +// if (memcmp(MSGNot("yes"), elementInfo.attributeValueStart, +// elementInfo.attributeValueEnd - +// elementInfo.attributeValueStart + 1) == 0) +// { +// mflCookie->s.enumerate.isDynamic = TRUE; +// } +// else +// { +// mflCookie->s.enumerate.isDynamic = FALSE; +// } +// } + } + else if (memcmp(tagName, MSGNot(TAG_GETSTATUSMFL), tagLen) == 0) + { + mflCookie->currentOp = MFL_OP_GET_STATUS; + } + else if (memcmp(tagName, MSGNot(TAG_VERIFYMFL), tagLen) == 0) + { + mflCookie->currentOp = MFL_OP_VERIFY; + } + else if (memcmp(tagName, MSGNot(TAG_REPAIRMFL), tagLen) == 0) + { + mflCookie->currentOp = MFL_OP_REPAIR; + } + else + { + mflCookie->currentOp = MFL_OP_END; + SetErrno(genMsg, zERR_BAD_TRANSFORMATION); + return zFAILURE; + } + return zOK; + +badFormat: + SetErrno(genMsg, zERR_BAD_TRANSFORMATION); + return zFAILURE; +} + +/**************************************************************************** + * Generate the modified files list for this volume. + ****************************************************************************/ +/* VIRTUAL FILE -- WRITE FUNCTION */ +STATUS SBS_volumeMFLControlWriteFunc( + NINT parmLen, + utf8_t *parm, + NINT dataLen, + BYTE *data, + NINT offset, + VirtInfo_s *virtInfo) +{ + GeneralMsg_s genMsg; + MFLAdminParms_s adminParms; + STATUS status; + MFLControlCookie_s *mflCookie; + Volume_s *volume; + XML_ElementInfo_s element; + typedef struct Stack_s { + BYTE volName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + if ((status = MGMT_FindFirstElement(virtInfo, TAG_NSSREQUEST, dataLen, + data, offset, &element)) != zOK) + { + goto done; + } + + volume = NULL; + + if ((status = allocateCookie(virtInfo)) != zOK) + { + goto done; + } + + mflCookie = (MFLControlCookie_s *)virtInfo->memPtr; + mflCookie->currentOp = MFL_OP_END; + + /* send out the start tag */ + strcpy(mflCookie->resultBuf, MSGNot("<"TAG_NSSREPLY">\n<"TAG_MODIFIEDFILELIST">\n")); + mflCookie->resultLen = strlen(mflCookie->resultBuf); + + /* Obtain the volume ptr */ + memcpy(aStack->volName, parm, parmLen); + aStack->volName[parmLen] = 0; + if ((status = findVolume(aStack->volName, &volume)) != zOK) + { + status = zERR_VOLUME_NOT_FOUND; + goto sendReturnCode; + } + if (COMN_LockVolumeActive(&genMsg, volume, FALSE) != zOK) + { + status = GetErrno(&genMsg); + goto sendReturnCodeRelease; + } + + /* Check if there is an actively maintained MFL for this volume */ + if (!SBS_MFL_ENABLED(volume)) + { + status = zERR_MFL_NOT_ENABLED; + goto sendReturnCodeUnlock; + } + + if ((status = parseMFLOp(&genMsg, &element, mflCookie)) != zOK) + { + status = GetErrno(&genMsg); + goto sendReturnCodeUnlock; + } + + switch (mflCookie->currentOp) + { + case MFL_OP_NONE: + case MFL_OP_END: + case MFL_OP_ENUMERATE: + break; + case MFL_OP_GET_STATUS: + status = volume->VOLcomnVolOps.VOL_administerMFL(&genMsg, volume, + VOL_MFL_ADMIN_GET_STATUS_OP, &adminParms); + if (status == zOK) + { + sprintf(mflCookie->resultBuf + mflCookie->resultLen, + MSGNot("<"TAG_STATUS" "ATR_COMPLETE"=\"%s\"/>\n"), + adminParms.status.incomplete ? MSGNot("no") : MSGNot("yes")); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + } + break; + case MFL_OP_VERIFY: + status = volume->VOLcomnVolOps.VOL_administerMFL(&genMsg, volume, + VOL_MFL_ADMIN_VERIFY_OP, &adminParms); + if (status == zOK) + { + sprintf(&mflCookie->resultBuf[mflCookie->resultLen], + MSGNot("<"TAG_STATISTICS" " + ATR_NUMMODIFIEDFILES"=\"%lu\" " + ATR_NUMMISSINGENTRIES"=\"%lu\" " + ATR_NUMEXTRAENTRIES"=\"%lu\"/>\n"), + adminParms.verifyStats.numModifiedFiles, + adminParms.verifyStats.numMissingEntries, + adminParms.verifyStats.numExtraEntries); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + } + break; + case MFL_OP_REPAIR: + status = volume->VOLcomnVolOps.VOL_administerMFL(&genMsg, volume, + VOL_MFL_ADMIN_FIX_OP, &adminParms); + if (status == zOK) + { + sprintf(&mflCookie->resultBuf[mflCookie->resultLen], + MSGNot("<"TAG_STATISTICS" " + ATR_NUMMODIFIEDFILES"=\"%lu\" " + ATR_NUMMISSINGENTRIES"=\"%lu\" " + ATR_NUMEXTRAENTRIES"=\"%lu\" " + ATR_NUMADDERRORS"=\"%ld\" " + ATR_NUMDELETEERRORS"=\"%ld\"/>\n"), + adminParms.verifyStats.numModifiedFiles, + adminParms.verifyStats.numMissingEntries, + adminParms.verifyStats.numExtraEntries, + adminParms.verifyStats.numAddErrors, + adminParms.verifyStats.numDeleteErrors); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + } + break; + default: + SetErrno(&genMsg, zERR_NOT_SUPPORTED); + status = zFAILURE; + break; + } + +sendReturnCodeUnlock: + COMN_UnlockVolumeActive(volume, FALSE); +sendReturnCodeRelease: + COMN_Release(&volume); +sendReturnCode: + if (mflCookie->currentOp != MFL_OP_ENUMERATE || status != zOK) + { + sprintf(mflCookie->resultBuf + mflCookie->resultLen, + MSGNot("\n")); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + MGMT_BuildResultNSS(status, + mflCookie->resultBuf + mflCookie->resultLen); + mflCookie->resultLen += strlen(mflCookie->resultBuf + mflCookie->resultLen); + sprintf(mflCookie->resultBuf + mflCookie->resultLen, + MSGNot("\n")); + mflCookie->resultLen += strlen(mflCookie->resultBuf + + mflCookie->resultLen); + status = zOK; + } +done: + MPKNSS_UNLOCK(); + STACK_FREE(); + return status; +}