diff --git a/include/nwnss/comnSA/psslib.h b/include/nwnss/comnSA/psslib.h new file mode 100644 index 0000000..8c9879e --- /dev/null +++ b/include/nwnss/comnSA/psslib.h @@ -0,0 +1,78 @@ +/**************************************************************************** + | + | (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: taysom $ + | $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $ + | + | $RCSfile$ + | $Revision: 465 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | NSS Library routine + | + | WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! + | + | This header file should ONLY be used for NSS internal development. + | This includes Semantic Agents (SA) and Loadable Storage Services (LSS). + | Any other use may cause conflicts which NSS will NOT fix. + +-------------------------------------------------------------------------*/ +#ifndef _PSSLIB_H_ +#define _PSSLIB_H_ + +#ifndef _OMNI_H_ +#include +#endif + +/* Pre-declare the following structure(s) */ +struct ScreenStruct; + +#ifdef __cplusplus +extern "C" { +#endif + +/* use rand in STDLIB.H +extern void seed(long seed); +extern NINT rnd(NINT range); +*/ + +extern void SetStdioScreenID( + struct ScreenStruct *screenID); + +extern NINT GetInstLen( + BYTE *instruction, + NINT *instType); + +#define INSTTYPE_NORMAL 0 +#define INSTTYPE_PCRELATIVE32 1 +#define INSTTYPE_PCRELATIVE16 2 +#define INSTTYPE_PCRELATIVE8 3 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/nwnss/include/mal.h b/include/nwnss/include/mal.h new file mode 100644 index 0000000..17f2ec5 --- /dev/null +++ b/include/nwnss/include/mal.h @@ -0,0 +1,120 @@ +/**************************************************************************** + | + | (C) Copyright 1995 - 2000 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) support module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2007-05-04 03:01:42 +0530 (Fri, 04 May 2007) $ + | + | $RCSfile$ + | $Revision: 1971 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | + | + | + | WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! + | + | This header file should ONLY be used for NSS internal development. + | This includes Semantic Agents (SA) and Loadable Storage Services (LSS). + | Any other use may cause conflicts which NSS will NOT fix. + +-------------------------------------------------------------------------*/ +#ifndef _MAL_H_ +#define _MAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +/*- MAL basic defines + | + | These are basic defines to determine the size of common items + | + +-------------------------------------------------------------------------*/ +#define MAL_ONEKBYTES 1024 +#define MAL_ONEMEG 0x00100000 + +#define MAL_BLKSHFT512 9 +#define MAL_BLKSHFT4K 12 +#define MAL_BLKSHFT64K 16 + +#define MAL_BUFSZ512 (1 << MAL_BLKSHFT512) +#define MAL_BUFSZ4K (1 << MAL_BLKSHFT4K) +#define MAL_BUFSZ64K (1 << MAL_BLKSHFT64K) + +#define MAL_DEFAULTBLKSIZE 4096 +#define MAL_STDUNITSIZE 512 +#define MAL_UNITSPER1MEG 2048 +#define MAL_BLKSPER1MEG 256 + +#define MAL_UNITSPERBLK 8 + +#define POOL_MAXNAME 64 +#define MAL_MAXNAME 64 /*- max. size of a pool name -*/ + + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +/*- Deposit Message Type Defined + | + | + +-------------------------------------------------------------------------*/ +typedef struct Deposit_s +{ + struct block_device *dp_dev; /* Linux block device structure */ + LONG unitsize; /*- smallest IO unit size in bytes -*/ + QUAD sizeinunits; /*- number of units for this storage deposit -*/ + LONG sizeinmeg; /*- number of meg for this storage deposit -*/ + GUID_t guid; /*- GUID (128 bits) when storage was created -*/ + void *dp_inode; /* pointer to a root inode on the pool */ + unicode_t name[MAL_MAXNAME]; + unicode_t snapname[MAL_MAXNAME]; +} Deposit_s; + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + +extern LONG MAL_RemoveDeposit (struct block_device *dev); +extern LONG MAL_ForwardDepositToConsumer(struct block_device *dev, LONG unitSize, char *poolName, LONG flags, char *snapname, void *inode); +#define ZLSS_DEV_FLAG_SHARED 0x00000001 +#define ZLSS_DEV_FLAG_BARRIER 0x00000002 +#define ZLSS_DEV_FLAG_SNAPSHOT 0x00000004 +#define ZLSS_DEV_FLAG_NEW 0x00000008 +extern LONG MAL_CreateDeposit (struct block_device *dev, LONG unitSize, char *poolName); + +extern STATUS MAL_GetPoolNameFromDevice (struct block_device *dev, char *poolName, NINT poolNameSize); + +extern STATUS ZLSS_GetPoolDev(unicode_t *uniName, struct block_device **dev); +extern STATUS ZLSS_SetPoolSize(struct block_device *dev, QUAD newSize); +extern STATUS ZLSS_SetPoolShared(struct block_device *dev, BOOL sharedstate); + +#ifdef __cplusplus +} +#endif + +#endif /* _MAL_H_ */ diff --git a/include/nwnss/include/nssOSAPIs.h b/include/nwnss/include/nssOSAPIs.h index b8141eb..a3c432c 100644 --- a/include/nwnss/include/nssOSAPIs.h +++ b/include/nwnss/include/nssOSAPIs.h @@ -43,6 +43,16 @@ #ifndef _NSSOSAPIS_H_ #define _NSSOSAPIS_H_ +#ifdef MARS_NWE_NWNSS_USERSPACE +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(_major, _minor, _patch) \ + (((_major) << 16) + ((_minor) << 8) + (_patch)) +#endif +#ifndef LINUX_VERSION_CODE +#define LINUX_VERSION_CODE 0 +#endif +#endif + #ifndef _ZOMNI_H_ # include #endif diff --git a/include/nwnss/include/zasAuthCache.h b/include/nwnss/include/zasAuthCache.h new file mode 100644 index 0000000..85bbc0e --- /dev/null +++ b/include/nwnss/include/zasAuthCache.h @@ -0,0 +1,143 @@ +/**************************************************************************** + | + | (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: randys $ + | $Date: 2005-08-05 01:19:13 +0530 (Fri, 05 Aug 2005) $ + | + | $RCSfile$ + | $Revision: 1166 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Defines structures used to cache file names in memory + +-------------------------------------------------------------------------*/ +#ifndef _ZASAUTHCACHE_H_ +#define _ZASAUTHCACHE_H_ + +#ifndef _OMNI_H_ +#include +#endif + +#ifndef _MSGGEN_H_ +#include +#endif + +#ifndef _ZASAUTHMODEL_H_ +#include "zasAuthModel.h" +#endif + + + +/*------------------------------------------------------------------------- + * This is the authorization cache node structure. One of these structures is + * maintained in memory for each entry in the cache. + *-------------------------------------------------------------------------*/ +typedef struct EffectiveACL_s +{ /* This is is the effective ACL structure used by the authorization cache. */ + LONG numEntries; /* number of entries in use */ + ACLEntry_s entry[1]; +} EffectiveACL_s; + + +typedef struct AuthCacheNode_s +{ + LONG signature; /* identifing field for entry */ + DQlink_t hashLink; /* hash list link field */ + DQlink_t LRUlink; /* LRU link field */ + NINT hashValue; /* computed full hash for this entry */ + DomainID_t domainID; /* directory services domain for this entry */ + EffectiveACL_s EACL; /* effective ACL being cached */ +} AuthCacheNode_s; + +/*------------------------------------------------------------------------- + * This is the control structure for the AuthCache. The AuthCache is + * global for the entire system. + *-------------------------------------------------------------------------*/ +typedef struct AuthCacheCtrl_s +{ + Latch_s latch; /* latch to control changes in this structure */ + NINT activationCount; /* number of volumes using the cache */ + NINT hashMask; /* and MASK used to index into hash */ + DQhead_t (*hash)[]; /* pointer to hash array */ + DQhead_t LRUqueue; /* head of the Least Recently Used queue */ + NINT maxEntries; /* max allowed entries are in the cache */ + NINT numEntries; /* number of entries in the cache */ + NINT signatureCount; /* the count used to create signatures */ + NINT resetCount; /* this count is incremented each time the + cache is reset. It should be incremented + before the actual reset occurs */ +} AuthCacheCtrl_s; + +extern AuthCacheCtrl_s AuthCache; /* control head for the name hash*/ + +/*------------------------------------------------------------------------- + * + * DEFINES + * + *-------------------------------------------------------------------------*/ + +#define MIN_AUTH_CACHE_SIZE 16 /* The minimum number of entries in the */ + /* authorization cache. */ +#define DEFAULT_AUTH_CACHE_SIZE 1024 /* The maximum number of entries in the */ + /* authorization cache. */ +#define MAX_AUTH_CACHE_SIZE 50000 /* The maximum number of entries in the */ + /* authorization cache. */ +#define HASH_TABLE_SIZE 1024 /* Size of the hash table (must be a power of 2)*/ + /* If you change this size change the hash algorithm */ + +#define EACL_SIZE(numACLs) \ + (sizeof(AuthCacheNode_s) + (sizeof(ACLEntry_s) * ((numACLs) - 1))) + +#define EACL_GROW_AMOUNT 10 + +/*------------------------------------------------------------------------- + * Functions for manipulating the name cache. + *-------------------------------------------------------------------------*/ +extern STATUS ZAS_CacheInit( + GeneralMsg_s *genMsg); + +extern void ZAS_CacheUninit(void); + +extern AuthCacheNode_s *ZAS_GetEACLCacheEntry( + NINT cacheIndex, + NINT signature); + +extern AuthCacheNode_s *ZAS_AddEACLCacheEntry( + struct AuthCacheNode_s *newEntry, + NINT inputResetCount, + LONG *cacheIndex); + +extern void ZAS_RemoveEACLCacheEntry( + NINT cacheIndex, + NINT signature); + +#if NSS_DEBUG IS_ENABLED +extern void ZAS_DisplayCache(void); +extern NINT AuthResets; +extern NINT AuthPartialResets; +#endif + +#endif /* _ZASAUTHCACH_H_ */ diff --git a/include/nwnss/internal/unixAuthModel.h b/include/nwnss/internal/unixAuthModel.h new file mode 100644 index 0000000..6aa39f3 --- /dev/null +++ b/include/nwnss/internal/unixAuthModel.h @@ -0,0 +1,172 @@ +/**************************************************************************** + | + | (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) Initialization module + | + |--------------------------------------------------------------------------- + | + | $Author: taysom $ + | $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $ + | + | $RCSfile$ + | $Revision: 465 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | This module defines the unix authorization system. + +-------------------------------------------------------------------------*/ +#ifndef _UXASAUTHMODEL_H_ +#define _UXASAUTHMODEL_H_ + +#ifndef _OMNI_H_ +#include +#endif + +#ifndef _LATCH_H_ +#include +#endif + +#ifndef _COMNBEASTS_H_ +#include "comnBeasts.h" +#endif + +#ifndef _COMNAUTHORIZE_H_ +#include "comnAuthorize.h" +#endif + +/*------------------------------------------------------------------------- + * Defines + *-------------------------------------------------------------------------*/ +#define UXAS_CURRENT_AUTH_VERSION 1 + +/* Unix mode bit definitions */ +#define UX_IXOTH 0x0001 /* other - execute */ +#define UX_IWOTH 0x0002 /* other - write */ +#define UX_IROTH 0x0004 /* other - read */ +#define UX_IXGRP 0x0010 /* group - execute */ +#define UX_IWGRP 0x0020 /* group - write */ +#define UX_IRGRP 0x0040 /* group - read */ +#define UX_IXUSR 0x0100 /* owner - execute */ +#define UX_IWUSR 0x0200 /* owner - write */ +#define UX_IRUSR 0x0400 /* owner - read */ +#define UX_ISVTX 0x1000 /* sticky bit */ +#define UX_ISGID 0x2000 /* set group ID on execution */ +#define UX_ISUID 0x4000 /* set user ID on execution */ + +#define UX_IRWXO 0x0007 /* mask for "other" */ +#define UX_IRWXG 0x0070 /* mask for "group" */ +#define UX_IRWXU 0x0700 /* mask for "owner" */ + +#define UX_IX 0x0001 /* execute */ +#define UX_IW 0x0002 /* write */ +#define UX_IR 0x0004 /* read */ + +#define UX_IMO 0 /* shift factor for other/world */ +#define UX_IMG 4 /* shift factor for group */ +#define UX_IMU 8 /* shift factor for user/owner */ + + +/*------------------------------------------------------------------------- + * Macros + *-------------------------------------------------------------------------*/ +typedef struct UXASPersistentAuthInfo_s +{ /* this is a space for the z authorization system to use */ + WORD version; /* the version of the authorization layout */ + WORD extra1; /* alignment space */ + LONG mode; /* see above (UX_*) */ + UserID_t groupID; + LONG unused[8]; +} NSS_MEDIA_STRUCTURE(UXASPersistentAuthInfo_s,unused[8]) UXASPersistentAuthInfo_s; + +typedef struct UXASAuthorizeInfo_s +{ /* Unix authorization model */ + UXASPersistentAuthInfo_s p; +} UXASAuthorizeInfo_s; + +/*------------------------------------------------------------------------- + * Public Structures for the authorization model + *-------------------------------------------------------------------------*/ +extern struct AuthModelOps_s UXASAuthorizeModelOps; +extern NINT UXASAuthorizeStarted; +extern NINT UX_InitialMode; + +/*------------------------------------------------------------------------- + * + * Function prototypes for the Unix authorization model + * + *-------------------------------------------------------------------------*/ + +STATUS UXAS_Startup(void); +void UXAS_Shutdown(void); + +STATUS UXAUTH_ConstructAuthBeast( + struct GeneralMsg_s *genMsg, + struct AuthBeast_s *authBeast); + +void UXAUTH_DestructAuthBeast( + struct AuthBeast_s *authBeast); + +NINT UXAUTH_PackedSize( + struct AuthBeast_s *authBeast); + +BYTE *UXAUTH_PackAuthBeast( + struct AuthBeast_s *authBeast, + BYTE *storeBuffer); + +void UXAUTH_NoPackAuthBeastCleanup( + struct AuthBeast_s *authBeast); + +BYTE *UXAUTH_UnpackAuthBeast( + struct GeneralMsg_s *genMsg, + struct AuthBeast_s *authBeast, + BYTE *storeBuffer); + +STATUS UXAS_ChangeOwner( + struct GeneralMsg_s *genMsg, + struct NamingMsg_s *nameMsg, + struct AuthBeast_s *beast, + UserID_t *newOwner); + +STATUS UXAS_ChangeGroup( + struct AuthBeast_s *beast, + UserID_t *newGroup); + +STATUS UXAS_ChangeMode( + struct AuthBeast_s *beast, + NINT mode); + +STATUS UXAS_GetAuthInfo( + struct AuthBeast_s *beast, + UserID_t *groupID, + NINT *mode); + +void UXAS_StoreIDInGUID( + NINT id, + UserID_t *guid); + +NINT UX_GetEffectivePermissions( + struct AuthBeast_s *authBeast, + UserID_t *IDs, + NINT numIDs, + NINT *mode); + +#endif /* _ZASAUTHMODL_H_ */ diff --git a/include/nwnss/public/nfsAPIs.h b/include/nwnss/public/nfsAPIs.h new file mode 100644 index 0000000..4ad568f --- /dev/null +++ b/include/nwnss/public/nfsAPIs.h @@ -0,0 +1,56 @@ +/**************************************************************************** + | + | (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: vandana $ + | $Date: 2006-10-31 02:59:05 +0530 (Tue, 31 Oct 2006) $ + | + | $RCSfile$ + | $Revision: 1585 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Defines to be used with the NFS APIs for the NFS Semantic Agent. + | + | For compelete documentation, see "NFS Illustrated" by Brent Callaghan, + | Addison-Wesley, 2000, ISBN 0-201-32570-5. + | + | WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! + | + | This header file should ONLY be used for NSS internal development. + | This includes Semantic Agents (SA) and Loadable Storage Services (LSS). + | Any other use may cause conflicts which NSS will NOT fix. + +-------------------------------------------------------------------------*/ + +#ifndef _NFSAPIS_H_ +#define _NFSAPIS_H_ + +typedef struct NFSHandle_s +{ + Zid_t zid; /* zid of the file */ + VolumeID_t volID; /* Id of the volume (a GUID) */ +} NFSHandle_s; + +#endif diff --git a/include/nwnss/public/nfsLock.h b/include/nwnss/public/nfsLock.h new file mode 100644 index 0000000..4ece02b --- /dev/null +++ b/include/nwnss/public/nfsLock.h @@ -0,0 +1,265 @@ +/**************************************************************************** + | + | (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: taysom $ + | $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $ + | + | $RCSfile$ + | $Revision: 465 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Define data structures used by NFS Lock Manager (NLM). + | + | WARNING! WARNING! WARNING! WARNNG! WARNING! WARNING! WARNING! WARNING! + | + | This header file should ONLY be used for NSS internal development. + +-------------------------------------------------------------------------*/ + + +#ifndef _NFSLOCKS_H_ +#define _NFSLOCKS_H_ + +#ifndef _STDDEF_H_ +# include +#endif +#ifndef _OMNI_H_ +# include +#endif + +#ifndef _NFSAPIS_H_ +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum LkMgrStat_t +{ + LKMGR_GRANTED, + LKMGR_DENIED, + LKMGR_DENIED_NOLOCKS, + LKMGR_BLOCKED, + LKMGR_DENIED_GRACE_PERIOD, + LKMGR_DEADLCK, + LKMGR_ROFS, + LKMGR_STALE_FH, + LKMGR_FBIG, + LKMGR_FAILED +} LkMgrStat_t; + + +typedef enum FshMode_t +{ + FSM_DN, /* Deny None */ + FSM_DR, /* Deny Read */ + FSM_DW, /* Deny Write */ + FSM_DRW /* Deny Read and Write */ +} FshMode_t; + + +typedef enum FshAccess_t +{ + FSA_NONE, /* No access */ + FSA_R, /* Read access */ + FSA_W, /* Write access */ + FSA_RW /* Read/Write access */ +} FshAccess_t; + + +typedef struct NetObj_s +{ + LONG length; + LONG data[1]; /* Opaque data, variable length */ +} NetObj_s; + + +/* + * In the NLM version 3 protocol, the length and offset are 32 bits wide, while + * they are 64 bits wide in the NLM version 4 protocol. NLM version 3 should + * cast them to 64 bits. + */ +typedef struct LkMgrLock_s +{ + BYTE *callerName; /* NULL terminated byte string, case insensitive */ + NFSHandle_s *fh; + NetObj_s *oh; + LONG svid; + QUAD offset; + QUAD len; +} LkMgrLock_s; + + +/*----------------------------------------------------------------------------------* + *----------------------------------------------------------------------------------*/ + +/************************************************************************************ + * Checks if a lock is available to the client. * + * Input: * + * testAccess: TRUE: Test if the client could get access (sharable) to the lock* + * FALSE: Test if there's a lock existing in the requested region * + * alock: the monitored lock that is being tested. * + * Output (only will be filled when status is LKMGR_DENIED): * + * isExclusive:TRUE if the conflicting lock is exclusively held * + * svid: the process id of the lock holder. If the lock holder is a NCP/ * + * Windows client, it will be set to 0. * + * oh: a pointer to lock holder's owner. If the lock holder is a NCP/ * + * Windows client, it will be set to NULL. * + * offset: the conflicting lock's byte offset * + * len: length, in bytes of the conflicting lock. * + ************************************************************************************/ +STATUS LkMgrTest( + BOOL testAccess, + LkMgrLock_s *alock, + BOOL *isExclusive, + LONG *svid, + NetObj_s **oh, + QUAD *offset, + QUAD *len); + + +/************************************************************************************ + * Creates a locked byte range on a file * + * Note: * + * 1: If a callback is supplied, the granted lock (either granted immediately or * + * blocked then granted later) will always be returned through callback * + * function, while this function returns LKMGR_BLOCKED. This also implies that * + * if input parameter "block" is TRUE, callback is a valid value. * + * 2: This function will make a local copy all the necessary information. Caller * + * can release its related memory if it chooses to do so * + ************************************************************************************/ +STATUS LkMgrLock( + NetObj_s *cookie, /* NULL terminated byte string */ + BOOL block, + BOOL isExclusive, + LkMgrLock_s *alock, + SLONG state, + NINT *callerCount, + void *callback( + STATUS status, + NetObj_s *cookie, + BOOL block, + BOOL isExclusive, + NINT callerCount, + LkMgrLock_s *alock)); + + +/******************************************************************************** + * Lock Manager will search all the locks on the requested file. * + * return: LCK_GRANTED if lock is found and removed from the waiting list * + * LCK_DENIED if lock couldn't be found from the waiting list. * + * Note: if a lock is granted after client sends the cancel request but before * + * server receives it, a LCK_DENIED will be returned. client should * + * try to call LkMgrUnlock instead * + ********************************************************************************/ +STATUS LkMgrCancel( + BOOL block, + BOOL isExclusive, + LkMgrLock_s *alock); + + +/******************************************************************************** + * Lock Manager will search all the locks on the requested file. * + * return: LCK_GRANTED if lock is found and removed from the locking list * + * LCK_DENIED if lock couldn't be found from the locking list or it is * + * still in the waiting state. * + * Note: client should call this routine if it knows the lock is granted * + ********************************************************************************/ +STATUS LkMgrUnlock( + LkMgrLock_s *alock, + NINT *callerCount); + + +/******************************************************************************** + * Creates a SHARE reservation on a file. * + ********************************************************************************/ +STATUS LkMgrShare( + BYTE *callerName, /* NULL terminated byte string */ + NFSHandle_s *fh, + NetObj_s *oh, + FshMode_t mode, + FshAccess_t access); + + +/******************************************************************************** + * Removes a SHARE reservation on a file. * + ********************************************************************************/ +STATUS LkMgrUnshare( + BYTE *callerName, /* NULL terminated byte string */ + NFSHandle_s *fh, + NetObj_s *oh, + FshMode_t mode, + FshAccess_t access); + + +/******************************************************************************** + * Creates a nonmonitored byte-range lock on a file. * + ********************************************************************************/ +STATUS LkMgrNmLock( + BOOL block, + BOOL isExclusive, + LkMgrLock_s *alock, + SLONG state); + + +/******************************************************************************** + * Clients has lost lock state and all server locks owned by this client * + * should be freed. (This also includes to release all the share reservations * + * created by this client). * + ********************************************************************************/ +void LkMgrFreeAll( + BYTE *callerName); /* NULL terminated byte string */ + + +/******************************************************************************** + * Clients has lost lock state and all server locks owned by this client * + * with state lower than the specified number should be freed. (This also * + * includes to release all the share reservations created by this client). * + ********************************************************************************/ +void LkMgrFreeAllWithState( + BYTE *callerName, /* NULL terminated byte string */ + SLONG state); + +void LkMgrCleanup(); + + +/*-------------------------------------------------------------------------------*/ +void displayLkMgrStats(); +void cleanupLkMgrStats(); +void startLkMgrBgCleanupThread(); + +STATUS initLkMgr(); +void uninitLkMgr(); + +NINT nssToLkMgrError (NINT status); + +#ifdef __cplusplus +} +#endif + +#endif /* _NFSLOCKS_H_ */ diff --git a/include/nwnss/support/lnxmbINC/aesproc.h b/include/nwnss/support/lnxmbINC/aesproc.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/include/nwnss/support/lnxmbINC/aesproc.h @@ -0,0 +1 @@ + diff --git a/include/nwnss/support/lnxmbINC/command.h b/include/nwnss/support/lnxmbINC/command.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/include/nwnss/support/lnxmbINC/command.h @@ -0,0 +1 @@ + diff --git a/include/nwnss/support/lnxmbINC/fsproto.h b/include/nwnss/support/lnxmbINC/fsproto.h new file mode 100644 index 0000000..11cbbc4 --- /dev/null +++ b/include/nwnss/support/lnxmbINC/fsproto.h @@ -0,0 +1,411 @@ +/**************************************************************************** + | + | (C) Copyright 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 + | + |***************************************************************************/ + +LONG GenerateAuditRecord( + LONG volumeNumber, + LONG eventTypeID, + LONG connectionID, /* ID of event initiator */ + LONG successFailureStatusCode, + ...); + +void ConvertNewTrusteeRightsToOld( + BYTE *accessRights, + BYTE macStationFlag, + LONG station, + LONG volume, + LONG directoryNumber, + LONG nameSpace); + +void ConvertOldTrusteeRightsToNew( + BYTE *accessRights, + BYTE macStationFlag); + +BYTE *FindLastComponent( + BYTE *componentString, + LONG componentCount); + +void AlertNCPSearchMapLost( + LONG Station); + +void BeginTrans( + LONG station, + LONG task, + LONG wtime, + void (*rplyf)()); + +LONG EndTrans( + LONG station, + LONG task); + +LONG LogPRec( + LONG station, + LONG hndle, + LONG start, + LONG length, + LONG flags, + LONG wtime, + void (*rplyf)(), + ...); + +void LogRec( + LONG station, + LONG task, + BYTE *string, + LONG flags, + LONG wtime, + void (*rplyf)()); + +LONG ClearFLocks( + LONG station, + LONG task, + LONG lastset); + +LONG INWReleaseFile( + LONG station, + LONG task, + LONG vol, + LONG dir); + +LONG INWClearFile( + LONG station, + LONG task, + LONG vol, + LONG dir); + +void LFileSet( + LONG station, + LONG task, + LONG wtime, + void (*rplyf)()); + +LONG RelFileSet( + LONG station, + LONG task, + LONG lastset); + +void INWLogFile( + LONG station, + LONG task, + LONG vol, + LONG dir, + BYTE *filename, + LONG flags, + LONG wtime, + void (*rplyf)()); + +LONG OpenEAHandle( + LONG Station, + LONG Task, + LONG OpenFlags, + LONG Flags, + LONG Volume, + LONG Handle, + LONG *EAHandle); + +LONG CloseEAHandle( + LONG Station, + LONG Task, + LONG eaHandle); + +LONG WriteEAData( + LONG Station, + LONG Task, + LONG eaHandle, + LONG TotalDataLength, + LONG StartPosition, + LONG AccessFlag, + LONG KeySize, + BYTE *keyBuf, + LONG DataSize, + BYTE *inBuf, + LONG *BytesWritten); + +LONG ReadEAData( + LONG Station, + LONG Task, + LONG eaHandle, + LONG StartPosition, + LONG InspectSize, + LONG KeySize, + BYTE *Key, + BYTE *OutBuf, + LONG *TotalEALen, + WORD *CurrentLen, + LONG *AccessFlag, + LONG MaximumDataSize); + +LONG EnumEA( + LONG Station, + LONG Task, + LONG eaHandle, + LONG InfoLevel, + LONG StartPosition, + LONG InspectSize, + LONG KeySize, + BYTE *Key, + BYTE *EnumBuf, + LONG *EnumBufSize, + WORD *NextPos, + LONG *TotalDataSizeOfEAs, + LONG *TotalEAs, + WORD *CurrentEAsInReply, + LONG *TotalKeySizeOfEAs, + LONG MaximumDataSize); + +LONG DupEA( + LONG Station, + LONG Task, + LONG srcTypeFlag, + LONG srcVolume, + LONG srcHandle, + LONG dstTypeFlag, + LONG dstVolume, + LONG dstHandle, + LONG *DupCount, + LONG *DupData, + LONG *DupKey); + +LONG GetCurrentDiskUsedAmount( + LONG volumeNumber, + LONG trusteeID); + +LONG VCStnLockStatus( + LONG station, + LONG BufferSize, + BYTE *buffer); + +LONG VCStnFiles( + LONG station, + LONG buffersize, + BYTE *buffer, + LONG next); + +LONG VCFileTasks( + BYTE vol, + LONG dir, + BYTE forktype, + LONG buffersize, + BYTE *buffer, + LONG next); + +LONG VCStnPhyLocks( + LONG station, + BYTE vol, + LONG dir, + BYTE forktype, + LONG buffersize, + BYTE *buffer, + LONG next); + +LONG VCFilePhyLocks( + BYTE vol, + LONG dir, + BYTE forktype, + LONG buffersize, + BYTE *buffer, + LONG next); + +LONG VCStnLRecs( + LONG station, + LONG buffersize, + BYTE *buffer, + LONG next); + +LONG VCLRecTasks( + BYTE length, + BYTE *name, + LONG buffersize, + BYTE *buffer, + LONG next); + +LONG VCStnSems( + LONG station, + LONG buffersize, + BYTE *buffer, + LONG next); + +LONG VCSemaphoreTasks( + LONG length, + BYTE *name, + LONG buffersize, + BYTE *buffer, + LONG next); + +LONG SCreateSemaphore( + LONG station, + LONG task, + BYTE *string, + LONG initial, + BYTE *repbuf); + +LONG SExamineSemaphore( + LONG station, + LONG task, + LONG semval, + BYTE *retbuf); + +void SPSemaphore( + LONG station, + LONG task, + LONG semval, + LONG wtime, + void (*rplyf)()); + +LONG SVSemaphore( + LONG station, + LONG task, + LONG semval); + +LONG SCloseSem( + LONG station, + LONG task, + LONG semval); + +void LockPRecSet( + LONG station, + LONG task, + LONG flags, + LONG wtime, + void (*rplyf)()); + +void LRecSet( + LONG station, + LONG task, + LONG flags, + LONG wtime, + void (*rplyf)()); + +void MultiLFileSet( + LONG station, + LONG task, + LONG wtime, + void (*rplyf)()); + +LONG TTSCheck(void); + +LONG TTrackOn( + LONG station, + LONG task); + +LONG TTrackOff( + LONG station, + LONG task, + BYTE *retbuf); + +LONG TTrackAbort( + LONG station, + LONG task); + +LONG TTSCheckTransaction( + LONG referenceNumber); + +LONG SetTTaskFlags( + LONG station, + LONG task, + LONG pthresh, + LONG lthresh); + +LONG GTTaskFlags( + LONG station, + LONG task, + BYTE *threshrets); + +LONG STTaskState( + LONG station, + LONG task, + LONG flags); + +void GTTaskState( + LONG station, + LONG task, + BYTE *threshrets); + +LONG SetTransFlags( + LONG station, + LONG pthresh, + LONG lthresh); + +void GTransFlags( + LONG station, + BYTE *threshrets); + +LONG RelPRecLocks( + LONG station, + LONG task, + LONG lastset, + LONG clrflag); + +LONG ReleasePRec( + LONG station, + LONG hndle, + LONG start, + LONG length, + LONG clrflag); + +void ResetStation( + LONG station, + LONG task); + +void ClearTemporaryDirectoryHandles( + LONG Station, + LONG Task); + +LONG ClearRLocks( + LONG station, + LONG task, + LONG lastset); + +LONG RelRecSet( + LONG station, + LONG task, + LONG lastset); + +LONG ReleaseRecord( + LONG station, + LONG task, + BYTE *string); + +LONG UnlockRec( + LONG station, + LONG task, + BYTE *string); + +LONG GetFileStatusInformation( + LONG Station, + LONG Task, + WORD Index, + LONG SourceBase, + LONG SearchAttributes, + BYTE *ModifierString, + BYTE *ReplyArea); + +LONG SetFileStatusInformation( + LONG Station, + LONG Task, + LONG Base, + BYTE *ModifierString, + BYTE SearchAttributes, + WORD fileAttributes, + LONG CreationDate, + LONG LastAccessedDate, + LONG LastUpdatedDateAndTime, + LONG OwnerID); diff --git a/include/nwnss/support/lnxmbINC/lanconf.h b/include/nwnss/support/lnxmbINC/lanconf.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/include/nwnss/support/lnxmbINC/lanconf.h @@ -0,0 +1 @@ + diff --git a/src/nwnss/CMakeLists.txt b/src/nwnss/CMakeLists.txt index a66f601..3d138c8 100644 --- a/src/nwnss/CMakeLists.txt +++ b/src/nwnss/CMakeLists.txt @@ -169,6 +169,29 @@ add_library(nwnss SHARED comn/namespace/extAttrNSpace.c comn/namespace/macNSpace.c nss/msg/msg.c + nssStartupNameGlobals.c + library/misc/lbVolume.c + library/os/currentTime.c + comn/common/volStartup.c + comn/common/comnDataStream.c + comn/common/nameLookup.c + comn/common/comnRename.c + comn/common/comnWild.c + comn/common/mgmtVol.c + comn/common/mgmtFiles.c + comn/common/cSAmanager.c + comn/common/cSAcache.c + comn/common/comnEFL.c + comn/common/comnLog.c + comn/common/checker.c + comn/common/ndpIdBrokerShared.c + comn/common/sysimpUserland.c + comn/main/comnCmdline.c + comn/authsys/authorize.c + comn/compression/cmActivity.c + comn/compression/cmBgCompress.c + comn/compression/cmAlgoMan.c + comn/compression/cmControl.c comn/common/temporaryComnStubs.c comn/namespace/dosNSWild.c nss/cache/asyncio.c diff --git a/src/nwnss/comn/authsys/authorize.c b/src/nwnss/comn/authsys/authorize.c new file mode 100644 index 0000000..42b0ba5 --- /dev/null +++ b/src/nwnss/comn/authsys/authorize.c @@ -0,0 +1,3783 @@ +/**************************************************************************** + | + | (C) Copyright 1999 - 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: taysom $ + | $Date: 2007-08-23 03:31:19 +0530 (Thu, 23 Aug 2007) $ + | + | $RCSfile$ + | $Revision: 2170 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | This defines the authorization module for PSS. We need to support + | multiple authorization modules. + +-------------------------------------------------------------------------*/ +#include /* netware includes*/ +#include +#include + +//#include /* NDS includes */ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "zParams.h" +#include "msgGen.h" +#include "volume.h" +#include "comnAuthorize.h" +#include "contextHandle.h" +#include "adminVolume.h" +#include "msgName.h" +#include "comnPublics.h" +#include "comnParams.h" +#include "searchMap.h" +#include "zasAuthModel.h" +#include "unixAuthModel.h" +#include "zasAuthSpace.h" +#include "comnBeasts.h" +#include "name.h" +#include "pssStartup.h" +#include "objectIDStore.h" +#include "pssConnection.h" +#include "ndp_idbroker.h" + + /* + * Instrumenation for authorization (what does it cost NSS to + * use NDS). + */ +typedef struct AuthInst_s +{ + struct + { + NINT enter; + NINT mapObj; + NINT resolveName; + NINT delay; + NINT added; + } id2guid; + struct + { + NINT enter; + NINT mapId; + NINT added; + } guid2id; +} AuthInst_s; + +AuthInst_s AuthInst; + +typedef struct ResolvePerf_s +{ + NINT start; + NINT diff; + NINT id; + NINT err; +} ResolvePerf_s; + +enum { MAX_PERF = 1024 }; + +ResolvePerf_s ResolvePerfLog[MAX_PERF]; +ResolvePerf_s *ResolvePerf = ResolvePerfLog; + +AuthModelBeast_s *AuthModels[MAX_AUTHORIZE_MODELS]; +AuthSpaceBeast_s *AuthSpaces[MAX_AUTHORIZE_MODELS][MAX_AUTHORIZE_SPACES]; + +AuthModelBeast_s *adminAuthModel = NULL; +AuthSpaceBeast_s *adminAuthSpace = NULL; + +#define GUID_CACHE_INVALIDATE_TIME 25*60*60 /* 1 day; one hour */ +#define I2G_NEGATIVE_CACHE_INVALIDATE_TIME 5*60 /* 5 minutes */ +NINT G2I_CacheInvalidateTime = GUID_CACHE_INVALIDATE_TIME; +void G2I_HandleAlarm(OneShot_s *alarm); + +NINT I2G_CacheInvalidateTime = GUID_CACHE_INVALIDATE_TIME; +NINT I2G_TotalIntervalDelay = 0; +void I2G_HandleAlarm(OneShot_s *alarm); + +#if zLINUX +LONG LinuxNobodyUID = 0; +BOOL HaveNobodyUID = FALSE; +#endif + +/************************************************************************** + * + * This function always returns a failure status + * + ***************************************************************************/ +STATUS COMN_ReturnAuthFailure(void) +{ + ASSERT_MPKNSS_LOCK(); + return zFAILURE; +} + +/************************************************************************** + * + * This will initialize the authorization information for the admin volume + * + ***************************************************************************/ +STATUS AUTHSYS_AdminVolPreInit( + GeneralMsg_s *genMsg, + AdminVolume_s *adminVol) +{ + NINT modelIndex; + NINT spaceIndex; + + ASSERT_MPKNSS_LOCK(); + + adminAuthModel = (AuthModelBeast_s *)zalloc(sizeof(AuthModelBeast_s)); + if (adminAuthModel == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + return zFAILURE; + } + adminAuthSpace = (AuthSpaceBeast_s *)zalloc(sizeof(AuthSpaceBeast_s)); + if (adminAuthSpace == NULL) + { + SetErrno(genMsg, zERR_NO_MEMORY); + return zFAILURE; + } + + /* + * Set up the default admin volume authorization model + */ + modelIndex = BST_ClassID2ArrayIndex(genMsg, &AuthModelIDMap, + zFTYPE_AUTH_MODEL /* use a type that will not be registered */); + if (modelIndex == -1) + { + SetErrno(genMsg, zERR_UNABLE_TO_INIT_ADMIN_VOL); + return zFAILURE; + } + AuthModels[modelIndex] = adminAuthModel; + adminAuthModel->modelIndex = modelIndex; + adminAuthModel->AMODLbeastClass = BST_GetBeastClass(zFTYPE_AUTH_MODEL); + adminAuthModel->AMODLuseCount = 1; + memcpy(&adminAuthModel->authModelOps, &ZASAuthorizeModelOps, + sizeof(AuthModelOps_s)); + + /* + * Set up the default admin volume authorization space + */ + spaceIndex = BST_ClassID2ArrayIndex(genMsg, &AuthSpaceIDMap, + zFTYPE_ZAS_AUTH_SPACE); + if (spaceIndex == -1) + { + SetErrno(genMsg, zERR_UNABLE_TO_INIT_ADMIN_VOL); + return zFAILURE; + } + + AuthSpaces[modelIndex][spaceIndex] = adminAuthSpace; + adminAuthSpace->spaceIndex = spaceIndex; + adminAuthSpace->ASPCbeastClass = BST_GetBeastClass(zFTYPE_ZAS_AUTH_SPACE); + adminAuthSpace->ASPCuseCount = 1; + memcpy(&adminAuthSpace->authSpaceOps, &ZASAuthorizeSpaceOps, + sizeof(AuthSpaceOps_s)); + memcpy(&adminAuthModel->authModelOps.authSpaceOps[spaceIndex], + &ZASAuthorizeSpaceOps, sizeof(AuthSpaceOps_s)); + + ZASindex = spaceIndex; + adminVol->AVOLauthModelIndex = modelIndex; + adminVol->AVOLauthModel = adminAuthModel; + return zOK; +} + +/************************************************************************** + * + * This will initialize the authorization information for the a volume + * + ***************************************************************************/ +STATUS AUTHSYS_VolInit( + GeneralMsg_s *genMsg, + Volume_s *volume, + NINT authModelID) +{ + ASSERT_MPKNSS_LOCK(); + volume->authModelIndex = BST_ClassID2ArrayIndex(genMsg, &AuthModelIDMap, + authModelID); + if (volume->authModelIndex == -1) + { + typedef struct Stack_s { + unicode_t volName[zMAX_COMPONENT_NAME]; + } Stack_s; + + STACK_ALLOC(); + + COMN_GetNameFromBeast(NULL,volume/* cnt zFNU_FIRST_PARENT*/,zNSPACE_LONG, + NELEMS(aStack->volName),aStack->volName,NULL); + errPrintf(WHERE, Module, 601, + MSG("Error initializing authorization system on " + "volume \"%U\", unknown authorization model id of %d.", 164), + aStack->volName, authModelID); + SetErrno(genMsg, zERR_INVALID_AUTHORIZE_MODEL); + STACK_FREE(); + return zFAILURE; + } + volume->authModel = AuthModels[volume->authModelIndex]; + return zOK; +} + +/************************************************************************** + * + * This will initialize the authorization system at load time + * + ***************************************************************************/ +STATUS AUTHSYS_Startup(GeneralMsg_s *genMsg) +{ + int sts; + + ASSERT_MPKNSS_LOCK(); + if (ZAS_Startup() != zOK) + { + goto error; + } + + if (UXAS_Startup() != zOK) + { + goto error; + } + +#if zLINUX + MPKNSS_UNLOCK(); + sts = ndp_GetUIDFromName("nobody", &LinuxNobodyUID); + MPKNSS_LOCK(); + if (sts == zOK) + { + zASSERT(LinuxNobodyUID != 0); + HaveNobodyUID = TRUE; + } + else + { + printk(KERN_ALERT "AUTHSYS_Startup - Failed to acquire Linux UID for nobody\n"); + } +#endif + + return zOK; + +error: + AUTHSYS_Shutdown(); + return zFAILURE; +} + +/************************************************************************** + * + * This will uninitialize the authorization system + * + ***************************************************************************/ +void AUTHSYS_Shutdown(void) +{ + NINT modelNum; + NINT spaceNum; + AuthModelBeast_s *model; + AuthSpaceBeast_s *space; + ASSERT_MPKNSS_LOCK(); + + ZAS_Shutdown(); + UXAS_Shutdown(); + + for (modelNum=0; modelNum < MAX_AUTHORIZE_MODELS; modelNum++) + { + model = AuthModels[modelNum]; + if(model != NULL) + { + for (spaceNum=0; spaceNum < MAX_AUTHORIZE_SPACES; spaceNum++) + { + space = AuthSpaces[modelNum][spaceNum]; + if (space != NULL) + { + BST_releaseAndFree(space); + AuthSpaces[modelNum][spaceNum] = 0; + } + } + BST_releaseAndFree(model); + AuthModels[modelNum] = 0; + } + } +} + + +/**************************************************************************** + * This is called after the admin volume is completly gone to do any + * final cleanup of the authorization system. + *****************************************************************************/ +void AUTHSYS_AdminVolPostShutdown(void) +{ + ASSERT_MPKNSS_LOCK(); + free(adminAuthModel); + free(adminAuthSpace); +} + +/************************************************************************** + * An authorization model needs to call this routine to register with + * PSS. They should do this at load time. + ***************************************************************************/ +AuthModelBeast_s *COMN_RegisterAuthorizeModel( + GeneralMsg_s *genMsg, + NINT version, + NINT authModelBeastType, + utf8_t *name, + AuthModelOps_s *modelOps) +{ + AuthModelBeast_s *authModel; + NINT index; + + ASSERT_MPKNSS_LOCK(); + + if (version != AUTH_MODEL_VERSION) + { + SetErrno(genMsg, zERR_INVALID_AUTH_MODEL_VERSION); + errPrintf(WHERE, Module, 602, + MSG("The authorization model \"%s\" has an invalid " + "version number %d, the correct version number is %d.", 165), + name, version, AUTH_MODEL_VERSION); + return NULL; + } + if (authModelBeastType > zFTYPE_MAX) + { + SetErrno(genMsg,zERR_INVALID_BEAST_ID); + errPrintf(WHERE, Module, 603, + MSG("The Authorization model ID %d for \"%s\" is invalid.", 166), + authModelBeastType, name); + return NULL; + } + + index = BST_ClassID2ArrayIndex(genMsg, &AuthModelIDMap, authModelBeastType); + if (index == -1) + { + return NULL; + } + + /* + * Instantiate the new authorization model beast + */ + if ((authModel = BST_new(genMsg, authModelBeastType, &AdminVolume)) == NULL) + { + return NULL; + } + + strncpy(authModel->name, name, MAX_AUTH_MODEL_NAME_SIZE); + authModel->name[MAX_AUTH_MODEL_NAME_SIZE - 1] = '\0'; + + zASSERT(index < MAX_AUTHORIZE_MODELS); + if (index >= MAX_AUTHORIZE_MODELS) + { + SetErrno(genMsg, zERR_EXCEEDED_MAX_AUTH_MODELS); + BST_free(authModel); + return NULL; + } + AuthModels[index] = authModel; + authModel->modelIndex = index; + memcpy(&authModel->authModelOps, modelOps, sizeof(AuthModelOps_s)); + + return authModel; +} + +/************************************************************************** + * Find an authorization model entry given a name. This returns the + * index into the array of auth models (AuthModels). If the name is not + * found then -1 is returned. + ***************************************************************************/ +SNINT COMN_FindAuthModelByName( + utf8_t *name) +{ + NINT i; + + for (i=0; i < MAX_AUTHORIZE_MODELS; i++) + { + if (AuthModels[i] != NULL) + { + if (strcmp(AuthModels[i]->name, name) == 0) + { + return i; + } + } + } + return -1; +} + + +/************************************************************************** + * An authorization space needs to call this routine to register with + * PSS. They should do this at load time. + ***************************************************************************/ +AuthSpaceBeast_s *COMN_RegisterAuthorizeSpace( + GeneralMsg_s *genMsg, + AuthModelBeast_s *authModel, + NINT authSpaceBeastType, + utf8_t *name, + AuthSpaceOps_s *spaceOps) +{ + NINT i; + AuthSpaceBeast_s *authSpace; + NINT index; + + ASSERT_MPKNSS_LOCK(); + + if (authSpaceBeastType > zFTYPE_MAX) + { + SetErrno(genMsg,zERR_INVALID_BEAST_ID); + errPrintf(WHERE, Module, 604, + MSG("The Authorization space ID %d for \"%s\" is invalid.", 167), + authSpaceBeastType, name); + return NULL; + } + + index = BST_ClassID2ArrayIndex(genMsg, &AuthSpaceIDMap, authSpaceBeastType); + if (index == -1) + { + return NULL; + } + if (index >= MAX_AUTHORIZE_SPACES) + { + SetErrno(genMsg,zERR_EXCEEDED_MAX_AUTH_SPACES); + errPrintf(WHERE, Module, 605, + MSG("Attempted to register Authorization space %d.\n" + "The number allowed is %d.", 168), + index, MAX_AUTHORIZE_SPACES); + return NULL; + } + + /* + * Instantiate the new authorization space beast + */ + if ((authSpace = BST_new(genMsg, authSpaceBeastType, &AdminVolume)) == NULL) + { + return NULL; + } + + strncpy(authSpace->name, name, MAX_AUTH_SPACE_NAME_SIZE); + authSpace->name[MAX_AUTH_SPACE_NAME_SIZE - 1] = '\0'; + + /* + * Add ops to the beasts (space and model) + */ + zASSERT(index < MAX_AUTHORIZE_SPACES); + if (index >= MAX_AUTHORIZE_SPACES) + { + SetErrno(genMsg, zERR_EXCEEDED_MAX_AUTH_SPACES); + BST_free(authSpace); + return NULL; + } + + for (i=0; i < MAX_AUTHORIZE_MODELS; i++) + { + if (AuthModels[i] == authModel) + { + AuthSpaces[i][index] = authSpace; + break; + } + } + authSpace->spaceIndex = index; + memcpy(&authSpace->authSpaceOps, spaceOps, sizeof(AuthSpaceOps_s)); + memcpy(&authModel->authModelOps.authSpaceOps[index], spaceOps, + sizeof(AuthSpaceOps_s)); + + return authSpace; +} + +/**************************************************************************** + **************************************************************************** + + GUID Conversion and cache code + + **************************************************************************** + ****************************************************************************/ + +#define DEFAULT_G2I_CACHE_SIZE (1<<14) /* must be a power of two or the + * compute hash routine needs to be + * changed. With the current hash + * algorithm it must not be greater + * than a shift of 28. */ +#define DEFAULT_I2G_CACHE_SIZE (1<<14) /* must be a power of two or the + * compute hash routine needs to be + * changed. With the current hash + * algorithm it must not be greater + * than a shift of 28. */ + +typedef enum CacheType_e +{ + GUID_TO_ID, + ID_TO_GUID +}CacheType_e; + +typedef struct GUIDCacheCtrl_s +{ + QUAD gets; /* number of times we did gets on the cache */ + QUAD hits; /* number of cache hits */ + Latch_s latch; /* latch to control changes in this structure */ + NINT numHashEntries; /* number of entries in the hash table */ + DQhead_t (*hash)[]; /* pointer to hash array */ + DQhead_t LRUqueue; /* head of the Least Recently Used queue */ + NINT maxEntries; /* max allowed entries in the cache */ + NINT numEntries; /* number of entries in the cache */ + NINT numAdded; /* incremented each time an entry is added */ + NINT numVictimSelected; /* number of entries that have been victim selected */ + OneShot_s alarm; /* alarm for invalidating the cache */ + FsmLite_s fsm; /* Fsm for scheduling a work to do */ + ObjCache_s guidObjectCache; /* object cache for cache nodes */ + BOOL shutdown; /* flag set if we are shutting down */ + BOOL running; /* flag set if the scheduled thread is running */ +} GUIDCacheCtrl_s; + +typedef struct GUIDtoIDCacheNode_s +{ + DQlink_t hashLink; /* hash list link field */ + DQlink_t LRUlink; /* LRU link field */ + NDSid_t guid; + NINT id; + NINT managementLevel;/* NDS management level for this object */ + NINT connID; /* connection ID associtated with management level */ + NINT flags; /* info flags about the entry */ +} GUIDtoIDCacheNode_s; + +/* flag values */ +#define G2I_POSITIVE_ENTRY 0x00000001 /* Entry represents a GUID that has an ID */ + +typedef struct IDtoGUIDCacheNode_s +{ + DQlink_t hashLink; /* hash list link field */ + DQlink_t LRUlink; /* LRU link field */ + NDSid_t guid; + NINT id; + NINT flags; /* info flags about the entry */ +} IDtoGUIDCacheNode_s; + +/* flag values */ +#define I2G_POSITIVE_ENTRY 0x00000001 /* Entry represents an ID that has a GUID */ + +GUIDCacheCtrl_s GUIDtoIDCache = /* control head for the GUID conversion cache */ +{ + 0, /* attempts on cache */ + 0, /* hits */ + {0}, /* latch */ + 0, /* num entries in the hash table (must be a power of 2)*/ + NULL, /* pointer to hash array */ + {NULL, NULL}, /* LRU */ + DEFAULT_G2I_CACHE_SIZE, /* max number of entries */ + 0, /* number of entries in the cache */ + 0, /* add count */ + 0, /* number of victom selects */ + {{0,0},0,0}, /* alarm */ + {0}, /* fsm */ + {0}, /* guid object cache */ +}; + +GUIDCacheCtrl_s IDtoGUIDCache = /* control head for the GUID conversion cache */ +{ + 0, /* attempts on cache */ + 0, /* hits */ + {0}, /* latch */ + 0, /* num entries in the hash table (must be a power of 2)*/ + NULL, /* pointer to hash array */ + {NULL, NULL}, /* LRU */ + DEFAULT_I2G_CACHE_SIZE, /* max number of entries */ + 0, /* number of entries in the cache */ + 0, /* add count */ + 0, /* number of victom selects */ + {{0,0},0,0}, /* alarm */ + {0}, /* fsm */ + {0}, /* guid object cache */ +}; + +/**************************************************************************** + * This will set the next Alarm time for the I2G cache + * It will sleep for a maximum of I2G_NEGATIVE_CACHE_INVALIDATE_TIME. + * This function keeps track of total sleep time since the last full + * cache reset. + * We wake up every I2G_NEGATIVE_CACHE_INVALIDATE_TIME sub-interval and clear + * negative cache entries. When the I2G_CacheInvalidateTime full interval + * expires, we clear all cache entries. + *****************************************************************************/ +void I2G_SetNextAlarm( void ) +{ + NINT nextSubInterval; + + nextSubInterval = I2G_NEGATIVE_CACHE_INVALIDATE_TIME; + if ((I2G_TotalIntervalDelay + nextSubInterval) > I2G_CacheInvalidateTime) + { + nextSubInterval = I2G_CacheInvalidateTime - I2G_TotalIntervalDelay; + if (nextSubInterval == 0) + { + /* Should never happen ... but just in case */ + nextSubInterval = 1; + } + } + I2G_TotalIntervalDelay += nextSubInterval; + secOneShot( &IDtoGUIDCache.alarm, nextSubInterval, I2G_HandleAlarm); +} + +/************************************************************************** + * This will change the change invalidate interval for the ID caches + **************************************************************************/ +void GUID_IDCacheResetInterval( + NINT value) +{ +#define GUID_MAX_SEC_DELAY 235987214 + if (value > GUID_MAX_SEC_DELAY) + { + value = GUID_MAX_SEC_DELAY; + } + +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(WHITE, "ID cache reset interval = %d\n", value); +#endif + + G2I_CacheInvalidateTime = value; + CANCEL_ALARM(GUIDtoIDCache.alarm); + secOneShot( &GUIDtoIDCache.alarm, G2I_CacheInvalidateTime, + G2I_HandleAlarm); + + I2G_CacheInvalidateTime = value; + CANCEL_ALARM(IDtoGUIDCache.alarm); + I2G_TotalIntervalDelay = 0; + I2G_SetNextAlarm(); + + return; +} + +/************************************************************************** + * This will initialize the GUID cache + **************************************************************************/ +STATUS GUID_CacheInit( + GUIDCacheCtrl_s *guidCache, + CacheType_e type) +{ + NINT i; + NINT hashSize; + STATUS status; + + /* + * We currently alloc one hash table entry for each possible cache + * entry. At some future time we may want to allocate fewer hash + * table entries if we are getting a great distribution and we need + * to save memory + */ + + X_LATCH(&guidCache->latch); + if (guidCache->numHashEntries != 0) + { /* return if already inited */ + UNX_LATCH(&guidCache->latch); + return zOK; + } + + hashSize = guidCache->maxEntries; + if (guidCache->hash == NULL) + { /* first init */ + guidCache->hash = zalloc(hashSize * sizeof(DQhead_t)); + if (guidCache->hash == NULL) + { + UNX_LATCH(&guidCache->latch); + return zFAILURE; + } + for (i=0; i < hashSize; i++) + { + DQ_INIT(&(*guidCache->hash)[i]); + } + guidCache->numHashEntries = hashSize; + DQ_INIT(&guidCache->LRUqueue); + guidCache->numEntries = 0; + guidCache->numAdded = 0; + INIT_ONESHOT(guidCache->alarm); + /* Allocate the memory for the GUID cache entries */ + if (type == GUID_TO_ID) + { + status = objCacheCreate(&guidCache->guidObjectCache, "GUIDtoIDCache", + sizeof(GUIDtoIDCacheNode_s), NULL); + } + else if (type == ID_TO_GUID) + { + status = objCacheCreate(&guidCache->guidObjectCache, "IDtoGUIDCache", + sizeof(IDtoGUIDCacheNode_s), NULL); + } + else + { + status = zFAILURE; + zASSERT("Invalid GUID cache type" == NULL); + } + if (status != zOK) + { + free(guidCache->hash); + guidCache->hash = NULL; + } + } + UNX_LATCH(&guidCache->latch); + return zOK; +} + +/************************************************************************** + * This will cleanup the GUID cache + **************************************************************************/ +void GUID_CacheUninit( + GUIDCacheCtrl_s *guidCache, + CacheType_e type) +{ + DQhead_t *hp; + NINT i; + GUIDtoIDCacheNode_s *itemGuid; + IDtoGUIDCacheNode_s *itemID; + + if (guidCache->numHashEntries == 0) + { + return; + } + + /* Free all of the cache entries */ + X_LATCH(&guidCache->latch); + if (guidCache->hash != NULL) + { + for (hp=&(*guidCache->hash)[0],i=guidCache->numHashEntries; i > 0; hp++,i--) + { + for (;;) + { + if (type == GUID_TO_ID) + { + DQ_DEQ(hp, itemGuid, GUIDtoIDCacheNode_s, hashLink); + if (itemGuid != NULL) + { + DQ_RMV(itemGuid, LRUlink); + --GUIDtoIDCache.numEntries; + objCacheFree(itemGuid); + } + else + { + break; + } + } + else if (type == ID_TO_GUID) + { + DQ_DEQ(hp, itemID, IDtoGUIDCacheNode_s, hashLink); + if (itemID != NULL) + { + DQ_RMV(itemID, LRUlink); + --IDtoGUIDCache.numEntries; + objCacheFree(itemID); + } + else + { + break; + } + } + else + { + zASSERT("Invalid GUID cache type in unint" == NULL); + } + } + zASSERT(DQ_EMPTY(hp)); + } + objCacheDestroy(&guidCache->guidObjectCache); + + free(guidCache->hash); + guidCache->hash = NULL; +// DQ_INIT(&guidCache->LRUqueue); + } + UNX_LATCH(&guidCache->latch); +} + +#if NSS_DEBUG IS_ENABLED +/************************************************************************** + * This will go through and display all cache nodes. + **************************************************************************/ +void G2I_DisplayCache(void) + +{ + DQhead_t *hashp; + NINT i; + GUIDtoIDCacheNode_s *node; + char buffer[GUID_FORMAT_SIZE]; + + DBG_DebugPrintf(LGRAY,MSGNot("-------- GUID to ID Cache Contents --------\n")); + ASSERT_LATCH(&GUIDtoIDCache.latch); + if (GUIDtoIDCache.hash != NULL) + { + for (hashp=&(*GUIDtoIDCache.hash)[0],i=0; i < GUIDtoIDCache.numHashEntries; hashp++,i++) + { + DQ_FOREACH(hashp, node, GUIDtoIDCacheNode_s, hashLink) + { + LB_GUIDToString(&node->guid, sizeof(buffer), buffer); + DBG_DebugPrintf(node->flags & G2I_POSITIVE_ENTRY ? LGREEN : LRED, + MSGNot("Hash=%d guid=%s id=0x%x mgmtLevel=0x%x connID=%d\n"), + i, buffer, node->id, node->managementLevel, node->connID); + } + } + } +} + +/************************************************************************** + * This will go through and display all GUID to ID cache nodes. + **************************************************************************/ +void G2I_DoDisplayCache( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) + +{ + MPKNSS_LOCK(); + S_LATCH(&GUIDtoIDCache.latch); + G2I_DisplayCache(); + UNS_LATCH(&GUIDtoIDCache.latch); + MPKNSS_UNLOCK(); +} + +#endif + +/************************************************************************** + * This will invalidate all entries in the GUID to ID cache + **************************************************************************/ +void G2I_InvalidateCache(void) +{ + DQhead_t *hp; + NINT i; + GUIDtoIDCacheNode_s *item; + + if (GUIDtoIDCache.numHashEntries == 0) + { + return; + } + + /* Free all of the cache entries */ + X_LATCH(&GUIDtoIDCache.latch); + if (GUIDtoIDCache.hash != NULL) + { + for (hp = &(*GUIDtoIDCache.hash)[0], i = GUIDtoIDCache.numHashEntries; + i > 0; hp++,i--) + { + for (;;) + { + DQ_DEQ(hp, item, GUIDtoIDCacheNode_s, hashLink); + if (item != NULL) + { + DQ_RMV(item, LRUlink); + --GUIDtoIDCache.numEntries; + objCacheFree(item); + } + else + { + break; + } + } + zASSERT(DQ_EMPTY(hp)); + } +// DQ_INIT(&GUIDtoIDCache.LRUqueue); + } + zASSERT(GUIDtoIDCache.numEntries == 0); + UNX_LATCH(&GUIDtoIDCache.latch); +#if NSS_DEBUG IS_ENABLED + //DBG_DebugPrintf(WHITE, "GUID to ID cache invalidated\n"); +#endif + return; +} +EXPORT_SYMBOL(G2I_InvalidateCache); + +/************************************************************************** + * This will invalidate the management level on all entries with the + * given connection ID. + **************************************************************************/ +void G2I_InvalidateManagementLevel( + NINT connID) +{ + DQhead_t *hashp; + NINT i; + GUIDtoIDCacheNode_s *node; + + if (GUIDtoIDCache.numHashEntries == 0) + { + return; + } + + /* Check all of the cache entries */ + X_LATCH(&GUIDtoIDCache.latch); + if (GUIDtoIDCache.hash != NULL) + { + for (hashp=&(*GUIDtoIDCache.hash)[0], i=0; + i < GUIDtoIDCache.numHashEntries; hashp++,i++) + { + DQ_FOREACH(hashp, node, GUIDtoIDCacheNode_s, hashLink) + { + if (node->connID == connID) + { + node->managementLevel = -1; + } + } + } + } + UNX_LATCH(&GUIDtoIDCache.latch); +#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(WHITE, "GUID to ID cache management levels invalidated\n"); +#endif + return; +} + +/************************************************************************** + * This will initialize the GUID cache + **************************************************************************/ +void G2I_AlarmThread (FsmLite_s *fsm) +{ + G2I_InvalidateCache(); + if (!GUIDtoIDCache.shutdown) + { + secOneShot( &GUIDtoIDCache.alarm, G2I_CacheInvalidateTime, + G2I_HandleAlarm); + } + GUIDtoIDCache.running = FALSE; +} + +void G2I_HandleAlarm (OneShot_s *alarm) +{ + GUIDtoIDCache.running = TRUE; + WORK_Schedule( &GUIDtoIDCache.fsm, G2I_AlarmThread, 0); +} + +/************************************************************************** + * This will initialize the GUID to ID cache + **************************************************************************/ +STATUS G2I_CacheInit(void) +{ + if (GUID_CacheInit(&GUIDtoIDCache, GUID_TO_ID) != zOK) + { + return zFAILURE; + } + + /* + * Invalidate the cache occasionally in case we have some + * bad entries from DS errors. + */ + if (!ONESHOT_SET(GUIDtoIDCache.alarm)) + { + secOneShot(&GUIDtoIDCache.alarm, G2I_CacheInvalidateTime, + G2I_HandleAlarm); + } + return zOK; +} + +/************************************************************************** + * This will cleanup the GUID to ID cache + **************************************************************************/ +void G2I_CacheUninit(void) +{ + GUIDtoIDCache.shutdown = TRUE; + CANCEL_ALARM(GUIDtoIDCache.alarm); + while (GUIDtoIDCache.running) + { + LB_delay(50); + } + GUID_CacheUninit(&GUIDtoIDCache, GUID_TO_ID); + return; +} + + +/************************************************************************** + * This generates the HASH value for an entry + **************************************************************************/ +NINT G2I_ComputeHash( + NDSid_t *guid) +{ + // This takes into account the fact the times in eDir GUIDS are really + // in milliseconds, not in 100 nanosecond increments. + LONG adjustedTime = guid->timeLow >> 4; + return adjustedTime & (GUIDtoIDCache.numHashEntries - 1); +} + + +/**************************************************************************** + * Check the cache for an entry. If it is found return a pointer to the + * entry, otherwise return a null. + *****************************************************************************/ +GUIDtoIDCacheNode_s *G2I_CheckCache( + NDSid_t *guid) +{ + GUIDtoIDCacheNode_s *cacheNode; + DQhead_t *hashptr; + NINT hashIndex; + + /* + * Init the cache if it has not already been done. + */ + if (GUIDtoIDCache.numHashEntries == 0) + { /* if not the entry is not found */ + return NULL; + } + + GUIDtoIDCache.gets++; + hashIndex = G2I_ComputeHash(guid); + hashptr = &(*GUIDtoIDCache.hash)[hashIndex]; + DQ_FOREACH(hashptr, cacheNode, GUIDtoIDCacheNode_s, hashLink) + { + if (LB_GUIDCompare(guid, &cacheNode->guid) == 0) + { /* these are the same entry */ +#if NSS_DEBUG IS_ENABLED +// char buffer[GUID_FORMAT_SIZE]; +// LB_GUIDToString(guid, sizeof(buffer), buffer); +// DBG_DebugPrintf(LGREEN, +// MSGNot("G2I cache hit: guid=%s\n"), buffer); +#endif + DQ_RMV(cacheNode, LRUlink); + DQ_ENQ(&GUIDtoIDCache.LRUqueue, cacheNode, LRUlink); + GUIDtoIDCache.hits++; + return cacheNode; + } + } +#if NSS_DEBUG IS_ENABLED +// { +// char buffer[GUID_FORMAT_SIZE]; +// LB_GUIDToString(guid, sizeof(buffer), buffer); +// DBG_DebugPrintf(LRED, MSGNot("G2I cache miss: guid=%s\n"), buffer); +// } +#endif + return NULL; +} + +/**************************************************************************** + * Add a new cache entry. + *****************************************************************************/ +GUIDtoIDCacheNode_s *G2I_AddEntryToCache( + NDSid_t *guid, + LONG id, + BOOL found) +{ + GUIDtoIDCacheNode_s *cacheNode = NULL; + NINT hashIndex; + static BOOL waitForFound = TRUE; + +#if NSS_DEBUG IS_ENABLED +// GUIDtoIDCache.gets--; +// if (G2I_CheckCache(guid) != NULL) +// { +// zASSERT("Trying to add a GUID to ID cache entry that is already there" == 0); +// } +#endif + + /* + * Don't add negative entries until we have gotten at least one positive + * so we know that NDS is functional. + */ + if (found) + { + waitForFound = FALSE; + } + +#if zNETWARE + if (waitForFound || !NdsPublicsLoaded) + { +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LMAGENTA, "G2I add to cache -- early exit\n"); +#endif + return NULL; + } +#endif + + /* + * Init the cache if it has not already been done. + */ + if (GUIDtoIDCache.numHashEntries == 0) + { /* if not inited then init */ + if (G2I_CacheInit() != zOK) + { + return NULL; + } + } + + /* we only get here if the entry is not found */ + X_LATCH(&GUIDtoIDCache.latch); + hashIndex = G2I_ComputeHash(guid); + zASSERT(GUIDtoIDCache.numEntries <= GUIDtoIDCache.maxEntries); + if (GUIDtoIDCache.numEntries >= GUIDtoIDCache.maxEntries) + { /* if we have all the entries allowed just reuse the oldest one */ + DQ_DEQ(&GUIDtoIDCache.LRUqueue, cacheNode, GUIDtoIDCacheNode_s, LRUlink); + DQ_RMV(cacheNode, hashLink); + GUIDtoIDCache.numVictimSelected++; + } + else + { + GUIDtoIDCache.numEntries++; + cacheNode = objCacheAlloc(&GUIDtoIDCache.guidObjectCache); + } + zASSERT(cacheNode != NULL); /* object cache should always succeed */ + + /* fill in new entry */ + cacheNode->guid = *guid; + cacheNode->id = id; + cacheNode->managementLevel = -1; + cacheNode->connID = -1; + cacheNode->flags = 0; + if (found) + { + cacheNode->flags |= G2I_POSITIVE_ENTRY; + } + + GUIDtoIDCache.numAdded++; + + NULLIFY(&cacheNode->hashLink); + DQ_PUSH(&(*GUIDtoIDCache.hash)[hashIndex], cacheNode, hashLink); /* link of hash list */ + NULLIFY(&cacheNode->LRUlink); + DQ_ENQ(&GUIDtoIDCache.LRUqueue, cacheNode, LRUlink); /* link to the LRU queue */ +#if NSS_DEBUG IS_ENABLED + { + char buffer[GUID_FORMAT_SIZE]; + LB_GUIDToString(guid, sizeof(buffer), buffer); + DBG_DebugPrintf(YELLOW, MSGNot("Added to GUID to ID cache: guid=%s found=%d\n"), + buffer, found); + } +// G2I_DisplayCache(); +#endif + UNX_LATCH(&GUIDtoIDCache.latch); + return cacheNode; +} + + +#if NSS_DEBUG IS_ENABLED +/************************************************************************** + * This will go through and display all cache nodes. + **************************************************************************/ +void I2G_DisplayCache(void) + +{ + DQhead_t *hashp; + NINT i; + IDtoGUIDCacheNode_s *node; + char buffer[GUID_FORMAT_SIZE]; + + + DBG_DebugPrintf(LGRAY,MSGNot("-------- ID to GUID Cache Contents --------\n")); + ASSERT_LATCH(&IDtoGUIDCache.latch); + if (IDtoGUIDCache.hash != NULL) + { + for (hashp=&(*IDtoGUIDCache.hash)[0],i=0; i < IDtoGUIDCache.numHashEntries; hashp++,i++) + { + DQ_FOREACH(hashp, node, IDtoGUIDCacheNode_s, hashLink) + { + LB_GUIDToString(&node->guid, sizeof(buffer), buffer); + DBG_DebugPrintf(node->flags & I2G_POSITIVE_ENTRY ? LGREEN : LRED, + MSGNot("Hash=%d id=0x%8.8x guid=%s\n"), + i, node->id, buffer); + } + } + } +} + +/************************************************************************** + * This will go through and display all ID to GUID cache nodes. + **************************************************************************/ +void I2G_DoDisplayCache( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) + +{ + MPKNSS_LOCK(); + S_LATCH(&IDtoGUIDCache.latch); + I2G_DisplayCache(); + UNS_LATCH(&IDtoGUIDCache.latch); + MPKNSS_UNLOCK(); +} + +#endif + + +/************************************************************************** + * This will invalidate entries in the ID to GUID cache + * - If doFullCache is TRUE, we do all entries. + * - else we just do negative entries. + **************************************************************************/ +void I2G_InvalidateCache( + BOOL doFullCache) +{ + DQhead_t *hp; + NINT i; + IDtoGUIDCacheNode_s *item; + DQhead_t hold; + + if (IDtoGUIDCache.numHashEntries == 0) + { + return; + } + + DQ_INIT( &hold); + + /* Free all of the cache entries */ + X_LATCH(&IDtoGUIDCache.latch); + if (IDtoGUIDCache.hash != NULL) + { + for (hp = &(*IDtoGUIDCache.hash)[0], i = IDtoGUIDCache.numHashEntries; + i > 0; hp++,i--) + { + for (;;) + { + DQ_DEQ(hp, item, IDtoGUIDCacheNode_s, hashLink); + if (item != NULL) + { + if (((item->flags & I2G_POSITIVE_ENTRY) == 0) || + (doFullCache)) + { + /* This is a negative entry ... or we are freeing + * the full cache. Free this entry. + */ + DQ_RMV(item, LRUlink); + --IDtoGUIDCache.numEntries; + objCacheFree(item); + } + else + { + /* We only get here if this is a Positive entry, and + * we are not flushing the full cache. + */ + DQ_ENQ( &hold, item, hashLink); + } + } + else + { + if (DQ_NOT_EMPTY(&hold)) + { + /* Put the saved entries back on the hash bucket */ + zASSERT(DQ_EMPTY(hp)); + DQ_APPEND( hp, &hold); + DQ_INIT( &hold); + } + break; + } + } +#if NSS_DEBUG IS_ENABLED + if (doFullCache) + { + zASSERT(DQ_EMPTY(hp)); + } +#endif + } +// DQ_INIT(&IDtoGUIDCache.LRUqueue); + } + UNX_LATCH(&IDtoGUIDCache.latch); +#if NSS_DEBUG IS_ENABLED + //DBG_DebugPrintf(WHITE, "ID to GUID cache invalidated\n"); +#endif + return; +} +EXPORT_SYMBOL(I2G_InvalidateCache); + +/************************************************************************** + * This will initialize the GUID cache + **************************************************************************/ +void I2G_AlarmThread (FsmLite_s *fsm) +{ + /* If the full interval has expired ... */ + if (I2G_TotalIntervalDelay >= I2G_CacheInvalidateTime) + { + /* Full has expired, reset the counter, and invalidate the full cache */ + I2G_TotalIntervalDelay = 0; + I2G_InvalidateCache(TRUE); + } + else + { + /* Partial timer has expired, invalidate just negative entries */ + I2G_InvalidateCache(FALSE); + } + I2G_SetNextAlarm(); +} + +void I2G_HandleAlarm (OneShot_s *alarm) +{ + WORK_Schedule( &IDtoGUIDCache.fsm, I2G_AlarmThread, 0); +} + +/************************************************************************** + * This will initialize the ID to GUID cache + **************************************************************************/ +STATUS I2G_CacheInit(void) +{ + if (GUID_CacheInit(&IDtoGUIDCache, ID_TO_GUID) != zOK) + { + return zFAILURE; + } + /* Invalidate the cache occasionally because user IDs can be reused. */ + if (!ONESHOT_SET(IDtoGUIDCache.alarm)) + { + I2G_SetNextAlarm(); + } + return zOK; +} + +/************************************************************************** + * This will cleanup the ID to GUID cache + **************************************************************************/ +void I2G_CacheUninit(void) +{ + IDtoGUIDCache.shutdown = TRUE; + CANCEL_ALARM(IDtoGUIDCache.alarm); + while (IDtoGUIDCache.running) + { + LB_delay(50); + } + GUID_CacheUninit(&IDtoGUIDCache, ID_TO_GUID); + return; +} + + +/************************************************************************** + * This generates the HASH value for an entry + **************************************************************************/ +NINT I2G_ComputeHash( + LONG id) +{ + return id & (IDtoGUIDCache.numHashEntries - 1); +} + + +/**************************************************************************** + * Check the cache for an entry. If it is found return a pointer to the + * entry, otherwise return a null. + *****************************************************************************/ +STATIC IDtoGUIDCacheNode_s *I2G_CheckCache( + LONG id) +{ + IDtoGUIDCacheNode_s *cacheNode; + DQhead_t *hashptr; + NINT hashIndex; + + /* + * Init the cache if it has not already been done. + */ + if (IDtoGUIDCache.numHashEntries == 0) + { /* if not the entry is not found */ + return NULL; + } + + IDtoGUIDCache.gets++; + hashIndex = I2G_ComputeHash(id); + hashptr = &(*IDtoGUIDCache.hash)[hashIndex]; + DQ_FOREACH(hashptr, cacheNode, IDtoGUIDCacheNode_s, hashLink) + { + if (id == cacheNode->id) + { /* these are the same entry */ +#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(LGREEN, +// MSGNot("I2G cache hit: id=0x%x\n"), id); +#endif + DQ_RMV(cacheNode, LRUlink); + DQ_ENQ(&IDtoGUIDCache.LRUqueue, cacheNode, LRUlink); + IDtoGUIDCache.hits++; + return cacheNode; + } + } +#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(LRED, MSGNot("I2G cache miss: id=0x%x\n"), id); +#endif + return NULL; +} + +/**************************************************************************** + * Add a new cache entry. + *****************************************************************************/ +IDtoGUIDCacheNode_s *I2G_AddEntryToCache( + NINT id, + NDSid_t *guid, + BOOL found) +{ + IDtoGUIDCacheNode_s *cacheNode = NULL; + NINT hashIndex; + static BOOL waitForFound = TRUE; + +#if NSS_DEBUG IS_ENABLED +// IDtoGUIDCache.gets--; +// if (I2G_CheckCache(id) != NULL) +// { +// zASSERT("Trying to add a ID to GUID cache entry that is already there" == 0); +// } +#endif + + /* + * Don't add negative entries until we have gotten at least one positive + * so we know that NDS is functional. + */ + if (found) + { + waitForFound = FALSE; + } + +#if zNETWARE + if (waitForFound || !NdsPublicsLoaded) + { +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LMAGENTA, "I2G add to cache -- early exit\n"); +#endif + return NULL; + } +#endif + + /* + * Init the cache if it has not already been done. + */ + if (IDtoGUIDCache.numHashEntries == 0) + { /* if not inited then init */ + if (I2G_CacheInit() != zOK) + { + return NULL; + } + } + + /* we only get here if the entry is not found */ + X_LATCH(&IDtoGUIDCache.latch); + hashIndex = I2G_ComputeHash(id); + zASSERT(IDtoGUIDCache.numEntries <= IDtoGUIDCache.maxEntries); + if (IDtoGUIDCache.numEntries >= IDtoGUIDCache.maxEntries) + { /* if we have all the entries allowed */ + DQ_DEQ(&IDtoGUIDCache.LRUqueue, cacheNode, IDtoGUIDCacheNode_s, LRUlink); + DQ_RMV(cacheNode, hashLink); + IDtoGUIDCache.numVictimSelected++; + } + else + { + IDtoGUIDCache.numEntries++; + cacheNode = objCacheAlloc(&IDtoGUIDCache.guidObjectCache); + } + zASSERT(cacheNode != NULL); /* object cache should always succeed */ + + /* fill in new entry */ + cacheNode->guid = *guid; + cacheNode->id = id; + cacheNode->flags = 0; + if (found) + { + cacheNode->flags |= I2G_POSITIVE_ENTRY; + } + + IDtoGUIDCache.numAdded++; + + NULLIFY(&cacheNode->hashLink); + DQ_PUSH(&(*IDtoGUIDCache.hash)[hashIndex], cacheNode, hashLink); /* link of hash list */ + NULLIFY(&cacheNode->LRUlink); + DQ_ENQ(&IDtoGUIDCache.LRUqueue, cacheNode, LRUlink); /* link to the LRU queue */ +#if NSS_DEBUG IS_ENABLED +// { +// char buffer[GUID_FORMAT_SIZE]; +// LB_GUIDToString(guid, sizeof(buffer), buffer); +// DBG_DebugPrintf(YELLOW, MSGNot("Added an ID to GUID cache entry: id=0x%x\n"), +// id); +// } +// I2G_DisplayCache(); +#endif + UNX_LATCH(&IDtoGUIDCache.latch); + return cacheNode; +} + +/**************************************************************************** + * Get the management level from the ID to GUID cache. If the entry is not + * there then add it. + *****************************************************************************/ +STATUS COMN_GetManagementLevel( + GeneralMsg_s *genMsg, + Volume_s *volume, + NDSid_t *guid, + NINT *managementLevel) +{ + GUIDtoIDCacheNode_s *cacheNode; + STATUS status; + LONG id; +#if zLINUX + UserID_t *connAuthenticatedIDs; + NINT connNumAuthenticatedIDs; +#endif + +// DBG_DebugPrintf(YELLOW, "Connection=%d GUID=%d ", genMsg->pssConn.id, +// guid->timeLow); + cacheNode = G2I_CheckCache(guid); + if (cacheNode) + { + if (cacheNode->flags & G2I_POSITIVE_ENTRY) + { + if (cacheNode->managementLevel != -1 && + genMsg->pssConn.id == cacheNode->connID) + { + *managementLevel = cacheNode->managementLevel; +// DBG_DebugPrintf(YELLOW, "return management level (cache) = %d\n", *managementLevel); + return zOK; + } + } + else + { /* negative cache entry found */ + *managementLevel = 0; +// DBG_DebugPrintf(YELLOW, "Negative cache entry found getting ID.\n",); + return zFAILURE; + } + } + +#if zNETWARE + /* + * If the cache node does not exist then do the GUID to ID conversion. + * This should force the entry into the cache. + */ + if (COMN_MapNDSGUIDToID(&status, volume, guid, &id) != zOK) + { + SetErrno(genMsg, status); + *managementLevel = 0; +// DBG_DebugPrintf(YELLOW, "Error getting ID: %d\n", status); + return zFAILURE; + } + + MPKNSS_UNLOCK(); + *managementLevel = + (*(NameService.GetManagementLevel))(genMsg->pssConn.id, id); + MPKNSS_LOCK(); +// DBG_DebugPrintf(YELLOW, "management level from GetManagementLevel = %d\n", *managementLevel); +#endif + +#if zLINUX + /* + * If the cache node does not exist then do the GUID to ID conversion. + * This should force the entry into the cache. + */ + if (COMN_MapNDSGUIDToUID(&status, guid, &id) != zOK) + { + SetErrno(genMsg, status); + *managementLevel = 0; +// DBG_DebugPrintf(YELLOW, "Error getting ID: %d\n", status); + return zFAILURE; + } + + /* Get the list of authenticated IDs from the connection structure, + * and call the NCP eDir code to calculate the management level + */ + if ((status = COMN_GetAuthenticatedIDs(genMsg, &connAuthenticatedIDs, + &connNumAuthenticatedIDs)) != zOK) + { + return zFAILURE; + } + + MPKNSS_UNLOCK(); + /* Use the ID list to get the management level from eDir */ + status = ndp_NCPMapGUIDToMgtLevel(connNumAuthenticatedIDs, + connAuthenticatedIDs, guid, managementLevel); + if (status != zOK) + { + *managementLevel = 0; + } + MPKNSS_LOCK(); + + /* We must free this buffer when done with it... */ + free(connAuthenticatedIDs); + +#endif + + if ((cacheNode = G2I_CheckCache(guid))) + { + cacheNode->connID = genMsg->pssConn.id; + if (cacheNode->flags & G2I_POSITIVE_ENTRY) + { + cacheNode->managementLevel = *managementLevel; + } + else + { + cacheNode->managementLevel = 0; + } + } + else + { + /* + * If it is not in the cache then it should be one of the special + * GUIDs that we do not cache during GUID to ID conversion. Go ahead + * and add it to the cache. + */ + zASSERT(guid->timeHighAndVersion == 0); + G2I_AddEntryToCache(guid, id, TRUE); + /* Get the new cache node and add the management info */ + if ((cacheNode = G2I_CheckCache(guid))) + { + zASSERT(cacheNode->flags & G2I_POSITIVE_ENTRY); + cacheNode->managementLevel = *managementLevel; + cacheNode->connID = genMsg->pssConn.id; + } + zASSERT(cacheNode); + } +// DBG_DebugPrintf(YELLOW, "return management level = %d\n", *managementLevel); + return zOK; +} + +/**************************************************************************** + **************************************************************************** + + Security Equivalence cache structures + + **************************************************************************** + ****************************************************************************/ +#define SE_CACHE_INVALIDATE_TIME 9*60 /* 9 minutes */ +NINT SE_CacheInvalidateTime = SE_CACHE_INVALIDATE_TIME; + +void SE_HandleAlarm(OneShot_s *alarm); + +#define DEFAULT_SE_CACHE_SIZE (1<<12) /* must be a power of two or the + * compute hash routine needs to be + * changed */ +typedef struct SECacheCtrl_s +{ + QUAD gets; /* number of times we did gets on the cache */ + QUAD hits; /* number of cache hits */ + Latch_s latch; /* latch to control changes in this structure */ + NINT numHashEntries; /* number of entries in the hash table */ + DQhead_t (*hash)[]; /* pointer to hash array */ + DQhead_t LRUqueue; /* head of the Least Recently Used queue */ + NINT maxEntries; /* max allowed entries in the cache */ + NINT numEntries; /* number of entries in the cache */ + NINT numAdded; /* incremented each time an entry is added */ + NINT numVictimSelected; /* number of entries that have been victim selected */ + OneShot_s alarm; /* alarm for invalidating the cache */ + FsmLite_s fsm; /* Fsm for scheduling a work to do */ + ObjCache_s seObjectCache; /* object cache for cache nodes */ + BOOL shutdown; /* flag set if we are shutting down */ + BOOL running; /* flag set if the scheduled thread is running */ +} SECacheCtrl_s; + +typedef struct SECacheNode_s +{ + DQlink_t hashLink; /* hash list link field */ + DQlink_t LRUlink; /* LRU link field */ + NINT reqSeEntries; /* number of requested entries */ + NINT numSeEntries; /* number of entries in the list of equivalents */ +#if zNETWARE + NINT id; + LONG *list; /* List of equivalents */ + LONG privileges; /* Name services privileges or "id" */ +#endif +#if zLINUX + NDSid_t guid; + NDSid_t *guidList; + BOOL isSupervisor; +#endif +} SECacheNode_s; + +SECacheCtrl_s SECache = /* control head for the cache */ +{ + 0, /* attempts on cache */ + 0, /* hits */ + {0}, /* latch */ + 0, /* num entries in the hash table (must be a power of 2)*/ + NULL, /* pointer to hash array */ + {NULL, NULL}, /* LRU */ + DEFAULT_SE_CACHE_SIZE, /* max number of entries */ + 0, /* number of entries in the cache */ + 0, /* add count */ + 0, /* number of victom selects */ + {{0,0},0,0}, /* alarm */ + {0}, /* fsm */ + {0}, /* SE object cache */ +}; + + +#if NSS_DEBUG IS_ENABLED +/************************************************************************** + * This will go through and display all cache nodes. + **************************************************************************/ +void SE_DisplayCache(void) +{ + DQhead_t *hashp; + NINT i; + SECacheNode_s *node; + + DBG_DebugPrintf(LGRAY,MSGNot("-------- Security Equivalence Cache Contents --------\n")); + ASSERT_LATCH(&SECache.latch); + if (SECache.hash != NULL) + { + for (hashp=&(*SECache.hash)[0],i=0; i < SECache.numHashEntries; + hashp++,i++) + { + DQ_FOREACH(hashp, node, SECacheNode_s, hashLink) + { +#if zNETWARE + DBG_DebugPrintf(GREEN, MSGNot("Hash=%d id=0x%8.8x pv=0x%x rq=%d list="), + i, node->id, node->privileges, node->reqSeEntries); +#endif +#if zLINUX + DBG_DebugPrintf(GREEN, MSGNot("Hash=%d id=0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x super=0x%x rq=%d list="), + i, node->guid, node->isSupervisor, node->reqSeEntries); +#endif + if (node->numSeEntries > 0) + { + NINT j; + for (j = 0; j < node->numSeEntries; j++) + { +#if zNETWARE + DBG_DebugPrintf(YELLOW, MSGNot("0x%8.8x "), + (node->list)[j]); +#endif +#if zLINUX + DBG_DebugPrintf(YELLOW, MSGNot("0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x, "), + (node->guidList)[j]); +#endif + } + } + else + { + DBG_DebugPrintf(YELLOW, MSGNot("")); + } + DBG_DebugPrintf(YELLOW, MSGNot("\n")); + } + } + } +} + +/************************************************************************** + * This will go through and display all ID to GUID cache nodes. + **************************************************************************/ +void SE_DoDisplayCache( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) + +{ + MPKNSS_LOCK(); + S_LATCH(&SECache.latch); + SE_DisplayCache(); + UNS_LATCH(&SECache.latch); + MPKNSS_UNLOCK(); +} +#endif /* Debug enabled */ + +/************************************************************************** + * This will initialize the security equivalence cache + **************************************************************************/ +STATUS SE_CacheInit() +{ + NINT i; + NINT hashSize; + STATUS status; + + /* + * We currently alloc one hash table entry for each possible cache + * entry. At some future time we may want to allocate fewer hash + * table entries if we are getting a great distribution and we need + * to save memory + */ + + X_LATCH(&SECache.latch); + if (SECache.numHashEntries != 0) + { /* return if already inited */ + UNX_LATCH(&SECache.latch); + return zOK; + } + + hashSize = SECache.maxEntries; + if (SECache.hash == NULL) + { /* first init */ + SECache.hash = zalloc(hashSize * sizeof(DQhead_t)); + if (SECache.hash == NULL) + { + UNX_LATCH(&SECache.latch); + return zFAILURE; + } + for (i=0; i < hashSize; i++) + { + DQ_INIT(&(*SECache.hash)[i]); + } + SECache.numHashEntries = hashSize; + DQ_INIT(&SECache.LRUqueue); + SECache.numEntries = 0; + SECache.numAdded = 0; + INIT_ONESHOT(SECache.alarm); + + /* Allocate the memory for the cache entries */ + status = objCacheCreate(&SECache.seObjectCache, "SECache", + sizeof(SECacheNode_s), NULL); + if (status != zOK) + { + free(SECache.hash); + SECache.hash = NULL; + } + } + UNX_LATCH(&SECache.latch); + + /* Invalidate the cache occasionally */ + if (!ONESHOT_SET(SECache.alarm)) + { + secOneShot(&SECache.alarm, SE_CacheInvalidateTime, + SE_HandleAlarm); + } + return zOK; +} + +/************************************************************************** + * This will free all cache entries. + **************************************************************************/ +void SE_FreeEntries(void) +{ + DQhead_t *hp; + NINT i; + SECacheNode_s *item; + + for (hp=&(*SECache.hash)[0],i=SECache.numHashEntries; i > 0; hp++,i--) + { + for (;;) + { + DQ_DEQ(hp, item, SECacheNode_s, hashLink); + if (item == NULL) + { + break; + } +#if zNETWARE + free(item->list); +#endif +#if zLINUX + free(item->guidList); +#endif + DQ_RMV(item, LRUlink); + --SECache.numEntries; + objCacheFree(item); + } + zASSERT(DQ_EMPTY(hp)); + } +} + +/************************************************************************** + * This will cleanup the security equivalence cache + **************************************************************************/ +void SE_CacheUninit() +{ + SECache.shutdown = TRUE; + CANCEL_ALARM(SECache.alarm); + + while (GUIDtoIDCache.running) + { + LB_delay(50); + } + + if (SECache.numHashEntries == 0) + { + return; + } + + /* Free all of the cache entries */ + X_LATCH(&SECache.latch); + if (SECache.hash != NULL) + { + SE_FreeEntries(); + objCacheDestroy(&SECache.seObjectCache); + + free(SECache.hash); + SECache.hash = NULL; +// DQ_INIT(&SECache.LRUqueue); + } + UNX_LATCH(&SECache.latch); +} + +/************************************************************************** + * This will invalidate all entries in the security equivalence cache + **************************************************************************/ +void SE_InvalidateCache(void) +{ + if (SECache.numHashEntries == 0) + { + return; + } + + /* Free all of the cache entries */ + X_LATCH(&SECache.latch); + if (SECache.hash != NULL) + { + SE_FreeEntries(); +// DQ_INIT(&SECache.LRUqueue); + } +// SECache.numEntries = 0; + UNX_LATCH(&SECache.latch); +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(WHITE, "SE cache invalidated\n"); +#endif + return; +} + +/************************************************************************** + * This will invalidate the cache and reset the alarm + **************************************************************************/ +void SE_AlarmThread (FsmLite_s *fsm) +{ + SE_InvalidateCache(); + if (!SECache.shutdown) + { + secOneShot( &SECache.alarm, SE_CacheInvalidateTime, + SE_HandleAlarm); + } + SECache.running = FALSE; +} + +void SE_HandleAlarm (OneShot_s *alarm) +{ + SECache.running = TRUE; + WORK_Schedule( &SECache.fsm, SE_AlarmThread, 0); +} + +/************************************************************************** + * This generates the HASH value for an entry + **************************************************************************/ +#if zNETWARE +NINT SE_ComputeHash( + LONG id) +{ + return id & (SECache.numHashEntries - 1); +} +#endif +#if zLINUX +NINT SE_ComputeHash( + NDSid_t *guid) +{ + // This takes into account the fact the times in eDir GUIDS are really + // in milliseconds, not in 100 nanosecond increments. + LONG adjustedTime = guid->timeLow >> 4; + return adjustedTime & (SECache.numHashEntries - 1); +} +#endif + +/**************************************************************************** + * Check the cache for an entry. If it is found return a pointer to the + * entry, otherwise return a null. + * + * NOTE: The cache node is not latched. The caller must not block while + * using the contents of the cache node. + *****************************************************************************/ +#if zNETWARE +STATIC SECacheNode_s *SE_CheckCache( + LONG id, + LONG reqNum) +#endif +#if zLINUX +STATIC SECacheNode_s *SE_CheckCache( + NDSid_t *id, + LONG reqNum) +#endif +{ + SECacheNode_s *cacheNode; + DQhead_t *hashptr; + NINT hashIndex; + + /* + * Init the cache if it has not already been done. + */ + if (SECache.numHashEntries == 0) + { /* if not the entry is not found */ + return NULL; + } + + SECache.gets++; + hashIndex = SE_ComputeHash(id); + hashptr = &(*SECache.hash)[hashIndex]; + DQ_FOREACH(hashptr, cacheNode, SECacheNode_s, hashLink) + { +#if zNETWARE + if ((id == cacheNode->id) && (reqNum == cacheNode->reqSeEntries)) +#endif +#if zLINUX + if ((LB_GUIDCompare(id,&cacheNode->guid)==0) && + (reqNum == cacheNode->reqSeEntries)) +#endif + { /* these are the same entry */ +#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(LGREEN, MSGNot("SE cache hit: id=0x%x\n"), id); +#endif + DQ_RMV(cacheNode, LRUlink); + DQ_ENQ(&SECache.LRUqueue, cacheNode, LRUlink); + SECache.hits++; + return cacheNode; + } + } +#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(LRED, MSGNot("SE cache miss: id=0x%x\n"), id); +#endif + return NULL; +} + +/**************************************************************************** + * Add a new cache entry. + *****************************************************************************/ +#if zNETWARE +SECacheNode_s *SE_AddEntryToCache( + NINT id, + NINT reqCount, + NINT idCount, + LONG *idList, + NINT privileges) +#endif +#if zLINUX +SECacheNode_s *SE_AddEntryToCache( + NDSid_t *id, + NINT reqCount, + NINT idCount, + NDSid_t *idList, + BOOL isSupervisor) +#endif +{ + SECacheNode_s *cacheNode = NULL; + NINT hashIndex; +#if zNETWARE + LONG *newList; +#endif +#if zLINUX + NDSid_t *newList; +#endif + +#if NSS_DEBUG IS_ENABLED +// SECache.gets--; +// if (SE_CheckCache(id) != NULL) +// { +// zASSERT("Trying to add SE cache entry that is already there" == 0); +// } +#endif + + /* + * Init the cache if it has not already been done. + */ + if (SECache.numHashEntries == 0) + { /* if not inited then init */ + if (SE_CacheInit() != zOK) + { + return NULL; + } + } + +#if zNETWARE + newList = malloc(sizeof(LONG) * idCount); + if (newList == NULL) + { + return NULL; + } + memcpy(newList, idList, sizeof(LONG) * idCount); +#endif +#if zLINUX + newList = malloc(sizeof(NDSid_t) * idCount); + if (newList == NULL) + { + return NULL; + } + memcpy(newList, idList, sizeof(NDSid_t) * idCount); +#endif + + X_LATCH(&SECache.latch); + hashIndex = SE_ComputeHash(id); + zASSERT(SECache.numEntries <= SECache.maxEntries); + if (SECache.numEntries >= SECache.maxEntries) + { /* if we have all the entries allowed */ + DQ_DEQ(&SECache.LRUqueue, cacheNode, SECacheNode_s, LRUlink); + DQ_RMV(cacheNode, hashLink); +#if zNETWARE + free(cacheNode->list); +#endif +#if zLINUX + free(cacheNode->guidList); +#endif + SECache.numVictimSelected++; + } + else + { + SECache.numEntries++; + cacheNode = objCacheAlloc(&SECache.seObjectCache); + } + zASSERT(cacheNode != NULL); /* object cache should always succeed */ + + /* fill in new entry */ + cacheNode->numSeEntries = idCount; + cacheNode->reqSeEntries = reqCount; +#if zNETWARE + cacheNode->list = newList; + cacheNode->id = id; + cacheNode->privileges = privileges; +#endif +#if zLINUX + cacheNode->guidList = newList; + memcpy(&cacheNode->guid, id, sizeof(NDSid_t)); + cacheNode->isSupervisor = isSupervisor; +#endif + + SECache.numAdded++; + + NULLIFY(&cacheNode->hashLink); + DQ_PUSH(&(*SECache.hash)[hashIndex], cacheNode, hashLink); /* link of hash list */ + NULLIFY(&cacheNode->LRUlink); + DQ_ENQ(&SECache.LRUqueue, cacheNode, LRUlink); /* link to the LRU queue */ +#if NSS_DEBUG IS_ENABLED +// { +// DBG_DebugPrintf(YELLOW, MSGNot("Added an ID to SE cache entry: id=0x%x\n"), +// id); +// } +// SE_DisplayCache(); +#endif + UNX_LATCH(&SECache.latch); + return cacheNode; +} + +/************************************************************************** + * Called to get security equivalence list. It front end the name service + * call with a cache. + ***************************************************************************/ +#if zNETWARE +STATUS COMN_GetSecurityEquivalenceList( + LONG objectID, + LONG bufferSizeInLongs, + LONG *securityEquivalenceList, + LONG *securityEquivalenceCount, + LONG *privileges) +{ + SECacheNode_s *node; + LONG status; + + node = SE_CheckCache(objectID, bufferSizeInLongs); + if (node != NULL) + { + memcpy(securityEquivalenceList, node->list, + sizeof(LONG) * node->numSeEntries); + *securityEquivalenceCount = node->numSeEntries; + *privileges = node->privileges; +#if NSS_DEBUG IS_ENABLED + { + NINT i; + DBG_DebugPrintf(YELLOW, MSGNot("Return SE cache entry: id=0x%x priv=0x%x\n"), + objectID, *privileges); + for (i = 0; i < node->numSeEntries; i++) + { + DBG_DebugPrintf(YELLOW, MSGNot(" (%d) id=0x%x\n"), i, (node->list)[i]); + } + } +#endif + return 0; + } + + MPKNSS_UNLOCK(); + status = (*(NameService.GetObjectSecurityEquivalenceList))( + 0, objectID, 0, + bufferSizeInLongs, securityEquivalenceList, + securityEquivalenceCount, NOCHECK); + if (status != 0) + { + MPKNSS_LOCK(); + return status; + } + status = (*(NameService.GetObjectPrivileges))(0, objectID, 0, privileges, + NOCHECK); + if (status != 0) + { + *privileges = 0; + } + MPKNSS_LOCK(); + + node = SE_AddEntryToCache(objectID, bufferSizeInLongs, + *securityEquivalenceCount, securityEquivalenceList, *privileges); +#if NSS_DEBUG IS_ENABLED + if (node == NULL) + { + aprintf(LRED, "NSS: Unable to add security equivelance cache entry\n"); + } +#endif + return 0; +} +#endif /* NetWare */ + +#if zLINUX +STATUS COMN_GetSecurityEquivalenceList( + NDSid_t *objectID, + LONG bufferSizeInGUIDs, + NDSid_t *securityEquivalenceList, + LONG *securityEquivalenceCount, + BOOL *isSupervisor) +{ + SECacheNode_s *node; + LONG status = 0; + NDSid_t *nwIDs; + unicode_t *objectDN; + size_t count; + + node = SE_CheckCache(objectID, bufferSizeInGUIDs); + if (node != NULL) + { + memcpy(securityEquivalenceList, node->guidList, + sizeof(NDSid_t) * node->numSeEntries); + *securityEquivalenceCount = node->numSeEntries; + *isSupervisor = node->isSupervisor; +#if NSS_DEBUG IS_ENABLED + { + NINT i; + DBG_DebugPrintf(YELLOW, MSGNot("Return SE cache entry: id=0x%x super=%d\n"), + objectID, *isSupervisor); + for (i = 0; i < node->numSeEntries; i++) + { + DBG_DebugPrintf(YELLOW, MSGNot(" (%d) id=0x%x 0x%x 0x%x 0x%x\n"), i, (node->guidList)[i]); + } + } +#endif + return 0; + } + + objectDN = malloc(sizeof(unicode_t) * (MAX_DN_CHARS+1)); + if (objectDN == NULL) + { + return( zERR_NO_MEMORY ); + } + + status = COMN_MapNDSGUIDToName(objectID, + (sizeof(unicode_t) * (MAX_DN_CHARS+1)), objectDN); + if (status != zOK) + { + free(objectDN); + return(status); + } + + MPKNSS_UNLOCK(); + status = ndp_NCPMapDNToSEV(objectDN, &count, &nwIDs, isSupervisor); + *securityEquivalenceCount = count; + free(objectDN); + if (status != zOK) + { + MPKNSS_LOCK(); + return status; + } + if (*securityEquivalenceCount > bufferSizeInGUIDs) + { + *securityEquivalenceCount = bufferSizeInGUIDs; + status = zERR_BUFFER_TOO_SMALL; + } + memcpy(securityEquivalenceList, nwIDs, + (sizeof(NDSid_t) * (*securityEquivalenceCount))); + kfree(nwIDs); + MPKNSS_LOCK(); + + node = SE_AddEntryToCache(objectID, bufferSizeInGUIDs, + *securityEquivalenceCount, securityEquivalenceList, *isSupervisor); +#if NSS_DEBUG IS_ENABLED + if (node == NULL) + { + aprintf(LRED, "NSS: Unable to add security equivelance cache entry\n"); + } +#endif + return(status); +} +EXPORT_SYMBOL(COMN_GetSecurityEquivalenceList); +#endif + +#if zNETWARE +/**************************************************************************** + * Given a resolved context, get the GUID for the object + *****************************************************************************/ +STATUS getGUID ( + LONG context, + NDSid_t *NDSid) +{ + enum + { + ATTR_DATA_SIZE = 512 + }; + + unsigned int count; + int err = zOK; + DDCVALUE *attributeData; + unicode_t *nameList[2]; + DDCReadFilter filter; + + MPKNSS_LOCK(); + + attributeData = zalloc(ATTR_DATA_SIZE); + if (attributeData == NULL) + { + err = zERR_NO_MEMORY; + goto out; + } + + nameList[0] = L"GUID"; + nameList[1] = 0; + + filter.syncFormat = 0; + filter.attributes = (DDCString **) &nameList; + filter.minValueTime.seconds = 0; + + + MPKNSS_UNLOCK(); + + err = (*DDCReadToBufferPtr)(context, &filter, DS_VALUE_INFO, + ATTR_DATA_SIZE - 1, ATTR_DATA_SIZE - 1, attributeData, &count); + if (err != 0) + { + *NDSid = zINVALID_GUID; + goto exit; + } + + zASSERT(count == 1); + zASSERT(attributeData->size == 16); + memcpy(NDSid, attributeData->data, 16); + +exit: + MPKNSS_LOCK(); + free(attributeData); +out: + MPKNSS_UNLOCK(); + return err; +} + +/************************************************************************** + * This routine converts a 32 bit NDS ID to a 128 bit NDS GUID. If it + * returns a failure then the GUID is set to an invalid GUID. The error + * return is only set if the return is zFAILURE. The error is not set + * in genMsg because this routine often front ends other routines that + * wish to set the error (and they cannot use the force method). + ***************************************************************************/ +STATUS COMN_MapNDSIDToGUID( + STATUS *error, + NINT objectID, + NDSid_t *ndsGUID) +{ +// ResolvePerf_s *resolvePerf; + IDtoGUIDCacheNode_s *cacheNode; + typedef struct Stack_s { + unicode_t unicodeDName[MAX_DN_CHARS+1]; + } Stack_s; + int context; + NINT status; + + STACK_ALLOC(); + +//#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, "Entering COMN_MapNDSIDToGUID. ID=%x\n",objectID); +//#endif + + ++AuthInst.id2guid.enter; + + switch (objectID) + { + case 0: + { + *ndsGUID = zINVALID_USERID; +//#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, "Return from COMN_MapNDSIDToGUID. ID=%x GUID=zINVALID_USERID\n",objectID); +//#endif + STACK_FREE(); + return zOK; + } + case 1: + { + *ndsGUID = zSECURE_CONNECTION_USERID; +//#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, "Return from COMN_MapNDSIDToGUID. ID=%x GUID=zSECURE_CONNECTION_USERID\n",objectID); +//#endif + STACK_FREE(); + return zOK; + } + case 0xff000001: /* special [public] ID from NDS */ + { +//#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, "Return from COMN_MapNDSIDToGUID. ID=%x GUID=Anyone\n",objectID); +//#endif + *ndsGUID = zANYONE_USERID; + STACK_FREE(); + return zOK; + } + case 0x1000000: /* special supervisor ID from NDS */ + { + *ndsGUID = zSUPERVISOR_USERID; +//#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, "Return from COMN_MapNDSIDToGUID. ID=%x GUID=zSUPERVISOR_USERID\n",objectID); +//#endif + STACK_FREE(); + return zOK; + } + default: + { + /* Check the cache */ + cacheNode = I2G_CheckCache(objectID); + if (cacheNode != NULL) + { /* cache node found */ + if (cacheNode->flags & I2G_POSITIVE_ENTRY) + { + *ndsGUID = cacheNode->guid; + STACK_FREE(); + return zOK; + } + else + { /* Negative Cache entry found */ + goto errorExitLocked; + } + } + + ++AuthInst.id2guid.mapObj; +// resolvePerf = ResolvePerf++; +// if (ResolvePerf == &ResolvePerfLog[MAX_PERF]) +// { +// ResolvePerf = ResolvePerfLog; +// } +// resolvePerf->start = Ticks; +// resolvePerf->diff = -1; +// resolvePerf->id = objectID; +// resolvePerf->err = 0; + MPKNSS_UNLOCK(); + if ((status = (*(NameService.MapObjectIDToGUID)) + (objectID, (char *)ndsGUID)) == 0) + { + MPKNSS_LOCK(); +//#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, +// "Return from COMN_MapNDSIDToGUID.\n"); +// DBG_DebugPrintf(YELLOW, " ID=%x GUID=%08x-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x\n", +// objectID, +// ndsGUID->timeLow, +// ndsGUID->timeMid, +// ndsGUID->timeHighAndVersion, +// ndsGUID->clockSeqHighAndReserved, +// ndsGUID->clockSeqLow, +// ndsGUID->node[0], +// ndsGUID->node[1], +// ndsGUID->node[2], +// ndsGUID->node[3], +// ndsGUID->node[4], +// ndsGUID->node[5]); +//#endif + goto exit; + } + + if (status != ERR_NO_SUCH_VALUE) + { + goto errorExit; + } + + /* + * Error handling on a value not found. + * + * We must check to see if this is a bindary object that can be + * mapped to a DS object (like the bindary server name). + */ + + if (!NdsPublicsLoaded) + { + MPKNSS_LOCK(); + if (LB_ImportNDSPublics((LONG)CMN_ModuleHandle) != zOK) + { +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED, "Error importing NDS publics.\n", + status); +#endif + goto errorExitLocked; + } + MPKNSS_UNLOCK(); + } + + /* + * Get local entry name + */ + status = (*DDSGetLocalEntryNamePtr)(objectID, + DDS_RESTRICT_TO_DS_NAMES, aStack->unicodeDName); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, "Error %d from DDSGetLocalEntryName.\n", + status); + MPKNSS_UNLOCK(); +#endif + goto errorExit; + } + + /* + * create context + */ + status = (*DDCCreateContextPtr)((LONG)CMN_ModuleHandle, &context); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "Error %d from DDCCreateContext.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExit; + } + + /* + * Set context flags + */ + status = (*DDCSetContextFlagsPtr)(context, + DDC_PRIVATE_CONNECTIONS | DDC_UNICODE_STRINGS, 0); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "Error %d from DDCSetContextFlags.\n", status); + MPKNSS_UNLOCK(); +#endif + (*DDCFreeContextPtr)(context); + goto errorExit; + } + + /* + * Resolve name + */ + ++AuthInst.id2guid.resolveName; + status = (*DDCResolveNamePtr)(context, + DS_READABLE | DS_DEREFERENCE_ALIASES, aStack->unicodeDName); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "Error %d from DDCResolveName.\n", status); + MPKNSS_UNLOCK(); +#endif + (*DDCFreeContextPtr)(context); + goto errorExit; + } + + status = getGUID(context, ndsGUID); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "Error %d from getGUID.\n", status); + MPKNSS_UNLOCK(); +#endif + (*DDCFreeContextPtr)(context); + goto errorExit; + } + + /* + * Release context + */ + (*DDCFreeContextPtr)(context); +// Return type is void and does not return a valid value +// status = (*DDCFreeContextPtr)(context); +// if (status != 0) +// { +//#if NSS_DEBUG IS_ENABLED +// MPKNSS_LOCK(); +// DBG_DebugPrintf(LRED, +// "Error %d from DDCFreeContext.\n", status); +// MPKNSS_UNLOCK(); +//#endif +// goto errorExit; +// } + MPKNSS_LOCK(); + goto exit; + } + } +exit: +// resolvePerf->diff = Ticks - resolvePerf->start; + ++AuthInst.id2guid.added; + I2G_AddEntryToCache(objectID, ndsGUID, TRUE); + STACK_FREE(); + return zOK; + +errorExit: + MPKNSS_LOCK(); +errorExitLocked: +// resolvePerf->diff = Ticks - resolvePerf->start; +// resolvePerf->err = status; + *ndsGUID = zINVALID_USERID; +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED, "Error %d converting ID to GUID. ID=%x\n", + status, objectID); +#endif + //zASSERT("Error converting ID to GUID" == 0); + *error = zERR_OBJECT_NOT_FOUND; + STACK_FREE(); + return zFAILURE; +} +#endif + + +#if zLINUX +/************************************************************************** + * This routine converts a 32 bit UID to a 128 bit NDS GUID. If it + * returns a failure then the GUID is set to an invalid GUID. The error + * return is only set if the return is zFAILURE. The error is not set + * in genMsg because this routine often front ends other routines that + * wish to set the error (and they cannot use the force method). + ***************************************************************************/ +STATUS COMN_MapUIDToNDSGUID( + STATUS *error, + NINT UID, + NDSid_t *ndsGUID) +{ + IDtoGUIDCacheNode_s *cacheNode; + typedef struct Stack_s { + unicode_t unicodeDName[MAX_DN_CHARS+1]; + } Stack_s; + NINT status; + unicode_t *ufdn; + + STACK_ALLOC(); + + ++AuthInst.id2guid.enter; + + if (UID == 0) + { + *ndsGUID = zSUPERVISOR_USERID; + STACK_FREE(); + return zOK; + } + else if ((HaveNobodyUID) && (LinuxNobodyUID == UID)) + { + *ndsGUID = zANYONE_USERID; + STACK_FREE(); + return zOK; + } + + /* Check the cache */ + cacheNode = I2G_CheckCache(UID); + if (cacheNode != NULL) + { /* cache node found */ + if (cacheNode->flags & I2G_POSITIVE_ENTRY) + { + *ndsGUID = cacheNode->guid; + STACK_FREE(); + return zOK; + } + else + { /* Negative Cache entry found */ + *ndsGUID = zINVALID_USERID; + *error = zERR_NEGATIVE_CACHE_ENTRY_FOUND; + STACK_FREE(); + return zFAILURE; + } + } + + ++AuthInst.id2guid.mapObj; + + MPKNSS_UNLOCK(); + status = ndp_NCPMapUIDToGUID(UID, ndsGUID); + if (status != zOK) + { + + /* If we failed to find the UID in eDir, it could be because the UID + * has never yet been used in NSS. Using LUM calls, try to get the DN + * and then get the eDir GUID from idBroker. + */ + + /* This functions returns the unicode FDN in a chunk of memory allocated + * by NDPMOD. When we are through with it, we must free it with a call + * to kfree. + */ + status = ndp_namGetUserFDNfromUID(UID, &ufdn); + if (status != zOK) + { +#if NSS_DEBUG IS_ENABLED + printk(KERN_ALERT "COMN_MapUIDToNDSGUID : UID %d is not a LUM enabled user\n", UID); +#endif + } + else + { + /* using the FDN, get the user's eDir GUID too. The act of making + * this call also tells the NCP-eDir code that NSS is interrested in + * tracking this GUID from now on ... + */ + status = ndp_NCPMapDNToGUID(1, ufdn, ndsGUID); + if (status != zOK) + { +#if NSS_DEBUG IS_ENABLED + printk("<1>" "COMN_MapUIDToNDSGUID Couldn't map the user's DN to a GUID, status=%d\n", status); +#endif + } + kfree( ufdn ); + } + } + MPKNSS_LOCK(); + + /* If we still failed, return an invalid GUID */ + if (status != zOK) + { + /* Add a negative cache node for this UID */ + *ndsGUID = zINVALID_USERID; +#if NSS_DEBUG IS_ENABLED + printk(KERN_ALERT "COMN_MapUIDToNDSGUID Adding NEGATIVE cache node for uid=%d\n", UID); +#endif + I2G_AddEntryToCache(UID, ndsGUID, FALSE); + goto errorExit; + } + + ++AuthInst.id2guid.added; + I2G_AddEntryToCache(UID, ndsGUID, TRUE); + STACK_FREE(); + return zOK; + +errorExit: + *ndsGUID = zINVALID_USERID; + *error = zERR_OBJECT_NOT_FOUND; + STACK_FREE(); + return zFAILURE; +} + +/**************************************************************************** + * COMN_UpdateUIDToGUIDCache - + * This function looks up the UID in the UID to GUID cache. + * If found, and if it is a negative entry, we change it to a positive entry + * and fill in the guid. + * If not found, or is already a positive entry, do nothing. + *****************************************************************************/ +void COMN_UpdateUIDToGUIDCache( + NINT UID, + NDSid_t *ndsGUID) +{ + IDtoGUIDCacheNode_s *cacheNode; + + /* Check the cache to see if it exists. */ + cacheNode = I2G_CheckCache(UID); + if (cacheNode != NULL) + { /* cache node found */ + if (cacheNode->flags & I2G_POSITIVE_ENTRY) + { + return; + } + else + { /* Negative Cache entry found */ + cacheNode->guid = *ndsGUID; +#if NSS_DEBUG IS_ENABLED + printk(KERN_ALERT "COMN_UpdateUIDToGUIDCache - Changing a negative to a positive entry for uid=%d\n", UID); +#endif + cacheNode->flags |= I2G_POSITIVE_ENTRY; + return; + } + } + /* Do nothing if not already in the cache. Let it get put there naturally. + * The purpose of this function was simply to get rid of a potential + * negative cache entry. + */ +} + +#endif + +/************************************************************************** + * This function checks to make sure the given name matches the given tree + * name. If it is not then the name is deleted from the object ID store. + ***************************************************************************/ +void COMN_ValidateTreeName( + GeneralMsg_s *genMsg, + Volume_s *volume, + NDSid_t *ndsGUID, + unicode_t *serverTreeName, + unicode_t *dName) +{ + NINT inLen; + NINT serverLen; + Xaction_s *xaction; + unicode_t noName = 0; + typedef struct Stack_s { + unicode_t inTreeName[MAX_TREE_NAME_CHARS + 1]; + } Stack_s; + + STACK_ALLOC(); + ASSERT_MPKNSS_LOCK(); + //DBG_DebugPrintf(YELLOW, "Validate names (%U / %U)................\n", serverTreeName, dName); + inLen = unilen(dName); + serverLen = unilen(serverTreeName); + /* + * This assumes that dName has dots around the tree name at the end of + * the full name. + */ + if ((serverLen + 2) <= inLen) + { + /* compare the server's tree name to the tree in the input name */ + if (dName[inLen-serverLen-2] == '.') + { + memcpy(aStack->inTreeName, &dName[inLen-serverLen-1], + serverLen*sizeof(unicode_t)); + aStack->inTreeName[serverLen] = 0; + //DBG_DebugPrintf(YELLOW, "inTreeName=%U................\n", aStack->inTreeName); + if (uniicmp(aStack->inTreeName, serverTreeName) == 0) + { + STACK_FREE(); + return; + } + } + } + + /* + * Remove user's name from the object ID store. We do not actually + * remove the user entry because it might still have ownership of + * some files and we do not want to lose the disk usage. The checker will + * eventually remove the user when all criteria are met. + */ + if (uniicmp(dName, L"") != 0) + { + aprintf(YELLOW, MSGNew("Removing %U from the NSS object ID store\n", 0), dName); + } + + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, X_CF_DEFAULT); + volume->VOLcomnVolOps.VOL_modifyObjectName(genMsg, volume, xaction, + ndsGUID, &noName, 0, 0); + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + STACK_FREE(); + return; +} + +#if zNETWARE +/************************************************************************** + * This function checks to make sure the given name is in the current + * tree. If it is not then the name is deleted from the object ID store. + ***************************************************************************/ +void COMN_CheckForValidTree( + GeneralMsg_s *genMsg, + Volume_s *volume, + int context, + NDSid_t *ndsGUID, + unicode_t *dName) +{ + uint32 version; + uint32 rootMostDepth; + uint32 returnedFlags; + char treeName[MAX_TREE_NAME_CHARS + 1]; + unicode_t serverTreeName[MAX_TREE_NAME_CHARS + 1]; + NINT status; + + if (dName[0] == 0) + { + return; + } + + /* Get the server's tree name */ + status = DDCPingPtr(context, &version, &rootMostDepth, treeName, + &returnedFlags, serverTreeName); + if (status == 0) + { + MPKNSS_LOCK(); + COMN_ValidateTreeName(genMsg, volume, ndsGUID, serverTreeName, dName); + MPKNSS_UNLOCK(); + } + else + { + zASSERT("Error from DDCPing in COMN_CheckForValidTree" == NULL); + } + return; +} +#endif + +/************************************************************************** + * This function checks to see if the current tree is the same as the + * last time we checked. If it has changed then we will invalidate the + * entries with the bad tree name. + ***************************************************************************/ +void COMN_CheckForChangedTree( + Volume_s *volume) +{ + enum + { + MAX_USER_INFO_ENTRIES = 16, + }; + + GeneralMsg_s genMsg; + NINT i; +#if zNETWARE + int context; + NINT status; + const unicode dotDelims[] = {DELIM_CFG_FALSE, DELIM_CFG_TRUE, + DELIM_DF_RDN, DELIM_DF_RDN, DELIM_DV, DELIM_VALUE, DELIM_WILD, + DELIM_DF_ESCAPE, 0}; +#endif + typedef struct Stack_s { + UserID_t lastUserReturned; + COMNUserRest_s userInfo[MAX_USER_INFO_ENTRIES]; +#if zNETWARE + uint32 version; + uint32 rootMostDepth; + uint32 returnedFlags; +#endif + } Stack_s; + NINT numReturned; + Xaction_s *xaction; +// unicode_t name[zMAX_COMPONENT_NAME]; + + + struct + { + unicode_t uniName[MAX_DN_CHARS+1]; + unicode_t storedTreeName[MAX_DN_CHARS+1]; + unicode_t serverTreeName[MAX_TREE_NAME_CHARS + 1]; +#if zNETWARE + char treeName[MAX_TREE_NAME_CHARS + 1]; +#endif + } *alloc = NULL; + + STACK_ALLOC(); + ASSERT_MPKNSS_LOCK(); + + if (volume->VOLenabledAttributes & zATTR_READONLY) + { + goto exit; + } + /* We must skip deleted volumes otherwise we may alloc blocks + * to the usertree after LV purge has deleted them all. This + * would cause unaccountable blocks. + */ + if ( volume->VOLpState == zVOL_PSTATE_DELETION ) + { + goto exit; + } + + alloc = malloc(sizeof(*alloc)); + if (alloc == NULL) + { + zASSERT("Error browsing users in volume (mem alloc)" == NULL); + goto exit; + } + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + +#if zLINUX +{ + int err; + + MPKNSS_UNLOCK(); + if ((err = ndp_NCPLocalTreeName(sizeof(alloc->serverTreeName), + alloc->serverTreeName)) != zOK) + { + MPKNSS_LOCK(); + printk(KERN_ALERT "Unable to get server tree name from eDir, err=%d\n", err); +// zASSERT("Unable to get tree name from eDir" == NULL); + goto exitFree; + } + MPKNSS_LOCK(); +} +#endif + +#if zNETWARE + if (!NdsPublicsLoaded) + { + if (LB_ImportNDSPublics((LONG)CMN_ModuleHandle) != zOK) + { + zASSERT("zERR_UNABLE_TO_IMPORT_NDS_PUBLICS" == NULL); + goto exitFree; + } + } + + MPKNSS_UNLOCK(); + /* + * create context + */ + status = (*DDCCreateContextPtr)((LONG)CMN_ModuleHandle, &context); + if (status != 0) + { + MPKNSS_LOCK(); +// zASSERT("Error from DDCCreateContext" == NULL); + goto exitFree; + } + + /* + * Set context flags + */ + status = (*DDCSetContextFlagsPtr)(context, + DDC_PRIVATE_CONNECTIONS | DDC_UNICODE_STRINGS, 0); + if (status != 0) + { + MPKNSS_LOCK(); + zASSERT("Error from DDCSetContextFlags." == NULL); + goto exitFree; + } + + /* + * Look for right-rooted (dot-delim) name + */ + status = (*DDCSetContextBaseDNPtr)(context, NULL, dotDelims); + if (status != 0) + { + zASSERT("Error from DDCSetContextBaseDNPtr." == NULL); + goto exitContext; + } + + /* Login as a server to have all rights */ + status = (*DDSLoginAsServerPtr)(context); + if (status != 0) + { + if (Ticks > 1000) zASSERT("Error from DDSLoginAsServerPtr." == NULL); + goto exitContext; + } + + /* Get the server's tree name */ + if (DDCPingPtr(context, &aStack->version, &aStack->rootMostDepth, alloc->treeName, + &aStack->returnedFlags, alloc->serverTreeName) != 0) + { + zASSERT("Unable to get the current tree for the server" == NULL); + goto exitLogout; + } + MPKNSS_LOCK(); +#endif + + /* + * Get the tree name from the last time we were activated. + */ + if (volume->VOLcomnVolOps.VOL_getObjectName(&genMsg, volume, + &zTREENAME_ID, alloc->storedTreeName, NULL, NULL) == zOK) + { + if (uniicmp(alloc->storedTreeName, alloc->serverTreeName) == 0) + { +//DBG_DebugPrintf(YELLOW, "eDir Trees are the same (%U)................\n", alloc->storedTreeName); + goto exitLogoutLocked; + } + } + else + { + ClearErrno(&genMsg); + alloc->storedTreeName[0] = L'\0'; + } + +//DBG_DebugPrintf(YELLOW, "eDir Trees are different (%U / %U)................\n", alloc->storedTreeName, alloc->serverTreeName); + aStack->lastUserReturned = zINVALID_USERID; + for (;;) + { + if (volume->VOLcomnVolOps.VOL_browseUsersInVolume(&genMsg, volume, + MAX_USER_INFO_ENTRIES, &aStack->lastUserReturned, aStack->userInfo, + &numReturned, BROWSE_USERS_GET_ALL) != zOK) + { + zASSERT("Error browsing users in volume" == NULL); + ClearErrno(&genMsg); + break; + } + if (numReturned == 0) + { + break; /* done */ + } + + /* Check the name for each entry */ + for (i = 0; i < numReturned; i++) + { + if (volume->VOLcomnVolOps.VOL_getObjectName(&genMsg, volume, + &aStack->userInfo[i].userID, alloc->uniName, NULL, NULL) == zOK) + { + /* Don't check special GUIDs. Their names don't change */ + if (aStack->userInfo[i].userID.timeHighAndVersion != 0) + { + COMN_ValidateTreeName(&genMsg, volume, &aStack->userInfo[i].userID, + alloc->serverTreeName, alloc->uniName); + } + } + else + { + ClearErrno(&genMsg); + zASSERT("Error getting object name" == NULL); + } + } + } + + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, X_CF_DEFAULT); + volume->VOLcomnVolOps.VOL_insertObjectName(&genMsg, volume, xaction, + &zTREENAME_ID, alloc->serverTreeName); + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + +exitLogoutLocked: + volume->VOLv_statusFlag &= ~VOL_SF_CHECK_EDIR_TREE; + +#if zNETWARE + MPKNSS_UNLOCK(); +exitLogout: + (*DDCLogoutPtr)(context); +exitContext: + (*DDCFreeContextPtr)(context); + MPKNSS_LOCK(); +#endif + +exitFree: + free(alloc); + +exit: + STACK_FREE(); + return; +} + +/************************************************************************** + * This function checks to see if the current tree is the same as the + * last time we checked on all active volumes. + ***************************************************************************/ +void COMN_CheckAllVolumesForChangedTree() +{ + GeneralMsg_s genMsg; + Volume_s *volume; +// unicode_t name[zMAX_COMPONENT_NAME]; + + ASSERT_MPKNSS_LOCK(); + + /* + * Start by checking all volumes to see if we are in the same tree as we + * were last time we checked. This is only occasionally since it is + * expensive. + */ +//DBG_DebugPrintf(YELLOW, "Checking all volumes for tree change..........\n"); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + SET_FOREACHBLOCKING(&NSSMasterVolumeList, volume, Volume_s, masterVolLink) + { /*** You MUST NOT use continue in this loop because the macro + *** SET_FOREACHBLOCKINGEND (at end of for loop) must be called + *** every time through the loop. Technically, you + *** can use a continue BEFORE any blocking calls. + ***/ +//COMN_GetVolumeName(&genMsg, volume, name, NELEMS(name)); +//DBG_DebugPrintf(YELLOW, "Checking a volume (%U) for tree change..........\n", name); + COMN_USE_BEAST(&volume->VOLroot); + if (COMN_LockVolumeActive(&genMsg, volume, FALSE) == zOK) + { + if (volume->VOLv_statusFlag & VOL_SF_CHECK_EDIR_TREE) + { + COMN_CheckForChangedTree(volume); + } + COMN_UnlockVolumeActive(volume, FALSE); + } + COMN_Release(&volume); + SET_FOREACHBLOCKINGEND(&NSSMasterVolumeList, volume, Volume_s, + masterVolLink); + } +} + +/************************************************************************** + * This function gets the name for an ID from the object ID store and + * resolves to the NDS object. It then reads the ID from the object and + * returns it. + ***************************************************************************/ +STATUS COMN_GetIDFromObjectStore( + STATUS *error, + Volume_s *volume, + NDSid_t *ndsGUID, + LONG *objectID) +{ + typedef struct Stack_s { + unicode_t unicodeDName[MAX_DN_CHARS+1]; + utf8_t utf8DName[4*(MAX_DN_CHARS+1)]; + } Stack_s; + NINT status; + GeneralMsg_s genMsg; +#if zNETWARE + int context; + const unicode dotDelims[] = {DELIM_CFG_FALSE, DELIM_CFG_TRUE, + DELIM_DF_RDN, DELIM_DF_RDN, DELIM_DV, DELIM_VALUE, DELIM_WILD, + DELIM_DF_ESCAPE, 0}; +#endif +#if zLINUX + NDSid_t otherGUID; +#endif + + STACK_ALLOC(); + +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(YELLOW, + "COMN_GetIDFromObjectStore: getting name for GUID 0x%x.\n", + ndsGUID->timeLow); +#endif + +#if zNETWARE + if (!NdsPublicsLoaded) + { + if (LB_ImportNDSPublics((LONG)CMN_ModuleHandle) != zOK) + { +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED, + "G2I:Unable to import NDS publics.\n"); +#endif + *error = zERR_UNABLE_TO_IMPORT_NDS_PUBLICS; + STACK_FREE(); + return zFAILURE; + } + } +#endif + + /* + * Start by checking to see if we are in the same tree as we were last + * time we checked. This is done here in case it was missed for this volume + * at startup time. + */ + if (volume->VOLv_statusFlag & VOL_SF_CHECK_EDIR_TREE) + { + //aprintf(YELLOW, "Calling COMN_CheckForChangedTree from COMN_GetIDFromObjectStore..........\n"); + COMN_CheckForChangedTree(volume); + } + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + if (OID_GetObjectName(&genMsg, volume, ndsGUID, aStack->unicodeDName) != zOK) + { + if (GetErrno(&genMsg) == zERR_FULL_NAME_NOT_FOUND) + { +#if NSS_DEBUG IS_ENABLED + status = zERR_FULL_NAME_NOT_FOUND; +#endif + goto errorExitLocked; + } + + *objectID = 0; + *error = GetErrno(&genMsg); +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED, + "G2I:Error %d from OID_GetObjectName.\n", *error); +#endif + STACK_FREE(); + return zFAILURE; + } + +#if zNETWARE + MPKNSS_UNLOCK(); + + /* + * create context + */ + status = (*DDCCreateContextPtr)((LONG)CMN_ModuleHandle, &context); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "G2I:Error %d from DDCCreateContext.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExitUnlocked; + } + + /* + * Set context flags + */ + status = (*DDCSetContextFlagsPtr)(context, + DDC_PRIVATE_CONNECTIONS | DDC_UNICODE_STRINGS, 0); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "G2I:Error %d from DDCSetContextFlags.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExitFree; + } + + /* + * Look for right-rooted (dot-delim) name + */ + status = (*DDCSetContextBaseDNPtr)(context, NULL, dotDelims); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "G2I:Error %d from DDCSetContextBaseDNPtr.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExitFree; + } + + /* Login as a server to have all rights */ + status = (*DDSLoginAsServerPtr)(context); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "G2I:Error %d from DDSLoginAsServerPtr.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExitFree; + } + + /* + * Resolve the name to an ID and create the xref + */ + status = (*DDCNameToIDPtr)(context, DS_CREATE_ID, aStack->unicodeDName); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "G2I:Error %d from DDCNameToID.\n", status); + MPKNSS_UNLOCK(); +#endif + COMN_CheckForValidTree(&genMsg, volume, context, ndsGUID, aStack->unicodeDName); + goto errorLogout; + } + +// /* +// * Resolve name +// */ +// status = (*DDCResolveNamePtr)(context, +// DS_READABLE | DS_DEREFERENCE_ALIASES, aStack->unicodeDName); +// if (status != 0) +// { +//#if NSS_DEBUG IS_ENABLED +// MPKNSS_LOCK(); +// DBG_DebugPrintf(LRED, +// "G2I:Error %d from DDCResolveName.\n", status); +// MPKNSS_UNLOCK(); +//#endif +// goto errorExitFree; +// } +// + /* Get entry info */ + status = (*DDCGetEntryInfoPtr)(context, DSI_ENTRY_ID, sizeof(*objectID), + objectID); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "Error %d from DDCGetEntryInfoPtr.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExitFree; + } + + /* + * Logout + */ + (*DDCLogoutPtr)(context); + + /* + * Release context + */ + (*DDCFreeContextPtr)(context); +// Return type is void and does not return a valid value +// status = (*DDCFreeContextPtr)(context); +// if (status != 0) +// { +//#if NSS_DEBUG IS_ENABLED +// MPKNSS_LOCK(); +// DBG_DebugPrintf(LRED, +// "Error %d from DDCFreeContext.\n", status); +// MPKNSS_UNLOCK(); +//#endif +// goto errorExitUnlocked; +// } + MPKNSS_LOCK(); +#endif + +#if zLINUX + /* force the eDir code to know about this DN. Make sure the + * returned guid is the same one we started with. + */ + MPKNSS_UNLOCK(); + status = ndp_NCPMapDNToGUID(1, aStack->unicodeDName,&otherGUID); + if ((status != 0) || (LB_GUIDCompare(ndsGUID, &otherGUID) != 0)) + { + if (status != 0) + { + if ((uni2utf(aStack->unicodeDName, aStack->utf8DName, sizeof(aStack->utf8DName))) == -1) + { + printk(KERN_ALERT "Error %d mapping a name to its GUID.\n", status); + } + else + { + if (status == -601) + { + printk(KERN_ALERT "Unable to find %s to get the GUID.\n", aStack->utf8DName); + } + else + { + printk(KERN_ALERT "Error %d mapping a name (%s) to its GUID.\n", status, aStack->utf8DName); + } + } + } + else + { + char edirGUID[GUID_FORMAT_SIZE]; + char nssGUID[GUID_FORMAT_SIZE]; + LB_GUIDToString(ndsGUID, sizeof(edirGUID), edirGUID); + LB_GUIDToString(&otherGUID, sizeof(nssGUID), nssGUID); + printk(KERN_ALERT "GUID in eDir (%s) does not match the GUID in NSS (%s)\n", edirGUID, nssGUID); + } + goto errorExitUnlocked; + } + /* Now, ask the eDir code to give us the UID for this GUID */ + status = ndp_NCPMapGUIDToUID(ndsGUID, objectID); + if (status != 0) + { + // Users that are not LUM enabled cause errors, so we only want to + // display the message if it is for some other reason. + if (status != -601) + { + printk(KERN_ALERT "Error %d getting UID for GUID.\n", status); + } + goto errorExitUnlocked; + } + MPKNSS_LOCK(); +#endif + + +#if NSS_DEBUG IS_ENABLED +DBG_DebugPrintf(LMAGENTA, "COMN_GetIDFromObjectStore: ID=%d Name=%U\n", + *objectID, aStack->unicodeDName); +#endif + STACK_FREE(); + *error = zOK; + return zOK; + +#if zNETWARE +errorLogout: + (*DDCLogoutPtr)(context); +errorExitFree: + (*DDCFreeContextPtr)(context); +#endif + +errorExitUnlocked: + MPKNSS_LOCK(); + +errorExitLocked: +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED, "Error %d converting GUID to ID. GUID=%x\n", + status, ndsGUID->timeLow); +#endif + *error = zERR_OBJECT_NOT_FOUND; + *objectID = 0; + STACK_FREE(); + return zFAILURE; +} + +#if zNETWARE +/************************************************************************** + * This routine converts a 128 bit NDS GUID to a 32 bit NDS ID. If it + * returns a failure then the ID is set to zero. The error + * return is only set if the return is zFAILURE. The error is not set + * in genMsg because this routine often front ends other routines that + * wish to set the error (and they cannot use the force method). + ***************************************************************************/ +STATUS COMN_MapNDSGUIDToID( + STATUS *error, + Volume_s *volume, + NDSid_t *ndsGUID, + LONG *objectID) +{ + return COMN_MapNDSGUIDToIDWithNameMsg(error, volume, ndsGUID, objectID, + NULL); +} +#endif +#if zLINUX +/************************************************************************** + * This routine converts a 128 bit NDS GUID to a 32 bit Linux UID. If it + * returns a failure then the UID is set to -1. The error + * return is only set if the return is zFAILURE. The error is not set + * in genMsg because this routine often front ends other routines that + * wish to set the error (and they cannot use the force method). + ***************************************************************************/ +STATUS COMN_MapNDSGUIDToUID( + STATUS *error, + NDSid_t *ndsGUID, + LONG *objectID) +{ + return COMN_MapNDSGUIDToIDWithNameMsg(error, NULL, ndsGUID, objectID, NULL); +} +#endif + +/*************************************************************************** + * This is the basic mapping routine without the calls to the object store + * to try to resolve the object ID to a name. + ***************************************************************************/ +STATUS COMN_LocalMapNDSGUIDToID( + STATUS *error, + NDSid_t *ndsGUID, + LONG *objectID, + NamingMsg_s *nameMsg, + BOOL *addToCache) +{ + GUIDtoIDCacheNode_s *cacheNode; + NINT status; + + ASSERT_MPKNSS_LOCK(); + + *addToCache = FALSE; + ++AuthInst.guid2id.enter; + *error = zOK; + if (ndsGUID->timeHighAndVersion == 0) + { /* special guid */ + if (LB_GUIDCompare(ndsGUID, &zINVALID_USERID) == 0) + { + *objectID = 0; + return zOK; + } + + if (LB_GUIDCompare(ndsGUID, &zSUPERVISOR_USERID) == 0) + { +#if zNETWARE + *objectID = 0x1000000; /* This is a special ID defined by NDS */ +#endif +#if zLINUX + *objectID = 0; /* This is a the ROOT UID defined by Linux */ +#endif + return zOK; + } + + if (LB_GUIDCompare(ndsGUID, &zANYONE_USERID) == 0) + { +#if zNETWARE + *objectID = 0xff000001; + return zOK; +#endif +#if zLINUX + if (HaveNobodyUID) + { + *objectID = LinuxNobodyUID; + return zOK; + } + *error = zERR_GUID_NOT_FOUND; + return zFAILURE; +#endif + } + + if (LB_GUIDCompare(ndsGUID, &zSECURE_CONNECTION_USERID) == 0) + { +#if zNETWARE + *objectID = 1; +#endif +#if zLINUX + *objectID = 0; /* This is a the ROOT UID defined by Linux */ +#endif + return zOK; + } + if (LB_GUIDCompare(ndsGUID, &zTREENAME_ID) == 0) + { + *objectID = 0; + return zOK; + } + if (ndsGUID->clockSeqHighAndReserved == 0xFF) + { + /* This is a special use of the GUID field to store a 32 bit ID */ + *objectID = ndsGUID->timeLow; + return zOK; + } + zASSERT("Bad special GUID" == 0); + *objectID = zERR_GUID_NOT_FOUND; + return zFAILURE; + } + + /* Check the cache */ + cacheNode = G2I_CheckCache(ndsGUID); + if (cacheNode != NULL) + { /* cache node found */ + if (cacheNode->flags & G2I_POSITIVE_ENTRY) + { + *objectID = cacheNode->id; + return zOK; + } + else + { +#if NSS_DEBUG IS_ENABLED +// DBG_DebugPrintf(YELLOW, "G2I - Negative cache hit. GUID=%x\n", ndsGUID->timeLow); +#endif + *objectID = 0; + *error = zERR_NEGATIVE_CACHE_ENTRY_FOUND; + return zFAILURE; + } + } + + ++AuthInst.guid2id.mapId; + + if (nameMsg) + { + COMN_UNLATCH_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + } + + MPKNSS_UNLOCK(); +#if zNETWARE + status = (*(NameService.MapGUIDToObjectID))((char *)ndsGUID, objectID); +#endif +#if zLINUX + status = ndp_NCPMapGUIDToUID(ndsGUID, objectID); +#endif + MPKNSS_LOCK(); + if (nameMsg) + { + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, nameMsg->latchType); + } + + *addToCache = TRUE; + if (status) + { +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LMAGENTA, "G2I: Error %d", status); +#endif + /* Don't put in negative cache entries for certain NDS errors */ + if (status == DSERR_TIMEOUT || status == ERR_DS_LOCKED) + { +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LMAGENTA, " -- not adding to cache"); +#endif + *addToCache = FALSE; + } +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LMAGENTA, "\n"); +#endif + *error = zERR_GUID_NOT_FOUND; + return zFAILURE; + } + return zOK; +} + + +/************************************************************************** + * This routine is almost the same as COMN_MapNDSGUIDToID except that + * caller holds latch/latches which should be released in order to avoid + * potential deadlock if guid is not found in cache and NDS routine has + * to be called. + ***************************************************************************/ +STATUS COMN_MapNDSGUIDToIDWithNameMsg( + STATUS *error, + Volume_s *volume, + NDSid_t *ndsGUID, + LONG *objectID, + NamingMsg_s *nameMsg) +{ + BOOL found = TRUE; + BOOL addToCache; + STATUS status; + + ASSERT_MPKNSS_LOCK(); + + if (COMN_LocalMapNDSGUIDToID(error, ndsGUID, objectID, nameMsg, + &addToCache) != zOK) + { + GeneralMsg_s genMsg; + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + if (*error == zERR_NEGATIVE_CACHE_ENTRY_FOUND) + { + return zFAILURE; + } + /* + * Try to get the ID from the volume's object store + */ + *objectID = 0; + if (nameMsg) + { + volume = nameMsg->curvol; + } + if (volume) + { + if (nameMsg) + { + COMN_UNLATCH_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + } + + if ((status = COMN_LockVolumeActive(&genMsg, volume, FALSE)) == zOK) + { + status = COMN_GetIDFromObjectStore(error, volume, ndsGUID,objectID); + COMN_UnlockVolumeActive(volume, FALSE); + } + else + { + ClearErrno(&genMsg); + } + if (nameMsg) + { + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, nameMsg->latchType); + } + if (status == zOK) + { + addToCache = TRUE; + } + else + { + found = FALSE; + } + } + else + { + SET_FOREACHBLOCKING(&NSSMasterVolumeList, volume, Volume_s, + masterVolLink) + { /*** You MUST NOT use continue in this loop because the macro + *** SET_FOREACHBLOCKINGEND (at end of for loop) must be called + *** every time through the loop. Technically, you + *** can use a continue BEFORE any blocking calls. + ***/ + COMN_USE_BEAST(&volume->VOLroot); + if (COMN_LockVolumeActive(&genMsg, volume, FALSE) != zOK) + { + ClearErrno(&genMsg); + COMN_Release(&volume); + goto next; + } + + if (nameMsg) + { + COMN_UNLATCH_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + } + status = COMN_GetIDFromObjectStore(error, volume, ndsGUID, + objectID); + if (nameMsg) + { + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, nameMsg->latchType); + } + COMN_UnlockVolumeActive(volume, FALSE); + COMN_Release(&volume); + if (status == zOK) + { + addToCache = TRUE; + goto addToCache; + } +next: + SET_FOREACHBLOCKINGEND(&NSSMasterVolumeList, volume, Volume_s, + masterVolLink); + } + found = FALSE; + } + } +addToCache: + if (addToCache) + { + G2I_AddEntryToCache(ndsGUID, *objectID, found); + } + return found ? zOK : zFAILURE; +} + +#if zLINUX +/*************************************************************************** + * This is the basic mapping routine without the calls to the object store + * to try to resolve the object ID to a name. + ***************************************************************************/ +STATUS COMN_MapNDSGUIDToName( + NDSid_t *ndsGUID, + size_t nameSize, + unicode_t *name) +{ + STATUS status; + + ASSERT_MPKNSS_LOCK(); + + if (ndsGUID->timeHighAndVersion == 0) + { /* special guid */ + //printk(KERN_ALERT "COMN_MapNDSGUIDToName checking for special GUIDs\n"); + + if (LB_GUIDCompare(ndsGUID, &zINVALID_USERID) == 0) + { + return zFAILURE; + } + + if (LB_GUIDCompare(ndsGUID, &zSUPERVISOR_USERID) == 0) + { + unicpy(name, L"[Supervisor]"); + return zOK; + } + + if (LB_GUIDCompare(ndsGUID, &zANYONE_USERID) == 0) + { + unicpy(name, L"[Public]"); + return zOK; + } + + if (LB_GUIDCompare(ndsGUID, &zSECURE_CONNECTION_USERID) == 0) + { + return zFAILURE; + } + if (LB_GUIDCompare(ndsGUID, &zTREENAME_ID) == 0) + { + return zFAILURE; + } + zASSERT("Bad special GUID" == 0); + } + + //printk(KERN_ALERT "COMN_MapNDSGUIDToName calling ndp_NCPMapGUIDToDN\n"); + MPKNSS_UNLOCK(); + status = ndp_NCPMapGUIDToDN(ndsGUID, nameSize, name); + MPKNSS_LOCK(); + + return status; +} +#endif diff --git a/src/nwnss/comn/common/cSAcache.c b/src/nwnss/comn/common/cSAcache.c new file mode 100644 index 0000000..26b590e --- /dev/null +++ b/src/nwnss/comn/common/cSAcache.c @@ -0,0 +1,163 @@ +/**************************************************************************** + | + | (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: vandana $ + | $Date: 2005-08-10 01:03:51 +0530 (Wed, 10 Aug 2005) $ + | + | $RCSfile$ + | $Revision: 1177 $ + | + |--------------------------------------------------------------------------- + +-------------------------------------------------------------------------*/ + +#include +#include + +#include +#include +#include + +#include "xMsg.h" +#include "csa.h" + + +/***************************************************************************** + * + ****************************************************************************/ +void CSA_MsgSendAll( + Volume_s *volume, + xMsg_s *msg, + NINT method) +{ + CsaVolumeDoor_s *csaVolObject; + CsaVolumeDoor_s *prevCsaVolObject; + + if (CSA_SLAVE_VOLUMES_FOUND(volume)) + { + DQ_FOREACH_NONEXT(&volume->v_csaVolInfo->CVI_csaVolumeDoorHead, + csaVolObject, CsaVolumeDoor_s, csaVolumeDoorLink) + { + MSG_USE_DOOR(&csaVolObject->door); + MSG_Send(csaVolObject->xlssVolumeKey, method, (Msg_s *)msg); + + DQ_FOREACH_NEXT(prevCsaVolObject, csaVolObject, + CsaVolumeDoor_s, csaVolumeDoorLink); + /*** WARNING - csaVolumeDoorLink now points to + *** the next item. Generally, code below this + *** should only be 'freeing' prevCsaVolObject. + ***/ + MSG_RELEASE_DOOR(&prevCsaVolObject->door); + } + } + + return; +} + +/***************************************************************************** + * + ****************************************************************************/ +void CSA_RemoveNameCacheEntry( + Volume_s *volume, + Zid_t parentZid, + NINT nameSpaceMask, + NINT nameType, + unicode_t *uniName, + NINT nsFlag) +{ + xMsg_s msg; + CSA_NameCacheInvalidateMsg_s *csaPacket = + &msg.body.nameCacheInvalidate.csaPacket; + + xMSG_INIT( &msg ); + + csaPacket->CNCM_parentZid = parentZid; + csaPacket->CNCM_nameSpaceMask = nameSpaceMask; + csaPacket->CNCM_nameType = nameType; + csaPacket->CNCM_nsFlag = nsFlag; + + msg.sys.data[0].start = (QUAD)(uintptr_t)uniName; + msg.sys.data[0].length = (unilen(uniName) + 1) * sizeof(unicode_t); + msg.sys.numDataAreas++; + msg.sys.readMask = 0x01; + + CSA_MsgSendAll(volume, &msg, XLSS_NAME_CACHE_CLEANUP); + return; +} + + +/***************************************************************************** + * + ****************************************************************************/ +void CSA_InvalidateAuthCache( + GeneralMsg_s *genMsg, + UserID_t *trusteeID, + BOOL entireCache) +{ + xMsg_s msg; + CSA_AuthCacheInvalidateMsg_s *csaPacket = + &msg.body.authCacheInvalidate.csaPacket; + Volume_s *volume; + + xMSG_INIT( &msg ); + + csaPacket->CACM_trusteeID = *trusteeID; + csaPacket->CACM_entireCache = entireCache; + + SET_FOREACHBLOCKING(&NSSMasterVolumeList, volume, Volume_s, masterVolLink) + { + if (CSA_SLAVE_VOLUMES_FOUND(volume)) + { + COMN_USE_BEAST(&volume->VOLroot); + if (COMN_LockVolumeActive(genMsg, volume, FALSE) != zOK) + { + COMN_Release(&volume); + ClearErrno(genMsg); + goto continueWithNextVolume; + } + CSA_MsgSendAll(volume, &msg, XLSS_AUTH_CACHE_CLEANUP); + COMN_UnlockVolumeActive(volume, FALSE); + COMN_Release(&volume); + } +continueWithNextVolume: + SET_FOREACHBLOCKINGEND(&NSSMasterVolumeList, volume, Volume_s, + masterVolLink) + } + return; +} + +/***************************************************************************** + * + ****************************************************************************/ +void CSA_NotifyAllSlavesSyncd( + Volume_s *volume) +{ + xMsg_s msg; + + xMSG_INIT( &msg ); + + CSA_MsgSendAll(volume, &msg, XLSS_ALL_SLAVES_SYNCD); + return; +} diff --git a/src/nwnss/comn/common/cSAmanager.c b/src/nwnss/comn/common/cSAmanager.c new file mode 100644 index 0000000..f0ef73e --- /dev/null +++ b/src/nwnss/comn/common/cSAmanager.c @@ -0,0 +1,517 @@ +/**************************************************************************** + | + | (C) Copyright 1995-1999 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 Loadable Storage Services (LSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2005-08-10 01:03:51 +0530 (Wed, 10 Aug 2005) $ + | + | $RCSfile$ + | $Revision: 1177 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Provide startup code for Cluster Semantic Agent + +-------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "csa.h" +#include "csaLease.h" +#include "guid.h" + + + /* + * Setup IPC + */ +typedef struct CsaMsgType_s +{ + mTypeHeader_s hdr; + statusfunc_t method[CSA_MSG_NUM_METHODS]; +} CsaMsgType_s; + +typedef statusfunc_t CM_t; +extern STATUS CsaObjectDestruct(CsaMsgDoor_s *volObject); +extern STATUS CsaVolumeObjectDestruct(CsaVolumeDoor_s *volObject); + +ADDR CSA_ConsumerIDExit; +BOOL CSA_StartupCompleted = TRUE; +CsamManager_s CsaMsgMgr = { 0 }; + +CsaMsgType_s CsaMsgType = +{ + MSG_INIT_TYPE("CsaMasterVolume", &DoorType.hdr, sizeof(CsaMsgDoor_s), + CSA_MSG_NUM_METHODS, + NULL, NULL, CsaObjectDestruct, NULL, MSG_BreakDoor), + { + (CM_t)CSA_VolNotifyMsg, /* CSA_VOL_NOTIFY */ + (CM_t)CSA_VolGetAuthModelIDMsg, /* CSA_VOL_GET_AUTH_ID */ + } +}; + +CsaVolumeType_s CsaVolumeType = +{ + MSG_INIT_TYPE("CsaVolume", &DoorType.hdr, sizeof(CsaVolumeDoor_s), + CSA_VOL_NUM_METHODS, + NULL, NULL, CsaVolumeObjectDestruct, NULL, MSG_BreakDoor), + { + (CM_t)CSA_VOL_GetBeastFromVolumeMsg, /* CSA_GET_BEAST */ + (CM_t)CSA_VOL_WildcardLookupMsg, /* CSA_WILD_LOOKUP */ + (CM_t)CSA_VOL_LookupByNameInDirectoryMsg, /* CSA_LOOKUP_NAME */ + (CM_t)CSA_VOL_GetStorageInfoMsg, /* CSA_GET_STORAGE_INFO */ + (CM_t)CSA_VOL_IsBlockInBeastMsg, /* CSA_IS_BLOCK_IN_BEAST */ + (CM_t)CSA_VOL_GetFileBlkMsg, /* CSA_GET_FILE_BLK */ + (CM_t)CSA_VOL_AsyncReadFileBlkMsg, /* CSA_ASYNC_READ_BLK */ + (CM_t)CSA_VOL_GetExtentListMsg, /* CSA_GET_EXTENT_LIST */ + (CM_t)CSA_VOL_IsDirectoryEmptyMsg, /* CSA_IS_DIR_EMPTY */ + (CM_t)CSA_VOL_GetPhysicalExtentMsg, /* CSA_GET_PHY_EXTENT */ + (CM_t)CSA_VOL_DioReadUnitsMsg, /* CSA_DIO_READ */ + (CM_t)CSA_SearchMapCleanupMsg, /* CSA_SMAP_CLEANUP */ + (CM_t)CSA_BeastLeaseTossMsg, /* CSA_BEAST_LEASE_TOSS */ + (CM_t)CSA_ReconnectNotifyMsg, /* CSA_RECONNECT_NOTIFY */ + (CM_t)CSA_BeastLeaseRecreateMsg, /* CSA_BEAST_LEASE_RECREATE */ + (CM_t)CSA_SearchMapReestablishMsg, /* CSA_SMAP_REESTABLISH */ + (CM_t)CSA_SearchMapCleanupAllMsg, /* CSA_SMAP_CLEANUP_ALL */ + (CM_t)CSA_AccessLeaseOpenMsg, /* CSA_ACCESS_LEASE_OPEN */ + (CM_t)CSA_AccessLeaseCloseMsg, /* CSA_ACCESS_LEASE_CLOSE */ + (CM_t)CSA_AccessLeaseCleanupAllMsg, /* CSA_ACCESS_LEASE_CLEANUP_ALL */ + } +}; + + +STATUS CSA_SupplyVolName (unicode_t *name, VolumeID_t *guid) +{ + STATUS rc; + GeneralMsg_s genMsg; + Key_t csaMsgKey; + CsaMsgDoor_s *volObject; + Volume_s *volume; + + ASSERT_MPKNSS_LOCK(); + volObject = MSG_CreateDoor(&CsaMsgType.hdr, CsaMsgMgr.mgr, 0, &csaMsgKey); + if (volObject == NULL) + { + return zFAILURE; + } + volObject->name = malloc((unilen(name) + 1) * sizeof(unicode_t)); + if (volObject->name == NULL) + { + goto errorReturn; + } + unicpy(volObject->name, name); + volObject->volumeID = *guid; + + COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE(&genMsg); + volume = COMN_VolumeIDLookup(&genMsg, guid, FALSE); + if (volume == NULL) + { + goto errorReturn; + } + volObject->volume = volume; + + rc = SWBD_SupplyKey(CsaMsgMgr.client, name, csaMsgKey); + if (rc) + { + goto errorReturn; + } + return zOK; + +errorReturn: + MSG_DestroyKey(csaMsgKey); + return zFAILURE; +} + +BOOL CSA_matchCleanup ( mDoor_s *door, VolumeID_t *guid ) +{ + CsaMsgDoor_s *volDoor = (CsaMsgDoor_s *)door; + + if (LB_GUIDCompare(&volDoor->volumeID, guid) == 0) + { + /* This will cause the object to be destroyed */ + return TRUE; + } + return FALSE; +} + +void CSA_SupplyVolCleanup( VolumeID_t *guid) +{ + MSG_BreakSetOfDoors(&CsaMsgType.hdr, CSA_matchCleanup, guid); +} + +LONG CSA_ChangeVolStateExit (struct EventBlock *evBlk) +{ + EventChangeVolStateExit_s *data; + Volume_s *volume; + GeneralMsg_s genMsg; + CsaVolumeDoor_s *csaVolObject; + + data = (EventChangeVolStateExit_s *)evBlk->EBEventData; + + if (data->oldState == data->newState) + { + return 0; + } + +// if (data->newState == zVOLSTATE_ACTIVE) +// { +// /* +// * We just had a volume come on line, advertise it in +// * the switchboard +// */ +// rc = xVolumeGUIDToName( &data->volID, volName, zMAX_COMPONENT_NAME); +// if (rc) +// { +// return 0; +// } +// MPKNSS_LOCK(); +// rc = CSA_SupplyVolName(volName, &data->volID); +// MPKNSS_UNLOCK(); +// } +// else + if (data->newState != zVOLSTATE_ACTIVE) + { + MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE(&genMsg); + volume = COMN_VolumeIDLookup(&genMsg, &data->volID, FALSE); + if (volume != NULL) + { + if (CSA_SLAVE_VOLUMES_FOUND(volume)) + { + while (1) + { + DQ_DEQ( &volume->v_csaVolInfo->CVI_csaVolumeDoorHead, + csaVolObject, CsaVolumeDoor_s, csaVolumeDoorLink); + if (csaVolObject == NULL) + { + break; + } + MSG_BreakDoor(&csaVolObject->door); + } + + if (volume->v_csaVolInfo->CVI_volume != NULL) + { + zASSERT(volume == volume->v_csaVolInfo->CVI_volume); + COMN_Release(&volume->v_csaVolInfo->CVI_volume); + } + } + COMN_Release(&volume); + } + + CSA_SupplyVolCleanup(&data->volID); + MPKNSS_UNLOCK(); + } + return 0; +} + +STATUS CSA_RegisterForVolumeEvents (void) +{ + struct ConsumerRegistrationInfo consumerRegInfo; + + ASSERT_MPKNSS_LOCK(); + + /* register for EVENT_ChangeVolState_Exit */ + consumerRegInfo.CRIVersion = NEB_CONSUMER_VERSION1; + consumerRegInfo.CRIConsumerName = MSGNot("NSS.cSA"); + + consumerRegInfo.CRIEventFlags = 0; + consumerRegInfo.CRIOwnerID = CMN_ModuleHandle; + consumerRegInfo.CRIConsumerESR = 0; + consumerRegInfo.CRISecurityToken = 0; + consumerRegInfo.CRIConsumerFlags = 0; + consumerRegInfo.CRIFilterName = 0; + consumerRegInfo.CRIFilterDataLength = 0; + consumerRegInfo.CRIFilterData = 0; + consumerRegInfo.CRIConsumerCallback = (void *)CSA_ChangeVolStateExit; + consumerRegInfo.CRIOrder = 0; + consumerRegInfo.CRIConsumerType = SYNCHRONOUS_CONSUMER; + + consumerRegInfo.CRIEventName = MSGNot("NSS.ChangeVolState.Exit"); + consumerRegInfo.CRIUserParameter = (void *)EVENT_ChangeVolState_Exit; + ZOS_RegisterConsumer( &consumerRegInfo); + CSA_ConsumerIDExit = (ADDR)consumerRegInfo.CRIConsumerID; + + return zOK; +} + +/* FixFixFix - Make this configurable */ +#define WAIT_FOR_SLAVE_TIMEOUT 5 +#define WAIT_FOR_SLAVE_SYNC_TIMEOUT 5 +#define WAIT_FOR_SLAVE_AL_SYNC_TIMEOUT 10 +#define WAIT_FOR_SLAVE_BL_SYNC_TIMEOUT 10 + +void CSA_CheckForSlavesAndSync( + Volume_s *volume) +{ + GeneralMsg_s genMsg; + STATUS rc; + NINT timeout; + CsaVolumeDoor_s *csaVolObject; + BOOL allSyncd = FALSE; + typedef struct Stack_s { + unicode_t volName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + if (!(volume->VOLenabledAttributes & zATTR_CFS_MASTER)) + { + STACK_FREE(); + return; + } + + /* + * We just had a volume come on line, advertise it in + * the switchboard + */ + + + rc = COMN_GetVolumeName(&genMsg, volume, aStack->volName, zMAX_COMPONENT_NAME); + if (rc) + { + STACK_FREE(); + return; + } + volume->v_statusFlag |= VOL_SF_RECONNECT; + rc = CSA_SupplyVolName(aStack->volName, &volume->VOLvolumeID); + if (rc) + { + volume->v_statusFlag &= ~VOL_SF_RECONNECT; + STACK_FREE(); + return; + } + + timeout = WAIT_FOR_SLAVE_TIMEOUT; + while ((volume->v_csaVolInfo == NULL) && timeout--) + { + LB_delay(1000); + } + if (volume->v_csaVolInfo == NULL) + { + volume->v_statusFlag &= ~VOL_SF_RECONNECT; + STACK_FREE(); + return; + } + + timeout = WAIT_FOR_SLAVE_SYNC_TIMEOUT; + while (DQ_EMPTY(&volume->v_csaVolInfo->CVI_csaVolumeDoorHead)) + { + LB_delay(1000); + if (--timeout == 0) + { + break; + } + } + if (timeout != 0) + { + LB_delay(5000); /* Wait for additional slaves to show up */ + } + zASSERT(timeout != 0); + + timeout = WAIT_FOR_SLAVE_AL_SYNC_TIMEOUT; + while (!allSyncd) + { + LB_delay(1000); + allSyncd = TRUE; + DQ_FOREACH( &volume->v_csaVolInfo->CVI_csaVolumeDoorHead, csaVolObject, + CsaVolumeDoor_s, csaVolumeDoorLink) + { + if (csaVolObject->reconnectState >= CRO_RECONNECT_STATE_SYNC_PHASE1) + { + continue; + } + else + { + allSyncd = FALSE; + } + } + if (--timeout == 0) + { + break; + } + } + zASSERT(timeout != 0); + + timeout = WAIT_FOR_SLAVE_BL_SYNC_TIMEOUT; + while (!allSyncd) + { + LB_delay(1000); + allSyncd = TRUE; + DQ_FOREACH( &volume->v_csaVolInfo->CVI_csaVolumeDoorHead, csaVolObject, + CsaVolumeDoor_s, csaVolumeDoorLink) + { + if (csaVolObject->reconnectState == CRO_RECONNECT_STATE_IN_SYNC) + { + continue; + } + else + { + allSyncd = FALSE; + } + } + if (--timeout == 0) + { + break; + } + } + zASSERT(timeout != 0); + + volume->v_statusFlag &= ~VOL_SF_RECONNECT; + if (allSyncd) + { + CSA_NotifyAllSlavesSyncd(volume); + } + + STACK_FREE(); + return; +} + +STATUS CsaObjectDestruct(CsaMsgDoor_s *volObject) +{ + if (volObject->volume != NULL) + { + COMN_Release(&volObject->volume); + } + if (volObject->name != NULL) + { + free(volObject->name); + volObject->name = NULL; + } + return zOK; +} + + +/* + * CsaVolumeObjectDestruct()- + * This is called whenever a CsaVolumeDoor_s is destroyed. + * + */ +STATUS CsaVolumeObjectDestruct(CsaVolumeDoor_s *volObject) +{ + if (QMEMBER(&volObject->csaVolumeDoorLink)) + { + DQ_RMV(volObject, csaVolumeDoorLink); + } + //FixFixFix Decide what to do at Clean deactivate: Should we tell the + // the slaves that we are going away or let the slave wait for reconnect + // So call MSG_DestroyKey only if we want slaves to go + // away. + + /* Tell slave that we are going away */ +// MSG_DestroyKey(volObject->xlssVolumeKey); + + /* The only time we don't have a volume is when we failed in + * the creation of the CsaVolumeDoor_s object. + */ + if (volObject->volume != NULL) + { + /* Clean up the resources that are connected to us */ + CSA_CloseFileHandlesForASlave( volObject); + CSA_SearchMapCleanupAll( volObject ); + CSA_CSABeastCleanup( volObject ); /* Uses volObject->volume */ + COMN_Release(&volObject->volume); + } + return zOK; +} + +STATUS CSA_Ipc (void) +{ + STATUS rc; + + ASSERT_MPKNSS_LOCK(); + + CsaMsgMgr.mgr = MSG_CreateObject( &ManagerType.hdr); + if (CsaMsgMgr.mgr == NULL) + { + return zFAILURE; + } + rc = MSG_RegisterType( &CsaMsgType.hdr, CsaMsgMgr.mgr); + if (rc) + { + goto error; + } + rc = MSG_RegisterType( &CsaVolumeType.hdr, CsaMsgMgr.mgr); + if (rc) + { + goto error; + } + CsaMsgMgr.client = SWBD_NewClient("Csa"); + if (CsaMsgMgr.client == NULL) + { + goto error; + } + if (CSA_RegisterForVolumeEvents()) + { + goto error; + } + return zOK; + +error: + MSG_KillManager(CsaMsgMgr.mgr); + return zFAILURE; +} + +void CSA_Shutdown (void) +{ + ASSERT_MPKNSS_LOCK(); + if (CSA_StartupCompleted ) + { + MSG_KillManager(CsaMsgMgr.mgr); + objCacheDestroy( &CSASearchMapCleanupList); + CSA_StartupCompleted = FALSE; + } +} + +STATUS CSA_Startup(void) +{ + ASSERT_MPKNSS_LOCK(); + /* + * Tell the IPC we are here + */ + if (CSA_Ipc() != 0) + { + goto error; + } + if (objCacheCreate( &CSASearchMapCleanupList, "CSASearchMapCleanupList", + sizeof(SearchMapCleanupIDList_s), NULL) != zOK) + { + goto error; + } + CSA_StartupCompleted = TRUE; + return zOK; + +error: + CSA_Shutdown(); + return zFAILURE; +} diff --git a/src/nwnss/comn/common/checker.c b/src/nwnss/comn/common/checker.c new file mode 100644 index 0000000..5ac6410 --- /dev/null +++ b/src/nwnss/comn/common/checker.c @@ -0,0 +1,1074 @@ +/**************************************************************************** + | + | (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: 2006-11-14 05:57:30 +0530 (Tue, 14 Nov 2006) $ + | + | $RCSfile$ + | $Revision: 1632 $ + | + |--------------------------------------------------------------------------- + | This module has the routines used to run the background checker. + +-------------------------------------------------------------------------*/ +#include /* NetWare includes*/ +#include + +//#include /* NDS includes */ +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include "comnPublics.h" +#include "pssStartup.h" +#include "volume.h" +#include "comnCmdline.h" +#include "comnAuthorize.h" +#include "xAdminVolume.h" +#include "checker.h" +#include "pssConfig.h" +#include "ndp_idbroker.h" +#include "nssPubs.h" + +#define CHK_DEBUG 0 + + +NINT CHK_RetryMax = CHK_RetryMax_DEFAULT; +NINT CHK_TimeThreshold = CHK_TimeThreshold_DEFAULT; +NINT CHK_StartupWaitSeconds = CHK_StartupWaitSeconds_DEFAULT; +NINT CHK_WaitSeconds = CHK_WaitSeconds_DEFAULT; + +#define CHK_NUM_REQUESTED_ZIDS 500 +#define CHECK_BUSY_NUM_BEASTS 1000 +#define CHK_DELAY_AMOUNT 100 +#define CHK_MAX_NUM_BETWEEN_DELAY CHK_NUM_REQUESTED_ZIDS + +/* GLOBALS */ +THREAD CHK_ThreadID; +BOOL CHK_ThreadRunning = FALSE; +BOOL CHK_ShutdownRequest = FALSE; +BOOL CHK_Sleeping = FALSE; +OneShot_s CHK_Alarm; + +NINT LastTimeChecked = 0; +NINT EndingBeastOpenCount = 0; +QUAD EndingReadWriteCount = 0; +NINT CHK_BeastsProcessed = 0; +NINT CHK_NumBetweenDelay = (CHK_MAX_NUM_BETWEEN_DELAY / 2); + +/*************************************************************************** + * This function is called to wake up the checker before the normal time. + ***************************************************************************/ +void CHK_Wakeup() +{ + if (CHK_Sleeping) + { + CANCEL_ALARM(CHK_Alarm); + Continue(CHK_ThreadID); + CHK_Sleeping = FALSE; + } +} + +/*************************************************************************** + * This function is called when the alarm goes off + ***************************************************************************/ +void CHK_TimedOut( + NINT seconds) +{ + zASSERT(CHK_Sleeping); + Continue(CHK_ThreadID); + CHK_Sleeping = FALSE; +} + +/*************************************************************************** + * This function puts the checker to sleep for the specified number of + * seconds. + ***************************************************************************/ +void CHK_Sleep( + NINT seconds) +{ + ASSERT_MPKNSS_LOCK(); + + INIT_ONESHOT(CHK_Alarm); + secOneShot( &CHK_Alarm, seconds, CHK_TimedOut); + CHK_Sleeping = TRUE; + Wait(); +} + +/*************************************************************************** + * This function logout of and releases a context + ***************************************************************************/ +void CHK_ComputeDelayTime() +{ + NINT actualTime; + NINT expectedTime; + NINT thresholdAmount; + + /* If it has not been long enough then just return */ + if (CHK_BeastsProcessed < CHECK_BUSY_NUM_BEASTS) + { + return; + } + + actualTime = GetHighResolutionTimer() - LastTimeChecked; + expectedTime = (CHK_BeastsProcessed * 10000 / CHK_NumBetweenDelay) / + (1000 / CHK_DELAY_AMOUNT); + + thresholdAmount = expectedTime + (expectedTime >> 3); /* 112.5% of expected */ + +#if CHK_DEBUG + aprintf(LMAGENTA, "Checker time: actual=%d expected=%d threshold=%d\n", + actualTime, expectedTime, thresholdAmount); +#endif + + if (actualTime > thresholdAmount) + { + CHK_NumBetweenDelay = (CHECK_BUSY_NUM_BEASTS * 100) / + ((actualTime * 100) / expectedTime); + /* Make sure we require at least one beast on each delay */ + if (CHK_NumBetweenDelay == 0) + { + CHK_NumBetweenDelay = 1; + } + } + else + { + CHK_NumBetweenDelay = CHECK_BUSY_NUM_BEASTS; + } + +#if CHK_DEBUG + aprintf(LCYAN, "Checker computed CHK_NumBetweenDelay=%d\n", + CHK_NumBetweenDelay); +#endif + LastTimeChecked = GetHighResolutionTimer(); + CHK_BeastsProcessed = 0; +} + +#if zNETWARE +/*************************************************************************** + * This function logout of and releases a context + ***************************************************************************/ +STATUS CHK_ReleaseContext( + int context) +{ + LONG status=zOK; + + MPKNSS_UNLOCK(); + /* + * Logout + */ + (*DDCLogoutPtr)(context); + + /* + * Release context + */ + (*DDCFreeContextPtr)(context); +// Return type is void and does not return a valid value +// status = (*DDCFreeContextPtr)(context); +// if (status != 0) +// { +//#if NSS_DEBUG IS_ENABLED +// MPKNSS_LOCK(); +// DBG_DebugPrintf(LRED, +// "CHK_GetConnection:Error %d from DDCFreeContext.\n", status); +// MPKNSS_UNLOCK(); +//#endif +// } + MPKNSS_LOCK(); + return status; +} + +/************************************************************************** + * This function creates an authenticated context. + ***************************************************************************/ +STATUS CHK_GetContext( + int *context) +{ + LONG status; + + const unicode dotDelims[] = {DELIM_CFG_FALSE, DELIM_CFG_TRUE, + DELIM_DF_RDN, DELIM_DF_RDN, DELIM_DV, DELIM_VALUE, DELIM_WILD, + DELIM_DF_ESCAPE, 0}; + + MPKNSS_UNLOCK(); + /* + * create context + */ + status = (*DDCCreateContextPtr)((LONG)CMN_ModuleHandle, context); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "CHK_GetConnection:Error %d from DDCCreateContext.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExit; + } + + /* + * Set context flags + */ + status = (*DDCSetContextFlagsPtr)(*context, + DDC_PRIVATE_CONNECTIONS | DDC_UNICODE_STRINGS, 0); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "CHK_GetConnection:Error %d from DDCSetContextFlags.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExitFree; + } + + /* + * Look for right-rooted (dot-delim) name + */ + status = (*DDCSetContextBaseDNPtr)(*context, NULL, dotDelims); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "CHK_GetConnection:Error %d from DDCSetContextBaseDNPtr.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExitFree; + } + + /* Login as a server to have all rights */ + status = (*DDSLoginAsServerPtr)(*context); + if (status != 0) + { +#if NSS_DEBUG IS_ENABLED + MPKNSS_LOCK(); + DBG_DebugPrintf(LRED, + "CHK_GetConnection:Error %d from DDSLoginAsServerPtr.\n", status); + MPKNSS_UNLOCK(); +#endif + goto errorExitFree; + } + MPKNSS_LOCK(); + return zOK; + + +errorExitFree: + (*DDCFreeContextPtr)(*context); +errorExit: +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED, "Error %d getting context.\n", status); +#endif + MPKNSS_LOCK(); + return zFAILURE; +} +#endif + +/************************************************************************** + * This function checks to see if we are shutting down the checker on this + * volume. It returns TRUE in that case. + ***************************************************************************/ +BOOL CHK_ShutdownVolume( + Volume_s *volume) +{ + /* + * If the volume is deactiviating or checking has been suspended + * then return TRUE. + */ + if (volume->v_statusFlag & VOL_SF_LEAVING_ACTIVE_STATE_CLEANUP || + (!Config.Storage.checker && !Config.Storage.forceChecker) || + CHK_ShutdownRequest) + { + return TRUE; + } + return FALSE; +} + +/************************************************************************** + * This function checks the user tree to make sure that the entries are + * still valid. + ***************************************************************************/ +void CHK_CheckUsers( + Volume_s *volume, + unicode_t *volName) +{ + enum + { + MAX_USER_INFO_ENTRIES = 16, + }; + + GeneralMsg_s genMsg; + NINT numReturned; + Xaction_s *xaction; + STATUS status; + NINT i; + NINT ccode; + Time_t timeNotFound; + NINT numberOfTimesNotFound; +#if zNETWARE + int context; + LONG oldID; + BOOL addToCache; +#endif + + struct + { + struct + { + unicode_t *namePtr; + unicode_t uniName[MAX_DN_CHARS+1]; + } name; + unicode_t uniName[MAX_DN_CHARS+1]; + COMNUserRest_s userInfo[MAX_USER_INFO_ENTRIES]; + UserID_t lastUserReturned; + UserID_t currentGUID; + } *alloc = NULL; + +#if zNETWARE + if (!NdsPublicsLoaded) + { + if (LB_ImportNDSPublics((LONG)CMN_ModuleHandle) != zOK) + { + return; + } + } +#endif + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + +#if CHK_DEBUG + DBG_DebugPrintf(LCYAN, "Volume: %x\n", volume); +#endif + if (CHK_ShutdownVolume(volume)) + { + return; + } + + alloc = malloc(sizeof(*alloc)); + if (alloc == NULL) + { + zASSERT("Error browsing users in volume (mem alloc)" == NULL); + goto exit; + } + +#if zNETWARE + if (CHK_GetContext(&context) != zOK) + { + zASSERT("Error browsing users in volume (get context)" == NULL); + goto exitFree; + } +#endif + + aprintf(YELLOW, "Doing NSS background check of user IDs on volume %U\n", + volName); + + alloc->lastUserReturned = zINVALID_USERID; + for (;;) + { + if (volume->VOLcomnVolOps.VOL_browseUsersInVolume(&genMsg, volume, + MAX_USER_INFO_ENTRIES, &alloc->lastUserReturned, alloc->userInfo, + &numReturned, BROWSE_USERS_GET_ALL) != zOK) + { + zASSERT("Error browsing users in volume" == NULL); + goto exitFreeContext; + } + if (numReturned == 0) + { + break; /* done */ + } + + /* Check the name for each entry */ + for (i = 0; i < numReturned; i++) + { + if (CHK_ShutdownVolume(volume)) + { + goto exitFreeContext; + } + +#if CHK_DEBUG + DBG_DebugPrintf(LCYAN, "Checking user %x\n", alloc->userInfo[i].userID.timeLow); +#endif + if (LB_GUIDCompare(&alloc->userInfo[i].userID, &zTREENAME_ID) == 0) + { + continue; + } + + /* Delay so we don't overload the system with background requests. */ + LB_delay(1); + +#if zLINUX + /* + * Make sure the name is up to date. It could have been + * renamed in NDS and the volume was not active so the event + * was missed. + */ + alloc->name.namePtr = alloc->name.uniName; + //printk(KERN_ALERT "CHK_CheckUsers calling COMN_MapNDSGUIDToName\n"); + ccode = COMN_MapNDSGUIDToName(&alloc->userInfo[i].userID, + sizeof(alloc->name.uniName), alloc->name.uniName); + if (ccode == 0) + { +#if CHK_DEBUG + DBG_DebugPrintf(YELLOW, + "CHK_CheckUsers: Change name to:%U\n", + alloc->name.namePtr); +#endif + + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, + X_CF_DEFAULT); + status = volume->VOLcomnVolOps.VOL_insertObjectName( + &genMsg, volume, xaction, &alloc->userInfo[i].userID, + alloc->name.namePtr); + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + if (status != zOK) + { + ClearErrno(&genMsg); + zASSERT("CHK_CheckUsers : Error changing name in object store" == NULL); + } + } +#endif +#if zNETWARE + if (COMN_LocalMapNDSGUIDToID(&status, &alloc->userInfo[i].userID, + &oldID, NULL, &addToCache) == zOK) + { + /* + * Set context using ID + */ + MPKNSS_UNLOCK(); + ccode = (*DDCSetContextEntryIDPtr)(context, oldID); + if (ccode == 0) + { + /* + * Get entry info + */ + ccode = (*DDCGetEntryInfoPtr)(context, DSI_ENTRY_DN, + sizeof(alloc->name), &alloc->name); + if (ccode == 0) + { +#if CHK_DEBUG + DBG_DebugPrintf(YELLOW, + "CHK_CheckUsers: Change name to:%U\n", + alloc->name.namePtr); +#endif + MPKNSS_LOCK(); + + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, + X_CF_DEFAULT); + status = volume->VOLcomnVolOps.VOL_insertObjectName( + &genMsg, volume, xaction, &alloc->userInfo[i].userID, + alloc->name.namePtr); + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + if (status != zOK) + { + ClearErrno(&genMsg); + zASSERT("CHK_CheckUsers : Error changing name in object store" == NULL); + } + } + else + { + MPKNSS_LOCK(); +// zASSERT("Error in DDCGetEntryInfo" == NULL); + } + } + else + { + MPKNSS_LOCK(); + zASSERT("Error from DDCSetContextEntryID" == NULL); + } + } +#endif + /* + * Get the object's name and check to make sure the name can still + * be found in NDS. + */ + + if (volume->VOLcomnVolOps.VOL_getObjectName(&genMsg, volume, + &alloc->userInfo[i].userID, alloc->uniName, &timeNotFound, + &numberOfTimesNotFound) != zOK) + { +#if CHK_DEBUG + DBG_DebugPrintf(YELLOW, + "CHK_CheckUsers:Can't find user. GUID=%d.\n", alloc->userInfo[i].userID.timeLow); +#endif + /* + * If there is no name and we have disk space then we are OK, + * otherwise, we can remove this entry. + */ + if (GetErrno(&genMsg) == zERR_FULL_NAME_NOT_FOUND) + { + if (alloc->userInfo[i].usedAmount > 0) + { + ClearErrno(&genMsg); + continue; + } + else + { + status = volume->VOLcomnVolOps.VOL_removeUser(&genMsg, + volume, &alloc->userInfo[i].userID); + } + } + } + else + { +#if CHK_DEBUG + DBG_DebugPrintf(YELLOW, + "CHK_CheckUsers: Found User=%U\n", &alloc->uniName); +#endif + /* + * Check to make sure we can still look up this name. + */ + MPKNSS_UNLOCK(); +#if zLINUX + ccode = ndp_NCPMapDNToGUID(1, alloc->uniName, + &alloc->currentGUID); +#endif +#if zNETWARE + ccode = (*DDCNameToIDPtr)(context, DS_CREATE_ID, + &alloc->uniName); +#endif + MPKNSS_LOCK(); + if (ccode != 0 || alloc->uniName[0] == 0) + { + /* + * Got an error looking up the name. If enough time has + * passed and we have re-tried enough times then get rid + * of this entry. + */ +#if CHK_DEBUG + DBG_DebugPrintf(LRED, + "CHK_CheckUsers:Error %d looking up user. count=%d time=%d curtime=%d\n", + status, numberOfTimesNotFound, timeNotFound, + GetUTCTime()); +#endif + if ((numberOfTimesNotFound >= CHK_RetryMax) && + (GetUTCTime() - timeNotFound > CHK_TimeThreshold) && + (alloc->userInfo[i].usedAmount <= 0)) + { +#if CHK_DEBUG + DBG_DebugPrintf(LRED, "CHK_CheckUsers: Removing User.\n"); +#endif + status = volume->VOLcomnVolOps.VOL_removeUser(&genMsg, + volume, &alloc->userInfo[i].userID); + } + else + { +#if CHK_DEBUG + DBG_DebugPrintf(LRED, "CHK_CheckUsers: Modifying User.\n"); +#endif + if (timeNotFound == 0) + { + timeNotFound = GetUTCTime(); + } + numberOfTimesNotFound++; + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, + X_CF_DEFAULT); + status = volume->VOLcomnVolOps.VOL_modifyObjectName( + &genMsg, volume, xaction, &alloc->userInfo[i].userID, + alloc->uniName, timeNotFound, + numberOfTimesNotFound); + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + } + } + else + { + /* + * Make sure that the guid from the name is the same one + * as the entry we started with. + */ +#if zNETWARE + /* On Linux, the above successful call to ndp_NCPMapDNToGUID + * already gave us a GUID + */ + if (COMN_MapNDSIDToGUID(&status, + DDCContextEntryIDPtr(context), &alloc->currentGUID) == zOK) +#endif + { + if (LB_GUIDCompare(&alloc->currentGUID, &alloc->userInfo[i].userID) + != 0) + { + timeNotFound = GetUTCTime() - CHK_TimeThreshold; + numberOfTimesNotFound = CHK_RetryMax; + alloc->uniName[0] = 0; + } + } + if (timeNotFound) + { + /* + * If found and it was previously not found then clear + * the "not found" time and count. + */ + if (alloc->uniName[0] != 0) + { + timeNotFound = 0; + numberOfTimesNotFound = 0; + } + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, + X_CF_DEFAULT); + status = volume->VOLcomnVolOps.VOL_modifyObjectName( + &genMsg, volume, xaction, &alloc->userInfo[i].userID, + alloc->uniName, timeNotFound, + numberOfTimesNotFound); + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + } + } + } +#if CHK_DEBUG + DBG_DebugPrintf(LCYAN, "user finished: %U\n", &alloc->uniName); +#endif + } + } + +exitFreeContext: +#if zNETWARE + CHK_ReleaseContext(context); +exitFree: +#endif + free(alloc); +exit: + return; +} + +/**************************************************************************** + * This function checks to see if the ID is still valid. + ****************************************************************************/ +STATUS CHK_VerifyID( + GeneralMsg_s *genMsg, + Volume_s *volume, + UserID_t *objectID, + BOOL *isOK) +{ + LONG oldID; + BOOL addToCache; + STATUS status; + + typedef struct Stack_s { + unicode_t uniName[MAX_DN_CHARS+1]; + } Stack_s; + + STACK_ALLOC(); + + *isOK = TRUE; + if (LB_GUIDCompare(objectID, &zINVALID_GUID) == 0) + { + *isOK = FALSE; + STACK_FREE(); + return zOK; + } + + if (volume->VOLcomnVolOps.VOL_getObjectName(genMsg, volume, + objectID, aStack->uniName, NULL, NULL) != zOK) + { + if (GetErrno(genMsg) != zERR_FULL_NAME_NOT_FOUND) + { + STACK_FREE(); + return zFAILURE; + } + ClearErrno(genMsg); + + /* + * Unable to find the name in the object ID store. Do another check of + * NDS just to make sure. If it's not found then return FALSE. + */ + if (COMN_LocalMapNDSGUIDToID(&status, objectID, + &oldID, NULL, &addToCache) != zOK) + { + *isOK = FALSE; + } + else + { + /* + * NDS knows about this GUID. It should be re-added to the object + * ID store the next time the checker runs. + */ + } + } + STACK_FREE(); + return zOK; +} + +/************************************************************************** + * This function checks the beast tree to make sure that the user IDs are + * still valid. + ***************************************************************************/ +void CHK_CheckFiles( + Volume_s *volume, + unicode_t *volName) +{ + GeneralMsg_s genMsg; + Zid_t startingZid = 0; + Zid_t *zidArray; + NINT numReturnedZids; + RootBeast_s *beast; + NINT index; + NINT numDone; + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + +#if CHK_DEBUG + DBG_DebugPrintf(LGREEN, "Volume for CHK_CheckFiles: %x\n", volume); +#endif + if (CHK_ShutdownVolume(volume)) + { + return; + } + + zidArray = malloc(CHK_NUM_REQUESTED_ZIDS * sizeof(Zid_t)); + if (zidArray == NULL) + { + goto exit; + } + + aprintf(YELLOW, "Doing NSS background check of files on volume %U\n", + volName); + + /* + * Update the object information for each beast + */ + LastTimeChecked = GetHighResolutionTimer(); + numDone = 0; + do + { + CHK_ComputeDelayTime(); + if (volume->VOLcomnVolOps.VOL_browseBeastsInVolume(&genMsg, volume, + SELECT_BEASTS_ALL, CHK_NUM_REQUESTED_ZIDS, &startingZid, zidArray, + &numReturnedZids) != zOK) + { + goto exitFree; + } + /* Process each entry */ + for (index = 0; index < numReturnedZids; index++) + { + if (CHK_ShutdownVolume(volume)) + { + goto exitFree; + } + + /* Delay so we don't overload the system with background requests. */ + if (++numDone >= CHK_NumBetweenDelay) + { + LB_delay(CHK_DELAY_AMOUNT); + numDone = 0; + } + + if ((beast = COMN_LookupByZid(&genMsg, volume, zidArray[index], + XLATCHED, TRUE)) == NULL) + { + ClearErrno(&genMsg); + continue; + } + + /* Take care of Authorization model fields */ + if (COMN_IsDerivedFrom(beast, zFTYPE_AUTH_BEAST)) + { + CHK_BeastsProcessed++; + ((AuthBeast_s *)beast)->AUTHauthModelOps-> + checkUserIDs(&genMsg, volume, (AuthBeast_s *)beast); + } + COMN_UnlatchAndRelease(&beast, XLATCHED); + } + } while (numReturnedZids > 0); + + /* Indicate that all beasts are upgraded to the current version */ + /* NOTE: This code only upgrades beasts to version 2. It does + * not upgrade to version 3 and beyond. + */ + if(volume->VOLbeastVersion == BEAST_VERSION_2) + { + volume->VOLbeastVersionMask = 1 << (BEAST_VERSION_2 - 1); + } + + + /* + * NOTE: Flushing the volume flushes the system beasts which writes the + * volume's persistent data, so the beastVersionMask will be written out + * and all of the beasts will have been flushed. + */ + (void)VOL_FlushVolume(&genMsg, volume); + +exitFree: + free(zidArray); +exit: + return; +} + +/*************************************************************************** + * This function checks the directory tree to make sure that the entries are + * still valid. + ***************************************************************************/ +void CHK_CheckDirectoryQuotas( + Volume_s *volume, + unicode_t *volName) +{ + enum + { + MAX_DIR_INFO_ENTRIES = 16, + }; + + GeneralMsg_s genMsg; + Zid_t lastDirReturned; + NINT numReturned; + Xaction_s *xaction; + NINT i; + RootBeast_s *beast; + typedef struct Stack_s { + COMNDirQuota_s dirInfo[MAX_DIR_INFO_ENTRIES]; + } Stack_s; + + STACK_ALLOC(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + +#if CHK_DEBUG + DBG_DebugPrintf(LCYAN, "Volume: %x\n", volume); +#endif + if (CHK_ShutdownVolume(volume)) + { + STACK_FREE(); + return; + } + + aprintf(YELLOW, "Doing NSS background check of directory quotas on volume %U\n", + volName); + + lastDirReturned = zINVALID_ZID; + for (;;) + { + /* Delay so we don't overload the system with background requests. */ + LB_delay(1); + + if (volume->VOLcomnVolOps.VOL_browseDirsInVolume(&genMsg, volume, + MAX_DIR_INFO_ENTRIES, &lastDirReturned, aStack->dirInfo, + &numReturned) != zOK) + { + zASSERT(GetErrno(&genMsg) == zERR_DIR_QUOTAS_NOT_ENABLED); + goto exit; + } + if (numReturned == 0) + { + break; /* done */ + } + + /* Check each entry */ + for (i = 0; i < numReturned; i++) + { + if (CHK_ShutdownVolume(volume)) + { + goto exit; + } + +#if CHK_DEBUG + DBG_DebugPrintf(LCYAN, "Checking dir %Lx\n", aStack->dirInfo[i].dirZid); +#endif + + if ((beast = COMN_LookupByZid(&genMsg, volume, aStack->dirInfo[i].dirZid, + NOTLATCHED, TRUE)) == NULL) + { + if (GetErrno(&genMsg) == zERR_ZID_NOT_FOUND) + { +#if CHK_DEBUG + DBG_DebugPrintf(LRED, "removing dir %Lx\n", aStack->dirInfo[i].dirZid); +#endif + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, + X_CF_DEFAULT); + if (volume->VOLcomnVolOps.VOL_removeDirectory(&genMsg, + volume, xaction, aStack->dirInfo[i].dirZid) != zOK) + { + zASSERT("Error removing dir entry dir background check" + == NULL); + ClearErrno(&genMsg); + } + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + } + else + { + zASSERT("Error getting beast during background dir quota check" + == NULL); + ClearErrno(&genMsg); + } + } + else + { + COMN_Release(&beast); + } + } + } + +exit: + STACK_FREE(); + return; +} + +/************************************************************************** + * This function is scheduled as a background thread to check the file + * system. + ***************************************************************************/ +void CHK_CheckerThread( + THREAD threadID, + void *info) +{ + GeneralMsg_s genMsg; + NINT count; + Volume_s *volume; + unicode_t *volName; + + MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + CHK_ThreadRunning = TRUE; + aprintf(YELLOW, "NSS background checking scheduled.\n"); + + volName = malloc(zMAX_COMPONENT_NAME * sizeof(unicode_t)); + if (!volName) + { + aprintf(LRED, "No memory for the NSS background checking process\n"); + goto exit; + } + + /* + * Pause at startup to let the server get going without getting in the + * way. + */ + + CHK_Sleep(CHK_StartupWaitSeconds); + if (CHK_ShutdownRequest) + { + goto exit; + } + + /* Main body of the checker */ + count = 0; + for (;;) + { + if (CHK_ShutdownRequest) + { + break; + } + + /* + * If checking has not been suspended then go for it... + */ + if ((Config.Storage.checker) || (Config.Storage.forceChecker)) + { + aprintf(YELLOW, "NSS background check running (%d)...\n", ++count); + + CHK_BeastsProcessed = 0; + + SET_FOREACHBLOCKING(&NSSMasterVolumeList, volume, Volume_s, masterVolLink) + { /*** You MUST NOT use continue in this loop because the macro + *** SET_FOREACHBLOCKINGEND (at end of for loop) must be called + *** every time through the loop. Technically, you + *** can use a continue BEFORE any blocking calls. + ***/ + if ( VOL_ChangeVolumeSetup( &genMsg, volume, 0 ) ) + { + if (!CHK_ShutdownVolume(volume)) + { + (void)COMN_GetVolumeName(&genMsg, volume, volName, + zMAX_COMPONENT_NAME); + ClearErrno( &genMsg ); + CHK_CheckUsers(volume, volName); + CHK_CheckDirectoryQuotas(volume, volName); + CHK_CheckFiles(volume, volName); + } + VOL_ChangeVolumeCleanup( volume ); + } + SET_FOREACHBLOCKINGEND(&NSSMasterVolumeList, volume, Volume_s, masterVolLink); + } + + aprintf(YELLOW, "NSS background check completed (%d)...\n", count); + } + + /* Reset the force flag if we were forced to check one time */ + Config.Storage.forceChecker = FALSE; + + /* + * Sleep until time to start again. + */ + CHK_Sleep(CHK_WaitSeconds); + } + +exit: + aprintf(YELLOW, "NSS background checking shut down.\n"); + free(volName); + CHK_ThreadRunning = FALSE; + MPKNSS_UNLOCK(); +} + +/************************************************************************** + * This function schedules a background thread to check the file system. + ***************************************************************************/ +void CHK_StartProcess() +{ +#if zNETWARE + ZOS_StartThreadWithModuleHandle(CHK_ThreadID, "NSS Checker", + (void *(*)(THREAD, void *))CHK_CheckerThread, + 0, 0, NULL, (LONG)CMN_ModuleHandle); +#endif +#if zLINUX + ZOS_StartThread(CHK_ThreadID, "NSS Checker", + (void *(*)(THREAD, void *))CHK_CheckerThread, + 0, 0, NULL); +#endif + if (CHK_ThreadID == 0) + { + errPrintf(WHERE, Module, -1, + MSG("Unable to start the background file system checker.\n", 534)); + } + return; +} + +/************************************************************************** + * This function shuts down the background checker thread. + ***************************************************************************/ +void CHK_StopProcess() +{ + NINT count; + enum + { + CHK_MAX_SHUTDOWN_SECONDS = 30 + }; + + CHK_ShutdownRequest = TRUE; + CHK_Wakeup(); + for (count = 0; count < CHK_MAX_SHUTDOWN_SECONDS; count++) + { + if (!CHK_ThreadRunning) + { + return; + } + LB_delay(1000); + } + errPrintf(WHERE, Module, -1, + MSG("Unable to shutdown the background file system checker.\n", 535)); + return; +} diff --git a/src/nwnss/comn/common/comnDataStream.c b/src/nwnss/comn/common/comnDataStream.c new file mode 100644 index 0000000..c96df87 --- /dev/null +++ b/src/nwnss/comn/common/comnDataStream.c @@ -0,0 +1,425 @@ +/**************************************************************************** + | + | (C) Copyright 1995-1997 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-01-21 04:09:53 +0530 (Sat, 21 Jan 2006) $ + | + | $RCSfile$ + | $Revision: 1315 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | This contains the top level internal file interfaces. All external + | interfaces call these routines. + +-------------------------------------------------------------------------*/ +#include + +#include +#include + +#include "comnPublics.h" +#include "xError.h" +#include "comnBeasts.h" +#include "comnDataStream.h" +#include "msgName.h" +#include "nameSpace.h" +#include "name.h" + +/**************************************************************************** + * COMN_InitDataStreamInfo + *****************************************************************************/ +STATUS COMN_InitDataStreamInfo( + GeneralMsg_s *genMsg, + File_s *file, + NINT nameType) +{ + DataStreamInfo_s *dsInfo; + SearchMsg_s searchMsg; + NameSpace_s *nameSpace; + NINT nameSpaceID; + NINT totalCount = 0; + NINT totalDataSize = 0; + NINT totalNameSize = 0; + NINT nameSize; + BOOL isUplatched = FALSE; + + typedef struct Stack_s { + NamingMsg_s nameMsg; + } Stack_s; + + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ASSERT_LATCH(&file->FILEbeastLatch); + COMN_INIT_NAMING_MSG(&aStack->nameMsg); +/*--------------------------------------------------------------------------- + * Return if nothing needs to be done. + *---------------------------------------------------------------------------*/ + switch (nameType) + { + case zNTYPE_DATA_STREAM: + if ((file->FILEdataStreamInfo) && + (file->FILEdataStreamInfo->dataStream.count != DSI_COUNT_INVALID)) + { + STACK_FREE(); + return(zOK); + } + nameSpaceID = zNSPACE_DATA_STREAM; + break; + + case zNTYPE_EXTENDED_ATTRIBUTE: + if ((file->FILEdataStreamInfo) && + (file->FILEdataStreamInfo->extAttr.count != DSI_COUNT_INVALID)) + { + STACK_FREE(); + return(zOK); + } + nameSpaceID = zNSPACE_EXTENDED_ATTRIBUTE; + break; + + default: + zASSERT(FALSE); + SetErrno(genMsg,zERR_INVALID_NAME_TYPE); + STACK_FREE(); + return(zFAILURE); + } + +/*--------------------------------------------------------------------------- + * When we get this far, we know that we need to calculate the appropriate + * counts based on the name type. + * + * Alloc file->dataStreamInfo structure if one does not yet exist + * Because we are playing with the file structure, even though technically + * this is a read operation, we need to get an exclusive latch on the + * beast. + *---------------------------------------------------------------------------*/ + ASSERT_LATCH(&file->FILEbeastLatch); + if (IS_SLATCHED( &file->FILEbeastLatch)) + { + UP_LATCH( &file->FILEbeastLatch); + isUplatched = TRUE; + } + if (file->FILEdataStreamInfo == NULL) + { + dsInfo = (DataStreamInfo_s *)zalloc(sizeof(DataStreamInfo_s)); + if (dsInfo == NULL) + { + SetErrno(genMsg,zERR_NO_MEMORY); + goto cleanup_latch; + } + + /* On a new one, set these to invalid until we have a successulf + * calculation to replace them with */ + dsInfo->dataStream.count = DSI_COUNT_INVALID; + dsInfo->extAttr.count = DSI_COUNT_INVALID; + + file->FILEdataStreamInfo = dsInfo; + } + else + { + dsInfo = file->FILEdataStreamInfo; + } +/*--------------------------------------------------------------------------- + * We need to setup a nameMsg pointing to the file beast. We must manually + * "USE" all of the necessary beast pointers. + * + * NOTE - we set the latchType to XLATCHED. This is dangerous, but we are + * careful here. The cleanup code will UN_XLATCH the beast unless we + * set the latchType to NOTLATCHED before cleanup is called. We must + * not unlatch the beast in this function. That is the responsibility of + * the caller!!!! + *---------------------------------------------------------------------------*/ + if ((nameSpace = COMN_NameSpaceIDLookup(genMsg, nameSpaceID)) == NULL) + { + goto cleanup_latch; + } + if (COMN_LockVolumeActive(genMsg,file->FILEvolume,FALSE) != zOK) + { + COMN_Release(&nameSpace); + goto cleanup_latch; + } + COMN_USE_BEAST(&file->FILEvolume->VOLroot); + COMN_USE_BEAST(&file->FILEroot); + COMN_USE_BEAST(&file->FILEroot); + COMN_SETUP_NAMING_MSG_FILE_BEAST_PTR(&aStack->nameMsg, file->FILEvolume, + file->FILEfirstParentZid, // cnt file->FILEfirstParentNameUniquifier, + file, NAMPMODE_FullyResolveAny, XLATCHED, /* See above comnents */ + nameSpace, file->FILEfirstParentNameType, NULL); + +/*--------------------------------------------------------------------------- + * Setup a search message to match all sub beasts of type nameType + * and open the file to enumerate its sub beasts + *---------------------------------------------------------------------------*/ + COMN_STRUCT_INIT(searchMsg); + COMN_SETUP_SEARCH_MSG (&searchMsg, -1, + SMAPOPT_32BitMode | SMAPOPT_matchAllEntries, nameType); + + if (COMN_WildOpen(genMsg,&aStack->nameMsg,&searchMsg) != zOK) + { + goto cleanup_nameMsg; + } +/*--------------------------------------------------------------------------- + * Read through the beast, and count every located dataStream. + *---------------------------------------------------------------------------*/ + genMsg->flags |= DO_NOT_SEND_FSHOOKS; + while (COMN_WildRead(genMsg, &aStack->nameMsg, &searchMsg) == zOK) + { + /* At this point the nameMsg should contain two XLATCHED pointers, + * curFile should point to container, and curDataStream should point to + * the next dataStream to be counted. Both pointers are XLATCHED + * and have useCounts. */ + if (NAME_GetFirstNameFromBeast(genMsg, aStack->nameMsg.curDataStream, 0, NULL, + NULL, NULL, &nameSize) != zOK) + { + goto cleanup_searchMap; + } + + totalCount++; + totalDataSize += aStack->nameMsg.curDataStream->NAMEDeof; + totalNameSize += nameSize; + + /* Put the nameMsg back to the parent file beast */ + COMN_UnlatchAndRelease(&aStack->nameMsg.curDataStream, XLATCHED); + aStack->nameMsg.curDataStream = (NamedBeast_s *)aStack->nameMsg.curFile; + COMN_USE_BEAST(&aStack->nameMsg.curFile->FILEroot); + } + if (isUplatched) + { + DOWN_LATCH( &file->FILEbeastLatch); + isUplatched = FALSE; + } + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + if (GetErrno(genMsg) == zERR_NAME_NOT_FOUND_IN_DIRECTORY) + { + ClearErrno(genMsg); + } +/*--------------------------------------------------------------------------- + * Close out the wildcard search map process + *---------------------------------------------------------------------------*/ + if (COMN_WildClose(genMsg,&searchMsg) != zOK) + { + goto cleanup_nameMsg; + } + +/*--------------------------------------------------------------------------- + * At this point, we have a valid set of counts to put into the dataStreamInfo + *---------------------------------------------------------------------------*/ + switch (nameType) + { + case zNTYPE_DATA_STREAM: + dsInfo->dataStream.count = totalCount; + dsInfo->dataStream.dataSize = totalDataSize; + dsInfo->dataStream.nameSize = totalNameSize; + break; + + case zNTYPE_EXTENDED_ATTRIBUTE: + dsInfo->extAttr.count = totalCount; + dsInfo->extAttr.dataSize = totalDataSize; + dsInfo->extAttr.nameSize = totalNameSize; + break; + + default: + zASSERT(FALSE); + break; + } +/*--------------------------------------------------------------------------- + * See above comments related to latch/unlatch of the beast in the nameMsg + *---------------------------------------------------------------------------*/ + aStack->nameMsg.latchType = NOTLATCHED; /* So cleanup wont unlatch it */ + COMN_CleanupNameMsg(genMsg, &aStack->nameMsg); + + zASSERT(((nameType == zNTYPE_DATA_STREAM) && + (dsInfo->dataStream.count != DSI_COUNT_INVALID)) || + ((nameType == zNTYPE_EXTENDED_ATTRIBUTE) && + (dsInfo->extAttr.count != DSI_COUNT_INVALID))); + STACK_FREE(); + return(zOK); + +/*===========================================================================*/ +cleanup_searchMap: + COMN_WildClose(genMsg,&searchMsg); + +cleanup_nameMsg: + aStack->nameMsg.latchType = NOTLATCHED; /* So cleanup wont unlatch it */ + COMN_CleanupNameMsg(genMsg, &aStack->nameMsg); +cleanup_latch: + if (isUplatched) + { + DOWN_LATCH( &file->FILEbeastLatch); + } + STACK_FREE(); + return(zFAILURE); +} + +/**************************************************************************** + * COMN_GetDataStreamUsedSpace + *****************************************************************************/ +STATUS COMN_GetDataStreamUsedSpace( + GeneralMsg_s *genMsg, + File_s *file, + NINT nameType, + BOOL adjustUsedSpace, + Xaction_s *xaction, + SQUAD *returnSize) +{ + GetStorageInfo_s getStorageInfo; + SearchMsg_s searchMsg; + NameSpace_s *nameSpace; + NINT nameSpaceID; + QUAD size; + typedef struct Stack_s { + NamingMsg_s nameMsg; + } Stack_s; + STACK_ALLOC(); + + ASSERT_XLATCH(&file->FILEbeastLatch); + COMN_INIT_NAMING_MSG(&aStack->nameMsg); + + *returnSize = 0; +/*--------------------------------------------------------------------------- + * We need to setup a nameMsg pointing to the file beast. We must manually + * "USE" all of the necessary beast pointers. + * + * NOTE - we set the latchType to XLATCHED. This is dangerous, but we are + * careful here. The cleanup code will UN_XLATCH the beast unless we + * set the latchType to NOTLATCHED before cleanup is called. We must + * not unlatch the beast in this function. That is the responsibility of + * the caller!!!! + *---------------------------------------------------------------------------*/ + switch (nameType) + { + case zNTYPE_DATA_STREAM: + nameSpaceID = zNSPACE_DATA_STREAM; + break; + + case zNTYPE_EXTENDED_ATTRIBUTE: + nameSpaceID = zNSPACE_EXTENDED_ATTRIBUTE; + break; + + default: + zASSERT(FALSE); + SetErrno(genMsg,zERR_INVALID_NAME_TYPE); + STACK_FREE(); + return(zFAILURE); + } + + if ((nameSpace = COMN_NameSpaceIDLookup(genMsg, nameSpaceID)) == NULL) + { + STACK_FREE(); + return(zFAILURE); + } + if (COMN_LockVolumeActive(genMsg,file->FILEvolume,FALSE) != zOK) + { + COMN_Release(&nameSpace); + STACK_FREE(); + return(zFAILURE); + } + COMN_USE_BEAST(&file->FILEvolume->VOLroot); + COMN_USE_BEAST(&file->FILEroot); + COMN_USE_BEAST(&file->FILEroot); + COMN_SETUP_NAMING_MSG_FILE_BEAST_PTR(&aStack->nameMsg, file->FILEvolume, + file->FILEfirstParentZid, // cnt file->FILEfirstParentNameUniquifier, + file, NAMPMODE_FullyResolveAny, XLATCHED, /* See above comments */ + nameSpace, file->FILEfirstParentNameType, NULL); + +/*--------------------------------------------------------------------------- + * Setup a search message to match all sub beasts of type nameType + * and open the file to enumerate its sub beasts + *---------------------------------------------------------------------------*/ + COMN_STRUCT_INIT(searchMsg); + COMN_SETUP_SEARCH_MSG (&searchMsg, -1, + SMAPOPT_32BitMode | SMAPOPT_matchAllEntries, nameType); + + if (COMN_WildOpen(genMsg,&aStack->nameMsg,&searchMsg) != zOK) + { + goto cleanup_nameMsg; + } +/*--------------------------------------------------------------------------- + * Read through the beast, and count every located dataStream. + *---------------------------------------------------------------------------*/ + size = 0; + genMsg->flags |= DO_NOT_SEND_FSHOOKS; + while (COMN_WildRead(genMsg, &aStack->nameMsg, &searchMsg) == zOK) + { + /* At this point the nameMsg should contain two XLATCHED pointers, + * curFile should point to container, and curDataStream should point to + * the next dataStream to be counted. Both pointers are XLATCHED + * and have useCounts. */ + + if (COMN_GetStorageInfo(genMsg, aStack->nameMsg.curDataStream, + &getStorageInfo) != zOK) + { + goto cleanup_searchMap; + } + if (!(aStack->nameMsg.curDataStream->NAMEDnameFlags & NFL_BLKS_NOT_IN_PURGEABLE_CNT)) + { + /* call back with size and user info if needed */ + if (adjustUsedSpace) + { + VOL_AdjustUsedUserSpace(xaction, + &aStack->nameMsg.curDataStream->NAMEDroot, + -getStorageInfo.filePhysSize); + } + size += getStorageInfo.filePhysSize; + } + + /* Put the nameMsg back to the parent file beast */ + COMN_UnlatchAndRelease(&aStack->nameMsg.curDataStream, XLATCHED); + aStack->nameMsg.curDataStream = (NamedBeast_s *)aStack->nameMsg.curFile; + COMN_USE_BEAST(&aStack->nameMsg.curFile->FILEroot); + } + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + if (GetErrno(genMsg) == zERR_NAME_NOT_FOUND_IN_DIRECTORY) + { + ClearErrno(genMsg); + } +/*--------------------------------------------------------------------------- + * Close out the wildcard search map process + *---------------------------------------------------------------------------*/ + if (COMN_WildClose(genMsg,&searchMsg) != zOK) + { + goto cleanup_nameMsg; + } + +/*--------------------------------------------------------------------------- + * See above comments related to latch/unlatch of the beast in the nameMsg + *---------------------------------------------------------------------------*/ + aStack->nameMsg.latchType = NOTLATCHED; /* So cleanup won't unlatch it */ + COMN_CleanupNameMsg(genMsg, &aStack->nameMsg); + *returnSize = size; + STACK_FREE(); + return(zOK); + +/*===========================================================================*/ +cleanup_searchMap: + COMN_WildClose(genMsg,&searchMsg); + +cleanup_nameMsg: + aStack->nameMsg.latchType = NOTLATCHED; /* So cleanup wont unlatch it */ + COMN_CleanupNameMsg(genMsg, &aStack->nameMsg); + STACK_FREE(); + return(zFAILURE); +} diff --git a/src/nwnss/comn/common/comnEFL.c b/src/nwnss/comn/common/comnEFL.c new file mode 100644 index 0000000..51087d0 --- /dev/null +++ b/src/nwnss/comn/common/comnEFL.c @@ -0,0 +1,324 @@ +/**************************************************************************** + | + | (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: + | Manage the event file list + +-------------------------------------------------------------------------*/ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pssStartup.h" +#include "comnPublics.h" + + + +typedef struct EFLCheckerControl_s +{ + BOOL checkerStarted; + BOOL inProgress; + OneShot_s alarm; /* Alarm for periodic background epoch checker */ + FsmLite_s fsm; /* thread on which backgroung checker happens */ +}EFLCheckerControl_s; + + +EFLCheckerControl_s eflCheckerControl = {0}; + +void eflCheckerStart(OneShot_s *alarm); + + +/* + * Seconds to elapse before the specified time of day, + * Wraps to next day if needed. + * (This routine is copied from cmBgCompress.c) + */ +NINT secondsToTimeOfDay(NINT targetTimeOfDay) +{ + DOSTime_t dosTime = UTC2dosTime(GetUTCTime()); + NINT hour = ((dosTime >> 11) & 0x1f); + NINT min = ((dosTime >> 5) & 0x3f); + NINT sec = ((dosTime & 0x1f) << 1); + NINT secOfDay = (hour * 60 + min) * 60 + sec; + SNINT waitSecs = targetTimeOfDay - secOfDay; + + if (waitSecs < 0) + { + waitSecs += 24 * 60 * 60; + } + + return waitSecs; +} + + +/**************************************************************************** + * + * This function browses through list of volumes, and send check epoch event + * to each volume. If the volume supports EFL, it will check if any of used + * epochs hasn't been pinged for a certain amount of time and delete it if + * it is the case + * + ****************************************************************************/ +void checkIdleEpochs( + FsmLite_s *fsm, + ADDR unused) +{ + GeneralMsg_s genMsg; + Volume_s *vol; + NINT secsToStart; + + ASSERT_MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + SET_FOREACHBLOCKING(&NSSMasterVolumeList, vol, Volume_s, masterVolLink) + { + if (!eflCheckerControl.checkerStarted) + { + break; + } + + vol->VOLcomnVolOps.VOL_administerEFL(&genMsg, vol, + VOL_EFL_ADMIN_CHECK_EPOCH, NULL, NULL); + + SET_FOREACHBLOCKINGEND(&NSSMasterVolumeList, vol, Volume_s, masterVolLink) + } + + /* restart checker */ + eflCheckerControl.inProgress = FALSE; + + if (eflCheckerControl.checkerStarted) + { + secsToStart = secondsToTimeOfDay(0); + + if (secsToStart) + { + secOneShot(&eflCheckerControl.alarm, secsToStart, + eflCheckerStart); + } + else + { + eflCheckerStart(&eflCheckerControl.alarm); + } + } +} + + +/**************************************************************************** + * + * This function schedules efl checker + * + ****************************************************************************/ +void eflCheckerStart(OneShot_s *alarm) +{ + if (!eflCheckerControl.inProgress) + { + eflCheckerControl.inProgress = TRUE; + WORK_Schedule(&eflCheckerControl.fsm, checkIdleEpochs, 0); + } +} + + +/**************************************************************************** + * + * This function starts efl checker + * + ****************************************************************************/ +void startupEFLChecker() +{ + NINT secsToStart; + + ASSERT_MPKNSS_LOCK(); + + eflCheckerControl.checkerStarted = TRUE; + eflCheckerControl.inProgress = FALSE; + + secsToStart = secondsToTimeOfDay(0); + if (!secsToStart) + { + /* Don't start epoch checker at the startup time */ + secsToStart = 24 * 60 * 60; + } + + /* set up epoch checker, let it run at mid-night */ + INIT_ONESHOT(eflCheckerControl.alarm); + FSMLITE_INIT(&eflCheckerControl.fsm, "EFL checker", 1); + + secOneShot(&eflCheckerControl.alarm, secsToStart, + eflCheckerStart); +} + + +/**************************************************************************** + * + * This function inits EFL related routines. It is called by pssStartup. + * + ****************************************************************************/ +void EFL_Init() +{ + ASSERT_MPKNSS_LOCK(); + + startupEFLChecker(); +} + + +/**************************************************************************** + * + * This function uninits EFL related items. + * + ****************************************************************************/ +void EFL_Uninit() +{ +#define COMN_EFL_SHUTDOWN_SECONDS 30 + + NINT i; + + ASSERT_MPKNSS_LOCK(); + + if (eflCheckerControl.checkerStarted) + { + eflCheckerControl.checkerStarted = FALSE; + + i = 0; + while (eflCheckerControl.inProgress) + { + LB_delay(1000); + + if (++i >= COMN_EFL_SHUTDOWN_SECONDS) + { + errPrintf(WHERE, Module, -1, + MSG("Unable to stop efl checker.\n", 591)); + break; + } + } + + CANCEL_ALARM(eflCheckerControl.alarm); + } +} + + +/**************************************************************************** + * + * This function is called by commandline. It resets volume's EFL tree. + * + ****************************************************************************/ +STATUS resetVolumeEFLTree( + GeneralMsg_s *genMsg, + unicode_t *volName) +{ + Volume_s *volume = NULL; + STATUS status = zFAILURE; + Xaction_s *xaction; + struct purgeLogInfo_s + { + PurgeLogMsg_s purgeLogMsg; + LONG purgeLogLoc[MAX_PLOG_LOCATION_SIZE]; + }; + struct purgeLogInfo_s *purgeLogInfo = NULL; + + /* find volume */ + volume = COMN_VolumeNameLookup(genMsg, volName, FALSE, NULL); + if (volume == NULL) + { + goto exit; + } + + if (COMN_LockVolumeActive(genMsg, volume, FALSE) != zOK) + { + goto exitRelease; + } + + /* set up purge log */ + purgeLogInfo = zalloc(sizeof(struct purgeLogInfo_s)); + if (purgeLogInfo == NULL) + { + errPrintf(WHERE, Module, 706, + MSGNew("Error allocating memory for remove epoch operation\n", 0)); + SetErrno(genMsg, zERR_NO_MEMORY); + goto exitUnlock; + } + + SETUP_RESET_EFL_TREE_LOG(&purgeLogInfo->purgeLogMsg, + (void *)&purgeLogInfo->purgeLogLoc, volume); + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, X_CF_DEFAULT); + status = volume->VOLcomnVolOps.VOL_addPurgeLogEntry( + genMsg, volume, PLOG_EFL_RESET_TREE, + &purgeLogInfo->purgeLogMsg, (Xaction_s *)xaction); + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + if (status != zOK) + { + goto exitUnlock; + } + + /* + * Reset the EFL tree + * + */ + status = volume->VOLcomnVolOps.VOL_resetEFL(genMsg, volume); + if (status != zOK) + { + if (GetErrno(genMsg) == zERR_VOLUME_STATE_CHANGE_REQUESTED) + { + /* volume state changes, don't remove purge log */ + goto exitUnlock; + } + } + + xaction = volume->VOLcomnVolOps.VOL_beginXLocal(volume, X_CF_DEFAULT); + status = volume->VOLcomnVolOps.VOL_removePurgeLogEntry( + genMsg, volume, PLOG_EFL_RESET_TREE, + &purgeLogInfo->purgeLogMsg, (Xaction_s *)xaction); + volume->VOLcomnVolOps.VOL_endXLocal(xaction); + +exitUnlock: + if (purgeLogInfo) + { + free(purgeLogInfo); + } + + COMN_UnlockVolumeActive(volume, FALSE); + +exitRelease: + COMN_Release(&volume); + +exit: + return status; +} diff --git a/src/nwnss/comn/common/comnLog.c b/src/nwnss/comn/common/comnLog.c new file mode 100644 index 0000000..8ae11de --- /dev/null +++ b/src/nwnss/comn/common/comnLog.c @@ -0,0 +1,295 @@ +/**************************************************************************** + | + | (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 + | + |*************************************************************************** + | + | NetWare Advance File 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: + | NSSLOG routines that are aware of Common Layer specific structures. + +-------------------------------------------------------------------------*/ +#include +#include +#include + +#include "comnPublics.h" +#include "volume.h" +#include "nssLog.h" + +/* + * NSSLOG_EventLogWithVolume() - + * Standard NSS Log routine that inserts the volume name into the message. + * + * Notes - + * Not part of NSS.NLM(nssLog.c), because volumes are common layer specific. + * + */ +STATUS NSSLOG_EventLogWithVolume( + Volume_s *volume, +#if zNETWARE + struct LoadDefinitionStructure *moduleHandle, +#endif +#if zLINUX + void *moduleHandle, +#endif + const char *where, + NINT logLevel, + NINT typeNumber, /* Type; see NSSLOG_TYPE_... defines */ + char *message ) /* strlen message + strlen type must be less than 384 characters */ +{ + int addedOrError; + unicode_t *volumeName; + typedef struct Stack_s { + char log_information[400]; + } Stack_s; + STACK_ALLOC(); + + if ( volume->v_volumeName ) + { + volumeName = volume->v_volumeName; + } + else + { + volumeName = MSGNot(L"_NoName_"); + } + + addedOrError = LB_snprintf( aStack->log_information, sizeof( aStack->log_information ), + MSGNot("Volume \"%U\" - %s"), + volumeName, message ); + if ( (addedOrError > 0) && (addedOrError < sizeof(aStack->log_information)) ) + { /* LB_snprintf succeeded - place into NSS.LOG */ + (void)NSSLOG_EventLog( moduleHandle, WHERE, logLevel, typeNumber, aStack->log_information ); + } + else + { /* Buffer size error (or encoded error) */ + STACK_FREE(); + return( zERR_LOG_MESSAGE_TOO_BIG ); + } + STACK_FREE(); + return( zOK ); + +} /* End of NSSLOG_EventLogWithVolume() */ + + +/* + * NSSLOG_EventLogWithVolumeAndGenMsg() - + * Standard NSS Log routine that inserts the volume name into the message. + * + * Notes - + * Not part of NSS.NLM(nssLog.c), because volumes are common layer specific. + * + */ +STATUS NSSLOG_EventLogWithVolumeAndGenMsg( + Volume_s *volume, + GeneralMsg_s *errorToReport, +#if zNETWARE + struct LoadDefinitionStructure *moduleHandle, +#endif +#if zLINUX + void *moduleHandle, +#endif + const char *where, + NINT logLevel, + NINT typeNumber, /* Type; see NSSLOG_TYPE_... defines */ + char *message ) /* strlen message + strlen type must be less than 384 characters */ +{ + int addedOrError; + unicode_t *volumeName; + typedef struct Stack_s { + char log_information[400]; + } Stack_s; + STACK_ALLOC(); + + if ( volume->v_volumeName ) + { + volumeName = volume->v_volumeName; + } + else + { + volumeName = MSGNot(L"_NoName_"); + } + + addedOrError = LB_snprintf( aStack->log_information, sizeof( aStack->log_information ), + MSGNot("Volume \"%U\" Status %d(%s) - %s"), + volumeName, + GetErrno( errorToReport ), GetErrnoSetter( errorToReport ), + message ); + if ( (addedOrError > 0) && (addedOrError < sizeof(aStack->log_information)) ) + { /* LB_snprintf succeeded - place into NSS.LOG */ + (void)NSSLOG_EventLog( moduleHandle, WHERE, logLevel, typeNumber, aStack->log_information ); + } + else + { /* Buffer size error (or encoded error) */ + STACK_FREE(); + return( zERR_LOG_MESSAGE_TOO_BIG ); + } + STACK_FREE(); + return( zOK ); + +} /* End of NSSLOG_EventLogWithVolumeAndGenMsg() */ + + +/* + * NSSLOG_EventLogWithPool() - + * Standard NSS Log routine that inserts the pool name into the message. + * + * Warnings - + * Caller must not own the Pool's beast latch. + * + * Notes - + * Not part of NSS.NLM(nssLog.c), because pools are common layer specific. + * + */ +STATUS NSSLOG_EventLogWithPool( + Pool_s *pool, +#if zNETWARE + struct LoadDefinitionStructure *moduleHandle, +#endif +#if zLINUX + void *moduleHandle, +#endif + const char *where, + NINT logLevel, + NINT typeNumber, /* Type; see NSSLOG_TYPE_... defines */ + char *message ) /* strlen message + strlen type must be less than 384 characters */ +{ + GeneralMsg_s dummyGenMsg; + int addedOrError; + typedef struct Stack_s { + char log_information[400]; + unicode_t poolName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE( &dummyGenMsg ); + (void)COMN_GetPoolName( &dummyGenMsg, pool, aStack->poolName, NELEMS(aStack->poolName) ); + + addedOrError = LB_snprintf( aStack->log_information, sizeof( aStack->log_information ), + MSGNot("Pool \"%U\" - %s"), + aStack->poolName, message ); + if ( (addedOrError > 0) && (addedOrError < sizeof(aStack->log_information)) ) + { /* LB_snprintf succeeded - place into NSS.LOG */ + (void)NSSLOG_EventLog( moduleHandle, WHERE, logLevel, typeNumber, aStack->log_information ); + } + else + { /* Buffer size error (or encoded error) */ + STACK_FREE(); + return( zERR_LOG_MESSAGE_TOO_BIG ); + } + STACK_FREE(); + return( zOK ); + +} /* End of NSSLOG_EventLogWithPool() */ + + +/* + * NSSLOG_EventLogWithPoolAndGenMsg() - + * Standard NSS Log routine that inserts the pool name into the message. + * + * Warnings - + * Caller must not own the Pool's beast latch. + * + * Notes - + * Not part of NSS.NLM(nssLog.c), because pools are common layer specific. + * + */ +STATUS NSSLOG_EventLogWithPoolAndGenMsg( + Pool_s *pool, + GeneralMsg_s *errorToReport, +#if zNETWARE + struct LoadDefinitionStructure *moduleHandle, +#endif +#if zLINUX + void *moduleHandle, +#endif + const char *where, + NINT logLevel, + NINT typeNumber, /* Type; see NSSLOG_TYPE_... defines */ + char *message ) /* strlen message + strlen type must be less than 384 characters */ +{ + GeneralMsg_s dummyGenMsg; + int addedOrError; + typedef struct Stack_s { + char log_information[400]; + unicode_t poolName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE( &dummyGenMsg ); + (void)COMN_GetPoolName( &dummyGenMsg, pool, aStack->poolName, NELEMS(aStack->poolName) ); + + addedOrError = LB_snprintf( aStack->log_information, sizeof( aStack->log_information ), + MSGNot("Pool \"%U\" Status %d(%s) - %s"), + aStack->poolName, + GetErrno( errorToReport ), GetErrnoSetter( errorToReport ), + message ); + if ( (addedOrError > 0) && (addedOrError < sizeof(aStack->log_information)) ) + { /* LB_snprintf succeeded - place into NSS.LOG */ + (void)NSSLOG_EventLog( moduleHandle, WHERE, logLevel, typeNumber, aStack->log_information ); + } + else + { /* Buffer size error (or encoded error) */ + STACK_FREE(); + return( zERR_LOG_MESSAGE_TOO_BIG ); + } + STACK_FREE(); + return( zOK ); + +} /* End of NSSLOG_EventLogWithPoolAndGenMsg() */ + + + +/* + * NSSLOG_EventLog() - + * Log a message to C:NSS.LOG using syslog.nlm. Your message MUST + * be less than LB_VSN_PRINTF_LIMIT (including the NULL). + * + * Notes - + * The log is intended to be used by Novell to help track down + * NSS issues. Messages should not be languaged enabled. + * If you attempt to log more that 240 characters then your message + * will be truncated. + * + */ +#if zLINUX +STATUS NSSLOG_EventLog( + void *moduleHandle, + const char *where, + NINT logLevel, + NINT typeNumber, /* Type; see NSSLOG_TYPE_... defines */ + char *message ) /* strlen message + strlen type must be less than 384 characters */ + +{ + STATUS status; + + status = NSSLOG_printf( moduleHandle, where, logLevel, typeNumber, "%s", message ); + return( status ); + +} /* End of NSSLOG_EventLog() */ +#endif diff --git a/src/nwnss/comn/common/comnRename.c b/src/nwnss/comn/common/comnRename.c new file mode 100644 index 0000000..1e70e6a --- /dev/null +++ b/src/nwnss/comn/common/comnRename.c @@ -0,0 +1,2165 @@ +/**************************************************************************** + | + | (C) Copyright 1993, 1996-2000 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) Rename source code + | + |--------------------------------------------------------------------------- + | + | $Author: mvijai $ + | $Date: 2008-08-28 12:38:40 +0530 (Thu, 28 Aug 2008) $ + | + | $RCSfile$ + | $Revision: 2457 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | This contains the top level internal file interface code for Rename. + +-------------------------------------------------------------------------*/ +#include +#include +#include /* NSS Library */ +#include +#include + +#include +#include +#include +#include + +#include "comnPublics.h" +#include "comnParams.h" +#include "msgName.h" +#include "zParams.h" +#include "nameSpace.h" +#include "comnBeasts.h" +#include "comnAuthorize.h" +#include "name.h" +#include "nameScan.h" +#include "fileHandle.h" +#include "opLock.h" +#include "sAgentHandle.h" +#include "contextHandle.h" +#include "eventSys.h" +#include "nssFSHooks.h" +#include "adminVolume.h" +#include "dirQuotas.h" +#include "objectIDStore.h" +#include "sbsMFL.h" +#include "nssDebug.h" +#include "lsa.h" +#include "inst.h" + +/************************************************************************** + * This routine will rename the beast defined in "srcNameMsg" to + * the directory defined in "destNameMsg". This will handle if the name + * in the destination directory already exists. + * + * Following are the input items. + * srcNameMsg->curFile - the beast to rename + * srcNameMsg->parentZid - the parentZid of the beast to rename + * srcNameMsg->nameSpace - the nameSpace used to locate the srcBeast + * destNameMsg->curFile - the target dir to rename to + ***************************************************************************/ +STATIC STATUS REN_DoRenameBeast( + GeneralMsg_s *genMsg, + NamingMsg_s *srcNameMsg, + NamingMsg_s *destNameMsg, + unicode_t *srcPattern, + unicode_t *replacePattern, + RenameMsg_s *renMsg) +{ +#if (zMAX_FULL_NAME < ((zMAX_COMPONENT_NAME*2)+2)) + #error The zMAX_FULL_NAME size must be >= (zMAX_COMPONENT_NAME * 2) + 2, + #error because we use a workbuffer which must be >= zMAX_FULL_NAME +#endif + unicode_t *tempWorkBuffer = NULL; + File_s *srcBeast; + File_s *targetDir; + File_s *srcDir = NULL; + File_s *existingBeast = NULL; + File_s *nextParent; + Zid_t nextParentZid; + Zid_t targetDirParentZid; +// cnt NINT targetDirNameUniquifier; + NINT targetDirNameType; +// cnt NINT existNameUniquifier; + NINT tempLen; + BOOL releaseSrcDir = FALSE; + BOOL releaseTargetDir = FALSE; + unicode_t *srcName; + unicode_t *newName; + Time_t currentTime; + BOOL srcDirLatched = FALSE; + BOOL targetDirLatched = FALSE; + NINT latchStatus; + NINT hookType; + BOOL SendBothRenameAndSalvageHooks = FALSE; + LONG id; + STATUS status; + UserID_t userID = COMN_GetUserID(genMsg); + NINT srcLatchType, destLatchType; + NINT backOff; + SQUAD usedAmount; + BOOL targetQuotas = FALSE; + BOOL sourceQuotas = FALSE; + GetStorageInfo_s storageInfo; + Xaction_s *xaction = NULL; + BOOL deleteExistingBeast = FALSE; + BOOL lsaInvDentry = FALSE; + BOOL lsaDelDentry = FALSE; + File_s *srcPrimaryBeast = NULL; + File_s *existingPrimaryBeast = NULL; + File_s *existingNeighborBeast = NULL; + SQUAD usedDataStreamSize = 0; + SQUAD usedEASize = 0; + File_s *quotaBeast; + + typedef struct Stack_s { + char asciiNewName[zMAX_COMPONENT_NAME]; + FSHooks_F3RenameFile_s renameParms; + FSHooks_SalvageFile_s salvageParms; + struct EventBlock evBlk; + EventRenameEnter_s enter; + EventRenameExit_s exit; + LSAInvalidateDentry_s lsaSrcInv; + STATUS srcStatus; + LSAInvalidateDentry_s lsaDestInv; + Zid_t lsaDestPzid; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ENTER(TCOMMON, REN_DoRenameBeast); + + srcBeast = srcNameMsg->curFile; + + zASSERT(srcBeast != NULL); + zASSERT(srcPattern != NULL); + zASSERT(srcNameMsg->latchType == NOTLATCHED); + zASSERT(destNameMsg->latchType == NOTLATCHED); +/*------------------------------------------------------------------------- + * Make sure we're not attempting to rename the root directory + *-------------------------------------------------------------------------*/ + if (srcBeast->FILEzid == zROOTDIR_ZID) + { + SetErrno(genMsg,zERR_RENAME_DIR_INVALID); + goto error_cleanupAndReturn; + } +/*------------------------------------------------------------------------- + * Check for RenameInhibit on source file + *-------------------------------------------------------------------------*/ + if ((srcBeast->FILEattributes & zFA_RENAME_INHIBIT) && + (srcNameMsg->workNameType != zNTYPE_DELETED_FILE)) + { + SetErrno(genMsg,zERR_NO_RENAME_PRIVILEGE); + goto error_cleanupAndReturn; + } + +/*------------------------------------------------------------------------- + * Check to see if we are returning a salvage file to an undeleted state. + * If so then check space restrictions. + *-------------------------------------------------------------------------*/ + if (srcBeast->FILEvolume->VOLenabledAttributes & + (zATTR_USER_SPACE_RESTRICTIONS | zATTR_DIR_QUOTAS)) + { + if (srcNameMsg->workNameType == zNTYPE_DELETED_FILE && + destNameMsg->workNameType != zNTYPE_DELETED_FILE) + { + /*------------------------------------------------------------------- + * If we are salvaging the file, check for quota overflows + *-------------------------------------------------------------------*/ + X_LATCH(&srcBeast->FILEbeastLatch); + srcPrimaryBeast = HL_CheckIfHardlinkAndReturnPrimary( + genMsg, srcBeast, XLATCHED); + + quotaBeast = srcPrimaryBeast ? srcPrimaryBeast : srcBeast; + + usedDataStreamSize = 0; + usedEASize = 0; + + if (quotaBeast->FILEnameFlags & NFL_HAS_DATA_STREAMS) + { + if (COMN_GetDataStreamUsedSpace(genMsg, quotaBeast, + zNTYPE_DATA_STREAM, FALSE, NULL, + &usedDataStreamSize) != zOK) + { + goto error_cleanupSrcPrimaryXLatchedAndReturn; + } + } + if (quotaBeast->FILEnameFlags & NFL_HAS_EXTENDED_ATTRIBUTES) + { + if (COMN_GetDataStreamUsedSpace(genMsg, quotaBeast, + zNTYPE_EXTENDED_ATTRIBUTE, FALSE, NULL, + &usedEASize) != zOK) + { + goto error_cleanupSrcPrimaryXLatchedAndReturn; + } + } + if (COMN_GetBeastStorageInfo(genMsg, "aBeast->FILEroot, + &storageInfo) != zOK) + { + goto error_cleanupSrcPrimaryXLatchedAndReturn; + } + + if (VOL_CheckUserSpace(genMsg, "aBeast->FILEroot, + storageInfo.filePhysSize) != zOK || + DIRQ_CheckDirQuotas(genMsg, "aBeast->FILEroot, + (storageInfo.filePhysSize + usedDataStreamSize + + usedEASize)) != zOK) + { + goto error_cleanupSrcPrimaryXLatchedAndReturn; + } + + if (srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&srcPrimaryBeast,XLATCHED); + } + UNX_LATCH(&srcBeast->FILEbeastLatch); + } + } + +/*------------------------------------------------------------------------- + * Setup and latch the srcDir and targetDir. + * If the renameFlags have the zRENAME_TARGET_IS_PATTERN bit set, + * then the target directory is the same as the source directory, + * and we do not use destNameMsg in this function. + * Else, the destNameMsg->curFile points to the target directory. + * If they are separate directories we latch them both. Else, + * we only latch them once... + *-------------------------------------------------------------------------*/ + if (renMsg->renameFlags & zRENAME_TARGET_IS_PATTERN) + { + zASSERT(destNameMsg->curFile == NULL); + /* destNameMsg needs to be ignored...we're renaming in the src dir only + * and the new name is in replacePattern */ + if ((targetDir = COMN_LookupByZid(genMsg, srcNameMsg->curvol, + srcNameMsg->fileParentZid, NOTLATCHED, FALSE)) == NULL) + { + zASSERT("Unable to locate parent dir of the file being renamed"==NULL); + goto error_cleanupAndReturn; + } + targetDirParentZid = targetDir->FILEfirstParentZid; + targetDirNameType = targetDir->FILEfirstParentNameType; + /*----------------------------------------------------------------- + * srcDir and targetDir share the same pointer to the directory. This + * pointer is NOTLATCHED and marked inUse, but it is not part of any + * nameMsg so we must track it separately. + * srcBeast points to the beast to be renamed + *-----------------------------------------------------------------*/ + releaseTargetDir = TRUE; + + /*------------------------------------------------------------- + * srcDir is simply a shared pointer with the targetDir. + *-------------------------------------------------------------*/ + srcDir = targetDir; + } + else /* destNameMsg points to the targetDir, new name is in replacePattern */ + { + targetDir = destNameMsg->curFile; + targetDirParentZid = destNameMsg->fileParentZid; + targetDirNameType = destNameMsg->curFile->FILEfirstParentNameType; + zASSERT((targetDir!=NULL) && (targetDir->FILEattributes & zFA_SUBDIRECTORY)); + + /* see if srcDir and targetDir are two different directories */ + if (srcNameMsg->fileParentZid != targetDir->FILEzid) + { + if ((srcDir = COMN_LookupByZid(genMsg, srcNameMsg->curvol, + srcNameMsg->fileParentZid, NOTLATCHED, FALSE)) == NULL) + { + zASSERT("Unable to locate parent dir of the file being renamed"==NULL); + goto error_cleanupAndReturn; + } + + /*---------------------------------------------------------- + * srcDir is a pointer to the source directory. This pointer + * is NOTLATCHED and marked inUse, but it is not part of any + * nameMsg so we must track it separately. + * srcBeast points to the beast to be renamed. + *----------------------------------------------------------*/ + releaseSrcDir = TRUE; + } + else + { + /*------------------------------------------------------------- + * srcDir is simply a shared pointer with the targetDir. + *-------------------------------------------------------------*/ + srcDir = targetDir; + } + } +/*--------------------------------------------------------------------------- + * Do not allow renaming to a deleted nameType This would be the case if + * the targetDirectory is a deleted directory or the dest nameType is + * a deleted nameType. + *---------------------------------------------------------------------------*/ + if ((targetDirNameType == zNTYPE_DELETED_FILE) || + (destNameMsg->workNameType == zNTYPE_DELETED_FILE)) + { + SetErrno(genMsg,zERR_CANT_RENAME_TO_DELETED); + goto error_cleanupReleaseAndReturn; + } + +/*------------------------------------------------------------------------- + * Check if the srcDir and targetDir are on different volumes + *-------------------------------------------------------------------------*/ + if (srcDir->FILEvolume != targetDir->FILEvolume) + { + /* + * Check to see if we are accessing files on the persistent admin + * volume via the admin volumes. + */ + if ((PersistAdminVolume == NULL) || + ((((srcDir->FILEvolume != &AdminVolume.vol) || + (srcDir->FILEzid < AVOL_FIRST_PERSISTENT_ZID)) || + targetDir->FILEvolume != PersistAdminVolume) && + (((targetDir->FILEvolume != &AdminVolume.vol) || + (targetDir->FILEzid < AVOL_FIRST_PERSISTENT_ZID)) || + srcDir->FILEvolume != PersistAdminVolume))) + { + SetErrno(genMsg,zERR_RENAME_TO_OTHER_VOLUME); + goto error_cleanupReleaseAndReturn; + } + } + +/*--------------------------------------------------------------------------- + * Check if the volume is read-only + *---------------------------------------------------------------------------*/ + if (srcDir->FILEvolume->VOLenabledAttributes & zATTR_READONLY) + { + SetErrno(genMsg, zERR_ALL_FILES_READ_ONLY); + goto error_cleanupReleaseAndReturn; + } + +/*------------------------------------------------------------------------- + * Allocate a temporary work buffer to hold additional name patterns, + * and get the src beast's name in the srcName buffer. + *-------------------------------------------------------------------------*/ + if ((tempWorkBuffer = COMN_GetPathNameWorkBuffer(genMsg)) == NULL) + goto error_cleanupReleaseAndReturn; + + srcName = tempWorkBuffer; + S_LATCH(&srcBeast->FILEbeastLatch); + if (COMN_GetNameFromBeast(genMsg, srcBeast,// cnt srcNameMsg->fileNameUniquifier, + srcNameMsg->workNameSpaceID, + zMAX_COMPONENT_NAME, srcName, &tempLen) != zOK) + { + UNS_LATCH(&srcBeast->FILEbeastLatch); + goto error_cleanupReleaseAndReturn; + } + + if ( !(renMsg->renameFlags & zRENAME_KEEP_VFS_CACHE)) + { + aStack->srcStatus = COMN_LsaCleanupSetup( &srcBeast->FILEnamed, + &aStack->lsaSrcInv); + aStack->lsaSrcInv.lid_pZid = srcDir->FILEzid; + aStack->lsaSrcInv.lid_zid = zINVALID_ZID; + } + + UNS_LATCH(&srcBeast->FILEbeastLatch); +/*------------------------------------------------------------------------- + * Generate a new target name using the nameSpace wildReplace function + *-------------------------------------------------------------------------*/ + newName = tempWorkBuffer + (zMAX_COMPONENT_NAME + 1); + if (srcNameMsg->workNameSpace->nSpaceOps->wildReplace(genMsg, + srcPattern,srcName,replacePattern,newName) != zOK) + { + goto error_cleanupReleaseAndReturn; + } + +/*--------------------------------------------------------------------------- + * wildreplace returns a syntactically valid name, but this check is necessary + * to check for reserved names etc... + *---------------------------------------------------------------------------*/ + if (srcNameMsg->workNameSpace->nSpaceOps->isLegalName(genMsg,newName) != zOK) + goto error_cleanupReleaseAndReturn; +/*------------------------------------------------------------------------- + * See if the newName already exists in the target directory. If it does + * handle the "zRENAME_ALLOW_RENAMES_TO_MYSELF" and the + * "zRENAME_DELETE_FILE_IF_THERE" cases. + *-------------------------------------------------------------------------*/ + S_LATCH(&targetDir->FILEbeastLatch); + if ((existingBeast = NAME_FindNameInDir(genMsg,targetDir, + srcNameMsg->workNameSpace,destNameMsg->workNameType, + newName,0,NULL,SLATCHED,TRUE, + (srcNameMsg->parseFlags & NAMPFL_dontDoVisibilityChecks)/* cnt &existNameUniquifier */)) != NULL) + { + if ((existingBeast->FILEzid == srcBeast->FILEzid) && + (renMsg->renameFlags & zRENAME_ALLOW_RENAMES_TO_MYSELF)) + { + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + } + else if ((renMsg->renameFlags & zRENAME_DELETE_FILE_IF_THERE) && + (existingBeast->FILEzid != srcBeast->FILEzid) && + ((srcBeast->FILEattributes & zFA_SUBDIRECTORY) == 0) && + ((existingBeast->FILEattributes & zFA_SUBDIRECTORY) == 0) && + (srcNameMsg->workNameType != zNTYPE_DELETED_FILE)) + { + /* Renaming to a different, but already existing beast. This + * is only legal if the caller specifed the correct flags, and if + * the beasts are non-deleted files and not directories. + * Check for Delete Privilege before proceeding. + */ + existingPrimaryBeast = HL_CheckIfHardlinkAndReturnPrimary( + genMsg, existingBeast, SLATCHED); + + if (existingBeast->FILEmayIDoThis(genMsg, + existingPrimaryBeast ? existingPrimaryBeast : existingBeast, + targetDir->FILEzid, MAY_I_DELETE) != zOK) + { + if (existingPrimaryBeast) + { + COMN_UnlatchAndRelease(&existingPrimaryBeast,SLATCHED); + } + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + SetErrno(genMsg, zERR_NO_DELETE_PRIVILEGE); + UNS_LATCH(&targetDir->FILEbeastLatch); + goto error_cleanupReleaseAndReturn; + } + if (existingPrimaryBeast) + { + COMN_UnlatchAndRelease(&existingPrimaryBeast,SLATCHED); + } + + if ((existingBeast->FILEdontDeleteWhileOpenCount != 0) && + (FH_OpenFileMayNotBeDeleted(genMsg,&existingBeast->FILEnamed))) + { + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + SetErrno(genMsg, zERR_CANT_DELETE_OPEN_FILE); + UNS_LATCH(&targetDir->FILEbeastLatch); + goto error_cleanupReleaseAndReturn; + } + if (existingBeast->FILEattributes & zFA_DELETE_INHIBIT) + { + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + SetErrno(genMsg, zERR_ALL_FILES_READ_ONLY); + UNS_LATCH(&targetDir->FILEbeastLatch); + goto error_cleanupReleaseAndReturn; + } + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + deleteExistingBeast = TRUE; + } + else if ((renMsg->renameFlags & zRENAME_DELETE_FILE_IF_THERE) && + (existingBeast->FILEzid != srcBeast->FILEzid) && + ((srcBeast->FILEattributes & zFA_SUBDIRECTORY)) && + ((existingBeast->FILEattributes & zFA_SUBDIRECTORY)) && + (srcNameMsg->workNameType != zNTYPE_DELETED_FILE)) + { + existingPrimaryBeast = HL_CheckIfHardlinkAndReturnPrimary( + genMsg, existingBeast, SLATCHED); + + if (existingBeast->FILEmayIDoThis(genMsg, + existingPrimaryBeast ? existingPrimaryBeast : existingBeast, + targetDir->FILEzid, MAY_I_DELETE) != zOK) + { + if (existingPrimaryBeast) + { + COMN_UnlatchAndRelease(&existingPrimaryBeast,SLATCHED); + } + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + SetErrno(genMsg, zERR_NO_DELETE_PRIVILEGE); + UNS_LATCH(&targetDir->FILEbeastLatch); + goto error_cleanupReleaseAndReturn; + } + if (existingPrimaryBeast) + { + COMN_UnlatchAndRelease(&existingPrimaryBeast,SLATCHED); + } + + if ((existingBeast->FILEdontDeleteWhileOpenCount != 0) && + (FH_OpenFileMayNotBeDeleted(genMsg,&existingBeast->FILEnamed))) + { + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + SetErrno(genMsg, zERR_CANT_DELETE_OPEN_FILE); + UNS_LATCH(&targetDir->FILEbeastLatch); + goto error_cleanupReleaseAndReturn; + } + if (existingBeast->FILEattributes & zFA_DELETE_INHIBIT) + { + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + SetErrno(genMsg, zERR_ALL_FILES_READ_ONLY); + UNS_LATCH(&targetDir->FILEbeastLatch); + goto error_cleanupReleaseAndReturn; + } + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + deleteExistingBeast = TRUE; + } + else + { + /* The name already exists. It is either a different file, + * or it is the same file, but we are not allowed to rename + * the file to itself. */ + COMN_UnlatchAndRelease(&existingBeast,SLATCHED); + SetErrno(genMsg,zERR_ALL_NAMES_EXIST); + UNS_LATCH(&targetDir->FILEbeastLatch); + goto error_cleanupReleaseAndReturn; + } + } + UNS_LATCH(&targetDir->FILEbeastLatch); + + if ((GetErrno(genMsg) != zOK) && + (GetErrno(genMsg) != zERR_NAME_NOT_FOUND_IN_DIRECTORY)) + { + goto error_cleanupReleaseAndReturn; + } + ClearErrno(genMsg); + +/*** Everything is unlatched at this time so don't need to do anything + *** before event/fshook is called. If RESERVE_RSRC are added to + *** this routine (Paul if you do this.. ) we will need to RELEASE_RSRC and + *** and RESERVE_RSRC again + ***/ + /* Based on the nameType, this is either a salvage or a rename */ + hookType = (srcNameMsg->workNameType == zNTYPE_DELETED_FILE) ? + SalvageFile_Hook : F3RenameFile_Hook; + + if (hookType == SalvageFile_Hook) + { + CHECK_FSHOOKS_SALVAGE_ENTER(SalvageFile_Hook, &aStack->salvageParms, status, + error_cleanupReleaseAndReturn, genMsg, srcNameMsg, + newName, aStack->asciiNewName); + /* If salvaging to a different dir, do a salvage and a rename */ + if (targetDir->FILEzid != srcDir->FILEzid) + { + SendBothRenameAndSalvageHooks = TRUE; + CHECK_FSHOOKS_RENAME_ENTER(F3RenameFile_Hook, &aStack->renameParms, status, + error_cleanupReleaseAndReturn, genMsg, srcNameMsg, + newName, aStack->asciiNewName, targetDir->FILEzid, renMsg); + } + } + else + { + CHECK_FSHOOKS_RENAME_ENTER(F3RenameFile_Hook, &aStack->renameParms, status, + error_cleanupReleaseAndReturn, genMsg, srcNameMsg, + newName, aStack->asciiNewName, targetDir->FILEzid, renMsg); + } + INIT_EVENT_ID_STATUS(id, aStack->exit.enterRetStatus); + if (NEBEventInfo[EVENT_Rename_Enter].consumers) + { + INIT_RENAME_ENTER_EVENT(genMsg, srcNameMsg, aStack->evBlk, + EVENT_Rename_Enter, aStack->enter, id, newName, renMsg, + targetDir->FILEzid); + ZOS_ProduceEvent(status,&aStack->evBlk); + CHECK_ENTER_RETURN(genMsg, status, aStack->evBlk, aStack->exit, + error_cleanupReleaseAndReturn); + } + +/*--------------------------------------------------------------------------- + * Check if the srcBeast is Locked + *---------------------------------------------------------------------------*/ +/* FixFixFix6 -- when we do record locking -- the old rename code + * checked here to make sure the srcBeast is not locked... The new code + * ought to do the same...*/ + + if (!(srcBeast->FILEattributes & zFA_HARDLINK) && + (srcBeast->opLockControl != NULL)) + { + X_LATCH( &srcBeast->FILEbeastLatch); + status = OPLOCK_Break(genMsg, srcBeast, TRUE); + UNX_LATCH( &srcBeast->FILEbeastLatch); + if (status != zOK) + { + goto error_cleanupRelease; + } + } + + + /* For now, just check if the file is exclusive locked */ + if ((srcBeast->FILEdenyReaderCount != 0) || + (srcBeast->FILEdenyWriterCount != 0)) + { + if (COMN_IsDenyReaderWriterNotMe(genMsg,(NamedBeast_s *)srcBeast)) + { + SetErrno(genMsg,zERR_ALL_FILES_IN_USE); + goto error_cleanupRelease; + } + } +/*--------------------------------------------------------------------------- + * If the beast is open and the caller specified "RENAME COMPATABILITY" + * then do not allow renaming of the open file. + *---------------------------------------------------------------------------*/ + if ((srcBeast->FILEopenCount != 0) && + (COMN_IsOpenerNotMe(genMsg,(NamedBeast_s *)srcBeast)) && + (renMsg->renameFlags & zRENAME_COMPATABILITY)) + { + SetErrno(genMsg,zERR_ALL_FILES_IN_USE); + goto error_cleanupRelease; + } +/*------------------------------------------------------------------------- + * If the targetDir is different than the srcDir then we are moving the + * beast to a different directory, as well as potentially changing its + * name. + *-------------------------------------------------------------------------*/ + if (targetDir->FILEzid != srcDir->FILEzid) + { + /*------------------------------------------------------------------- + * If we are salvaging the file, check for salvage rights + *-------------------------------------------------------------------*/ + S_LATCH(&srcBeast->FILEbeastLatch); + srcPrimaryBeast = HL_CheckIfHardlinkAndReturnPrimary( + genMsg, srcBeast, SLATCHED); + + if (srcNameMsg->workNameType == zNTYPE_DELETED_FILE) + { + if (srcBeast->FILEmayIDoThis(genMsg, + srcPrimaryBeast ? srcPrimaryBeast : srcBeast, + srcNameMsg->fileParentZid, MAY_I_SALVAGE) != zOK) + { + SetErrno(genMsg,zERR_NO_SALVAGE_PRIVILEGE); + if (srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&srcPrimaryBeast,SLATCHED); + } + UNS_LATCH(&srcBeast->FILEbeastLatch); + goto error_cleanupRelease; + } + } + /*================================================================ + * we're moving a beast to a different directory... + * We must have rights to delete the beast and create it in the new + * target directory + *=================================================================*/ + else if ((srcBeast->FILEmayIDoThis(genMsg, targetDir, + targetDirParentZid, MAY_I_CREATE) != zOK) || + /*------------------------------------------------------------- + * NOTE - the MAY_I_MOVE... decision function does the necessary + * rights checking for Delete and Read rights on the source beast + * (and all of it's children. . .) + *-------------------------------------------------------------*/ + (srcBeast->FILEmayIDoThis(genMsg, + srcPrimaryBeast ? srcPrimaryBeast : srcBeast, + srcNameMsg->fileParentZid, MAY_I_MOVE_THE_OBJECT) != zOK)) + { + SetErrno(genMsg,zERR_NO_RENAME_PRIVILEGE); + if (srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&srcPrimaryBeast,SLATCHED); + } + UNS_LATCH(&srcBeast->FILEbeastLatch); + goto error_cleanupRelease; + } + + if (srcPrimaryBeast) + { + UNS_LATCH(&srcPrimaryBeast->FILEbeastLatch); + } + UNS_LATCH(&srcBeast->FILEbeastLatch); + + /* If the beast being moved is a subdirectory, we need to do a + * check to make sure we're not moving the subdirectory to + * a location below itself. */ + if (srcBeast->FILEattributes & zFA_SUBDIRECTORY) + { + /* for simplicity, start looking at the target dir itself */ + nextParent = targetDir; + COMN_USE_BEAST(&nextParent->FILEroot); + + for (;;) + { + /* See if targetDir's parent is the srcBeast */ + if (nextParent->FILEzid == srcBeast->FILEzid) + { + SetErrno(genMsg,zERR_RENAME_DIR_INVALID); + COMN_Release(&nextParent); + goto error_cleanupRelease; + } + + /* Find next higher parent unless we are at rootdir */ + if (nextParent->FILEzid == zROOTDIR_ZID) + break; + + nextParentZid = nextParent->FILEfirstParentZid; + COMN_Release(&nextParent); + nextParent = COMN_LookupByZid(genMsg,targetDir->FILEvolume, + nextParentZid,NOTLATCHED, FALSE); + if (nextParent==NULL) + goto error_cleanupRelease; + } + COMN_Release(&nextParent); + } + + /* + * Before the file(s) can be moved we need to make sure that the + * directory quotas are checked. This has to be done before + * the directories are latched because computing the used space + * latches the directory. This may lead to an inaccuracy + * in the used amount if file lengths are changing while we are moving + * the directory, but that can happen anyway with files that are + * already open. We will have to live with any adjustment errors. + */ + sourceQuotas = + DIRQ_ThereAreDirQuotas(srcDir->FILEvolume, srcDir->FILEzid); + targetQuotas = + DIRQ_ThereAreDirQuotas(targetDir->FILEvolume, targetDir->FILEzid); + if (sourceQuotas || targetQuotas) + { + BOOL isPrimaryHardLink; + + /* See if we are renaming a non-Primary hard link */ + isPrimaryHardLink = ((srcPrimaryBeast) && + (srcBeast->FILEattributes & zFA_HARDLINK) && + (((HardLinkBeast_s *)srcBeast)->HARDLhlFlags & zHL_FIRST_HLNAME)); + + /* If no hardlinks involved, or if we are the Primary hardlink ... */ + if ((srcPrimaryBeast == NULL) || (isPrimaryHardLink)) + { + DIRQ_ComputeUsedAmount(srcBeast->FILEvolume, + srcPrimaryBeast ? srcPrimaryBeast->FILEzid : srcBeast->FILEzid, + &usedAmount, TRUE); + } + else + { + /* Prevent updating of quotas for non-Primary hardlinks */ + sourceQuotas = FALSE; + targetQuotas = FALSE; + } + } + if (targetQuotas) + { + if (DIRQ_CheckDirQuotas(genMsg, &targetDir->FILEroot, usedAmount) + != zOK) + { + goto error_cleanupRelease; + } + } + if (srcPrimaryBeast) + { + COMN_Release(&srcPrimaryBeast); + } + +/*------------------------------------------------------------------------- + * Renaming the beast to a different directory. + * We must prelatch both directories and the beast. + * To prevent deadlock, first latch the srcDir. Then attempt to XLATCH the + * targetDir WITHOUT waiting. If it is already latched, we will release the + * srcDir, and wait for a latch on the targetDir. Then, free up the targetDir + * and try again from the start. + *-------------------------------------------------------------------------*/ + backOff = MILLISEC_PER_TICK; + for (;;) + { + X_LATCH( &srcDir->FILEbeastLatch); + X_NOWAIT( &targetDir->FILEbeastLatch, latchStatus); + if (latchStatus != WAITED) + { + break; /* We got both directories, go on now */ + } + /* + * The target could not be latched. Release the srcDir + * and wait for the targetDir to be freed up by whoever + * has it. Then release targetDir and start over from + * the start. + */ + UNX_LATCH( &srcDir->FILEbeastLatch); + + X_LATCH( &targetDir->FILEbeastLatch); + X_NOWAIT( &srcDir->FILEbeastLatch, latchStatus); + if (latchStatus != WAITED) + { + break; /* We got both directories, go on now */ + } + /* + * We couldn't get the src, unlatch the target and start over + */ + UNX_LATCH( &targetDir->FILEbeastLatch); + LB_delay(random() % backOff); + backOff += MILLISEC_PER_TICK; + } + + destNameMsg->latchType = XLATCHED; /* targetDir -- cleaned up by nameMsg */ + srcDirLatched = TRUE; /* srcDir - must be unlatched */ + +/*--------------------------------------------------------------------------- + * Now that the target directory is latched, make sure it is not in the process + * of being deleted. If it is being deleted, fail the rename. + *---------------------------------------------------------------------------*/ + if (targetDir->FILEbstState & BST_STATE_PURGING) + { + SetErrno(genMsg,zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto error_cleanupUnlatch; + } + +/*--------------------------------------------------------------------------- + The directorys are latched but before latching the actual beasts, we have + to deal with the possibility of hardlink delete of the existing beast. We + can't latch the source existing and primary if the rename-delete is occurring + on top a sibling hardlink. + *---------------------------------------------------------------------------*/ + + if ((existingBeast = NAME_FindNameInDir(genMsg,targetDir, + srcNameMsg->workNameSpace,destNameMsg->workNameType, + newName,0,NULL,NOTLATCHED,TRUE, + (srcNameMsg->parseFlags & NAMPFL_dontDoVisibilityChecks))) != NULL) + { + if ((existingBeast->FILEzid == srcBeast->FILEzid) && + (renMsg->renameFlags & zRENAME_ALLOW_RENAMES_TO_MYSELF)) + { + COMN_Release(&existingBeast); + } + else if (deleteExistingBeast) + { + /* Latch the beast to be deleted and start a transaction. + * We must keep this latch until after the transaction ends. + */ + X_LATCH( &existingBeast->FILEbeastLatch ); + + if(BST_deleteSetup(genMsg, existingBeast, &existingPrimaryBeast, + &existingNeighborBeast) != zOK) + { + goto error_cleanupUnlatch; + } + xaction = COMN_BeginXLocal(srcBeast); + + if (!(renMsg->renameFlags & zRENAME_KEEP_VFS_CACHE)) + { + if ( COMN_LsaCleanupSetup( &existingBeast->FILEnamed, + &aStack->lsaDestInv) == zOK ) + { + if (existingPrimaryBeast != NULL) + { + aStack->lsaDestInv.lid_zid = + existingPrimaryBeast->FILEzid; + } + else + { + aStack->lsaDestInv.lid_zid = existingBeast->FILEzid; + } + aStack->lsaDestInv.lid_pZid = targetDir->FILEzid; + lsaDelDentry = TRUE; + } + } + /* Delete the existing beast first. */ + if (BST_delete( genMsg, targetDir, existingBeast, + existingPrimaryBeast, existingNeighborBeast, + xaction, FALSE, TRUE) != zOK) + { + COMN_EndXLocal(srcDir, &xaction); + goto error_cleanupUnlatch; + } + /* The delete of the existing beast has succeeded. Keep the + * transaction until done with all portions of the rename. + */ + } + else + { + /* The name already exists. It is either a different file, + * or it is the same file, but we are not allowed to rename + * the file to itself. */ + COMN_Release(&existingBeast); + SetErrno(genMsg,zERR_ALL_NAMES_EXIST); + goto error_cleanupUnlatch; + } + } + ClearErrno(genMsg); + +/*--------------------------------------------------------------------------- + Now that a potential delete is finished, the srcPrimary and srcBeasts must + be latched. These MAY BE the same as existingPrimary and existingNeighbor. + *---------------------------------------------------------------------------*/ + if(srcBeast->FILEattributes & zFA_HARDLINK) + { + zASSERT(((HardLinkBeast_s *)srcBeast)->HARDLprimaryZid != zINVALID_ZID); + + srcPrimaryBeast = COMN_LookupByZid(genMsg, srcBeast->FILEvolume, + ((HardLinkBeast_s *)srcBeast)->HARDLprimaryZid, + NOTLATCHED, TRUE); + if(srcPrimaryBeast == NULL) + { + zASSERT("Primary beast has dissappeared" == NULL); + ForceSetErrno(genMsg, zERR_INTERNAL_DIRECTORY_ERROR); + goto error_cleanupUnlatch; + } + if(srcPrimaryBeast != existingPrimaryBeast) + { + X_LATCH(&srcPrimaryBeast->FILEbeastLatch); + } + } + + if(srcBeast != existingNeighborBeast) + { + X_LATCH( &srcBeast->FILEbeastLatch); + } + srcNameMsg->latchType = XLATCHED; /* transfer the latch to the namemsg for later cleanup */ + +/*--------------------------------------------------------------------------- + * Three or four beasts (ALL possible beasts involved in the rename) are now XLATCHED. + * This function is atomic. It either works or it doesn't. There is a + * possibility that if it fails and is un-recoverable, it will do an + * AbendTheVolume error down deep. + *---------------------------------------------------------------------------*/ + + if (NAME_RenameBeast(genMsg,srcBeast,srcPrimaryBeast, srcDir, + targetDir,srcName,newName, + srcNameMsg->workNameSpace,srcNameMsg->workNameType, + destNameMsg->workNameType,renMsg,xaction) != zOK) + { + if (deleteExistingBeast) + { + COMN_AbortXLocal(genMsg,srcBeast->FILEvolume,xaction, WHERE); + } + goto error_cleanupUnlatch; + } + + /* + * Update the directory quotas for source and destination if it is + * needed. + */ + if (sourceQuotas || targetQuotas) + { + zASSERT(targetDir->FILEvolume == srcDir->FILEvolume); + if (xaction == NULL) + { + xaction = COMN_BeginXLocal(srcBeast); + } + if (targetQuotas) + { + DIRQ_AdjustUsedDirSpace(xaction, targetDir->FILEvolume, + &destNameMsg->curFile->FILEroot, usedAmount); + } + if (sourceQuotas) + { + /* + * Use srcDir instead of srcBeast because the beast is now at + * the destination. + */ + DIRQ_AdjustUsedDirSpace(xaction, srcDir->FILEvolume, + &srcDir->FILEroot, -usedAmount); + } + /* + * Invalidate the cache so that entries in the subtree that was + * just moved will be recalculated. They currently point to old + * parents. + */ + DIRQ_InvalidateDirQuotaCache(srcDir->FILEvolume); + } + if (xaction != NULL) + { + COMN_EndXLocal(srcBeast, &xaction); + } + /* + * We moved the file to a new location so it's authorization info + * may no longer be valid. + */ + targetDir->FILEauthModelOps->invalidateAuthInfo(genMsg); + ClearErrno(genMsg); + + OID_SaveObjectID(srcBeast->FILEvolume, &userID); + currentTime = GetUTCTime(); + srcDir->FILEmodifiedTime = currentTime; + srcDir->FILEmodifiedDOSTime = INVALID_DOS_TIME; + srcDir->FILEmodifierID = userID; + srcDir->FILEmetaDataSeqNum++; + srcDir->FILEvolume->VOLfile.FILEmodifiedTime = currentTime; + COMN_MARK_BEAST_MESSY(&srcDir->FILEroot); + } + else /* (targetDir->FILEzid == srcDir->FILEzid)*/ + { + /*------------------------------------------------------------------- + * If we are salvaging the file, check for salvage rights + *-------------------------------------------------------------------*/ + S_LATCH(&srcBeast->FILEbeastLatch); + srcPrimaryBeast = HL_CheckIfHardlinkAndReturnPrimary( + genMsg, srcBeast, SLATCHED); + + if (srcNameMsg->workNameType == zNTYPE_DELETED_FILE) + { + if (srcBeast->FILEmayIDoThis(genMsg, + srcPrimaryBeast ? srcPrimaryBeast : srcBeast, + srcNameMsg->fileParentZid, MAY_I_SALVAGE) != zOK) + { + SetErrno(genMsg,zERR_NO_SALVAGE_PRIVILEGE); + if (srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&srcPrimaryBeast,SLATCHED); + } + UNS_LATCH(&srcBeast->FILEbeastLatch); + goto error_cleanupRelease; + } + } + /*=================================================================* + * we're simply renaming the beast within the same directory + *=================================================================*/ + else if (srcBeast->FILEmayIDoThis(genMsg, + srcPrimaryBeast ? srcPrimaryBeast : srcBeast, + srcNameMsg->fileParentZid, MAY_I_MODIFY_METADATA) != zOK) + { + SetErrno(genMsg,zERR_NO_RENAME_PRIVILEGE); + if (srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&srcPrimaryBeast,SLATCHED); + } + UNS_LATCH(&srcBeast->FILEbeastLatch); + goto error_cleanupRelease; + } + if (srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&srcPrimaryBeast,SLATCHED); + } + UNS_LATCH(&srcBeast->FILEbeastLatch); +/*------------------------------------------------------------------------- + * At this point we know that there is only one directory involved. + * It is now safe to latch the directories without the potential of causing + * a deadlock. We couldn't do it before, because we had not yet guaranteed + * that the target directory was not below the src directory. + *-------------------------------------------------------------------------*/ + + X_LATCH(&targetDir->FILEbeastLatch); + + /* targetDir is same as destNameMsg->curFIle, unless releaseTargetDir + * is TRUE. Set the proper flags so either the nameMsg cleanup + * will unlatch it, or it will be done manually */ + if (releaseTargetDir) /* set if renameFlags & zRENAME_TARGET_IS_PATTERN */ + targetDirLatched = TRUE; + else + destNameMsg->latchType = XLATCHED; + +/*------------------------------------------------------------------------- + * Rename the beast within the same directory. This function is atomic. It + * either works or it doesn't. There is a possibility that if it fails and + * is un-recoverable, it will do an AbendTheVolume error down deep. + *-------------------------------------------------------------------------*/ + if ((existingBeast = NAME_FindNameInDir(genMsg,targetDir, + srcNameMsg->workNameSpace,destNameMsg->workNameType, + newName,0,NULL,NOTLATCHED,TRUE, + (srcNameMsg->parseFlags & NAMPFL_dontDoVisibilityChecks))) != NULL) + { + if ((existingBeast->FILEzid == srcBeast->FILEzid) && + (renMsg->renameFlags & zRENAME_ALLOW_RENAMES_TO_MYSELF)) + { + COMN_Release(&existingBeast); + } + else if (deleteExistingBeast) + { + /* Latch the beast to be deleted and start a transaction. + * We must keep this latch until after the transaction ends. + */ + X_LATCH( &existingBeast->FILEbeastLatch ); + + if(BST_deleteSetup(genMsg, existingBeast, &existingPrimaryBeast, + &existingNeighborBeast) != zOK) + { + goto error_cleanupUnlatch; + } + xaction = COMN_BeginXLocal(srcBeast); + + if (!(renMsg->renameFlags & zRENAME_KEEP_VFS_CACHE)) + { + if ( COMN_LsaCleanupSetup( &existingBeast->FILEnamed, + &aStack->lsaDestInv) == zOK ) + { + if (existingPrimaryBeast != NULL) + { + aStack->lsaDestInv.lid_zid = + existingPrimaryBeast->FILEzid; + } + else + { + aStack->lsaDestInv.lid_zid = existingBeast->FILEzid; + } + aStack->lsaDestInv.lid_pZid = targetDir->FILEzid; + lsaDelDentry = TRUE; + } + } + /* Delete the existing beast first. */ + if (BST_delete( genMsg, targetDir, existingBeast, + existingPrimaryBeast, existingNeighborBeast, + xaction, FALSE, TRUE) != zOK) + { + COMN_EndXLocal(srcDir, &xaction); + goto error_cleanupUnlatch; + } + /* The delete of the existing beast has succeeded. Keep the + * transaction until done with all portions of the rename. + */ + } + else + { + /* The name already exists. It is either a different file, + * or it is the same file, but we are not allowed to rename + * the file to itself. */ + COMN_Release(&existingBeast); + SetErrno(genMsg,zERR_ALL_NAMES_EXIST); + goto error_cleanupUnlatch; + } + } + if ((GetErrno(genMsg) != zOK) && + (GetErrno(genMsg) != zERR_NAME_NOT_FOUND_IN_DIRECTORY)) + goto error_cleanupUnlatch; + + ClearErrno(genMsg); + +/*--------------------------------------------------------------------------- + Now that a potential delete is finished, the srcPrimary and srcBeasts must + be latched. These MAY BE the same as existingPrimary and existingNeighbor. + *---------------------------------------------------------------------------*/ + if(srcBeast->FILEattributes & zFA_HARDLINK) + { + zASSERT(((HardLinkBeast_s *)srcBeast)->HARDLprimaryZid != zINVALID_ZID); + + srcPrimaryBeast = COMN_LookupByZid(genMsg, srcBeast->FILEvolume, + ((HardLinkBeast_s *)srcBeast)->HARDLprimaryZid, + NOTLATCHED, TRUE); + if(srcPrimaryBeast == NULL) + { + zASSERT("Primary beast has dissappeared" == NULL); + ForceSetErrno(genMsg, zERR_INTERNAL_DIRECTORY_ERROR); + goto error_cleanupUnlatch; + } + if(srcPrimaryBeast != existingPrimaryBeast) + { + X_LATCH(&srcPrimaryBeast->FILEbeastLatch); + } + } + + if(srcBeast != existingNeighborBeast) + { + X_LATCH( &srcBeast->FILEbeastLatch); + } + srcNameMsg->latchType = XLATCHED; /* transfer the latch to the namemsg for later cleanup */ + +/*--------------------------------------------------------------------------- + * Two or three beasts (ALL possible beasts involved in the rename) are now XLATCHED. + * This function is atomic. It either works or it doesn't. There is a + * possibility that if it fails and is un-recoverable, it will do an + * AbendTheVolume error down deep. + *---------------------------------------------------------------------------*/ + + if (NAME_RenameBeast(genMsg,srcBeast,srcPrimaryBeast, srcDir, + targetDir,srcName,newName, + srcNameMsg->workNameSpace,srcNameMsg->workNameType, + destNameMsg->workNameType,renMsg,xaction) != zOK) + { + if (deleteExistingBeast) + { + COMN_AbortXLocal(genMsg,srcBeast->FILEvolume,xaction, WHERE); + } + goto error_cleanupUnlatch; + } + } + if (xaction != NULL) + { + COMN_EndXLocal(srcBeast, &xaction); + } + + /* + * Set the archive bit and add the entry to the MFL + */ + if (!(srcBeast->FILEattributes & (zFA_ARCHIVE | zFA_ATTR_ARCHIVE))) + { + /* + * If this is the OFF-to-ON transition of the file archive bits, + * add the file to the volume's Modified Files List (if any). + */ + SBS_markFileModified(srcBeast, zFA_ARCHIVE | zFA_ATTR_ARCHIVE, 0); + } + else + { + srcBeast->FILEattributes |= (zFA_ARCHIVE | zFA_ATTR_ARCHIVE); + } + COMN_MARK_BEAST_MESSY(&srcBeast->FILEroot); + +/*------------------------------------------------------------------------- + * Change the metadata timestamp on the file which was renamed and + * change the modify timestamp on the directories. + * NOTE--We do this here because inside of NAME_RenameBeast, we are only + * dealing with NAMED beasts which don't have the time stamps... + *-------------------------------------------------------------------------*/ + OID_SaveObjectID(targetDir->FILEvolume, &userID); + currentTime = GetUTCTime(); +/* Defect 219994 - Leave originial owner and createTime when salvaging because + * this messed up user quotas and does not make sense. + * if (srcNameMsg->workNameType == zNTYPE_DELETED_FILE) + * { + * srcBeast->FILEcreatedTime = currentTime; + * srcBeast->FILEcreatedDOSTime = INVALID_DOS_TIME; + * srcBeast->FILEownerID = userID; + * } + * End Defect 219994 */ + srcBeast->FILEmetaDataModifiedTime = currentTime; + srcBeast->FILEmetaDataModifiedDOSTime = INVALID_DOS_TIME; + srcBeast->FILEmetaDataSeqNum++; + srcDir->FILEvolume->VOLfile.FILEmodifiedTime = currentTime; + COMN_MARK_BEAST_MESSY(&srcBeast->FILEroot); + + targetDir->FILEmodifiedTime = currentTime; + targetDir->FILEmodifiedDOSTime = INVALID_DOS_TIME; + targetDir->FILEmodifierID = userID; + targetDir->FILEmetaDataSeqNum++; + targetDir->FILEvolume->VOLfile.FILEmodifiedTime = currentTime; + COMN_MARK_BEAST_MESSY(&targetDir->FILEroot); +/*------------------------------------------------------------------------- + * NOTE - Classic NetWare only moved trustees to the new target if + * the user had ChangeAccessControl rights in the targetDir. We have + * determined that the trustees should always be moved along with the beasts. + * We actually came up with a scenario where stripping trustees allowed + * a user to actually gain rights to a beast by moving it. + * Trustees do not have to be explicitly moved with a file . . . where ever + * the file goes, the trustees automatically follow. + *-------------------------------------------------------------------------*/ + /* If there are open file handles pointing to this file then + * point them to the new place (same zid, but different parentZid) */ + FH_FixupAllFileHandlesOnBeast(genMsg, (NamedBeast_s *)srcBeast, + (NamedBeast_s *)srcDir, (NamedBeast_s *)targetDir, + /* cnt srcNameMsg->fileNameUniquifier, renMsg->retNameUniquifier, */ + destNameMsg->workNameType); + if (srcBeast->FILEattributes & zFA_SUBDIRECTORY) + { + /* If there are context handles pointing to this directory then + * point them to the new place (same zid, but different parentZid) */ + CXH_FixupAllContextHandlesOnBeast(genMsg,srcBeast,srcDir,targetDir, +// cnt srcNameMsg->fileNameUniquifier, renMsg->retNameUniquifier, + destNameMsg->workNameType); + } +// /* Fixup any generic semantic agent handles which may point to the +// * beast which was just moved */ +// SAH_FixupAllSAHsOnBeast(genMsg, (NamedBeast_s *)srcBeast, +// srcDir, targetDir, +// srcNameMsg->fileNameUniquifier, renMsg->retNameUniquifier, +// destNameMsg->workNameType); + + + if ( !(renMsg->renameFlags & zRENAME_KEEP_VFS_CACHE)) + { + aStack->lsaDestPzid = targetDir->FILEzid; + lsaInvDentry = TRUE; + } + + /* if existing neighbor exists, unlatch it. There is a potential case + * where existingNeighborBeast is the same as srcBeast, but only ONE + * latch exists for the two pointers + */ + if(srcBeast == existingNeighborBeast) + { + /* Tell the nameMsg cleanup to not unlatch */ + srcNameMsg->latchType = NOTLATCHED; + } + + if(existingNeighborBeast) + { + COMN_UnlatchAndRelease(&existingNeighborBeast, XLATCHED); + } + + + if (existingPrimaryBeast) + { + if(existingPrimaryBeast != srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&existingPrimaryBeast, XLATCHED); + } + else + { + COMN_Release(&existingPrimaryBeast); + } + } + + if(srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&srcPrimaryBeast, XLATCHED); + } + + if (srcDirLatched) + UNX_LATCH(&srcDir->FILEbeastLatch); + + if (targetDirLatched) + UNX_LATCH(&targetDir->FILEbeastLatch); + + if (releaseSrcDir) + COMN_Release(&srcDir); + + if (releaseTargetDir) + COMN_Release(&targetDir); + + + if (existingBeast) + { + COMN_UnlatchAndRelease(&existingBeast, XLATCHED); + } + if (lsaDelDentry && Ptr_lsa_invalidate_dentry) + { + COMN_UNLATCH_NAMEMSG_BEASTS(destNameMsg, &destLatchType); + Ptr_lsa_invalidate_dentry( &aStack->lsaDestInv); + } + if (lsaInvDentry) + { + if ((aStack->srcStatus == zOK) && (Ptr_lsa_invalidate_dentry)) + { + COMN_UNLATCH_NAMEMSG_BEASTS(srcNameMsg, &srcLatchType); + Ptr_lsa_invalidate_dentry( &aStack->lsaSrcInv); + COMN_LATCH_NAMEMSG_BEASTS(srcNameMsg, srcLatchType); + } + if (COMN_LsaCleanupSetup( &srcBeast->FILEnamed, + &aStack->lsaDestInv) == zOK ) + { + aStack->lsaDestInv.lid_zid = zINVALID_ZID; + aStack->lsaDestInv.lid_pZid = aStack->lsaDestPzid; + if (Ptr_lsa_invalidate_dentry) + { + COMN_UNLATCH_NAMEMSG_BEASTS(destNameMsg, &destLatchType); + Ptr_lsa_invalidate_dentry( &aStack->lsaDestInv); + } + } + } + status = zOK; + +sendExitEvent: + if (FSHOOKS_OR_EVENTS(hookType, EVENT_Rename_Exit)) + { + /* srcNameMsg points to the beast that was renamed. + * destNameMsg points to the target directory to which it was renamed */ + COMN_UNLATCH_NAMEMSG_BEASTS(srcNameMsg, &srcLatchType); + COMN_UNLATCH_NAMEMSG_BEASTS(destNameMsg, &destLatchType); + /* Using zINVALID_ZID instead of targetDir->FILEzid because + * the targetdir may have been released and also at exit time + * this field is not used. + */ + if (hookType == SalvageFile_Hook) + { + CHECK_FSHOOKS_SALVAGE_EXIT(SalvageFile_Hook, &aStack->salvageParms, genMsg, + srcNameMsg, newName, aStack->asciiNewName); + if (SendBothRenameAndSalvageHooks) + { + CHECK_FSHOOKS_RENAME_EXIT(F3RenameFile_Hook, &aStack->renameParms, + genMsg, srcNameMsg, newName, aStack->asciiNewName, + zINVALID_ZID, renMsg); + } + } + else + { + CHECK_FSHOOKS_RENAME_EXIT(F3RenameFile_Hook, &aStack->renameParms, genMsg, + srcNameMsg, newName, aStack->asciiNewName, zINVALID_ZID, renMsg); + } + if (NEBEventInfo[EVENT_Rename_Exit].consumers) + { + INIT_EXIT_EVENT(status, genMsg, aStack->evBlk, EVENT_Rename_Exit, aStack->exit, id); + ZOS_ProduceEvent(status,&aStack->evBlk); + } + /* We saw a deadlock here because when we re-latched, we were latching + * the srcNameMsg first. At this point, srcNameMsg points to the + * beast that was renamed, and destNameMsg points to the directory + * into which it was renamed. + */ +// COMN_LATCH_NAMEMSG_BEASTS(destNameMsg, destLatchType); + COMN_LATCH_NAMEMSG_BEASTS(srcNameMsg, srcLatchType); + } + + /* Don't release this till after the above event stuff because the "newName" + * variable points to memory in this buffer, and it is used above. + */ + COMN_ReleasePathNameWorkBuffer(&tempWorkBuffer); + + if (hookType == SalvageFile_Hook) + { + Inst.file.salvagedCount++; + } + + +justReturn: + STACK_FREE(); + RTN_STATUS(status); + +/*=========================================================================*/ +error_cleanupUnlatch: + if (xaction != NULL) + { + COMN_EndXLocal(srcDir, &xaction); + } + + + /* if existing neighbor exists, unlatch it. There is a potential case + where existingNeighborBeast is the same as srcBeast, but only ONE + latch exists for the two pointers */ + if(srcBeast == existingNeighborBeast) + { + /* Tell the nameMsg cleanup to not unlatch */ + srcNameMsg->latchType = NOTLATCHED; + } + + if(existingNeighborBeast) + { + UNX_LATCH(&existingNeighborBeast->FILEbeastLatch); + } + + if(existingPrimaryBeast && (existingPrimaryBeast != srcPrimaryBeast)) + { + UNX_LATCH(&existingPrimaryBeast->FILEbeastLatch); + } + + if(srcPrimaryBeast) + { + UNX_LATCH(&srcPrimaryBeast->FILEbeastLatch); + } + + if (srcDirLatched) + UNX_LATCH(&srcDir->FILEbeastLatch); + + if (targetDirLatched) + UNX_LATCH(&targetDir->FILEbeastLatch); + + if (existingBeast) + UNX_LATCH(&existingBeast->FILEbeastLatch); + +error_cleanupRelease: + if (srcPrimaryBeast) + COMN_Release(&srcPrimaryBeast); + + if (existingPrimaryBeast) + COMN_Release(&existingPrimaryBeast); + + if (existingNeighborBeast) + COMN_Release(&existingNeighborBeast); + + if (releaseSrcDir) + COMN_Release(&srcDir); + + if (releaseTargetDir) + COMN_Release(&targetDir); + + if (existingBeast) + COMN_Release(&existingBeast); + + if (tempWorkBuffer) + COMN_ReleasePathNameWorkBuffer(&tempWorkBuffer); + + status = zFAILURE; + goto sendExitEvent; + +error_cleanupReleaseAndReturn: + if (srcPrimaryBeast) + COMN_Release(&srcPrimaryBeast); + + if (existingPrimaryBeast) + COMN_Release(&existingPrimaryBeast); + + if (existingNeighborBeast) + COMN_Release(&existingNeighborBeast); + + if (releaseSrcDir) + COMN_Release(&srcDir); + + if (releaseTargetDir) + COMN_Release(&targetDir); + + if (existingBeast) + COMN_Release(&existingBeast); + + if (tempWorkBuffer) + COMN_ReleasePathNameWorkBuffer(&tempWorkBuffer); + +error_cleanupAndReturn: + status = zFAILURE; + goto justReturn; + +error_cleanupSrcPrimaryXLatchedAndReturn: + if (srcPrimaryBeast) + { + COMN_UnlatchAndRelease(&srcPrimaryBeast,XLATCHED); + } + UNX_LATCH(&srcBeast->FILEbeastLatch); + status = zFAILURE; + goto justReturn; +} + + +/************************************************************************** + * This routine renames file objects. You can use wildcarding during + * the rename if you are renaming files, you can not use it for anything + * else. This will allow you to rename files from one directory to + * another. + * NOTE -- THIS FUNCTION DEALS DIFFERENTLY WITH LATCHES. IT DOES NOT KEEP + * LATCHES AT THIS LEVEL -- BECAUSE THEY ARE VERY PRONE TO DEADLOCK. + * The above REN_DoRenameBeast does all latching internally. + ***************************************************************************/ +STATUS COMN_Rename( + GeneralMsg_s *genMsg, + NamingMsg_s *srcNameMsg, + NamingMsg_s *destNameMsg, + RenameMsg_s *renMsg) +{ +#if (zMAX_FULL_NAME < ((zMAX_COMPONENT_NAME*2)+2)) + #error The zMAX_FULL_NAME size must be >= (zMAX_COMPONENT_NAME * 2) + 2, + #error because we use a workbuffer which must be >= zMAX_FULL_NAME +#endif + SearchMsg_s srchMsg; + File_s *tempDir = NULL; + Zid_t tempParentZid; +// cnt NINT tempNameUniquifier; + unicode_t *saveCurComponent; + unicode_t *srcPattern; + unicode_t *replacePattern; + unicode_t *tempWorkBuffer = NULL; + NINT tempLen; + BOOL noRights = FALSE; + BOOL dupToMyself = FALSE; + BOOL invalidReplacePattern = FALSE; + BOOL locked = FALSE; + BOOL readonly = FALSE; + Xaction_s *xaction; + ParentEntry_s *parentEntry; + VolInfoLog_s volLog; + BOOL targetExistsAsDirectory = FALSE; + STATUS rc; + + + ASSERT_MPKNSS_LOCK(); + ENTER(TCOMMON, COMN_Rename); + + /* Defect #306666. We can't allow unlicensed connection access */ + if (!ConnectionIsLoggedIn(genMsg->pssConn.id)) + { + /* They are not logged in (LICENCED), so limit their access */ + if ((srcNameMsg->workNameType == zNTYPE_DELETED_FILE) && + (destNameMsg->workNameType == zNTYPE_FILE)) + { + SetErrno(genMsg, zERR_NO_CREATE_PRIVILEGE); + } + else + { + SetErrno(genMsg, zERR_NO_RENAME_PRIVILEGE); + } + goto cleanup_error; + } + +/*--------------------------------------------------------------------------- + * Require that the latchTypes come in == XLATCHED, but change them temporarily + * to NOTLATCHED. We will do our own XLATCHING later. + *---------------------------------------------------------------------------*/ + zASSERT(destNameMsg->curDataStream == (NamedBeast_s *)destNameMsg->curFile); + zASSERT(srcNameMsg->curDataStream == (NamedBeast_s *)srcNameMsg->curFile); + + zASSERT(destNameMsg->hlFile == NULL); + zASSERT(srcNameMsg->hlFile == NULL); + if ((destNameMsg->hlFile != NULL) || (srcNameMsg->hlFile != NULL)) + { + SetErrno(genMsg, zERR_INVALID_INTERNAL_LINK_STRUCTURE); + goto cleanup_error; + } + + if (destNameMsg->curFile != NULL) + COND_UNLATCH(&destNameMsg->curFile->FILEbeastLatch, + destNameMsg->latchType); + destNameMsg->latchType = NOTLATCHED; + + if (srcNameMsg->curFile != NULL) + COND_UNLATCH(&srcNameMsg->curFile->FILEbeastLatch, + srcNameMsg->latchType); + srcNameMsg->latchType = NOTLATCHED; + + renMsg->retNumRenamed = 0; /* init count*/ +/*--------------------------------------------------------------------------- + * Allocate a temporary work buffer to hold the rename patterns. + *---------------------------------------------------------------------------*/ + if ((tempWorkBuffer = COMN_GetPathNameWorkBuffer(genMsg)) == NULL) + goto cleanup_target; + srcPattern = tempWorkBuffer + (zMAX_COMPONENT_NAME + 1); + replacePattern = NULL; +/*--------------------------------------------------------------------------- + * Check if the destination is a full path, or if it simply contains + * a new leaf name. If it only contains a new leaf name, we process the path + * string for validity but we put off other processing till later... + *---------------------------------------------------------------------------*/ + COMN_ALLOW_WILDCARDING(destNameMsg); + if (renMsg->renameFlags & zRENAME_TARGET_IS_PATTERN) + { + /* destNameMsg->path points to a new leaf name, but does not contain any + * path information. Normalize the nameMsg so that the workBuffer is + * inited and curComponent points to a normalized leaf pattern. */ + COMN_SET_NAMING_MSG_FORCE_CONVERT_TO_UNICODE(destNameMsg); + if (NMSG_ValidateNameMsg(genMsg,destNameMsg) != zOK) + goto cleanup_target; + + /* Make sure that a single component exists */ + if ((destNameMsg->retParseFlags & + (NAMRETPFL_haveAParsedComponent | NAMRETPFL_lastComponent)) != + (NAMRETPFL_haveAParsedComponent | NAMRETPFL_lastComponent)) + { + SetErrno(genMsg,zERR_INVALID_PATH); + goto cleanup_target; + } + zASSERT(destNameMsg->scanMsg.retScanFlags & NSRETSFL_componentIsUnicode); + zASSERT(destNameMsg->scanMsg.retUnicodeComp != NULL); + + /* Move the replace pattern to a separate work buffer */ + replacePattern = tempWorkBuffer; + unimcpy(replacePattern,destNameMsg->scanMsg.retUnicodeComp, + zMAX_COMPONENT_NAME); + replacePattern[zMAX_COMPONENT_NAME] = 0; /* Force null termination */ + + goto processSourceName; + } +/*--------------------------------------------------------------------------- + * Dest contains full path information. + * Resolve the destination name down to the LEAF name. We do this so we + * can determine if there are destination wildcard characters or not. + *---------------------------------------------------------------------------*/ + zASSERT(destNameMsg->parseMode == NAMPMODE_Undefined); + destNameMsg->parseMode = NAMPMODE_DoNotResolveLeafName; + if (COMN_Lookup(genMsg,destNameMsg) != zOK) + { + if (GetErrno(genMsg) == zERR_LINK_IN_PATH) + { + ForceSetErrno(genMsg, zERR_LINK_IN_DEST_PATH); + } + goto cleanup_target; + } +/*--------------------------------------------------------------------------- + * It is possible that the target is explicitly identified by ZID or handle, + * in which case the above COMN_lookup call would resolve directly to a file. + * If this is the case we need to return an error... + *---------------------------------------------------------------------------*/ + if ( (!(destNameMsg->retParseFlags & NAMRETPFL_lastComponent)) || + ((!(destNameMsg->retParseFlags & NAMRETPFL_haveAParsedComponent)) && + (!(destNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY))) ) + { + SetErrno(genMsg,zERR_INVALID_PATH); + goto cleanup_target; + } + + if ((destNameMsg->scanMsg.retScanFlags & NSRETSFL_hasWildcardChars)) + { +/*--------------------------------------------------------------------------- + * Wildcard characters exist in the dest name. + * destNameMsg->curFile - points to the target directory. + * destNameMsg->scanMsg.retUnicodeComp - points to the wildcard replace pattern. + * destNameMsg->retParseFlags - better be NAMRETPFL_lastComponent & NAMRETPFL_haveAParsedComponent + *---------------------------------------------------------------------------*/ + zASSERT((destNameMsg->retParseFlags & + (NAMRETPFL_haveAParsedComponent | NAMRETPFL_lastComponent)) == + (NAMRETPFL_haveAParsedComponent | NAMRETPFL_lastComponent)); + zASSERT(destNameMsg->scanMsg.retScanFlags & NSRETSFL_componentIsUnicode); + zASSERT(destNameMsg->scanMsg.retUnicodeComp != NULL); + zASSERT(destNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY); + + /* Move the replace pattern to a separate work buffer */ + replacePattern = tempWorkBuffer; + unimcpy(replacePattern,destNameMsg->scanMsg.retUnicodeComp, + zMAX_COMPONENT_NAME); + replacePattern[zMAX_COMPONENT_NAME] = 0; /* Force null termination */ + } + else /* No wildcard characters in dest name */ + { +/*--------------------------------------------------------------------------- + * No wildcard characters are in the dest name. Resolve the leafname + * to figure out what kind of rename to do. + * Following are a list rules for rename: + * - If the dest filename does not exist, we want to rename/move the src + * file to this filename in this directory. + * - if the dest file does exist and it is a directory, we assume we want + * to move the src files into this dest directory. Later we will check + * to see if we are actually renaming directories. + * - if the dest file does exist and it is a file, we may be renaming to + * ourselves which is zOK so continue with this. + *---------------------------------------------------------------------------*/ + tempDir = (File_s *)destNameMsg->curFile; /* save pointer to current Dir */ + COMN_USE_BEAST(&tempDir->FILEroot); /* mark an extra useCount to keep it around*/ + tempParentZid = destNameMsg->fileParentZid; /* Save the dir's parent zid too */ +// cnt tempNameUniquifier = destNameMsg->fileNameUniquifier; + + saveCurComponent = destNameMsg->scanMsg.retUnicodeComp; + + /* Finish resolving destNameMsg. It may already be fully resolved, + * but we call it anyway just in case... */ + destNameMsg->parseMode = NAMPMODE_FullyResolveAny; + if (COMN_Lookup(genMsg,destNameMsg) == zOK) + { + /* The target exists, see if it is a file or a subdirectory */ + if ((destNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) && + !( renMsg->renameFlags & zRENAME_DELETE_FILE_IF_THERE)) + { + /* target exists, and it is a directory. + * + * POSSIBILITY 1: If the sourceFile is a directory (but not the + * same directory as this targetDir), this means we want to MOVE + * the sourceFile to exist inside of the target directory, using + * the same name it already has. In this case we want + * "replacepattern" to be NULL, because we are not actually + * changing names. + * + * POSSIBILITY 2: If the sourceFile is a directory, and it is + * the exact same directory as the targetFile, then we do want + * to actually rename the directory itself. In this case we do + * want to set "replacePattern" to be the new name. However + * we can't set it here, because we do not yet know what the + * source file is. Therefore, copy it to tempWorkBuffer so + * we can assign it later on. */ + + /* Release tempDir now, because it is not guaranteed to be + * our parent dir (it could be the same as destNameMsg-> + * curFile. If we need to back up later, we will do it + * using parentZid. */ + COMN_Release(&tempDir); + + /* Move the replace pattern to a separate work buffer and */ + /* leave replacePattern == NULL until later on - SEE ABOVE */ + if (saveCurComponent != NULL) + { + unimcpy(tempWorkBuffer,saveCurComponent,zMAX_COMPONENT_NAME); + tempWorkBuffer[zMAX_COMPONENT_NAME] = 0; + } + else + { + tempWorkBuffer[0] = 0; + } + + + /* This flag is used to indicate that we have already verified + * that the target is an existing directory AND to indocate + * that tempWorkBuffer contains the new name for the directory */ + targetExistsAsDirectory = TRUE; + + } + else + { + /* target exists, and it is a file. This is only legal if + * we are renaming the file to itself, and if that is allowed. + * Save the file pointer and reset destNameMsg to the directory. + * We will check later to see if we're renaming to ourself... + * This situation will arise if we are attempting to change the + * case on a case-insensitive, but case-preserving namespace. + * If this happens, it is important to preserve the target + * name, because its case may be different. */ + COMN_Release(&destNameMsg->curFile); + COMN_Release(&destNameMsg->curDataStream); + destNameMsg->curFile = tempDir; /* restore file's parent dir */ + destNameMsg->curDataStream = (NamedBeast_s *)tempDir; /* restore file's parent dir */ + COMN_USE_BEAST(&destNameMsg->curDataStream->NAMEDroot); + destNameMsg->fileParentZid = tempParentZid; +// cnt destNameMsg->fileNameUniquifier = tempNameUniquifier; + destNameMsg->fileNameType = destNameMsg->workNameType; + tempDir = NULL; + + /* Move the replace pattern to a separate work buffer */ + zASSERT(saveCurComponent != NULL); + replacePattern = tempWorkBuffer; + unimcpy(replacePattern,saveCurComponent,zMAX_COMPONENT_NAME); + replacePattern[zMAX_COMPONENT_NAME] = 0; /* Force null termination */ + } + } + else /* An error looking up the file */ + { + if (GetErrno(genMsg) == zERR_LINK_IN_PATH) + { + ForceSetErrno(genMsg, zERR_LINK_IN_DEST_PATH); + goto cleanup_target; + } + if (GetErrno(genMsg) != zERR_NAME_NOT_FOUND_IN_DIRECTORY) + { + goto cleanup_target; + } + + /* The target file does not exist yet...curFile is still + * pointing to the directory. We will rename the + * src file(s) to the directory identified by curFile. + * The replacepattern is the new filename in curComponent. */ + ClearErrno(genMsg); + COMN_Release(&tempDir); + + zASSERT(destNameMsg->curFile != NULL); + zASSERT(destNameMsg->scanMsg.retUnicodeComp != NULL); + zASSERT((destNameMsg->retParseFlags & + (NAMRETPFL_haveAParsedComponent | NAMRETPFL_lastComponent)) == + (NAMRETPFL_haveAParsedComponent | NAMRETPFL_lastComponent)); + + /* Move the replace pattern to a separate work buffer */ + replacePattern = tempWorkBuffer; + unimcpy(replacePattern,destNameMsg->scanMsg.retUnicodeComp, + zMAX_COMPONENT_NAME); + replacePattern[zMAX_COMPONENT_NAME] = 0; /* Force null termination */ + } +/*--------------------------------------------------------------------------- + * We dont currently allow renaming anything to be owned by a file object + * rather than a directory object. + * FixFixFix6 -- We may want to revisit this decision + *---------------------------------------------------------------------------*/ + if ((destNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) == 0) + { + SetErrno(genMsg,zERR_CANT_RENAME_DATA_STREAMS); + goto cleanup_target; + } + + zASSERT(destNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY); + } + +/*=========================================================================== + * When we GET here we have the following state: + * destNameMsg->curFile - the target directory (or NULL if dest + * is just a leaf name) + * replacePattern - points to the replace pattern or is NULL + *===========================================================================*/ + +/*=========================================================================== + * Now we are going to resolve the Source name. + *===========================================================================*/ + processSourceName: + COMN_ALLOW_WILDCARDING(srcNameMsg); + srcNameMsg->parseFlags |= NAMPFL_dontProcessHardLink; + srcNameMsg->parseMode = NAMPMODE_DoNotResolveLeafName; + if (COMN_Lookup(genMsg,srcNameMsg) != zOK) + goto cleanup_source; + srcNameMsg->parseFlags &= ~NAMPFL_dontProcessHardLink; + +/*--------------------------------------------------------------------------- + * We dont currently allow renaming anything to be owned by a file object + * rather than a directory object. + *---------------------------------------------------------------------------*/ + if ((srcNameMsg->retParseFlags & NAMRETPFL_haveAParsedComponent) && + ((srcNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) == 0)) + { + SetErrno(genMsg,zERR_CANT_RENAME_DATA_STREAMS); + goto cleanup_target; + } +/*--------------------------------------------------------------------------- + * It is possible to use an open file handle for the source file identifier, + * in which case the COMN_Lookup would resolve directly to the beast. + * If there are no leaf components, and the curFile is a file, this is OK. + *---------------------------------------------------------------------------*/ + zASSERT( (!(srcNameMsg->retParseFlags & NAMRETPFL_haveAParsedComponent)) || + (srcNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) ); + + if (!(srcNameMsg->scanMsg.retScanFlags & NSRETSFL_hasWildcardChars)) + { +/*--------------------------------------------------------------------------- + * There were no wildcard characters, resolve directly to the leaf item + * which is to be renamed. + *---------------------------------------------------------------------------*/ + srcNameMsg->parseMode = NAMPMODE_FullyResolveAny; + srcNameMsg->parseFlags |= NAMPFL_dontProcessHardLink; + rc = COMN_Lookup(genMsg,srcNameMsg); + srcNameMsg->parseFlags &= ~NAMPFL_dontProcessHardLink; + if ( rc != zOK) + goto cleanup_source; +/*--------------------------------------------------------------------------- + * If the target name exists as a directory and if the srcNameMsg is a deleted + * beast, don't allow the salvage to happen. + *---------------------------------------------------------------------------*/ + if ((targetExistsAsDirectory) && + (srcNameMsg->workNameType == zNTYPE_DELETED_FILE)) + { + SetErrno(genMsg,zERR_ALL_NAMES_EXIST); + goto cleanup_source; + } +/*--------------------------------------------------------------------------- + * If the target name exists as a directory, and we are renaming only in + * a single name space, and if the source beast is different than the + * target beast then this is illegal. The zRENAME_THIS_NAME_SPACE_ONLY + * option does not allow for a source beast to be moved. + *---------------------------------------------------------------------------*/ + if ((targetExistsAsDirectory) && + (renMsg->renameFlags & zRENAME_THIS_NAME_SPACE_ONLY) && + (srcNameMsg->curFile != destNameMsg->curFile)) + { + SetErrno(genMsg,zERR_FILE_ALREADY_EXISTS); + goto cleanup_source; + } +/*--------------------------------------------------------------------------- + * We dont currently allow renaming anything to be owned by a file object + * rather than a directory object. + * FixFixFix6 -- We may want to revisit this decision + *---------------------------------------------------------------------------*/ + if (!(COMN_IsDerivedFrom(srcNameMsg->curDataStream,zFTYPE_FILE)) && + !(srcNameMsg->curDataStream->NAMEDattributes & zFA_HARDLINK)) + { + SetErrno(genMsg,zERR_CANT_RENAME_DATA_STREAMS); + goto cleanup_source; + } +/*--------------------------------------------------------------------------- + * If this is a subdirectory and we're not allowed to rename subdirectories, + * or vice-versa then return an error + *---------------------------------------------------------------------------*/ + if ((((srcNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) == 0) && + (renMsg->renameFlags & zRENAME_DONT_RENAME_FILES)) || + ((srcNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) && + (renMsg->renameFlags & zRENAME_DONT_RENAME_DIRECTORIES))) + { + SetErrno(genMsg,zERR_NO_FILES_FOUND); + goto cleanup_source; + } +/*------------------------------------------------------------------------- + * Check if the source beast is a directory, and if it is the exact same + * directory as the target directory. If it is, we need to back the target + * up to its parent directory...because it is the directory itself which + * is being renamed, so we need destNameMsg to point at the directory's + * parent directory. + *-------------------------------------------------------------------------*/ + if ((srcNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) && + (srcNameMsg->curFile == destNameMsg->curFile)) + { + zASSERT(destNameMsg != NULL); /* We shouldn't get here if it is NULL */ + if (destNameMsg->curFile->FILEzid == zROOTDIR_ZID) + { + SetErrno(genMsg,zERR_RENAME_DIR_INVALID); + goto cleanup_source; + } + COMN_Release(&destNameMsg->curFile); + COMN_Release(&destNameMsg->curDataStream); + destNameMsg->curFile = COMN_LookupByZid(genMsg, destNameMsg->curvol, + destNameMsg->fileParentZid,NOTLATCHED, FALSE); + if (destNameMsg->curFile == NULL) + goto cleanup_source; + destNameMsg->curDataStream = (NamedBeast_s *)destNameMsg->curFile; + COMN_USE_BEAST(&destNameMsg->curDataStream->NAMEDroot); + destNameMsg->fileParentZid = destNameMsg->curFile->FILEfirstParentZid; +// cnt destNameMsg->fileNameUniquifier = +// cnt destNameMsg->curFile->FILEfirstParentNameUniquifier; + destNameMsg->fileNameType = + destNameMsg->curFile->FILEfirstParentNameType; + destNameMsg->workNameType = + destNameMsg->curFile->FILEfirstParentNameType; + if (destNameMsg->workNameType == zNTYPE_FILE) + destNameMsg->retParseFlags &= ~NAMRETPFL_hasDeletedNameType; + + if ((targetExistsAsDirectory) && (tempWorkBuffer[0] != 0)) + { + /* The new target name was previously saved in tempWorkBuffer.*/ + replacePattern = tempWorkBuffer; + } + } +/*------------------------------------------------------------------------- + * Set the beast's name as the srcPattern + *-------------------------------------------------------------------------*/ + S_LATCH(&srcNameMsg->curFile->FILEbeastLatch); + if (COMN_GetNameFromBeast(genMsg, srcNameMsg->curFile, + /* cnt srcNameMsg->fileNameUniquifier ,*/ srcNameMsg->workNameSpaceID, + zMAX_COMPONENT_NAME, srcPattern, &tempLen) != zOK) + { + UNS_LATCH(&srcNameMsg->curFile->FILEbeastLatch); + goto cleanup_source; + } + UNS_LATCH(&srcNameMsg->curFile->FILEbeastLatch); +/*------------------------------------------------------------------------- + * When we GET here we have following state: + * srcNameMsg->curFile - the source beast to be renamed + * srcPattern - the source pattern (beast's name). + * destNameMsg->curFile - the target directory (or NULL if dest + * is simply a leaf pattern) + * replacePattern - the replace pattern or NULL. + *-------------------------------------------------------------------------*/ + renMsg->renameSeqNum = 0; + if (REN_DoRenameBeast(genMsg,srcNameMsg,destNameMsg,srcPattern, + replacePattern,renMsg) != zOK) + { + goto cleanup_source; + } + + renMsg->retNumRenamed = 1; + } + else /* There is wildcarding in the source name. */ + { +/*--------------------------------------------------------------------------- + * This is a WILDCARD rename on the Source File. We need to get a rename + * sequence number from the volume in order to prevent recursive renames. + * This is necessary, because the act of renaming a beast may move it down + * in the name tree so that we would try to rename it again later with the + * exact same rename. This also prevents us from renaming a beast if another + * rename from a different thread is started after us, but renames the beast + * before we get to it. + *---------------------------------------------------------------------------*/ + X_LATCH(&srcNameMsg->curvol->VOLbeastLatch); + X_LATCH(&srcNameMsg->curFile->FILEbeastLatch); + xaction = COMN_BeginXLocal(srcNameMsg->curFile); + + renMsg->renameSeqNum = ++srcNameMsg->curvol->VOLrenameSeqNum; + + volLog.delta = 1; + volLog.action = VOLINFO_CHANGE_REN_SEQ_NUM; + srcNameMsg->curvol->VOLcomnVolOps.VOL_writeVolumeLoggedData( + srcNameMsg->curvol, xaction, &volLog); + + COMN_EndXLocal(srcNameMsg->curFile,&xaction); + UNX_LATCH(&srcNameMsg->curFile->FILEbeastLatch); + UNX_LATCH(&srcNameMsg->curvol->VOLbeastLatch); + +/*------------------------------------------------------------------------- + * We had source WILDCARD characters, locate src files using wildcard reads. + *-------------------------------------------------------------------------*/ + zASSERT(srcNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY); + COMN_INIT_SEARCH_MSG(&srchMsg); + COMN_SETUP_WILDOPEN_SEARCH_MSG(&srchMsg,srcNameMsg->workNameType); + + if (COMN_WildOpen(genMsg,srcNameMsg,&srchMsg) != zOK) + goto cleanup_source; +/*------------------------------------------------------------------------- + * Save the search pattern as the srcPattern + *-------------------------------------------------------------------------*/ + zASSERT(srcNameMsg->scanMsg.retScanFlags & NSRETSFL_componentIsUnicode); + unimcpy(srcPattern,srcNameMsg->scanMsg.retUnicodeComp, + zMAX_COMPONENT_NAME); + srcPattern[zMAX_COMPONENT_NAME] = 0; /* force NULL termination */ +/*------------------------------------------------------------------------- + * Now, read the directory for the next wildcard match... + *-------------------------------------------------------------------------*/ + for (;;) + { + genMsg->flags |= DO_NOT_SEND_FSHOOKS; + if (COMN_WildRead(genMsg,srcNameMsg,&srchMsg) != zOK) + { + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; + if (GetErrno(genMsg) != zERR_NAME_NOT_FOUND_IN_DIRECTORY) + goto cleanup_closedir; + + ClearErrno(genMsg); + break; + } + genMsg->flags &= ~DO_NOT_SEND_FSHOOKS; +/*------------------------------------------------------------------------- + * If this is a subdirectory and were not allowed to rename subdirectories, + * or vice-versa then skip this file + *-------------------------------------------------------------------------*/ + if ((((srcNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) == 0) && + (renMsg->renameFlags & zRENAME_DONT_RENAME_FILES)) || + ((srcNameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) && + (renMsg->renameFlags & zRENAME_DONT_RENAME_DIRECTORIES))) + { + goto checkNextFile; + } +/*------------------------------------------------------------------------- + * When we GET here we have following state: + * srcNameMsg->curFile - the source beast to be renamed + * srcPattern - the source pattern used to locate the beast + * destNameMsg->curFile - the target directory + * replacePattern - the replace pattern or NULL. + *-------------------------------------------------------------------------*/ + S_LATCH(&srcNameMsg->curFile->FILEbeastLatch); + parentEntry = NAME_GetParentEntry(genMsg,srcNameMsg->curFile + /* cnt srcNameMsg->fileNameUniquifier */); + UNS_LATCH(&srcNameMsg->curFile->FILEbeastLatch); + + zASSERT(parentEntry != NULL); + if (parentEntry == NULL) + goto cleanup_closedir; + + if (parentEntry->p.renameSeqNum < renMsg->renameSeqNum) + { + /* Do this rename, and set the file's renameSeqNum to the + * current volume renameSeqNum */ + if (REN_DoRenameBeast(genMsg,srcNameMsg,destNameMsg,srcPattern, + replacePattern,renMsg) != zOK) + { + /* Check return error code, set flags and continue + * with the next file.....When were done with all of the + * wildcarded files we will re-set the appropriate error */ + switch (GetErrno(genMsg)) + { + case zERR_NO_RENAME_PRIVILEGE: + ClearErrno(genMsg); + noRights = TRUE; + break; + + case zERR_ALL_NAMES_EXIST: + ClearErrno(genMsg); + dupToMyself = TRUE; + break; + + case zERR_RESERVED_NAME: + case zERR_INVALID_NAME: + ClearErrno(genMsg); + invalidReplacePattern = TRUE; + break; + + case zERR_RENAME_DIR_INVALID: + goto cleanup_closedir; + + case zERR_ALL_FILES_IN_USE: + ClearErrno(genMsg); + locked = TRUE; + break; + + case zERR_ALL_FILES_READ_ONLY: + ClearErrno(genMsg); + readonly = TRUE; + break; + } + } + else + { + renMsg->retNumRenamed++; + } + } + + /* reset the nameMessage back to a search pattern type for the + * next loop of ReadDir */ +checkNextFile: + if (COMN_ResetNameMsgToSearchPattern(genMsg,srcNameMsg) != zOK) + goto cleanup_closedir; + srcNameMsg->latchType = NOTLATCHED; + + COND_UNLATCH(&destNameMsg->curFile->FILEbeastLatch, + destNameMsg->latchType); + destNameMsg->latchType = NOTLATCHED; + } + if (COMN_WildClose(genMsg,&srchMsg) != zOK) + { + zASSERT("Error calling COMN_CloseDir on wildcard rename"==NULL); + } + + if (renMsg->retNumRenamed == 0) + { + if (locked) + SetErrno(genMsg,zERR_ALL_FILES_IN_USE); + else if (readonly) + SetErrno(genMsg,zERR_ALL_FILES_READ_ONLY); + else if (dupToMyself) + SetErrno(genMsg,zERR_ALL_NAMES_EXIST); + else if (noRights) + SetErrno(genMsg,zERR_NO_RENAME_PRIVILEGE); + else if (invalidReplacePattern) + SetErrno(genMsg,zERR_INVALID_NAME); + else + SetErrno(genMsg,zERR_NO_FILES_FOUND); + goto cleanup_source; + } + else /* some files were renamed */ + { + if (locked) + SetErrno(genMsg,zERR_SOME_FILES_IN_USE); + else if (readonly) + SetErrno(genMsg,zERR_SOME_FILES_READ_ONLY); + else if (dupToMyself) + SetErrno(genMsg,zERR_SOME_NAMES_EXIST); + else if (noRights) + SetErrno(genMsg,zERR_NO_RENAME_PRIVILEGE); + else if (invalidReplacePattern) + SetErrno(genMsg,zERR_INVALID_NAME); + else + goto someFilesRenamedOK; + + goto cleanup_source; + } + } +someFilesRenamedOK: + COMN_ReleasePathNameWorkBuffer(&tempWorkBuffer); + RTN_STATUS(zOK); + + +/*=========================================================================*/ +cleanup_closedir: + COMN_WildClose(genMsg,&srchMsg); + +cleanup_source: + +cleanup_target: + if (tempDir) + COMN_Release(&tempDir); + + if (tempWorkBuffer) + COMN_ReleasePathNameWorkBuffer(&tempWorkBuffer); + +cleanup_error: + RTN_STATUS(zFAILURE); +} diff --git a/src/nwnss/comn/common/comnWild.c b/src/nwnss/comn/common/comnWild.c new file mode 100644 index 0000000..2900fad --- /dev/null +++ b/src/nwnss/comn/common/comnWild.c @@ -0,0 +1,1760 @@ +/**************************************************************************** + | + | (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: blarsen $ + | $Date: 2006-04-12 01:44:11 +0530 (Wed, 12 Apr 2006) $ + | + | $RCSfile$ + | $Revision: 1342 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | This contains common layer interfaces for directory wildcarding + +-------------------------------------------------------------------------*/ +#include +#include +#include +#include + +#include /* NSS Library */ +#include +#include + +#include "zParams.h" +#include "comnPublics.h" +#include "msgName.h" +#include "searchMap.h" +#include "volume.h" +#include "pssConnection.h" +#include "comnAuthorize.h" +#include "nameScan.h" +#include "nameSpace.h" +#include "fullDirectoryInfo.h" +#include "name.h" +#include "nssFSHooks.h" + +STATUS WILD_searchForFile( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg); +STATUS WILD_searchAllDirsForFile( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg); +STATIC STATUS WILD_searchForSpecificFile( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg); +/************************************************************************** + * This will reset the wildcard searching back to the front of the + * given directory directory. + ***************************************************************************/ +STATUS COMN_WildClose( + GeneralMsg_s *genMsg, + SearchMsg_s *srchMsg) +{ + SearchMap_s *smap; + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, COMN_WildClose); + + if ((smap = SMAP_RESOLVE_SEARCHMAP(genMsg,&srchMsg->srchMap, + srchMsg->srchOpt)) == NULL) + { + RTN_STATUS(zFAILURE); + } + + SMAP_FreeSearchMap(genMsg,&srchMsg->srchMap,srchMsg->srchOpt); + RTN_STATUS(zOK); +} + + +/************************************************************************** + * This will open a directory for wildcard searching. + ***************************************************************************/ +STATUS COMN_WildOpen( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg) +{ + ENTER(TWILD, COMN_WildOpen); + ASSERT_MPKNSS_LOCK(); + + if (COMN_Lookup(genMsg,nameMsg) != zOK) + RTN_STATUS(zFAILURE); + + if (nameMsg->curDataStream != (NamedBeast_s *)nameMsg->curFile) + { + /* This is a dataStram, we cant open it for wild card enumeration */ + if (srchMsg->nameType == zNTYPE_FILE) + SetErrno(genMsg,zERR_NOT_DIRECTORY_FILE); + else + SetErrno(genMsg,zERR_CANT_WILDOPEN_A_DATASTREAM); + RTN_STATUS(zFAILURE); + } + else + { + if ((srchMsg->nameType == zNTYPE_FILE) && + !(nameMsg->curDataStream->NAMEDattributes & zFA_SUBDIRECTORY)) + { + SetErrno(genMsg,zERR_NOT_DIRECTORY_FILE); + RTN_STATUS(zFAILURE); + } + } + + zASSERT((nameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) || + (srchMsg->nameType == zNTYPE_DATA_STREAM) || + (srchMsg->nameType == zNTYPE_EXTENDED_ATTRIBUTE)); + + if (SMAP_AllocAndInitSearchMap(genMsg,nameMsg,srchMsg) != zOK) + RTN_STATUS(zFAILURE); + + RTN_STATUS(zOK); +} + +/************************************************************************** + * A search map couldn't be found for the given ZID. This routine will + * attempt to restablish a search map back to that ZID location. The ZID + * is the ID of the last entry returned from the search map. + ***************************************************************************/ +STATIC STATUS WILD_ReestablishSearchMap( + GeneralMsg_s *genMsg, + SearchMsg_s *srchMsg, + NamingMsg_s *nameMsg, + Zid_t zid) +{ + NamedBeast_s *beast; + unicode_t *workBuf; + Zid_t parentZID; + STATUS status; +// cnt NINT nameUniquifier; + typedef struct Stack_s { + NamingMsg_s localNameMsg; + } Stack_s; + + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, WILD_ReestablishSearchMap); + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("WILD_ReestablishSearchMap: Restablishing searchmap for ZID %u\n"),(NINT)zid)); + + /* We have seen deadlock here, so unlatch the nameMsg while we are playing + * with the other beasts */ + COMN_UNLATCH_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); +/*------------------------------------------------------------------------- + * get a buffer to put the beast name into + *-------------------------------------------------------------------------*/ + if ((workBuf = COMN_GetPathNameWorkBuffer(genMsg)) == NULL) + { + goto error_return; + } +/*------------------------------------------------------------------------- + * Load the beast for the given ZID and extract the name and release the + * beast. + *-------------------------------------------------------------------------*/ + if ((beast = COMN_LookupByZid(genMsg,nameMsg->curvol,zid, + SLATCHED,FALSE)) == NULL) + { + goto error_releaseWork; + } + parentZID = beast->NAMEDfirstParentZid; /* save off parent */ + +// cnt if (NAME_GetFirstNameUniquifierForParentZid(genMsg, beast, +// cnt nameMsg->curDataStream->NAMEDzid, &nameUniquifier) != zOK) +// cnt { +// cnt goto error_releaseBst; +// cnt } + if (COMN_GetNameFromBeast(genMsg, beast, /* cnt nameUniquifier,*/ + nameMsg->nameSpaceID, UNI_PATHWORKBUF_SIZE, workBuf, NULL) != zOK) + { + goto error_releaseBst; + } + COMN_UnlatchAndRelease(&beast,SLATCHED); +/*------------------------------------------------------------------------- + * Now load the parent directory of this beast which is the directory we + * want the searchmap to be in. This bumps the usecount on this beast + *-------------------------------------------------------------------------*/ + if ((beast = COMN_LookupByZid(genMsg,nameMsg->curvol,parentZID, + SLATCHED,FALSE)) == NULL) + { + goto error_releaseWork; + } +/*------------------------------------------------------------------------- + * We now need to initialize a local NameMsg structure so we can search + * for this name to reset the cursor in the search map properly. + *-------------------------------------------------------------------------*/ + if (COMN_LockVolumeActive(genMsg,nameMsg->curvol, + (nameMsg->parseFlags & NAMPFL_dontLockVolumeActive)) != zOK) + { + goto error_releaseBst; + } + COMN_USE_BEAST(&nameMsg->curvol->VOLroot); + COMN_USE_BEAST(&nameMsg->workNameSpace->NSPACEroot); + COMN_USE_BEAST(&beast->NAMEDroot); /* Extra usecount for dataStream ptr */ + COMN_INIT_NAMING_MSG(&aStack->localNameMsg); + COMN_SETUP_NAMING_MSG_FILE_BEAST_PTR_WITH_WORKBUF(&aStack->localNameMsg, + nameMsg->curvol, + beast->NAMEDfirstParentZid, + // cnt beast->NAMEDfirstParentNameUniquifier, + (File_s *)beast, + NAMPMODE_FullyResolveDirectory, + SLATCHED, + nameMsg->workNameSpace, + nameMsg->workNameType, + NULL, + workBuf); + + /* These are now part of the nameMsg */ + beast = NULL; + workBuf = NULL; + + status = SMAP_AllocAndInitSearchMap(genMsg,&aStack->localNameMsg,srchMsg); + if (status == zOK) + { + /* Temporarily clear the matchAllEntries bit if it is set. This bit + * disables pattern matching and causes a match on the first file in + * the directory */ + if (srchMsg->srchOpt & SMAPOPT_matchAllEntries) + { + srchMsg->srchMap.ptr->options &= ~SMAPOPT_matchAllEntries; + } + + status = WILD_searchForFile(genMsg,&aStack->localNameMsg,srchMsg); + if (status != zOK) + { + SMAP_FreeSearchMap(genMsg,&srchMsg->srchMap,srchMsg->srchOpt); + goto exit; + } + + /* Deleted files can have duplicates, and it is possible we just + * looked up the wrong duplicate. If we don't have the correct + * ZID, and we are working with deleted files, scan other + * duplicate files with the same name. + */ + while ( (aStack->localNameMsg.curFile->FILEzid != zid) && + (srchMsg->nameType == zNTYPE_DELETED_FILE) ) + { + /* Re-lookup the parent "beast" directory */ + if ((beast = COMN_LookupByZid(genMsg,nameMsg->curvol,parentZID, + SLATCHED,FALSE)) == NULL) + { + SMAP_FreeSearchMap(genMsg,&srchMsg->srchMap,srchMsg->srchOpt); + goto exit; + } + + /* Reset the nameMsg to have a component and to point to the + * directory. Release the current beast pointer and put the + * parent directory back in. We already have an SLATCH and + * a usecount of 1 on the directory. We need one extra use count + * for the curDataStream pointer. + */ + COMN_UNLATCH_AND_RELEASE_NAMEMSG_BEASTS_KEEP_LATCHTYPE(&aStack->localNameMsg); + COMN_USE_BEAST(&beast->NAMEDroot); + aStack->localNameMsg.curFile = (File_s *)beast; + aStack->localNameMsg.curDataStream = beast; + aStack->localNameMsg.retParseFlags |= NAMRETPFL_haveAParsedComponent; + aStack->localNameMsg.parseFlags &= ~NAMPFL_nameMsgFullyResolved; + + /* Search again, using the same search criteria (looking for + * a duplicate name with the correct zid. + */ + if ((status=WILD_searchForFile(genMsg,&aStack->localNameMsg,srchMsg)) != zOK) + { + SMAP_FreeSearchMap(genMsg,&srchMsg->srchMap,srchMsg->srchOpt); + goto exit; + } + } + + /* Now, reset the matchAllEntries bit if it needs to be set. */ + if (srchMsg->srchOpt & SMAPOPT_matchAllEntries) + { + srchMsg->srchMap.ptr->options |= SMAPOPT_matchAllEntries; + } + } +exit: + COMN_CleanupNameMsg(genMsg,&aStack->localNameMsg); + COMN_LATCH_NAMEMSG_BEASTS(nameMsg,nameMsg->latchType); + STACK_FREE(); + RTN_STATUS(status); + +/*=========================================================================*/ +error_releaseBst: + COMN_UnlatchAndRelease(&beast,SLATCHED); +error_releaseWork: + COMN_ReleasePathNameWorkBuffer(&workBuf); +error_return: + COMN_LATCH_NAMEMSG_BEASTS(nameMsg,nameMsg->latchType); + STACK_FREE(); + RTN_STATUS(zFAILURE); +} + + +/************************************************************************** + * This attempt to find a search map that is already set up to point to the + * specified volume and zid. + ***************************************************************************/ +STATUS COMN_WildFindOpenContainerWithZID( + GeneralMsg_s *genMsg, + SearchMsg_s *srchMsg, + NamingMsg_s *nameMsg, + Zid_t zid) /* zid to match against */ +{ + NSSConnection_s *pssConn; + SearchMap_s *smap; + SearchMap_s *first; + VolumeID_t *volID = &nameMsg->curvol->VOLvolumeID; + NINT noWildCardSmapOpt; + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, COMN_WildFindOpenContainerWithZID); + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("COMN_WildFindOpenContainerWithZID: Searching for ID=%u\n"),(NINT)zid)); + + /* FixFixFix6 -- the searchmap tables need to be indexed by ZID to speed this operation up */ + + zASSERT(zid != zINVALID_ZID); + + if ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) == NULL) + RTN_STATUS(zFAILURE); + + if (((srchMsg->srchOpt & SMAPOPT_matchAllEntries) == 0) && + ((nameMsg->scanMsg.retScanFlags & NSRETSFL_hasWildcardChars) == 0) && + (srchMsg->nameType == zNTYPE_FILE)) + { + noWildCardSmapOpt = SMAPOPT_noWildCardChars; + } + else + { + noWildCardSmapOpt = 0; + } +/*------------------------------------------------------------------------ + * Search the appropriate lists trying to find the SEARCHMAP structure + *-------------------------------------------------------------------------*/ + S_LATCH(&pssConn->searchMaps.smLatch); + if (srchMsg->srchOpt & SMAPOPT_notReusable) + { + DQ_FOREACH(&pssConn->searchMaps.inuseList,smap,SearchMap_s,link) + { + if ((smap->useCount == 1) && /* On active list but not otherwise inuse */ + (smap->lookupZID == zid) && + (smap->fileNameSpaceID == nameMsg->nameSpaceID) && + (LB_GUIDCompare(&smap->volumeID,volID) == 0) && + (smap->taskID == genMsg->taskID) && + ((smap->options & SMAPOPT_noWildCardChars) == noWildCardSmapOpt)) + { + /* We are getting a new pointer to this searchMap */ + ++smap->useCount; + UNS_LATCH(&pssConn->searchMaps.smLatch); + goto foundSMAP; + } + } + } + else + { + DQ_FOREACH(&pssConn->searchMaps.reuseActiveList,smap,SearchMap_s,link) + { + if ((smap->useCount == 1) && /* On active list but not otherwise inuse */ + (smap->lookupZID == zid) && + (smap->fileNameSpaceID == nameMsg->nameSpaceID) && + (LB_GUIDCompare(&smap->volumeID,volID) == 0) && + (smap->taskID == genMsg->taskID) && + ((smap->options & SMAPOPT_noWildCardChars) == noWildCardSmapOpt)) + { + /* We are getting a new pointer to this searchMap */ + ++smap->useCount; + UNS_LATCH(&pssConn->searchMaps.smLatch); + goto foundSMAP; + } + } + } + UNS_LATCH(&pssConn->searchMaps.smLatch); +/*------------------------------------------------------------------------- + * We could not find a search map for this request. We are first going to + * read in the next beast we are going to try and access. Then get the + * parent of that beast and resetup a search map. + *-------------------------------------------------------------------------*/ + if (WILD_ReestablishSearchMap(genMsg,srchMsg,nameMsg,zid) == zOK) + { + /* The useCount should already be incremented here */ + smap = srchMsg->srchMap.ptr; + goto foundSMAP; + } +/*--------------------------------------------------------------------------- + * We could not find the search map and we could not reestablish it based + * on lookupZid. We have seen a scenario (in purge all) where the lookupZid + * has been advanced to the next beast by a Scan Deleted Files command. BUT + * the reply to the scan was lost so the scan was reissued with the ZID that + * was deleted. The WILD_ReestablishSearchMap failed because the ZID has + * been purged. + * The safest thing to do here is start the search map over at the beginning + * if the name type is zNTYPE_DELETED_FILE. + *---------------------------------------------------------------------------*/ + if (srchMsg->nameType == zNTYPE_DELETED_FILE) + { + ClearErrno(genMsg); + if (COMN_WildOpen(genMsg,nameMsg,srchMsg) == zOK) + { + /* The useCount should already be incremented here */ + smap = srchMsg->srchMap.ptr; + goto foundSMAP; + } + } +/*------------------------------------------------------------------------- + * + *-------------------------------------------------------------------------*/ + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("COMN_WildFindOpenContainerWithZID: Could not establishSearchMap Not found for ZID %u\n"),(NINT)zid)); + //ForceSetErrno(genMsg,zERR_BAD_SEARCHMAP_ID); + RTN_STATUS(zFAILURE); +/*------------------------------------------------------------------------- + * See if this entry is at the front of the active list. If so, go on. + * if not, remove it from where it is (it may be on the inactive list) + * and insert it at the front of the active list. + *-------------------------------------------------------------------------*/ +foundSMAP: + if ( !(srchMsg->srchOpt & SMAPOPT_notReusable) ) + { + S_LATCH(&pssConn->searchMaps.smLatch); + DQ_PEEK(&pssConn->searchMaps.reuseActiveList,first,SearchMap_s,link); + if (smap != first) + { + UP_LATCH(&pssConn->searchMaps.smLatch); + DQ_RMV(smap,link); + DQ_PUSH(&pssConn->searchMaps.reuseActiveList,smap,link); + DOWN_LATCH(&pssConn->searchMaps.smLatch); + smap->options &= ~SMAPOPT_inactive; + } + UNS_LATCH(&pssConn->searchMaps.smLatch); + } + /* In all cases above, we have already incremented the useCount for + * this SearchMapIDP_s pointer */ + COMN_SET_SEARCHMAP(&srchMsg->srchMap,smap->mapID,smap); + RTN_STATUS(zOK); +} + + +/************************************************************************** + * This routine returns information about the next file found in the + * wildcard search. + ***************************************************************************/ +STATUS COMN_WildRead( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg) +{ + SearchMap_s *smap; + NINT origLatchType; + NSSConnection_s *pssConn; + zMatchAttr_s *saveMatchAttr; + FSHooks_DirectorySearch_s parms; + File_s *dirBeast; + Volume_s *volume; + STATUS status; + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, COMN_WildRead); +/*--------------------------------------------------------------------------- + * Resolve the search map ID to a ptr + *---------------------------------------------------------------------------*/ +Restart_WildRead: + if ((smap = SMAP_RESOLVE_SEARCHMAP(genMsg,&srchMsg->srchMap, + srchMsg->srchOpt)) == NULL) + { + status = zFAILURE; + goto cleanup_error; + } + if (srchMsg->srchOpt & SMAPOPT_matchAllEntries) + { + smap->options |= SMAPOPT_matchAllEntries; + } + + if (genMsg->taskID == zNO_TASK) + { + genMsg->taskID = smap->taskID; + } + else if (genMsg->taskID != smap->taskID) + { + status = zFAILURE; + SetErrno(genMsg,zERR_BAD_SEARCHMAP_ID); + goto cleanup_error; + } + + if (smap->options & SMAPOPT_atEndOfDir) + { + status = zFAILURE; + SetErrno(genMsg,zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto cleanup_error; + } + +/*------------------------------------------------------------------------- + * See if they are restarting. If not see if they are at the correct + * sequence. If not we fail for now. + *-------------------------------------------------------------------------*/ + if ((smap->options & SMAPOPT_seqNumber) && + (srchMsg->srchSeqNum != smap->seqNum)) + { + /* This does happen in nature, it looks like a client problem */ + status = zFAILURE; + SetErrno(genMsg,zERR_INVALID_SEARCH_SEQ_NUM); + goto cleanup_error; + } + +/*--------------------------------------------------------------------------- + * Validate that the name message is of the correct supported type + * for a search pattern and open the directory. The directory is identified + * by the searchmap. If the nameMsg does not point to the correct directory + * it is modified to do so. + *---------------------------------------------------------------------------*/ + /* Reset the fully resolved flag because we are resetting the nameMsg */ + nameMsg->parseFlags &= ~NAMPFL_nameMsgFullyResolved; + + nameMsg->nameType = smap->fileNameType; + switch (smap->nameType) + { + case zNTYPE_DATA_STREAM: + nameMsg->nameSpaceID = zNSPACE_DATA_STREAM; + break; + case zNTYPE_EXTENDED_ATTRIBUTE: + nameMsg->nameSpaceID = zNSPACE_EXTENDED_ATTRIBUTE; + break; + default: + /* Just use the user's passed in name space already in + * the nameMsg */ + break; + } + + /* If a context handle, call comn_lookup to convert it to volume_zid */ + if (nameMsg->handlePathType == zHPT_CONTEXT) + { + if (COMN_Lookup(genMsg,nameMsg) != zOK) + { + status = zFAILURE; + goto cleanup_error; + } + } + + switch (nameMsg->handlePathType) + { + case zHPT_SEARCH_PATTERN: + /* nameMsg->path points to the pattern. Normalize the nameMsg + * so that the workBuffer is inited and curComponent points to + * a normalized search pattern. */ + COMN_SET_NAMING_MSG_FORCE_CONVERT_TO_UNICODE(nameMsg); + if (NMSG_ValidateNameMsg(genMsg,nameMsg) != zOK) + { + status = zFAILURE; + goto cleanup_error; + } + + if ((nameMsg->retParseFlags & + (NAMRETPFL_haveAParsedComponent|NAMRETPFL_lastComponent)) != + (NAMRETPFL_haveAParsedComponent|NAMRETPFL_lastComponent)) + { + status = zFAILURE; + SetErrno(genMsg,zERR_INVALID_PATH); + goto cleanup_error; + } + zASSERT(nameMsg->curFile == NULL); + zASSERT(nameMsg->curDataStream == NULL); + zASSERT(nameMsg->curvol == NULL); + + /* Set up the name message to point to the directory to be + * searched. This is done in a "KLUDGEY - BRUTE FORCE type of + * way. If we just call COMN_LOOKUP, we will get an error if + * the workNameSpace is Data Stream or Extended Attribute because + * those types are not supported in the volume bit masks. We + * just look up the container beast separately and stuff it + * into the name message. */ + volume = COMN_VolumeIDLookup(genMsg, &smap->volumeID, TRUE); + if (volume == NULL) + { + status = zFAILURE; + goto cleanup_error; + } + if ((dirBeast = COMN_LookupByZid(genMsg,volume,smap->dirZid, + NOTLATCHED,FALSE)) == NULL) + { + status = zFAILURE; + COMN_Release(&volume); + goto cleanup_error; + } + if (COMN_LockVolumeActive(genMsg,volume, + (nameMsg->parseFlags & NAMPFL_dontLockVolumeActive)) != zOK) + { + status = zFAILURE; + COMN_Release(&dirBeast); + COMN_Release(&volume); + goto cleanup_error; + } + nameMsg->curvol = volume; + nameMsg->curFile = dirBeast; + nameMsg->curDataStream = (NamedBeast_s *)dirBeast; + nameMsg->fileParentZid = smap->fileParentZid; +// cnt nameMsg->fileNameUniquifier = smap->fileNameUniquifier; + nameMsg->fileNameType = smap->fileNameType; + nameMsg->zidNameType = smap->fileNameType; + nameMsg->handlePathType = zHPT_VOLUME_ZID_PATH; + nameMsg->parseMode = NAMPMODE_DoNotResolveLeafName; + nameMsg->parseFlags |= NAMPFL_allowWildcardChars; + COMN_LATCH_AND_USE_NAMEMSG_BEASTS(nameMsg,nameMsg->latchType); + COMN_Release(&dirBeast); /* Release the extra use count */ + + zASSERT(nameMsg->scanMsg.retUnicodeComp != NULL); + break; + + case zHPT_VOLUME_ZID: + /* Make sure the caller requested to match all entries without a + * search pattern. Then fall into the next case element. */ + if (!(smap->options & SMAPOPT_matchAllEntries)) + { + status = zFAILURE; + SetErrno(genMsg, zERR_INVALID_PATH); + goto cleanup_error; + } + /* Yes, do fall into the next code... */ + + case zHPT_VOLUME_ZID_PATH: + /* NOTE-- the above code falls into this code on purpose... */ + + /* If there is a volume, but it is the wrong one, reset it to the + * correct one */ + if ((nameMsg->curvol) && + (LB_GUIDCompare(&nameMsg->curvol->VOLvolumeID,&smap->volumeID) != 0)) + { + COMN_UnlockVolumeActive(nameMsg->curvol, + (nameMsg->parseFlags & NAMPFL_dontLockVolumeActive)); + COMN_Release(&nameMsg->curvol); + } + /* If no volume, use the one from searchMap */ + if (nameMsg->curvol == NULL) + { + nameMsg->volumeID = smap->volumeID; + + if (nameMsg->curFile) + { + COMN_UNLATCH_AND_RELEASE_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + } + nameMsg->fileZid = smap->dirZid; + nameMsg->dataStreamZid = smap->dirZid; + nameMsg->fileParentZid = smap->fileParentZid; +// cnt nameMsg->fileNameUniquifier = smap->fileNameUniquifier; + nameMsg->fileNameType = smap->fileNameType; + nameMsg->zidNameType = smap->fileNameType; + + zASSERT(nameMsg->curDataStream == NULL); + } + + /* If there is a curFile/DataStream, but it is the wrong one, reset it to the + * correct one */ + if ((nameMsg->curDataStream) && + (nameMsg->curDataStream->NAMEDzid != smap->dirZid)) + { + COMN_UNLATCH_AND_RELEASE_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + } + if (nameMsg->curDataStream == NULL) + { + zASSERT(nameMsg->curFile == NULL); + nameMsg->fileZid = smap->dirZid; + nameMsg->dataStreamZid = smap->dirZid; + nameMsg->fileParentZid = smap->fileParentZid; +// cnt nameMsg->fileNameUniquifier = smap->fileNameUniquifier; + nameMsg->fileNameType = smap->fileNameType; + nameMsg->zidNameType = smap->fileNameType; + } + + /* If a path exists, make sure it is only a single component */ + if (nameMsg->handlePathType == zHPT_VOLUME_ZID_PATH) + { + nameMsg->parseMode = NAMPMODE_DoNotResolveLeafName; + nameMsg->parseFlags |= NAMPFL_allowWildcardChars; + + COMN_SET_NAMING_MSG_FORCE_CONVERT_TO_UNICODE(nameMsg); + if (NMSG_ValidateNameMsg(genMsg,nameMsg) != zOK) + { + status = zFAILURE; + goto cleanup_error; + } + zASSERT(nameMsg->scanMsg.retUnicodeComp != NULL); + + if ((nameMsg->retParseFlags & + (NAMRETPFL_haveAParsedComponent|NAMRETPFL_lastComponent)) != + (NAMRETPFL_haveAParsedComponent|NAMRETPFL_lastComponent)) + { + status = zFAILURE; + SetErrno(genMsg,zERR_INVALID_PATH); + goto cleanup_error; + } + /* Now finish looking up the nameMsg so that curFile will + * be initialized to the parent container */ + if (COMN_Lookup(genMsg,nameMsg) != zOK) + { + status = zFAILURE; + goto cleanup_error; + } + + } + else /* zHPT_VOLUME_ZID */ + { + /* We are looking up a directory to be searched with no path. + * The COMN_Lookup call applies match attributes here since + * there is no path, but we don't want to apply the match + * attributes in this case. Save them and restore them + */ + saveMatchAttr = nameMsg->match; + nameMsg->match = NULL; + status = COMN_Lookup(genMsg,nameMsg); + nameMsg->match = saveMatchAttr; + + if (status != zOK) + { + if ((srchMsg->srchOpt & SMAPOPT_searchAllDirs) && + ((GetErrno(genMsg) == zERR_INVALID_BEAST_ID) || + (GetErrno(genMsg) == zERR_ZID_NOT_FOUND))) + { + /* This error means we were searching all directories, + * and one of the directories disappeared on us. + * This is legal!! Our response here is to back up + * the search to the parent directory and continue + * at that level, ignoring the remainder of the + * tree below us which is now totally gone */ + if (smap->parentMap == NULL) + { /* no parent directory search map */ + ForceSetErrno(genMsg,zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto cleanup_error; + } + else + { + ClearErrno(genMsg); + + /* Get the parent searchMap, free the current one, + * and start this function over. NOTE--The use + * count for this parentMap is already incremented + * twice ... once for the IDP pointer and once + * for having been created and not freed. */ + smap = smap->parentMap; + srchMsg->srchMap.ptr->parentMap = NULL; + SMAP_FreeSearchMap(genMsg,&srchMsg->srchMap,srchMsg->srchOpt); + /* The useCount is still incremented twice from before */ + zASSERT(smap->useCount >= 2); + COMN_SET_SEARCHMAP(&srchMsg->srchMap,smap->mapID,smap); + goto Restart_WildRead; + } + } + goto cleanup_error; + } + } + break; + + default: + SetErrno(genMsg,zERR_INVALID_PATH); + status = zFAILURE; + goto cleanup_error; + } +/*--------------------------------------------------------------------------- + * Make sure the nameMsg workNameType and workNameSpace info matches + * that of the searchMap that we are using for the search + *---------------------------------------------------------------------------*/ + nameMsg->workNameType = smap->nameType; + switch (smap->nameType) + { + case zNTYPE_DATA_STREAM: + nameMsg->workNameSpaceID = zNSPACE_DATA_STREAM; + break; + case zNTYPE_EXTENDED_ATTRIBUTE: + nameMsg->workNameSpaceID = zNSPACE_EXTENDED_ATTRIBUTE; + break; + } + if ((nameMsg->workNameSpace == NULL) || + (nameMsg->workNameSpaceID != nameMsg->workNameSpace->nSpaceID)) + { + if (nameMsg->workNameSpace) + COMN_Release(&nameMsg->workNameSpace); + if ((nameMsg->workNameSpace = NSPACE_LOOKUP_NAMESPACE(genMsg, + nameMsg->workNameSpaceID,nameMsg->workNameSpace)) == NULL) + { + status = zFAILURE; + goto cleanup_error; + } + } + + zASSERT((nameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) || + (nameMsg->workNameType == zNTYPE_DATA_STREAM) || + (nameMsg->workNameType == zNTYPE_EXTENDED_ATTRIBUTE)); +/*--------------------------------------------------------------------------- + * We now have a nameMsg which points to the directory to be searched, and + * which contains a searchPattern in the nameMsg->curComponent ptr. + *---------------------------------------------------------------------------*/ + + CHECK_FSHOOKS_DIRECTORY_SEARCH_ENTER(DirectorySearch_Hook, &parms, + status, cleanup_error, genMsg, nameMsg, srchMsg); + + if ( (origLatchType = nameMsg->latchType) == NOTLATCHED) + { + S_LATCH(&nameMsg->curFile->FILEbeastLatch); + nameMsg->latchType = SLATCHED; + } + if (srchMsg->srchOpt & SMAPOPT_searchAllDirs) + { + if (WILD_searchAllDirsForFile(genMsg,nameMsg,srchMsg) != zOK) + { + /* The above function may change the value of srchMsg->srchMap.ptr, + * so for proper error cleanup, our smap pointer must be resest + * to the most recently used searchMap */ + smap = srchMsg->srchMap.ptr; + goto cleanup_errorExitEvent; + } + } + else + { + if (((srchMsg->srchOpt & SMAPOPT_matchAllEntries) == 0) && + ((nameMsg->scanMsg.retScanFlags & NSRETSFL_hasWildcardChars) == 0) && + (smap->nameType == zNTYPE_FILE)) + { + /* Do an exact filename lookup wild search */ + srchMsg->srchMap.ptr->options |= SMAPOPT_noWildCardChars; + + if (WILD_searchForSpecificFile(genMsg,nameMsg,srchMsg) != zOK) + goto cleanup_errorExitEvent; + } + else + { + /* Do a standard "pattern-matching" wild search */ + if (WILD_searchForFile(genMsg,nameMsg,srchMsg) != zOK) + goto cleanup_errorExitEvent; + } + } + if (origLatchType == NOTLATCHED) + { + UNS_LATCH(&nameMsg->curFile->FILEbeastLatch); + nameMsg->latchType = NOTLATCHED; + } + +/*------------------------------------------------------------------------- + * If they have requested a sequence number, update now + *-------------------------------------------------------------------------*/ + smap = srchMsg->srchMap.ptr; + if (smap->options & SMAPOPT_seqNumber) + { + smap->seqNum++; + switch (SMAPOPT_MODE(smap->options)) + { + case SMAPOPT_16BitMode: + if (smap->seqNum > ENDING_SEQ16) + smap->seqNum = STARTING_SEQ; + break; + + case SMAPOPT_32BitMode: + default: + if (smap->seqNum > ENDING_SEQ) + smap->seqNum = STARTING_SEQ; + break; + } + srchMsg->srchSeqNum = smap->seqNum; + } + status = zOK; + +sendExitEvent: + CHECK_FSHOOKS_DIRECTORY_SEARCH_EXIT(DirectorySearch_Hook, &parms, + genMsg, nameMsg, srchMsg); + + RTN_STATUS(status); + +/*===========================================================================*/ +cleanup_error: + /* If a search map was located, mark it is invalid until it is cleaned up + * or rewound */ + if (smap) + { + smap->options |= SMAPOPT_atEndOfDir; + if (((smap->options & SMAPOPT_notReusable) == 0) && + ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) != NULL)) + { + X_LATCH(&pssConn->searchMaps.smLatch); + DQ_RMV(smap,link); + DQ_ENQ(&pssConn->searchMaps.reuseActiveList,smap,link); + UNX_LATCH(&pssConn->searchMaps.smLatch); + smap->options &= ~SMAPOPT_inactive; + zASSERT(smap->useCount >= 1); + } + } + RTN_STATUS(status); + +cleanup_errorExitEvent: + if (smap) + { + smap->options |= SMAPOPT_atEndOfDir; + if (((smap->options & SMAPOPT_notReusable) == 0) && + ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) != NULL)) + { + X_LATCH(&pssConn->searchMaps.smLatch); + DQ_RMV(smap,link); + DQ_ENQ(&pssConn->searchMaps.reuseActiveList,smap,link); + UNX_LATCH(&pssConn->searchMaps.smLatch); + smap->options &= ~SMAPOPT_inactive; + } + } + status = zFAILURE; + goto sendExitEvent; +} + + +/************************************************************************** + * This will reset the wildcard searching back to the front of the + * given directory directory. + ***************************************************************************/ +STATUS COMN_WildRewind( + GeneralMsg_s *genMsg, + SearchMsg_s *srchMsg) +{ + SearchMap_s *smap; + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, COMN_WildRewind); + + if ((smap = SMAP_RESOLVE_SEARCHMAP(genMsg,&srchMsg->srchMap, + srchMsg->srchOpt)) == NULL) + { + RTN_STATUS(zFAILURE); + } + + /* Reset the internal end-Of-Dir flag */ + smap->options &= ~(SMAPOPT_atEndOfDir | SMAPOPT_usedDOSafterLONG); + + /* cleanup the search cursor */ + if (smap->cleanup != NULL) /* call cleanup routine if defined*/ + smap->cleanup(smap); + + srchMsg->srchSeqNum = STARTING_SEQ; + smap->seqNum = STARTING_SEQ; + bzero(&smap->nextSrch,sizeof(smap->nextSrch)); + RTN_STATUS(zOK); +} + + +/************************************************************************** + * Set the bit that will cause the next read to read the same record again. + ***************************************************************************/ +STATUS COMN_WildSetupReread( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg) +{ + SearchMap_s *smap; + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, COMN_SetupRereadDir); + + if ((smap = SMAP_RESOLVE_SEARCHMAP(genMsg,&srchMsg->srchMap, + srchMsg->srchOpt)) == NULL) + { + RTN_STATUS(zFAILURE); + } + + if (smap->options & SMAPOPT_seqNumber) + { + if (smap->seqNum > 0) + { + --smap->seqNum; + --srchMsg->srchSeqNum; + } + } + smap->options |= SMAPOPT_returnLastEntry; + RTN_STATUS(zOK); +} + +/**************************************************************************** + * We looked up a name in a directory and we found that the beast pointed + * to by the ZID does not exist. This routine re-looksup the name getting + * detailed information (like the name) and then calls a routine that will + * remove that name from the directory as well as reporting it to the + * administrator. + *****************************************************************************/ +STATIC void WILD_HandleBeastlessName( + NamingMsg_s *nameMsg, + SearchMap_s *smap, + Zid_t badzid) +{ + Zid_t curZid; + GeneralMsg_s genMsg; + NamedBeast_s *curdir; +// cnt NINT nameUniquifier; + typedef struct Stack_s { + FullDirectoryInfo_s dirInfo; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, WILD_HandleBeastlessName); + curdir = (NamedBeast_s *)nameMsg->curFile; + ASSERT_LATCH(&curdir->NAMEDbeastLatch); /* make sure directory is latched */ + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + /* try and look-up the entry again, but this time return the name. If we + * can't find it, something strange is going on, ignore it for now and + * move on. */ + smap->options |= SMAPOPT_returnLastEntry; + if ((curZid = curdir->NAMEDcomnOps.BST_wildcardLookup( &genMsg, curdir, + nameMsg->workNameSpace, smap->nameType, + nameMsg->scanMsg.retUnicodeComp, + smap,/* cnt &nameUniquifier ,*/ &aStack->dirInfo)) == zINVALID_ZID) + { + STACK_FREE(); + RTN_VOID(); + } + + /* verify that it is the same bad ZID. if not, then something is changing + * and ignore this and skip the entry */ + if (curZid != badzid) + { + STACK_FREE(); + RTN_VOID(); + } + + NAME_RemoveBeastlessNameFromDir(&genMsg,badzid,curdir, + nameMsg->workNameSpace, smap->nameType,&aStack->dirInfo); + STACK_FREE(); + RTN_VOID(); +} + +/************************************************************************** + * This routine will search for the specific file in the given directory that + * matches the wildcard pattern. The pattern has already been set into + * the WORKNAME buffer, and we know it contains no wildcard characters. + * + ***************************************************************************/ +STATIC STATUS WILD_searchForSpecificFile( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg) +{ + NamedBeast_s *curFile; +// cnt NINT nameUniquifier; + NameSpace_s *dosNameSpace = NULL; + + ASSERT_MPKNSS_LOCK(); + /* This is a wildRead with a search pattern, but the search pattern + * does not contain any wildcard characters in it. Because of + * this we can do an optimization to do a direct name lookup here, + * rather than having to search the whole directory for a match. + */ + + /* Use this function to lookup the name. It follows some special rules, + * including trying the DOS name space if a lookup fails in the LONG name + * space, and it also converts a special character sequence. + */ + curFile = NAME_FindNameInDirSpecialRules(genMsg, nameMsg, &dosNameSpace, + TRUE, FALSE /* cnt &nameUniquifier */); + if (dosNameSpace != NULL) + { + /* The above function may lookup the DOS name space. If it does, + * we must release the pointer here. */ + COMN_Release(&dosNameSpace); + } + + /* With this optimization, we need to make sure that a second + * call using the same searchMap and pattern will get a no more + * files found error */ + srchMsg->srchMap.ptr->options |= SMAPOPT_atEndOfDir; + + if (curFile == NULL) + goto cleanup_errorExit; + + /* Now that we have found a beast, we must make sure it meets any + * optional match criteria before we return it. */ + if ((nameMsg->match) && + (!(NAME_MatchAttributes(curFile->NAMEDattributes,nameMsg->match)))) + { + COMN_UnlatchAndRelease(&curFile,nameMsg->latchType); + SetErrno(genMsg,zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto cleanup_errorExit; + } + + /* We have the new file beast. Save it completely into the + * nameMsg curFile and curDataStream ptrs as the located beast. */ + nameMsg->fileParentZid = nameMsg->curFile->FILEzid; +// cnt nameMsg->fileNameUniquifier = nameUniquifier; + nameMsg->fileNameType = nameMsg->workNameType; + nameMsg->zidNameType = nameMsg->workNameType; + COMN_UNLATCH_AND_RELEASE_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + nameMsg->curFile = (File_s *)curFile; /* Already latched */ + nameMsg->curDataStream = curFile; + COMN_USE_BEAST(&nameMsg->curDataStream->NAMEDroot); + nameMsg->retParseFlags &= ~NAMRETPFL_haveAParsedComponent; + nameMsg->handlePathType = zHPT_VOLUME_ZID; + nameMsg->parseFlags |= NAMPFL_nameMsgFullyResolved; + + srchMsg->srchMap.ptr->lookupZID = curFile->NAMEDzid; + return(zOK); + +/*===========================================================================*/ +cleanup_errorExit: + return(zFAILURE); +} + + +/* + * + */ +typedef struct ErrnoInfo_s +{ + STATUS EI_Errno; + char *EI_ErrnoSetter; +} ErrnoInfo_s; + +/* LB_SaveErrno - + * Saves the errno and setter of a genMsg. + */ +void LB_SaveErrno( + GeneralMsg_s *genMsg, /* Source */ + ErrnoInfo_s *ei ) /* Destination */ +{ + + ei->EI_Errno = GetErrno( genMsg ); + ei->EI_ErrnoSetter = GetErrnoSetter( genMsg ); + +} /* End of LB_SaveErrno() */ + + +/* LB_CombineErrno - + * Combines errnos giving the Original errno standard perferences. I.E. + * the same as the following. + * + * SetErrno( genMsg, Original ); + * if ( status != zOK ) SetErrno( genMsg, Current ); + * + * Notes - + * Original Current Returned + * -------- ------- -------- + * zERR_O zERR_C zERR_O(1) + * zERR_O zOK_C zERR_O + * zOK_O zERR_C zERR_C + * zOK_O zOK_C zOK_O + * + * (1) In some rare cases zERR_C will be returned (see LB_SetErrno). + */ +void LB_CombineErrno( + GeneralMsg_s *genMsg, /* Current Errno */ + ErrnoInfo_s *ei ) /* Original Errno */ +{ + ErrnoInfo_s tempEI; + + if ( (ei->EI_Errno == zOK) && ( GetErrno( genMsg ) == zOK ) ) + { + genMsg->errStatusSetter = ei->EI_ErrnoSetter; + return; + } + LB_SaveErrno( genMsg, &tempEI ); + /* Force the original errno into genMsg so that LB_SetErrno + * can be used so that its rules are applied. + */ + genMsg->errStatus = ei->EI_Errno; + genMsg->errStatusSetter = ei->EI_ErrnoSetter; + if ( tempEI.EI_Errno != zOK ) + { + LB_SetErrno( genMsg, tempEI.EI_Errno, tempEI.EI_ErrnoSetter ); + } + +} /* End of LB_CombineErrno() */ + + +/* LB_CombineErrnoWithForce - + * Combines errnos giving the Current errno force perferences. I.E. + * the same as the following. + * + * SetErrno( genMsg, Original ); + * if ( status != zOK ) ForceSetErrno( genMsg, Current ); + * + * + * Notes - + * Original Current Returned + * -------- ------- -------- + * zERR_O zERR_C zERR_C + * zERR_O zOK_C zERR_O + * zOK_O zERR_C zERR_C + * zOK_O zOK_C zOK_O + * + */ +void LB_CombineErrnoWithForce( + GeneralMsg_s *genMsg, /* Current Errno */ + ErrnoInfo_s *ei ) /* Original Errno */ +{ + + if ( (ei->EI_Errno == zOK) && ( GetErrno( genMsg ) == zOK ) ) + { + genMsg->errStatusSetter = ei->EI_ErrnoSetter; + return; + } + if ( ei->EI_Errno != zOK ) + { + genMsg->errStatus = ei->EI_Errno; + genMsg->errStatusSetter = ei->EI_ErrnoSetter; + } + +} /* End of LB_CombineErrnoWithForce() */ + + +/* LB_RestoreErrno - + * Restores the errno and setter of a genMsg. + * + * Notes - + * Original Current Returned + * -------- ------- -------- + * zERR_O zERR_C zERR_O + * zERR_O zOK_C zERR_O + * zOK_O zERR_C zERR_O + * zOK_O zOK_C zOK_O + * + */ +void LB_RestoreErrno( + GeneralMsg_s *genMsg, /* Current Errno */ + ErrnoInfo_s *ei ) /* Original Errno */ +{ + + genMsg->errStatus = ei->EI_Errno; + genMsg->errStatusSetter = ei->EI_ErrnoSetter; + +} /* End of LB_RestoreErrno() */ + + +/************************************************************************** + * This routine will search for the next file in the given directory that + * matches the wildcard pattern. The pattern has already been set into + * the WORKNAME buffer. + * + * outputs: + * nameMsg.curVnode the next file we found + ***************************************************************************/ +STATIC STATUS WILD_searchForFile( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg) +{ + enum { MAX_TRYS = 50 }; /* Maximum number of files we will search for + * a match before relinquishing our latches + * and letting another thread through. + */ + NamedBeast_s *curFile; + Zid_t curZid; + SearchMap_s *smap; +// cnt NINT nameUniquifier; + BOOL accessDenied = FALSE; + ParentEntry_s *pentry; + NameSpace_s *dosNameSpace = NULL; + BOOL matchAttrAlreadyChecked; + NINT numTrys; + ErrnoInfo_s savedErrno; + + typedef struct Stack_s { + FullDirectoryInfo_s fullDirInfo; + FCNTL_SetHardLinkFlags_s fcntlSetHLFlags; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, WILD_searchForFile); + +/*------------------------------------------------------------------------- + * Validate the filename + *-------------------------------------------------------------------------*/ + zASSERT( (srchMsg->srchOpt & SMAPOPT_matchAllEntries) || + ((nameMsg->handlePathType == zHPT_VOLUME_ZID_PATH) && + (nameMsg->scanMsg.retScanFlags & NSRETSFL_componentIsUnicode) && + (nameMsg->retParseFlags & NAMRETPFL_haveAParsedComponent) && + (nameMsg->retParseFlags & NAMRETPFL_lastComponent )) ); + zASSERT(nameMsg->curFile != NULL); + zASSERT(nameMsg->curDataStream == (NamedBeast_s *)nameMsg->curFile); + zASSERT(nameMsg->workNameSpace != NULL); + + smap = SMAP_RESOLVE_SEARCHMAP(genMsg,&srchMsg->srchMap,srchMsg->srchOpt); + smap->match = nameMsg->match; + +/* commented out 7/22/97 by Brenda and Neal. We don't want to invalidate + * this field unless we successfully find a new file. + * + * smap->lookupZID = zINVALID_ZID; + */ +/*------------------------------------------------------------------------- + * Search for the file + *-------------------------------------------------------------------------*/ + zASSERT((nameMsg->curFile->FILEattributes & zFA_SUBDIRECTORY) || + (smap->nameType == zNTYPE_DATA_STREAM) || + (smap->nameType == zNTYPE_EXTENDED_ATTRIBUTE)); + ASSERT_LATCH(&nameMsg->curFile->FILEbeastLatch); /* make sure directory is latched */ + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: nSpace=%d pattern=\"%U\"\n"), + nameMsg->workNameSpace->nSpaceID,nameMsg->scanMsg.retUnicodeComp)); + for (numTrys = 0;; ++numTrys) + { + if (numTrys == MAX_TRYS) + { + /* + * Give it a rest + */ + COMN_UNLATCH_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + COMN_LATCH_NAMEMSG_BEASTS(nameMsg, nameMsg->latchType); + numTrys = 0; + } + + matchAttrAlreadyChecked = FALSE; + + if (smap->options & SMAPOPT_usedDOSafterLONG) + { + /* Don't try LONG again, we have switched to DOS */ + curZid = zINVALID_ZID; + } + else + { + curZid = nameMsg->curFile->FILEcomnOps.BST_wildcardLookup( + genMsg,&nameMsg->curFile->FILEnamed,nameMsg->workNameSpace, smap->nameType, + nameMsg->scanMsg.retUnicodeComp,smap,// cnt &nameUniquifier , + &aStack->fullDirInfo); + } + + /* We have some clients which get confused and mix LONG names with + * "DOS-8.3" names in the same path string. To get around this + * problem, if a non-wildcarded name is not found in the long name + * space, we double check (if instructed to do so) the DOS name space + * to see if it exists there. */ + if ((curZid == zINVALID_ZID) && + (nameMsg->workNameSpaceID == zNSPACE_LONG) && + (nameMsg->parseFlags & NAMPFL_tryDosIfLongFails) && + ((srchMsg->srchOpt & SMAPOPT_matchAllEntries) == 0) && + ((nameMsg->scanMsg.retScanFlags & NSRETSFL_hasWildcardChars) == 0)) + { + if (dosNameSpace == NULL) + { + dosNameSpace = NSPACE_LOOKUP_NAMESPACE(genMsg, + zNSPACE_DOS, dosNameSpace); + } + + if (dosNameSpace != NULL) + { + /* Reset the error and look for the name in + * the DOS name space */ + ClearErrno(genMsg); + curZid = nameMsg->curFile->FILEcomnOps.BST_wildcardLookup( + genMsg,&nameMsg->curFile->FILEnamed,dosNameSpace,smap->nameType, + nameMsg->scanMsg.retUnicodeComp,smap, + /* &nameUniquifier,*/ &aStack->fullDirInfo); + + /* Set the SMAPOPT_usedDOSafterLONG option so that subsequent + * searches will fail until this searchmap is rewound. */ + smap->options |= SMAPOPT_usedDOSafterLONG; + } + } + + if (curZid == zINVALID_ZID) + { + /* This directory has no more files in the specified smap->nameType. + * if the SMAPOPT_includeDeletedNameType bit was specified, and + * if we just finished scanning the zNTYPE_FILE nameType, then + * rewind the search map and start over, searching the + * zNTYPE_DELETED_FILE nameType. */ + if ((smap->options & SMAPOPT_includeDeletedNameType) && + (smap->nameType == zNTYPE_FILE)) + { + if (COMN_WildRewind(genMsg,srchMsg) != zOK) + goto cleanup_release; + smap->nameType = zNTYPE_DELETED_FILE; + continue; /* Restart at beginning of main for loop */ + } + /* FixFixFix6 -- + * else + * { + * If, and ONLY IF, we ever add a user interface + * which exposes this bit, we may need to add code which resets + * the smap->nameType back to the original name type. For + * today, this is a non-issue + * } */ + + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: Error looking for next name, status=%d\n"),GetErrno(genMsg))); + smap->options &= ~SMAPOPT_usedDOSafterLONG; + goto cleanup_release; + } + + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: found ZID=%u\n"),(NINT)curZid)); + + if ((smap->nameType != zNTYPE_DATA_STREAM) && + (smap->nameType != zNTYPE_EXTENDED_ATTRIBUTE) && + (nameMsg->match) && + (aStack->fullDirInfo.matchAttributes & MA_ATTRS_ARE_VALID)) + { + /* If the fullDirInfo has valid matchAttributes, perform the + * check now, before upacking/reading the beast into memory. */ + if (!NAME_MatchAttributes( + (aStack->fullDirInfo.matchAttributes & ~MA_ATTRS_ARE_VALID), + nameMsg->match)) + { + /* We failed on the match attributes check. Skip over this file */ + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: matchAttr failed for ZID=%u\n"),(NINT)curZid)); + continue; + } + else + { + /* We passed the match attributes test ... keep going */ + matchAttrAlreadyChecked = TRUE; + } + } + /* We save errno because we would like zERR_INVALID_CHAR_IN_NAME + * to be returned if the beast is not found, but we must clear + * errno before the call to COMN_LookupByZidWhileWildcarding + * because we check for explicit error codes. These codes will + * not be set if genMsg already has an error (see LB_SetErrno()) + * for more information. + */ + LB_SaveErrno( genMsg, &savedErrno ); + ClearErrno( genMsg ); + if ((curFile = COMN_LookupByZidWhileWildcarding(genMsg,nameMsg->curvol, + curZid,nameMsg->latchType)) == NULL) + { + if ( savedErrno.EI_Errno != zOK ) + { /* If we had an errno in genMsg prior to clearing it + * we want to return that error. This is how the code has + * worked (or not worked) for years. + */ + LB_RestoreErrno( genMsg, &savedErrno ); + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: error finding beast for ZID=%u, status=%u\n"),(NINT)curZid,GetErrno(genMsg))); + goto cleanup_release; + } + if (GetErrno(genMsg) == zERR_ACCESS_DENIED) + { /* access denied */ + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: access error on ZID=%u\n"),(NINT)curZid)); + accessDenied = TRUE; + ClearErrno(genMsg); + continue; + } + if (GetErrno(genMsg) == zERR_ZID_NOT_FOUND) + { + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: beast not found for ZID=%u\n"),(NINT)curZid)); + WILD_HandleBeastlessName(nameMsg,smap,curZid); + ClearErrno(genMsg); + continue; + } + LB_CombineErrno( genMsg, &savedErrno ); + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: general error finding beast for ZID=%u, status=%u\n"),(NINT)curZid,GetErrno(genMsg))); + goto cleanup_release; + } + LB_RestoreErrno( genMsg, &savedErrno ); + /* Just in case genMsg has an error because of an invalid path, + * clear it because even though the path may have been invalid, + * we located it anyway */ + if (GetErrno(genMsg) == zERR_INVALID_CHAR_IN_NAME) + { + ClearErrno(genMsg); + } + + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: found \"%U\"\n"), + NAME_GetFirstNameForDebug(curFile))); + + if ( !(nameMsg->curvol->VOLenabledAttributes & zATTR_READONLY) && + !(aStack->fullDirInfo.matchAttributes & MA_ATTRS_ARE_VALID) ) + { + /* Set the Hidden, System, Subdirectory & VALID bits into the + * match attributes for this name entry. This does not need + * to be part of a transaction. The data is considered "Messy" + * meaning it doesn't matter if it makes it back to disk or not. + * If the system crashes before it is flushed, it will just get + * updated "on-the-fly" the next time the data is read + */ + if (nameMsg->latchType == SLATCHED) + { + /* At this point nameMsg->curFile points the directory and + * curFile points to the located file in the directory. When + * we do an UP_LATCH, it actually releases the latch and then + * reacquires an XLATCH. Because of this, we cannot keep the + * child latched during this process, or we could cause a + * deadlock. We will re-latch the child after down-latching + * the parent directory. */ + UNS_LATCH(&curFile->NAMEDbeastLatch); + UP_LATCH(&nameMsg->curFile->FILEbeastLatch); + } + curFile->NAMEDcomnOps.BST_setMatchAttributesInDirectory(genMsg, + curFile,&nameMsg->curFile->FILEnamed, + aStack->fullDirInfo.nameSpaceMask, aStack->fullDirInfo.nameType, + aStack->fullDirInfo.name, /* cnt aStack->fullDirInfo.nameUniquifier,*/ + MA_ATTR_SET_MASK(curFile->NAMEDattributes), NULL); + if (nameMsg->latchType == SLATCHED) + { + DOWN_LATCH(&nameMsg->curFile->FILEbeastLatch); + S_LATCH(&curFile->NAMEDbeastLatch); + } + } + + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, "Hardlink flags are %x for zid %x, name %U\n", + aStack->fullDirInfo.miscFlags, (LONG)aStack->fullDirInfo.zid, + aStack->fullDirInfo.name)); + + if ( !(nameMsg->curvol->VOLenabledAttributes & zATTR_READONLY) && + !(aStack->fullDirInfo.miscFlags & HL_FLAG_IS_VALID) ) + { + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, "Upgrading HL Flags on zid %x, name %U\n", + (LONG)aStack->fullDirInfo.zid, aStack->fullDirInfo.name)); + + /* Make the Hardlink flags accurately reflect whether or not + * curFile is a hardlink beast. This does not need + * to be part of a transaction. The data is considered "Messy" + * meaning it doesn't matter if it makes it back to disk or not. + * If the system crashes before it is flushed, it will just get + * updated "on-the-fly" the next time the data is read + */ + if (nameMsg->latchType == SLATCHED) + { + /* At this point nameMsg->curFile points the directory and + * curFile points to the located file in the directory. When + * we do an UP_LATCH, it actually releases the latch and then + * reacquires an XLATCH. Because of this, we cannot keep the + * child latched during this process, or we could cause a + * deadlock. We will re-latch the child after down-latching + * the parent directory. */ + UNS_LATCH(&curFile->NAMEDbeastLatch); + UP_LATCH(&nameMsg->curFile->FILEbeastLatch); + } + + aStack->fcntlSetHLFlags.beast = curFile; + aStack->fcntlSetHLFlags.directory = &nameMsg->curFile->FILEnamed; + aStack->fcntlSetHLFlags.nameSpaceMask = aStack->fullDirInfo.nameSpaceMask; + aStack->fcntlSetHLFlags.nameType = aStack->fullDirInfo.nameType; + aStack->fcntlSetHLFlags.name = aStack->fullDirInfo.name; + aStack->fcntlSetHLFlags.newHardLinkFlags = HL_FLAG_IS_VALID; + if (curFile->NAMEDattributes & zFA_HARDLINK) + { + aStack->fcntlSetHLFlags.newHardLinkFlags |= HL_FLAG_IS_HARD_LINK; + } + curFile->NAMEDvolume->VOLcomnVolOps.VOL_FCNTL(genMsg, + curFile->NAMEDvolume, + VOL_FCNTL_SET_HARDLINK_NAMETREE_FLAGS, + (FCNTL_In_s *)&aStack->fcntlSetHLFlags, + NULL, NULL); + if (nameMsg->latchType == SLATCHED) + { + DOWN_LATCH(&nameMsg->curFile->FILEbeastLatch); + S_LATCH(&curFile->NAMEDbeastLatch); + } + } + +// now being done in COMN_LookupByZid +// if (nameMsg->curBeast->NAMEDmayIDoThis(genMsg, curFile, +// nameMsg->curBeast->NAMEDzid, MAY_I_SEE_THE_OBJECT) != zOK) +// { +// COMN_UnlatchAndRelease(&curFile,nameMsg->latchType); +// continue; +// } + + /* We have a new beast. See if we are wildcarding on the dataStream + * name type. If we are, we have to behave differently */ + if ((smap->nameType != zNTYPE_DATA_STREAM) && + (smap->nameType != zNTYPE_EXTENDED_ATTRIBUTE)) + { + if ((nameMsg->match) && + (!matchAttrAlreadyChecked) && + (!(NAME_MatchAttributes(curFile->NAMEDattributes,nameMsg->match)))) + { + DEBUG_PRINTF(TWILD, DBG_INDENT, (LGREEN, MSGNot("Wildcard: matchAttr failed for ZID=%u\n"),(NINT)curZid)); + COMN_UnlatchAndRelease(&curFile,nameMsg->latchType); + continue; + } + + if ((pentry = NAME_GetParentEntry(genMsg, curFile /* cnt nameUniquifier*/)) == NULL) + { + COMN_UnlatchAndRelease(&curFile,nameMsg->latchType); + goto cleanup_release; + } + + /* We have the new file beast. Save it completely into the + * nameMsg curFile and curDataStream ptrs as the located beast. */ + nameMsg->fileParentZid = nameMsg->curFile->FILEzid; +// cnt nameMsg->fileNameUniquifier = nameUniquifier; + nameMsg->fileNameType = pentry->p.nameType; + nameMsg->zidNameType = pentry->p.nameType; + + COMN_UNLATCH_AND_RELEASE_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + nameMsg->curFile = (File_s *)curFile; /* Already latched */ + nameMsg->curDataStream = curFile; + COMN_USE_BEAST(&nameMsg->curDataStream->NAMEDroot); + } + else + { + /* We just looked up a datasteam, move it, but + * leave the file pointer alone. In this case, + * both pointers are separately latched and "used" */ + COMN_Release(&nameMsg->curDataStream); + nameMsg->curDataStream = curFile; /* Already latched */ + } + + nameMsg->retParseFlags &= ~NAMRETPFL_haveAParsedComponent; + nameMsg->handlePathType = zHPT_VOLUME_ZID; + nameMsg->parseFlags |= NAMPFL_nameMsgFullyResolved; + + smap->lookupZID = curFile->NAMEDzid; /* save the last found ZID for lookup*/ + + if (dosNameSpace != NULL) + COMN_Release(&dosNameSpace); + + smap->match = NULL; + STACK_FREE(); + RTN_STATUS(zOK); + } +/*------------------------------------------------------------------------- + * Error handling cleanup + *-------------------------------------------------------------------------*/ +cleanup_release: + if ((accessDenied) && + (srchMsg->srchOpt & SMAPOPT_preserveAccessDenied) && + (GetErrno(genMsg)==zERR_NAME_NOT_FOUND_IN_DIRECTORY)) + { + ForceSetErrno(genMsg,zERR_ACCESS_DENIED); + } + + if (dosNameSpace != NULL) + COMN_Release(&dosNameSpace); + + smap->match = NULL; + STACK_FREE(); + RTN_STATUS(zFAILURE); +} + + +/************************************************************************** + * This routine will search for the next file that matches the wildcard + * pattern. The pattern has already been set into the WORKNAME buffer. + * The search includes the original directory and all subdirectories. + * + * outputs: + * nameMsg.curVnode the next file we found + ***************************************************************************/ +STATIC STATUS WILD_searchAllDirsForFile( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + SearchMsg_s *srchMsg) +{ + SearchMap_s *smap; + + ASSERT_MPKNSS_LOCK(); + ENTER(TWILD, WILD_searchAllDirsForFile); + + for (;;) + { + if (WILD_searchForFile(genMsg, nameMsg, srchMsg) == zOK) + { + /* + * If this is a subdirectory then save the search map for the current + * subdirectory and start a search map for the subdirectory just found. + * + * If there is a check function then call it to see if the subdir + * should be saved. + */ + if ((nameMsg->curDataStream->NAMEDattributes & zFA_SUBDIRECTORY) && + (srchMsg->checkFunc == NULL || srchMsg->checkFunc(nameMsg, + srchMsg->parm1, srchMsg->parm2))) + { + smap = srchMsg->srchMap.ptr; + if (SMAP_AllocAndInitSearchMap(genMsg, nameMsg, srchMsg) != zOK) + { + RTN_STATUS(zFAILURE); + } + /* Note -- the new search map and the parent-to-be smap both + * have a use count of two (created and in use). We keep the + * double use count on the parentMap for now. + * When we release the parentMap, this will be decremented twice.*/ + zASSERT(smap->useCount >= 2); + srchMsg->srchMap.ptr->parentMap = smap; + } + if ((nameMsg->curDataStream->NAMEDattributes & zFA_SUBDIRECTORY) && + (srchMsg->srchOpt & SMAPOPT_returnAllFilesFirst)) + { + continue; /* next iteration of for loop */ + } + /* returns pointing to the directory, but with a search map that + * when called next time will search the subdirectory */ + RTN_STATUS(zOK); + } + else + { + if (GetErrno(genMsg) == zERR_NAME_NOT_FOUND_IN_DIRECTORY) + { /* There are no more entries in the directory */ + smap = srchMsg->srchMap.ptr; + if (smap->parentMap == NULL) + { /* no parent directory search map */ + if (srchMsg->srchOpt & SMAPOPT_returnAllFilesFirst) + { + /* Return a pointer to the directory now, since we + * have finished searching everything below it */ + RTN_STATUS(zOK); + } + RTN_STATUS(zFAILURE); + } + else + { + ClearErrno(genMsg); + + /* Get the parent searchMap, free the current one, and then + * reset the nameMsg to point to the parent searchMap */ + smap = smap->parentMap; + if (smap->taskID != genMsg->taskID) + { + zASSERT("InUse Parent SearchMap was re-used"==NULL); + SetErrno(genMsg,zERR_BAD_SEARCHMAP_ID); + RTN_STATUS(zFAILURE); + } + /* Since we are keeping the parent, remove the link to it + * so free will not free up the parent chain. Then + * release and destroy the child map. Note, the searchMap + * as a double use count (created and inUse) */ + srchMsg->srchMap.ptr->parentMap = NULL; + SMAP_FreeSearchMap(genMsg,&srchMsg->srchMap,srchMsg->srchOpt); + /* The parent map already has a double use count on it */ + zASSERT(smap->useCount >= 2); + COMN_SET_SEARCHMAP(&srchMsg->srchMap,smap->mapID,smap); + + if (srchMsg->srchOpt & SMAPOPT_returnAllFilesFirst) + { + /* Return a pointer to the directory now, since we + * have finished searching everything below it */ + RTN_STATUS(zOK); + } + + /* Setup the parent searchmap in the nameMsg as curFile */ + nameMsg->fileParentZid = smap->fileParentZid; +// cnt nameMsg->fileNameUniquifier = smap->fileNameUniquifier; + nameMsg->fileNameType = smap->fileNameType; + nameMsg->zidNameType = smap->fileNameType; + COMN_UNLATCH_AND_RELEASE_NAMEMSG_BEASTS_KEEP_LATCHTYPE(nameMsg); + nameMsg->curFile = COMN_LookupByZid(genMsg,nameMsg->curvol, + smap->dirZid,nameMsg->latchType, FALSE); + if (nameMsg->curFile == NULL) + { + SetErrno(genMsg,zERR_BAD_SEARCHMAP_ID); + RTN_STATUS(zFAILURE); + } + nameMsg->curDataStream = (NamedBeast_s *)nameMsg->curFile; + COMN_USE_BEAST(&nameMsg->curDataStream->NAMEDroot); + continue; + } + } + else + { + RTN_STATUS(zFAILURE); + } + } + } +} diff --git a/src/nwnss/comn/common/mgmtFiles.c b/src/nwnss/comn/common/mgmtFiles.c new file mode 100644 index 0000000..c213e39 --- /dev/null +++ b/src/nwnss/comn/common/mgmtFiles.c @@ -0,0 +1,1526 @@ +/**************************************************************************** + | + | (C) Copyright 1999, 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) module + | + |--------------------------------------------------------------------------- + | + | $Author: gpachner $ + | $Date: 2007-06-07 02:25:28 +0530 (Thu, 07 Jun 2007) $ + | + | $RCSfile$ + | $Revision: 2044 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Static Management files code. + +-------------------------------------------------------------------------*/ +#if zLINUX +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msgGen.h" +#include "comnBeasts.h" +#include "mgmt.h" +#include "name.h" +#include "pssStartup.h" +#include "inst.h" +#include "pssConfig.h" +#include "comnCmdline.h" +#include "cacheControl.h" +#include "beastClass.h" +#include "pssConnection.h" +#include "zasAuthCache.h" +#include "control.h" +#include "nssPubs.h" +#include "virtualIO.h" +#include "xmlTags.h" +#include "cmControl.h" +#include "nssOSAPIs.h" +#if zLINUX +#include "cmActivity.h" +#include "cmRuntime.h" +#else +#include "..\compression\cmActivity.h" +#include "..\compression\cmRuntime.h" +#endif + +#if zLINUX + #define OS_NAME_SPACE zNSPACE_UNIX +#else + #define OS_NAME_SPACE zNSPACE_LONG +#endif + +/**************************************************************************** + * Global Array that defines the static Mgmt Files. * + ****************************************************************************/ +typedef struct ReadInst_s +{ + BYTE *tag; + BOOL isFile; /* if set then this is a file not an element */ + void *RI_data; /* address of data. Must be a pointer to a + * NINT if callFunc is NULL. + */ + void (*RI_callFunc)( BYTE *data, struct ReadInst_s *); + /* Where to call if RI_data does not point to + * an NINT (or other special hanlding is needed). + */ + +} ReadInst_s; + + + +/* + * Generic routine to display a QUAD value stat. + */ +void QUADStat( + BYTE *data, ReadInst_s *rec ) +{ + QUAD *stat; + + stat = rec->RI_data; + sprintf(data, MSGNot("%Ld"), *stat ); +} + +/* + * Generic routine to convert from up time into UTC time. + * + * Notes - + * This routine is needed as GetUTCTime() does not + * return UTC time in the first few minutes of the server + * coming up. By storing up time we can safely convert + * to UTC time after the first few minutes. + * + * Warning - + * If this routine is called by GetUTCTime() is + * still returning local time then the result will be + * in local time. There is no event as to when GetUTCTime() + * starts tracking time in UTC. + * + */ +void genUTCFromUpTime( + BYTE *data, ReadInst_s *rec ) +{ + LONG *upTime; + + upTime = rec->RI_data; + sprintf(data, MSGNot("%ld"), UpTimeToUTCTime( *upTime ) ); +} + + + +/**************************************************************************** + * Cache Statictics (functions for those files which can't get its value * + * directly). * + ****************************************************************************/ + +QUAD genTotalSystemCacheHit() +{ + return Inst.cache.ioHitSystemTotal + + Inst.cache.ioHitSystem + + Inst.cache.ioHitLinuxSystemTotal + + Inst.cache.ioHitLinuxSystem; +} + +QUAD genTotalSystemCacheMiss() +{ + return Inst.cache.ioMissSystemTotal + + Inst.cache.ioMissSystem + + Inst.cache.ioMissLinuxSystemTotal + + Inst.cache.ioMissLinuxSystem; +} + +QUAD genTotalCacheHit() +{ + return Inst.cache.ioHitUserSystemTotal + + Inst.cache.ioHitUserSystem + + Inst.cache.ioHitLinuxUserSystemTotal + + Inst.cache.ioHitLinuxUserSystem; +} + +QUAD genTotalCacheMiss() +{ + return Inst.cache.ioMissUserSystemTotal + + Inst.cache.ioMissUserSystem + + Inst.cache.ioMissLinuxUserSystemTotal + + Inst.cache.ioMissLinuxUserSystem; +} + +QUAD genTotalUserCacheHit() +{ + return genTotalCacheHit() - genTotalSystemCacheHit(); +} + +QUAD genTotalUserCacheMiss() +{ + return genTotalCacheMiss() - genTotalSystemCacheMiss(); +} + +QUAD genTotalLinuxCacheHit() +{ + return Inst.cache.ioHitLinuxUserSystemTotal + + Inst.cache.ioHitLinuxUserSystem; +} + +QUAD genTotalLinuxCacheMiss() +{ + return Inst.cache.ioMissLinuxUserSystemTotal + + Inst.cache.ioMissLinuxUserSystem; +} + +QUAD genTotalLinuxSystemCacheHit() +{ + return Inst.cache.ioHitLinuxSystemTotal + + Inst.cache.ioHitLinuxSystem; +} + +QUAD genTotalLinuxSystemCacheMiss() +{ + return Inst.cache.ioMissLinuxSystemTotal + + Inst.cache.ioMissLinuxSystem; +} + +QUAD genTotalLinuxUserCacheHit() +{ + return genTotalLinuxCacheHit() - genTotalLinuxSystemCacheHit(); +} + +QUAD genTotalLinuxUserCacheMiss() +{ + return genTotalLinuxCacheMiss() - genTotalLinuxSystemCacheMiss(); +} + + +static void genCachePercentage( + BYTE *data, ReadInst_s *rec, QUAD tHit, QUAD tMiss ) +{ + int percent; + + ASSERT_MPKNSS_LOCK(); + if ( (tHit + tMiss) != 0 ) + { + percent = (int)((tHit * 100) / (tHit + tMiss)); + } + else + { + percent = 0; + } + sprintf(data, MSGNot("%d"), percent ); +} + +static void genCacheIOLinuxTotalHitPercentage( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + genCachePercentage(data,rec, genTotalLinuxCacheHit(), genTotalLinuxCacheMiss() ); +} + +static void genCacheIOLinuxSystemTotalHitPercentage( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + genCachePercentage(data,rec, genTotalLinuxSystemCacheHit(), genTotalLinuxSystemCacheMiss() ); +} + +static void genCacheIOLinuxUserTotalHitPercentage( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + genCachePercentage(data,rec, genTotalLinuxUserCacheHit(), genTotalLinuxUserCacheMiss() ); +} + +void genCacheIOUserHitPercentage( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + genCachePercentage(data,rec, genTotalUserCacheHit(), genTotalUserCacheMiss() ); +} + +void genStatIOUserTotalHit( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalUserCacheHit() ); +} + +void genStatIOUserTotalMiss( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalUserCacheMiss() ); +} + + +void genCacheIOSystemHitPercentage( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + genCachePercentage(data,rec, genTotalSystemCacheHit(), genTotalSystemCacheMiss() ); +} + + +static void genStatIOLinuxSystemTotalHit( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalLinuxSystemCacheHit() ); +} + +static void genStatIOLinuxSystemTotalMiss( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalLinuxSystemCacheMiss() ); +} + + +static void genStatIOLinuxUserTotalHit( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalLinuxUserCacheHit() ); +} + +static void genStatIOLinuxUserTotalMiss( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalLinuxUserCacheMiss() ); +} + + +static void genStatIOLinuxTotalHit( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalLinuxCacheHit() ); +} + +static void genStatIOLinuxTotalMiss( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalLinuxCacheMiss() ); +} + + +void genStatIOSystemTotalHit( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalSystemCacheHit() ); +} + +void genStatIOSystemTotalMiss( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalSystemCacheMiss() ); +} + + +void genCacheHitPercentage( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + genCachePercentage(data,rec, genTotalCacheHit(), genTotalCacheMiss() ); +} + + +void genUTCTimeCurrent( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%ld"), GetUTCTime() ); +} + + +void genStatTotalHit( + BYTE *data, ReadInst_s *rec ) +{ /* Total hits in any of our caches */ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalCacheHit() ); +} + +void genStatTotalMiss( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), genTotalCacheMiss() ); +} + + + /* Cache.bucketPageBuffer items. Items for hash used to lookup meta-data himem pages. */ +void cacheMDHimemBucketMaxEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT maxInBucket; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(&maxInBucket, ¶m1, ¶m2, Cache.bucketPageBuffer, Config.cache.privateHashSize); + sprintf(data, MSGNot("%u"), maxInBucket); +} + +void cacheMDHimemTotalEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT totalEntries; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(¶m1, &totalEntries, ¶m2, Cache.bucketPageBuffer, Config.cache.privateHashSize); + sprintf(data, MSGNot("%u"), totalEntries); +} + +void cacheMDHimemBucketPercentage( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT numUsedBuckets; + + ASSERT_MPKNSS_LOCK(); + + if (Config.cache.privateHashSize == 0) + { + sprintf(data, MSGNot("0")); + } + else + { + getBucketStats(¶m1, ¶m2, &numUsedBuckets, Cache.bucketPageBuffer, Config.cache.privateHashSize); + sprintf(data, MSGNot("%d"), (numUsedBuckets*100) / Config.cache.privateHashSize); + } +} + + + /* Cache.Bucket items */ +void cacheBucketMaxEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT maxInBucket; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(&maxInBucket, ¶m1, ¶m2, Cache.bucket, Config.cache.hashSize); + + sprintf(data, MSGNot("%u"), maxInBucket); +} + +void cacheTotalEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT totalEntries; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(¶m1, &totalEntries, ¶m2, Cache.bucket, Config.cache.hashSize); + + sprintf(data, MSGNot("%u"), totalEntries); +} + +void cacheBucketPercentage( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT numUsedBuckets; + + ASSERT_MPKNSS_LOCK(); + + if (Config.cache.hashSize == 0) + { + sprintf(data, MSGNot("0")); + } + else + { + getBucketStats(¶m1, ¶m2, &numUsedBuckets, Cache.bucket, Config.cache.hashSize); + sprintf(data, MSGNot("%d"), (numUsedBuckets*100) / Config.cache.hashSize); + } +} + + +/**************************************************************************** + * Name Cache Statictics (functions for those files which can't get its * + * value directly, sometimes because the value is a QUAD and the normal routine + * expects a NINT). * + ****************************************************************************/ +void nameBucketMaxEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT uniMaxInBucket; + NINT asciiMaxInBucket; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(&uniMaxInBucket, ¶m1, ¶m2, NameCache.uniHash, NameCache.numHashEntries); + getBucketStats(&asciiMaxInBucket, ¶m1, ¶m2, NameCache.asciiHash, NameCache.numHashEntries); + + sprintf(data, MSGNot("%u"), (uniMaxInBucket >= asciiMaxInBucket) ? uniMaxInBucket : asciiMaxInBucket); +} + +void nameBucketPercentage( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT uniNumUsedBuckets; + NINT asciiNumUsedBuckets; + + ASSERT_MPKNSS_LOCK(); + if ((Config.cache.hashSize == 0) || (NameCache.numHashEntries == 0)) + { + sprintf(data, MSGNot("0")); + } + else + { + getBucketStats(¶m1, ¶m2, &uniNumUsedBuckets, NameCache.uniHash, NameCache.numHashEntries); + getBucketStats(¶m1, ¶m2, &asciiNumUsedBuckets, NameCache.asciiHash, NameCache.numHashEntries); + sprintf(data, MSGNot("%u"), ((uniNumUsedBuckets + asciiNumUsedBuckets)*100) / (NameCache.numHashEntries*2)); + } +} + +void nameChangeCount( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), NameCache.changeCount); +} + +void nameGets( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), NameCache.uniGets + NameCache.asciiGets); +} + +void nameHits( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), NameCache.uniHits + NameCache.asciiHits); +} + +void nameHitPercentage( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + + sprintf(data, MSGNot("%Lu"), + (((NameCache.uniGets + NameCache.asciiGets) != UI64_CONST(0)) ? + (((NameCache.uniHits + NameCache.asciiHits) * UI64_CONST(100)) / (NameCache.uniGets + NameCache.asciiGets)) : + UI64_CONST(0))); +} + +void nameNegativeHits( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + + sprintf(data, MSGNot("%Lu"), NameCache.uniNegativeHits + NameCache.asciiNegativeHits); +} + +void nameNumAllocs( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), NameCache.numAllocs); +} + +void nameNumAlreadyAdded ( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), NameCache.numAlreadyAdded); +} + +void nameNumNegativeAdds( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), NameCache.numNegativeAdds); +} + +void nameNumRemoved ( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), NameCache.numRemoved); +} + +void nameNumVictimSelected ( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), NameCache.numVictimSelected); +} + +void namePositiveHits( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + + sprintf(data, MSGNot("%Lu"), NameCache.uniPositiveHits + NameCache.asciiPositiveHits); +} + +void nameTotalEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT uniTotalEntries; + NINT asciiTotalEntries; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(¶m1, &uniTotalEntries, ¶m2, NameCache.uniHash, NameCache.numHashEntries); + getBucketStats(¶m1, &asciiTotalEntries, ¶m2, NameCache.asciiHash, NameCache.numHashEntries); + + sprintf(data, MSGNot("%u"), uniTotalEntries + asciiTotalEntries); +} + + +/**************************************************************************** + * File Statictics (functions for those files which can't get its value * + * directly). * + ****************************************************************************/ +void fileBytesRead( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Lu"), Inst.file.curBytesRead + Inst.file.totalBytesRead); +} + +void fileBytesWrite( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + + sprintf(data, MSGNot("%Lu"), Inst.file.curBytesWritten + Inst.file.totalBytesWritten); +} + +void fileReadCount( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + + sprintf(data, MSGNot("%Lu"), Inst.file.curFileReadCount + Inst.file.totalFileReadCount); +} + +void fileWriteCount( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + + sprintf(data, MSGNot("%Lu"), Inst.file.curFileWriteCount + Inst.file.totalFileWriteCount); +} + + +/**************************************************************************** + * Beast Cache Statictics (functions for those files which can't get its * + * value directly). * + ****************************************************************************/ +void bstTotalHit( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), Inst.bst.hitTotal + Inst.bst.hit ); +} + +void bstPositiveHit( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), Inst.bst.positiveHitTotal + Inst.bst.positiveHit ); +} + +void bstNegativeHit( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), Inst.bst.negativeHitTotal + Inst.bst.negativeHit ); +} + +void bstTotalMiss( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%Ld"), Inst.bst.missTotal + Inst.bst.miss ); +} + +void bstHitPercentage( + BYTE *data, ReadInst_s *rec ) +{ + QUAD hit = Inst.bst.hit+Inst.bst.hitTotal; + QUAD miss =Inst.bst.miss+Inst.bst.missTotal ; + + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%d"), (int)((hit != 0) ? ((hit * 100)/ + (hit + miss)) : 0)); +} + +void bstInuseCount( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + + sprintf(data, MSGNot("%u"), Config.bst.total); +} + +void bstBucketMaxEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT maxInBucket; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(&maxInBucket, ¶m1, ¶m2, RootBeastHash, Config.bst.hashSize); + + sprintf(data, MSGNot("%u"), maxInBucket); +} + +void bstTotalEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT totalEntries; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(¶m1, &totalEntries, ¶m2, RootBeastHash, Config.bst.hashSize); + + sprintf(data, MSGNot("%u"), totalEntries); +} + +void bstBucketPercentage( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT numUsedBuckets; + + ASSERT_MPKNSS_LOCK(); + if (Config.cache.hashSize == 0) + { + sprintf(data, MSGNot("0")); + } + else + { + getBucketStats(¶m1, ¶m2, &numUsedBuckets, RootBeastHash, Config.bst.hashSize); + sprintf(data, MSGNot("%d"), (numUsedBuckets*100) / Config.bst.hashSize); + } + +} + + +/**************************************************************************** + * FSM and Mailbox Statictics (functions for those files which can't get * + * its value directly). * + ****************************************************************************/ +void mailWaiting( + BYTE *data, ReadInst_s *rec ) +{ + NINT count; + + ASSERT_MPKNSS_LOCK(); + count = (char *)InterruptMailbox.give - (char *)InterruptMailbox.take; + + if (count < 0) + { + count = (char *)InterruptMailbox.end - (char *)InterruptMailbox.start - count; + } + + sprintf(data, MSGNot("%u"), count); +} + +void fsmWaiting( + BYTE *data, ReadInst_s *rec ) +{ + NINT count = 0; + CIRlink_t next; + + ASSERT_MPKNSS_LOCK(); + if (CIR_NOT_EMPTY(FsmReadyQ)) + { + next = FsmReadyQ; + do + { + count++; + next = (CIRlink_t)NEXT(next); + } while (next != FsmReadyQ); + } + + sprintf(data, MSGNot("%u"), count); +} + + +/**************************************************************************** + * Authorization Statictics (functions for those files which can't get its * + * value directly). * + ****************************************************************************/ +void authHashSize( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + + sprintf(data, MSGNot("%u"), AuthCache.hashMask+1); +} + +void authBucketMaxEntries( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT maxInBucket; + + ASSERT_MPKNSS_LOCK(); + getBucketStats(&maxInBucket, ¶m1, ¶m2, (DQhead_t *)AuthCache.hash, AuthCache.hashMask + 1); + + sprintf(data, MSGNot("%u"), maxInBucket); +} + +void authBucketPercentage( + BYTE *data, ReadInst_s *rec ) +{ + NINT param1, param2; + NINT numUsedBuckets; + + ASSERT_MPKNSS_LOCK(); + if (AuthCache.hashMask + 1 == 0) + { + sprintf(data, MSGNot("0")); + } + else + { + getBucketStats(¶m1, ¶m2, &numUsedBuckets, (DQhead_t *)AuthCache.hash, AuthCache.hashMask + 1); + sprintf(data, MSGNot("%u"), (numUsedBuckets*100) / ( AuthCache.hashMask + 1)); + } +} + + +/**************************************************************************** + * General Statictics (functions for those files which can't get its value * + * directly). * + ****************************************************************************/ +void genStatsCacheSize( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.cache.numPagesAllocated * 4 * PAGE_SIZE); +} + +void genStatsPrivateCacheSizeInBlocksTarget( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.cache.privateCachePageBuffers * PAGE_SIZE); +} + +void genStatsPrivateCacheSizeInBlocksCurrent( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.cache.privateCachePages * PAGE_SIZE); +} + +void genStatsPrivateCacheSizeInBlocksCurrentLow( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Inst.cache.numMetadataHimemPagesInLowMemory * PAGE_SIZE); +} + +void genStatsMinCacheSize( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.cache.numBuffers * 4 * PAGE_SIZE); +} + +void genStatsMinNWCacheSize( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.cache.minOSFree * 4 * PAGE_SIZE); +} + +void genStatsCacheBalPercent( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.cache.percentOfOSFree); +} + +void genStatsCacheBalTimer( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.cache.balanceTimerSecs); +} + + +void genStatsOpenFileHashSize( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.bst.hashSize); +} + +void genStatsCloseFileHashSize( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.bst.notInUseMax); +} + +void genStatsFileFlushTimer( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Config.sec.beast); +} + + +#if NSS_DEBUG IS_ENABLED +/**************************************************************************** + * Latch Statictics (functions for those files which can't get its value * + * directly). * + ****************************************************************************/ +void latchWaiter( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Latch_Waiter()); +} + +void latchHolder( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Latch_Holder()); +} + +void latchAll( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Latch_All()); +} + +void latchFree( + BYTE *data, ReadInst_s *rec ) +{ + ASSERT_MPKNSS_LOCK(); + sprintf(data, MSGNot("%u"), Latch_Free()); +} +#endif + +void getCompInfo( + BYTE *data, ReadInst_s *rec ) +{ + GeneralMsg_s genMsg; + RootBeast_s *beast; + Volume_s *volume; + Volume_s *prevVolume; + CMActivity_s *activity; + BOOL latched = FALSE; + NINT len; +typedef struct { + unicode_t volName[zMAX_COMPONENT_NAME]; + unicode_t fileName[zMAX_FULL_NAME + 1]; +} AllocStuff_s; + AllocStuff_s *as; + + ASSERT_MPKNSS_LOCK(); + + as = zalloc( sizeof( *as ) ); + if ( as == NULL ) + { + zASSERT(MSG("Unable to Allocate Memory\n", 190) == NULL); + return; + } + + S_LATCH(&CM_curCompStatistics.latch); + + /* fill in general info */ + sprintf(data, MSGNot("<"TAG_GENERALSTATS">\n" + "<"TAG_LASTCOMPRATIO">%d\n" + "<"TAG_AVECOMPRATIO">%d\n" + "<"TAG_NUMQUEUEDCOMPREQS">%d\n" + "<"TAG_NUMQUEUEDBGCOMPREQS">%d\n" + "<"TAG_USEDCOMPACTIVITY">%d\n" + "<"TAG_USEDDECOMPACTIVITY">%d\n" + "\n"), + CM_curCompStatistics.percentSpaceSaved, + CM_curCompStatistics.averageCompRatio, + CM_curCompStatistics.numQueuedCompReqs, + CM_curCompStatistics.numQueuedBGCompReqs, + CM_curCompStatistics.numCompActivities, + CM_curCompStatistics.numDecompActivities); + len = strlen(data); + + /* fill in activity info */ + sprintf(&data[len], MSGNot("<"TAG_CURRENTACTIVITY">\n")); + len += strlen(&data[len]); + + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + if (DQ_NOT_EMPTY(&CM_activities)) + { + DQ_FOREACH(&CM_activities, activity, CMActivity_s, allActivitiesChain) + { + if (activity->state != CM_ACTIVITY_STATE_RUNNING) + { + continue; + } + + beast = activity->decompStream.beast; + + /* get the volume name on which this beast resides */ + volume = beast->ROOTvolume; + + if (COMN_GetVolumeName(&genMsg, volume, + as->volName, NELEMS(as->volName)) != zOK) + { + zASSERT("can't get volume's name" == NULL); + continue; + } + + /* get the beast name */ + if (LATCH_FREE(&beast->ROOTbeastLatch)) + { + S_LATCH(&beast->ROOTbeastLatch); + latched = TRUE; + } + + if (COMN_GetFileNameFromZid(&genMsg, volume, beast->zid, OS_NAME_SPACE, + as->fileName, FALSE) != zOK) + { + if (latched) + { + UNS_LATCH(&beast->ROOTbeastLatch); + latched = FALSE; + } + + /* This could happen if the beast is during the purging process */ +// zASSERT("can't get beast's name" == NULL); + continue; + } + + if (latched) + { + UNS_LATCH(&beast->ROOTbeastLatch); + latched = FALSE; + } + + sprintf(&data[len], MSGNot("<"TAG_FILE">\n" + "<"TAG_VOLUME">%U\n" + "<"TAG_NAME">%U\n"), + as->volName, as->fileName); + len += strlen(&data[len]); + + /* mark what is the operation on this file (comp or decomp) */ + if (activity->op == CM_ACTIVITY_OP_COMPRESS) + { + sprintf(&data[len], MSGNot("<"TAG_OPERATION">compression\n")); + len += strlen(&data[len]); + } + else + { + sprintf(&data[len], MSGNot("<"TAG_OPERATION">decompression\n")); + len += strlen(&data[len]); + } + + sprintf(&data[len], MSGNot("\n")); + len += strlen(&data[len]); + } + } + + sprintf(&data[len], MSGNot("\n")); + len += strlen(&data[len]); + + + sprintf(&data[len], MSGNot("<"TAG_VOLUMECOMPRESSIONINFO">\n")); + len += strlen(&data[len]); + + /* individaul volume compression info */ + prevVolume = NULL; + + while (TRUE) + { + volume = COMN_GetNextVolume(prevVolume); + if (prevVolume) + { + COMN_Release(&prevVolume); + } + + if (volume == NULL) + { + break; + } + + prevVolume = volume; + + if (!(volume->VOLenabledAttributes & zATTR_COMPRESSION)) + { + continue; + } + + if (COMN_GetVolumeName(&genMsg, volume, + as->volName, NELEMS(as->volName)) != zOK) + { + zASSERT("can't get volume's name" == NULL); + continue; + } + + sprintf(&data[len], + MSGNot("<"TAG_VOLUME">\n" + "<"TAG_VOLUMENAME">%U\n" + "<"TAG_COMPRESSEDFILES">%Lu\n" + "<"TAG_COMPRESSEDDELETEDFILES">%Lu\n" + "<"TAG_UNCOMPRESSIBLEFILES">%Lu\n" + "<"TAG_PRECOMPRESSIONBYTES">%Lu\n" + "<"TAG_COMPRESSEDBYTES">%Lu\n" + "\n"), + as->volName, + volume->VOLnumCompressedFiles - volume->VOLnumCompDelFiles, + volume->VOLnumCompDelFiles, + volume->VOLnumUncompressibleFiles, + volume->VOLnumPreCompressedFileBlocks << volume->VOLblockShift, + volume->VOLnumCompressedFileBlocks << volume->VOLblockShift); + len += strlen(&data[len]); + } + + sprintf(&data[len], MSGNot("\n")); + + UNS_LATCH(&CM_curCompStatistics.latch); + + free(as); + + +} + +/******************************************************************************** + * These are the static files which only have read overrides * + ********************************************************************************/ +ReadInst_s MgmtReadInsts[] = +{ + {NULL, TRUE, 0, 0}, /* dummy entry */ +/*------------------------------------------------------------------------------* + * Genearal Statistics * + *------------------------------------------------------------------------------*/ + {TAG_GENERALSTATS, TRUE, 0, 0}, + {TAG_CURRENTBUFFERCACHESIZE, FALSE, 0, &genStatsCacheSize}, + {TAG_MINIMUMNSSBUFFERCACHESIZE, FALSE, 0, &genStatsMinCacheSize}, + {TAG_MINIMUMNETWAREBUFFERCACHESIZE, FALSE, 0, &genStatsMinNWCacheSize}, + {TAG_CACHEBALANCEPERCENT, FALSE, 0, &genStatsCacheBalPercent}, + {TAG_CACHEBALANCETIMER, FALSE, 0, &genStatsCacheBalTimer}, + /* Added May 2007 for OES2(start) */ + {TAG_CACHEJOURNALFLUSHTIMER, FALSE, &Config.sec.journalGroupWriteTime, NULL}, + {TAG_CACHEMETADATAFLUSHTIMER, FALSE, &Config.sec.metadataGroupWriteTime, NULL}, + {TAG_CACHEUSERDATAFLUSHTIMER, FALSE, &Config.sec.userDataGroupWriteTime, NULL}, + /* Added May 2007 for OES2(end) */ + {TAG_OPENFILEHASHTABLESIZE, FALSE, 0, &genStatsOpenFileHashSize}, + {TAG_CLOSEDFILECACHESIZE, FALSE, (ADDR *)&Config.bst.notInUseMax, 0}, + {TAG_FILEFLUSHTIMER, FALSE, 0, &genStatsFileFlushTimer}, + {TAG_NAMECACHESIZE, FALSE, (ADDR *)&NameCache.maxEntries, 0}, + {TAG_AUTHORIZATIONCACHESIZE, FALSE, (ADDR *)&AuthCache.maxEntries, 0}, + {TAG_MAILBOXSIZE, FALSE, (ADDR *)&Config.os.sizeMailbox, 0}, + {TAG_MINIMUMNUMBEROFASYNCIOS, FALSE, (ADDR *)&Config.cache.numAsyncios, 0}, + {TAG_MINIMUMNUMBEROFBONDS, FALSE, (ADDR *)&Config.cache.numBonds, 0}, + {TAG_MINIMUMNUMBEROFWORKTODOS, FALSE, (ADDR *)&Config.os.workLimit, 0}, + /* Added Nov 2006 */ + {TAG_METADATABUFFERCACHESIZETARGET, FALSE, 0, &genStatsPrivateCacheSizeInBlocksTarget}, + {TAG_METADATABUFFERCACHESIZECURRENT, FALSE, 0, &genStatsPrivateCacheSizeInBlocksCurrent}, + {TAG_METADATABUFFERCACHESIZECURRENTLOW, FALSE, 0, &genStatsPrivateCacheSizeInBlocksCurrentLow}, + /* Added May 2007 for OES2 */ + {TAG_CACHEMETADATAGROUPWRITELIMIT, FALSE, &Config.cache.metadataBlocksReadyForGroupWriteLimit, NULL}, + {TAG_CACHEMETADATAGROUPWRITECOUNT, FALSE, &Config.cache.metadataBlocksReadyForGroupWrite, NULL}, +/*------------------------------------------------------------------------------* + * Cache * + *------------------------------------------------------------------------------*/ + {TAG_BUFFERCACHE, TRUE, 0, 0}, + {TAG_RESETTIME, FALSE, &Inst.resetUpTime, &genUTCFromUpTime }, + {TAG_TIME, FALSE, NULL, &genUTCTimeCurrent }, + {TAG_CACHEHITS, FALSE, NULL, &genStatTotalHit }, + {TAG_CACHEMISSES, FALSE, NULL, &genStatTotalMiss}, + {TAG_CACHEHITPERCENT, FALSE, 0, &genCacheHitPercentage}, + {TAG_CACHEIOSYSTEMHITS, FALSE, NULL, &genStatIOSystemTotalHit }, + {TAG_CACHEIOSYSTEMMISSES, FALSE, NULL, &genStatIOSystemTotalMiss}, + {TAG_CACHEIOSYSTEMHITPERCENT, FALSE, NULL, &genCacheIOSystemHitPercentage}, + {TAG_CACHEIOUSERHITS, FALSE, NULL, &genStatIOUserTotalHit }, + {TAG_CACHEIOUSERMISSES, FALSE, NULL, &genStatIOUserTotalMiss}, + {TAG_CACHEIOUSERHITPERCENT, FALSE, NULL, &genCacheIOUserHitPercentage}, + {TAG_CACHEBUFFERSNUMBER, FALSE, (ADDR *)&Config.cache.numBuffers, 0}, + {TAG_HASHBUCKETS, FALSE, (ADDR *)&Config.cache.hashSize, 0}, + {TAG_MINIMUMOSFREEBUFFERS, FALSE, (ADDR *)&Config.cache.minOSFree, 0}, + {TAG_CACHEPAGESALLOCATED, FALSE, (ADDR *)&Config.cache.numPagesAllocated, 0}, + {TAG_BUCKETMAXIMUMENTRIES, FALSE, 0, &cacheBucketMaxEntries}, + {TAG_TOTALENTRIES, FALSE, 0, &cacheTotalEntries}, + {TAG_BUCKETSUSEDPERCENT, FALSE, 0, &cacheBucketPercentage}, + /* Added Oct 2006 */ + {TAG_CACHEIOLINUXHITS, FALSE, NULL, &genStatIOLinuxTotalHit }, + {TAG_CACHEIOLINUXHITSPERCENT, FALSE, NULL, &genCacheIOLinuxTotalHitPercentage }, + {TAG_CACHEIOLINUXMISSES, FALSE, NULL, &genStatIOLinuxTotalMiss}, + {TAG_CACHEIOLINUXSYSTEMHITS, FALSE, NULL, &genStatIOLinuxSystemTotalHit }, + {TAG_CACHEIOLINUXSYSTEMHITSPERCENT, FALSE, NULL, &genCacheIOLinuxSystemTotalHitPercentage }, + {TAG_CACHEIOLINUXSYSTEMMISSES, FALSE, NULL, &genStatIOLinuxSystemTotalMiss}, + {TAG_CACHEIOLINUXUSERHITS, FALSE, NULL, &genStatIOLinuxUserTotalHit }, + {TAG_CACHEIOLINUXUSERHITSPERCENT, FALSE, NULL, &genCacheIOLinuxUserTotalHitPercentage }, + {TAG_CACHEIOLINUXUSERMISSES, FALSE, NULL, &genStatIOLinuxUserTotalMiss}, + /* Added Nov 2006 */ + {TAG_HMCCACHETYPE, FALSE, &Config.cache.hmcCacheType, 0}, + {TAG_HASHBUCKETSPRIVATE, FALSE, &Config.cache.privateHashSize, 0}, + {TAG_MDHIMEMBUCKETMAXIMUMENTRIES, FALSE, 0, &cacheMDHimemBucketMaxEntries}, + {TAG_MDHIMEMTOTALENTRIES, FALSE, 0, &cacheMDHimemTotalEntries}, + {TAG_MDHIMEMBUCKETSUSEDPERCENT, FALSE, 0, &cacheMDHimemBucketPercentage}, +/*------------------------------------------------------------------------------* + * Name Cache * + *------------------------------------------------------------------------------*/ + {TAG_NAMECACHE, TRUE, 0, 0}, + {TAG_MAXIMUMENTRIES, FALSE,(ADDR *)&NameCache.maxEntries,0}, + {TAG_USEDENTRIES, FALSE, (ADDR *)&NameCache.numEntries, 0}, + {TAG_UNUSEDENTRIES, FALSE, (ADDR *)&NameCache.numUnusedEntries, 0}, + {TAG_TOTALATTEMPTS, FALSE, 0, &nameGets}, + {TAG_CACHEHITS, FALSE, 0, &nameHits}, + {TAG_CACHEHITPERCENT, FALSE, 0, &nameHitPercentage}, + {TAG_CACHEPOSITIVEHITS, FALSE, 0, &namePositiveHits}, + {TAG_CACHENEGATIVEHITS, FALSE, 0, &nameNegativeHits}, + {TAG_ALLOCATEDPACKETS, FALSE, 0, &nameNumAllocs}, + {TAG_ADDS, FALSE, 0, &nameChangeCount}, + {TAG_NEGATIVEADDS, FALSE, 0, &nameNumNegativeAdds}, + {TAG_DUPLICATEADDS, FALSE, 0, &nameNumAlreadyAdded}, + {TAG_SELECTEDVICTIMS, FALSE, 0, &nameNumVictimSelected}, + {TAG_REMOVEDENTRIES, FALSE, 0, &nameNumRemoved}, + {TAG_BUCKETMAXIMUMENTRIES, FALSE, 0, &nameBucketMaxEntries}, + {TAG_TOTALENTRIES, FALSE, 0, &nameTotalEntries}, + {TAG_BUCKETSUSEDPERCENT, FALSE, 0, &nameBucketPercentage}, +/*------------------------------------------------------------------------------* + * File * + *------------------------------------------------------------------------------*/ + {TAG_FILESTATS, TRUE, 0, 0}, + {TAG_RESETTIME, FALSE, &Inst.resetUpTime, &genUTCFromUpTime }, + {TAG_TIME, FALSE, NULL, &genUTCTimeCurrent }, + {TAG_CURRENTOPENCOUNT, FALSE, (ADDR *)&Inst.file.openCount, 0}, + {TAG_BYTESREAD, FALSE, 0, &fileBytesRead}, + {TAG_BYTESWRITTEN, FALSE, 0, &fileBytesWrite}, + {TAG_FILEREADCOUNTS, FALSE, 0, &fileReadCount}, + {TAG_FILEWRITECOUNTS, FALSE, 0, &fileWriteCount}, + {TAG_FILESDELETED, FALSE, (ADDR *)&Inst.file.deletedCount, 0}, + {TAG_FILESPURGED, FALSE, (ADDR *)&Inst.file.purgedCount, 0}, + {TAG_FILESSALVAGED, FALSE, (ADDR *)&Inst.file.salvagedCount, 0}, +/*------------------------------------------------------------------------------* + * Beast Cache * + *------------------------------------------------------------------------------*/ + {TAG_OBJECTCACHE, TRUE, 0, 0}, + {TAG_CACHEHITS, FALSE, NULL, &bstTotalHit}, + {TAG_CACHEPOSITIVEHITS, FALSE, NULL, &bstPositiveHit}, + {TAG_CACHENEGATIVEHITS, FALSE, NULL, bstNegativeHit}, + {TAG_CACHEMISSES, FALSE, NULL, &bstTotalMiss}, + {TAG_CACHEHITPERCENT, FALSE, 0, &bstHitPercentage}, + {TAG_SIMULTANEOUSOBJECTREADCOUNT, FALSE, (ADDR *)&SimultaneousBeastReadCount, 0}, + {TAG_MAXIMUMOBJECTSINMEMORY, FALSE, (ADDR *)&Config.bst.total, 0}, + {TAG_INUSEOBJECTCOUNT, FALSE, 0, &bstInuseCount}, + {TAG_NOTINUSEOBJECTCOUNT, FALSE, (ADDR *)&Config.bst.notInUse, 0}, + {TAG_MAXIMUMNOTINUSEOBJECTS, FALSE, (ADDR *)&Config.bst.notInUseMax, 0}, + {TAG_HASHBUCKETS, FALSE, (ADDR *)&Config.bst.hashSize, 0}, + {TAG_BUCKETMAXIMUMENTRIES, FALSE, 0, &bstBucketMaxEntries}, + {TAG_TOTALENTRIES, FALSE, 0, &bstTotalEntries}, + {TAG_BUCKETSUSEDPERCENT, FALSE, 0, &bstBucketPercentage}, +/*------------------------------------------------------------------------------* + * Thread (FSM & Work) * + *------------------------------------------------------------------------------*/ + {TAG_THREAD, TRUE, 0, 0}, +#if HISTOGRAM IS_ENABLED + {TAG_TOTALWORKSTODO, FALSE, (ADDR *)&WorkControl.histogram, 0}, +#endif + {TAG_PENDINGWORKSCOUNT, FALSE, (ADDR *)&PendingWork, 0}, + {TAG_MAXIMUMPENDINGWORKNUMBER, FALSE, (ADDR *)&Config.os.workLimit, 0}, + {TAG_HIGHWORKSWAITINGCOUNT, FALSE, (ADDR *)&WorkHighWaitingCount, 0}, + {TAG_MAXIMUMHIGHWORKSWAITINGNUMBER, FALSE, (ADDR *)&Config.work.waitingHigh, 0}, + {TAG_NORMALWORKSWAITINGCOUNT, FALSE, (ADDR *)&WorkWaitingCount, 0}, + {TAG_MAXIMUMNORMALWORKSWAITINGNUMBER, FALSE, (ADDR *)&Config.work.waiting, 0}, + {TAG_TOTALWORKSDONE, FALSE, (ADDR *)&WorkInst.loop, 0}, + {TAG_MAILBOXSIZE, FALSE, (ADDR *)&Config.os.sizeMailbox, 0}, + {TAG_MAILBOXINTERRUPTSWAITING, FALSE, 0, &mailWaiting}, + {TAG_MAILBOXINTERRUPTSDONE, FALSE, (ADDR *)&FsmInst.mailDone, 0}, + {TAG_FSMSWAITING, FALSE, 0, &fsmWaiting}, + {TAG_FSMSDONE, FALSE, (ADDR *)&FsmInst.fsmDone, 0}, +/*------------------------------------------------------------------------------* + * Authorization * + *------------------------------------------------------------------------------*/ + {TAG_AUTHORIZATIONCACHE, TRUE, 0, 0}, + {TAG_CACHESIZE, FALSE, 0, &authHashSize}, + {TAG_MAXIMUMENTRIES, FALSE, (ADDR *)&AuthCache.maxEntries, 0}, + {TAG_USEDENTRIES, FALSE, (ADDR *)&AuthCache.numEntries, 0}, + {TAG_BUCKETMAXIMUMENTRIES, FALSE, 0, &authBucketMaxEntries}, + {TAG_BUCKETSUSEDPERCENT, FALSE, 0, &authBucketPercentage}, + {TAG_CACHEACTIVATIONCOUNT, FALSE, (ADDR *)&AuthCache.activationCount, 0}, + {TAG_CACHESIGNATURE, FALSE, (ADDR *)&AuthCache.signatureCount, 0}, + {TAG_CACHERESETCOUNT, FALSE, (ADDR *)&AuthCache.resetCount, 0}, +/*------------------------------------------------------------------------------* + * Latch * + *------------------------------------------------------------------------------*/ +#if NSS_DEBUG IS_ENABLED + {TAG_LATCHSTATS, TRUE, 0, 0}, + {TAG_LATCHWAITER, FALSE, 0, &latchWaiter}, + {TAG_LATCHHOLDER, FALSE, 0, &latchHolder}, + {TAG_LATCHALL, FALSE, 0, &latchAll}, + {TAG_LATCHFREE, FALSE, 0, &latchFree}, +#endif + +/*------------------------------------------------------------------------------* + * Compression * + *------------------------------------------------------------------------------*/ + {TAG_COMPRESSIONSTATS, TRUE, 0, 0}, + {"", FALSE, 0, &getCompInfo}, + + {0}, +}; + +/******************************************************************************** + * All management files (defined above) under MgmtFiles directory + * use the same readOverride. + ********************************************************************************/ +/* VIRTUAL FILE -- READ FUNCTION */ +STATUS MGMT_readOverride( + NINT parmLen, + utf8_t *parm, + VirtInfo_s *virtInfo) +{ + NINT index; + STATUS status = zOK; + utf8_t holdParm[10]; + NINT saveIndex; + + typedef struct Stack_s { + BYTE data[4096]; /* must be large enough for largest element content */ + } Stack_s; + STACK_ALLOC(); + + MPKNSS_LOCK(); + + zASSERT(parmLen < 10); + memcpy(holdParm, parm, parmLen); + holdParm[parmLen] = 0; + index = atol(holdParm); + + if (index == 0) + { + status = zFAILURE; + goto exit; + } + + saveIndex = index; + if ((status = VIRT_AddResultTag(virtInfo, TAG_NSSREPLY, FALSE, + TRUE)) != zOK) + { + goto exit; + } + if ((status = VIRT_AddResultTag(virtInfo, MgmtReadInsts[index].tag, + FALSE, TRUE)) != zOK) + { + goto exit; + } + /* + * For each tag in the table generate an element in the return XML. Stop + * when we get to the next file entry. Index comes in pointing to the + * entry with the current file name. + */ + while ((MgmtReadInsts[++index].tag != NULL) && + !MgmtReadInsts[index].isFile) + { + /* Generate the actual element data */ + + if (MgmtReadInsts[index].RI_callFunc == NULL) + { /* No special routine so assume we need to display a int */ + sprintf(aStack->data, MSGNot("%u"), *((int *)MgmtReadInsts[index].RI_data) ); + } + else + { /* Use a function to get the result */ + MgmtReadInsts[index].RI_callFunc(aStack->data, &MgmtReadInsts[index]); + } + if (strcmp(MgmtReadInsts[index].tag, MSGNot(""))) + { + if ((status = VIRT_AddResultElement(virtInfo, + MgmtReadInsts[index].tag, aStack->data, TRUE)) != zOK) + { + break; + } + } + else + { + if ((status = VIRT_AddResultData(virtInfo, aStack->data)) != zOK) + { + break; + } + } + } + if ((status = VIRT_AddResultTag(virtInfo, MgmtReadInsts[saveIndex].tag, + TRUE, TRUE)) != zOK) + { + goto exit; + } + if ((status = VIRT_AddResultTag(virtInfo, TAG_NSSREPLY, TRUE, + TRUE)) != zOK) + { + goto exit; + } + +exit: + MPKNSS_UNLOCK(); + STACK_FREE(); + return status; +} + + +/******************************************************************************** + * This is the start up routine for all (static) management files (defined * + * above) under MgmtFiles directory. They share the same readOverride * + ********************************************************************************/ +STATUS MGMT_StartupReadInsts( + GeneralMsg_s *genMsg) +{ + NINT i; + char parm[10]; + STATUS status; + Key_t rootKey; + Key_t retKey; + + typedef struct Stack_s { + char pathStr[zMAX_FULL_NAME]; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + + strcpy(aStack->pathStr, AVFileMgmtDir); + + ZOS_zRootKey(status, 0, &rootKey); + if (status != zOK) + { + SetErrno(genMsg, status); + goto errorExit; + } + + /* Export the symbol */ + ZOS_ModuleRegister(MGMT_readOverride); + + /* + * Create the directories and files. + */ + for(i = 1; MgmtReadInsts[i].tag != 0; i++) + { + if (MgmtReadInsts[i].isFile) + { + strcpy(&aStack->pathStr[AVFileMgmtDirLen], MgmtReadInsts[i].tag); + aStack->pathStr[AVFileMgmtDirLen] = toupper(aStack->pathStr[AVFileMgmtDirLen]); + strcat(aStack->pathStr, MSG(".xml", 571)); + ZOS_zCreate(status, rootKey, zNO_TASK, 0, + zNSPACE_LONG | zMODE_UTF8, aStack->pathStr, zFILE_REGULAR, AVFILEFILEATTR, + zCREATE_OPEN_IF_THERE, zRR_WRITE_ACCESS, &retKey); + if (status != zOK) + { + SetErrno(genMsg, status); + goto errorClose; + } + + /* Write the transformation template to the file */ + sprintf(parm, "%d", i); + if ((status = MGMTS_MakeFunctionVirtualFile(retKey, + "MGMT_readOverride", parm, NULL, NULL, FALSE)) != zOK) + { + SetErrno(genMsg, status); + ZOS_zClose(status, retKey); + goto errorClose; + } + + ZOS_zClose(status, retKey); + zASSERT(status == zOK); + } + } + + ZOS_zClose(status, rootKey); + zASSERT(status == zOK); + STACK_FREE(); + return zOK; + +errorClose: + ZOS_zClose(status, rootKey); + +errorExit: + zASSERT("Error creating management read files" == 0); + MGMT_ShutdownReadInsts(); + STACK_FREE(); + return zFAILURE; +} + + +/******************************************************************************** + * This is the shutdown routine for all (static) management files (defined * + * above) under MgmtFiles directory. * + ********************************************************************************/ +void MGMT_ShutdownReadInsts() +{ + STATUS status; + Key_t rootKey; + NINT i; + typedef struct Stack_s { + BYTE pathStr[zMAX_FULL_NAME]; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + + ZOS_zRootKey(status, 0, &rootKey); + if (status != zOK) + { + zASSERT("Error getting rootkey" == 0); + STACK_FREE(); + return; + } + + strcpy(aStack->pathStr, AVFileMgmtDir); + + /* + * Delete the created management files. + */ + for(i = 1; MgmtReadInsts[i].tag != 0; i++) + { + if (MgmtReadInsts[i].isFile) + { + sprintf(&aStack->pathStr[AVFileMgmtDirLen], MSG("%s.xml", 573), + MgmtReadInsts[i].tag); + + ZOS_zDelete(status, rootKey, 0, zNSPACE_LONG | zMODE_UTF8, aStack->pathStr, + zMATCH_ALL, zDELETE_FORCE_DELETE); + zASSERT(status == zOK); + } + } + + ZOS_zClose(status, rootKey); + ZOS_ModuleUnregister(MGMT_readOverride); + STACK_FREE(); + return; +} diff --git a/src/nwnss/comn/common/mgmtVol.c b/src/nwnss/comn/common/mgmtVol.c new file mode 100644 index 0000000..2d4659c --- /dev/null +++ b/src/nwnss/comn/common/mgmtVol.c @@ -0,0 +1,2855 @@ +/**************************************************************************** + | + | (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: cteerlink $ + | $Date: 2008-04-18 03:39:54 +0530 (Fri, 18 Apr 2008) $ + | + | $RCSfile$ + | $Revision: 2319 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Management volume files + +-------------------------------------------------------------------------*/ +#if zLINUX +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msgGen.h" +#include "msgName.h" +#include "comnPublics.h" +#include "mgmt.h" +#include "nssPubs.h" +#include "sbsMFL.h" +#include "xmlTags.h" +#include "virtualIO.h" +#include "dconst.h" +#include "comnAuthorize.h" +#include "sysimp.h" +#include "checker.h" +#include "zasAuthModel.h" +#include "objectIDStore.h" +#include "adminVolume.h" + +SNINT MGMT_VolumeFunctionsRegistered = 0; + +/**************************************************************************** + * Volume Statistics + ****************************************************************************/ +/* Note: if the following definitions in NWSALib.h NWSAVol.h change, change here too */ +#define MAX_VOL_NAME 256 + +BOOL VolumeInstPathIsSetUp = FALSE; +BOOL VolumeBaseDirIsSetUp = FALSE; + +#define MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL 21 + +/**************************************************************************** + * Given a parameter (normally a file path) , and a file name, find which * + * volume this management file belongs to. * + ****************************************************************************/ +STATUS findVolume( + utf8_t *volName, + Volume_s **volumePtr) +{ + GeneralMsg_s genMsg; + VolumeID_t retVolID; + typedef struct Stack_s { + unicode_t volumeName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + if (utf2uni(volName, aStack->volumeName, sizeof(aStack->volumeName)) == -1) + { + STACK_FREE(); + return zERR_INVALID_UTF8_CHAR; + } + + genMsg.flags |= GM_FLAGS_INTERNAL_VOLUME; + *volumePtr = COMN_VolumeNameLookup(&genMsg, aStack->volumeName, FALSE, &retVolID); + STACK_FREE(); + return GetErrno(&genMsg); +} + +/**************************************************************************** + * Given a volume, find the number of user bytes read + ****************************************************************************/ +STATUS volume_userReadSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->v_stats.IO_user_readSize); + return VIRT_AddResultElement(virtInfo, TAG_READSIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of successful user reads + ****************************************************************************/ +STATUS volume_userReadCount( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->v_stats.IO_user_read_success); + return VIRT_AddResultElement(virtInfo, TAG_READCOUNT, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of user written bytes + ****************************************************************************/ +STATUS volume_userWriteSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->v_stats.IO_user_writeSize); + return VIRT_AddResultElement(virtInfo, TAG_WRITESIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of successful user writes * + ****************************************************************************/ +STATUS volume_userWriteCount( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->v_stats.IO_user_write_success); + return VIRT_AddResultElement(virtInfo, TAG_WRITECOUNT, data, TRUE); +} + + +#if NSS_DEBUG IS_ENABLED +/**************************************************************************** + * Given a volume, find the number of system bytes read + ****************************************************************************/ +STATUS volume_systemReadSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->v_stats.IO_system_readSize); + return VIRT_AddResultElement(virtInfo, TAG_READSIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of successful system reads + ****************************************************************************/ +STATUS volume_systemReadCount( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->v_stats.IO_system_read_success); + return VIRT_AddResultElement(virtInfo, TAG_READCOUNT, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of system bytes written + ****************************************************************************/ +STATUS volume_systemWriteSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->v_stats.IO_system_writeSize); + return VIRT_AddResultElement(virtInfo, TAG_WRITESIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of successful system writes + ****************************************************************************/ +STATUS volume_systemWriteCount( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->v_stats.IO_system_write_success); + return VIRT_AddResultElement(virtInfo, TAG_WRITECOUNT, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of failed user reads + ****************************************************************************/ +STATUS volume_userReadFailure( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->v_stats.IO_user_read_failure); + return VIRT_AddResultElement(virtInfo, TAG_READFAILURES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of failed system reads + ****************************************************************************/ +STATUS volume_systemReadFailure( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->v_stats.IO_system_read_failure); + return VIRT_AddResultElement(virtInfo, TAG_READFAILURES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of failed user writes + ****************************************************************************/ +STATUS volume_userWriteFailure( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->v_stats.IO_user_write_failure, NULL); + return VIRT_AddResultElement(virtInfo, TAG_WRITEFAILURES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of failed system writes + ****************************************************************************/ +STATUS volume_systemWriteFailure( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->v_stats.IO_system_write_failure); + return VIRT_AddResultElement(virtInfo, TAG_WRITEFAILURES, data, TRUE); +} +#endif + + +/**************************************************************************** + * Given a volume, find the precompression size + ****************************************************************************/ +STATUS volume_compPreCompressedBytes( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[60]; + BYTE *byteval; + LONG size, sized; + + formattedSize(volume->VOLnumPreCompressedFileBlocks << volume->VOLblockShift, + &size, &sized, &byteval); + + sprintf(data, MSGNot("%Lu (%d.%d %s)"), + volume->VOLnumPreCompressedFileBlocks << volume->VOLblockShift, + size, sized, byteval); + + return VIRT_AddResultElement(virtInfo, TAG_PRECOMPRESSIONBYTES, data, TRUE); +} + +/**************************************************************************** + * Given a volume, find the compression bytes + ****************************************************************************/ +STATUS volume_compCompressedBytes( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[60]; + BYTE *byteval; + LONG size, sized; + + formattedSize(volume->VOLnumCompressedFileBlocks << volume->VOLblockShift, &size, &sized, &byteval); + + sprintf(data, MSGNot("%Lu (%d.%d %s)"), + volume->VOLnumCompressedFileBlocks << volume->VOLblockShift, + size, sized, byteval); + + return VIRT_AddResultElement(virtInfo, TAG_COMPRESSEDBYTES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of non-deleted compressed files + ****************************************************************************/ +STATUS volume_compCompFiles( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLnumCompressedFiles); + return VIRT_AddResultElement(virtInfo, TAG_COMPRESSEDFILES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of compressed deleted files + ****************************************************************************/ +STATUS volume_compCompDeletedFiles( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLnumCompDelFiles); + return VIRT_AddResultElement(virtInfo, TAG_COMPRESSEDDELETEDFILES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of uncompressible files + ****************************************************************************/ +STATUS volume_compUnableFiles( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLnumUncompressibleFiles); + return VIRT_AddResultElement(virtInfo, TAG_UNCOMPRESSIBLEFILES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the freeable size + ****************************************************************************/ +STATUS volume_salFreeableSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[60]; + BYTE *byteval; + LONG size, sized; + + formattedSize(volume->VOLpurgeableBlocks << volume->VOLblockShift, &size, &sized, &byteval); + + sprintf(data, MSGNot("%Lu (%d.%d %s)"), + volume->VOLpurgeableBlocks << volume->VOLblockShift, + size, sized, byteval); + + return VIRT_AddResultElement(virtInfo, TAG_FREEABLESIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the non-freeable size + ****************************************************************************/ +STATUS volume_salNonFreeableSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[60]; + BYTE *byteval; + LONG size, sized; + + formattedSize(volume->VOLnonPurgeableBlocks << volume->VOLblockShift, &size, &sized, &byteval); + + sprintf(data, MSGNot("%Lu (%d.%d %s)"), + volume->VOLnonPurgeableBlocks << volume->VOLblockShift, + size, sized, byteval); + + return VIRT_AddResultElement(virtInfo, TAG_NONFREEABLESIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of delete files in salvage + ****************************************************************************/ +STATUS volume_salDeletedFiles( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLnumDeletedFiles); + return VIRT_AddResultElement(virtInfo, TAG_DELETEDFILES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the minimum keep seconds of the salvage system * + ****************************************************************************/ +STATUS volume_salMinKeepSeconds( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->VOLminKeepSeconds); + return VIRT_AddResultElement(virtInfo, TAG_MINKEEPTIME, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the maximum keep seconds of the salvage system * + ****************************************************************************/ +STATUS volume_salMaxKeepSeconds( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->VOLmaxKeepSeconds); + return VIRT_AddResultElement(virtInfo, TAG_MAXKEEPTIME, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the low water mark of the volume's salvage system * + ****************************************************************************/ +STATUS volume_salLowWaterMark( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->VOLlowWaterMark); + return VIRT_AddResultElement(virtInfo, TAG_LOWWATERMARK, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the high water mark of the volume's salvage system * + ****************************************************************************/ +STATUS volume_salHighWaterMark( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->VOLhighWaterMark); + return VIRT_AddResultElement(virtInfo, TAG_HIGHWATERMARK, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the size + ****************************************************************************/ +STATUS volume_size( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[60]; + BYTE *byteval; + LONG size, sized; + + formattedSize(volume->VOLtotalBlocks << volume->VOLblockShift, &size, &sized, &byteval); + + sprintf(data, MSGNot("%Lu (%d.%d %s)"), + volume->VOLtotalBlocks << volume->VOLblockShift, + size, sized, byteval); + + return VIRT_AddResultElement(virtInfo, TAG_SIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the not in use size + ****************************************************************************/ +STATUS volume_notInUseSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[60]; + BYTE *byteval; + LONG size, sized; + QUAD notInUseSize; + + notInUseSize = (SQUAD)(volume->VOLtotalBlocks - volume->VOLinUseBlocks + volume->VOLpurgeableBlocks) > volume->VOLfreeBlockAdjustment ? + volume->VOLtotalBlocks - volume->VOLinUseBlocks + volume->VOLpurgeableBlocks - volume->VOLfreeBlockAdjustment : 0; + + formattedSize(notInUseSize << volume->VOLblockShift, &size, &sized, &byteval); + + sprintf(data, MSGNot("%Lu (%d.%d %s)"), + notInUseSize << volume->VOLblockShift, + size, sized, byteval); + + return VIRT_AddResultElement(virtInfo, TAG_NOTINUSESIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the percentage of free * + * space * + ****************************************************************************/ +STATUS volume_freeSpacePercent( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + if (volume->VOLtotalBlocks == 0) + { + strcpy(data, "0"); + } + else + { + sprintf(data, MSGNot("%d"), + (((SQUAD)(volume->VOLtotalBlocks - volume->VOLinUseBlocks + volume->VOLpurgeableBlocks) > volume->VOLfreeBlockAdjustment) ? + 100 * (volume->VOLtotalBlocks - volume->VOLinUseBlocks + volume->VOLpurgeableBlocks - volume->VOLfreeBlockAdjustment) : 0) + /volume->VOLtotalBlocks ); + } + return VIRT_AddResultElement(virtInfo, TAG_PERCENTFREESPACE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the block size + ****************************************************************************/ +STATUS volume_blockSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->VOLblockSize); + return VIRT_AddResultElement(virtInfo, TAG_BLOCKSIZE, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the supported attributes + ****************************************************************************/ +STATUS volume_attributes( + VirtInfo_s *virtInfo, + Volume_s *volume, + BOOL supportedFlag) +{ + NINT attributes; + STATUS status; + + if (supportedFlag) + { + attributes = volume->VOLsupportedAttributes; + if ((status = VIRT_AddResultTag(virtInfo, + TAG_SUPPORTEDATTRIBUTES, FALSE, FALSE)) != zOK) + { + goto exit; + } + } + else + { + attributes = volume->VOLenabledAttributes; + if ((status = VIRT_AddResultTag(virtInfo, + TAG_ENABLEDATTRIBUTES, FALSE, FALSE)) != zOK) + { + goto exit; + } + } + + if (attributes & zATTR_SALVAGE) + { + if ((status = VIRT_AddResultData(virtInfo, MSGNot("SALVAGE "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_USER_SPACE_RESTRICTIONS) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("USER_SPACE_RESTRICTIONS "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_READONLY) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("READ_ONLY "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_COMPRESSION) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("COMPRESSION "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_EXTENDED_ATTRIBUTES) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("EXTENDED_ATTRIBUTES "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_DATA_STREAMS) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("DATA_STREAMS "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_DOS_METADATA) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("DOS_METADATA "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_NETWARE_METADATA) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("NETWARE_METADATA "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_MAC_METADATA) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("MAC_METADATA "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_UNIX_METADATA) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("UNIX_METADATA "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_HARD_LINKS) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("HARD_LINKS "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_TRANSACTION) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("SYSTEM_TRANSACTION "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_SPARSE_FILES) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("SPARSE_FILES "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_PHYSICAL_EOF) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("PHYSICAL_EOF "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_DIRECT_IO) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("DIRECT_IO "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_PERSISTENT_ATTRIBUTES) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("PERSISTENT_ATTRIBUTES "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_VERIFY) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("VERIFY "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_REBUILD) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("REBUILD "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_COW) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("SNAP_SHOTTING "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_VIRTUAL_FILES) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("VIRTUAL_FILES "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_USER_TRANSACTION) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("USER_TRANSACTIONS_PENDING "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_USER_TRANSACTION_ACTIVE) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("USER_TRANSACTION "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_DONT_BACKUP) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("DONT_BACKUP "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_MFL) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("MFL "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_DIR_QUOTAS) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("DIRECTORY_QUOTAS "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_SHRED_DATA) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("SHRED_DATA "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_SHARED) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("SHARED "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_HIGH_INTEGRITY) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("HIGH_INTEGRITY "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_CFS_MASTER) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("CFS_MASTER "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_CFS_SLAVE) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("CFS_SLAVE "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_MIGRATION) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("MIGRATION "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_ENCRYPTED) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("ENCRYPTED "))) != zOK) + { + goto exit; + } + } + if (attributes & zATTR_NO_ATIME) + { + if ((status = VIRT_AddResultData(virtInfo, + MSGNot("NO_ACCESS_TIME "))) != zOK) + { + goto exit; + } + } + + if (supportedFlag) + { + status = VIRT_AddResultTag(virtInfo, TAG_SUPPORTEDATTRIBUTES, TRUE, + TRUE); + } + else + { + status = VIRT_AddResultTag(virtInfo, TAG_ENABLEDATTRIBUTES, TRUE, + TRUE); + } +exit: + return status; +} + + +/**************************************************************************** + * Given a volume, find the supported name spaces + ****************************************************************************/ +STATUS volume_nameSpaces( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + STATUS status; + if ((status = VIRT_AddResultTag(virtInfo, + TAG_NAMESPACES, FALSE, FALSE)) != zOK) + { + goto exit; + } + + if (volume->VOLnameSpaceMask & zNSPACE_DOS_MASK) + { + if ((status = VIRT_AddResultData(virtInfo, MSGNot("DOS "))) != zOK) + { + goto exit; + } + } + if (volume->VOLnameSpaceMask & zNSPACE_LONG_MASK) + { + if ((status = VIRT_AddResultData(virtInfo, MSGNot("LONG "))) != zOK) + { + goto exit; + } + } + if (volume->VOLnameSpaceMask & zNSPACE_MAC_MASK) + { + if ((status = VIRT_AddResultData(virtInfo, MSGNot("MAC "))) != zOK) + { + goto exit; + } + } + if (volume->VOLnameSpaceMask & zNSPACE_UNIX_MASK) + { + if ((status = VIRT_AddResultData(virtInfo, MSGNot("UNIX "))) != zOK) + { + goto exit; + } + } + if (volume->VOLnameSpaceMask & zNSPACE_DATA_STREAM_MASK) + { + if ((status = VIRT_AddResultData(virtInfo, MSGNot("DATA_STREAM "))) != zOK) + { + goto exit; + } + } + if (volume->VOLnameSpaceMask & zNSPACE_EXTENDED_ATTRIBUTE_MASK) + { + if ((status = VIRT_AddResultData(virtInfo, MSGNot("EXTENDED_ATTRIBUTE "))) != zOK) + { + goto exit; + } + } + status = VIRT_AddResultTag(virtInfo, TAG_NAMESPACES, TRUE, TRUE); + +exit: + return status; +} + + +/**************************************************************************** + * Given a volume, find the number of files residing on the volume + ****************************************************************************/ +STATUS volume_files( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLnumFiles); + return VIRT_AddResultElement(virtInfo, TAG_FILES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the maximum file size for the volume + ****************************************************************************/ +STATUS volume_maxFileSize( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLmaximumFileSize); + return VIRT_AddResultElement(virtInfo, TAG_MAXFILESIZE, data, TRUE); +} + + +#if NSS_DEBUG IS_ENABLED +/**************************************************************************** + * Given a volume, find the number of objects on the volume + ****************************************************************************/ +STATUS volume_objects( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLnumObjects); + return VIRT_AddResultElement(virtInfo, TAG_TOTALOBJECTS, data, TRUE); +} +#endif + + +/**************************************************************************** + * Given a volume, find the total entries on the volume * + ****************************************************************************/ +STATUS volume_totalEntries( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), UI64_CONST(0x7FFFFFFFFFFFFFFF)); + return VIRT_AddResultElement(virtInfo, TAG_TOTALENTRIES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the used entries on the volume + ****************************************************************************/ +STATUS volume_usedEntries( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLnumObjects); + return VIRT_AddResultElement(virtInfo, TAG_USEDENTRIES, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the percentage of used entries on the volume * + ****************************************************************************/ +STATUS volume_usedEntriesPercent( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%d"), 100 * volume->VOLnumObjects/UI64_CONST(0x7FFFFFFFFFFFFFFF)); + return VIRT_AddResultElement(virtInfo, TAG_PERCENTENTRIESUSED, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the number of times the volume has been rebuilt + ****************************************************************************/ +STATUS volume_rebuildTimes( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->p.rebuildCount); + return VIRT_AddResultElement(virtInfo, TAG_REBUILDCOUNT, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the mount status of the volume * + ****************************************************************************/ +STATUS volume_mountStatus( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + GeneralMsg_s genMsg; + LONG result = 0; +#ifndef __linux__ // LINUX_NetWareVol + LONG volNumber; +#endif + typedef struct Stack_s { + char volName[zMAX_COMPONENT_NAME]; + unicode_t vname[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + if (COMN_GetVolumeName(&genMsg, volume, aStack->vname, zMAX_COMPONENT_NAME) != zOK) + { + zASSERT("Error getting volume name" == NULL); + STACK_FREE(); + return GetErrno(&genMsg); + } + LB_UnicodeToByte(NSS_UNI_CONVERSION_RAW, &aStack->volName[1], + zMAX_COMPONENT_NAME, aStack->vname, NULL); + aStack->volName[0] = strlen(&aStack->volName[1]); + +#ifndef __linux__ // LINUX_NetWareVol + ZOS_MapVolumeNameToNumber(result, (BYTE *)aStack->volName, &volNumber); +#endif + if (result == 0) + { + sprintf(data, MSGNot("MOUNTED")); + } + else + { + sprintf(data, MSGNot("DISMOUNTED")); + } + STACK_FREE(); + return VIRT_AddResultElement(virtInfo, TAG_MOUNTEDSTATUS, data, TRUE); +} + + +/**************************************************************************** + * Given a volume, find the NDS ID of this volume* + ****************************************************************************/ +STATUS volume_ndsID( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[64]; + STATUS status; + + status = LB_GUIDToString(&volume->VOLndsObjectID, 64, data); + if (status != zOK) + { + return status; + } + return VIRT_AddResultElement(virtInfo, TAG_NDSID, data, TRUE); +} + +/**************************************************************************** + * Given a volume, find the read ahead blocks on the volume + ****************************************************************************/ +STATUS volume_readAhead( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[20]; + + sprintf(data, MSGNot("%u"), volume->readAheadBlocks); + return VIRT_AddResultElement(virtInfo, TAG_READAHEADBLOCKS, data, TRUE); +} + +/**************************************************************************** + * Given a volume, find the next allocatable zid on the volume + ****************************************************************************/ +STATUS volume_nextZid( + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + utf8_t data[MAX_QUAD_LEN_IN_DECIMAL_WITH_NULL]; + + sprintf(data, MSGNot("%Lu"), volume->VOLnextZid); + return VIRT_AddResultElement(virtInfo, TAG_VOLNEXTZID, data, TRUE); +} + + +/**************************************************************************** + * volume_getExtendedInfo - returns extended 'getinfo' information about a + * volume. Allows the LSS that owns the volume to return LSS + * specific information also. + ****************************************************************************/ +/* VIRTUAL FILE -- READ FUNCTION */ +STATUS volume_getExtendedInfo( + NINT parmLen, + utf8_t *parm, + VirtInfo_s *virtInfo, + Volume_s *volume) +{ + STATUS status; + GeneralMsg_s genMsg; + typedef struct + { + unicode_t uni_pname[zMAX_COMPONENT_NAME]; + BYTE data[6*1024]; + VCO_VolumeCommonOps_s pCD; + } AllocStuff_s; + AllocStuff_s *as; + NINT retLen = 0; + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + as = zalloc( sizeof( *as ) ); + if ( as == NULL ) + { + MPKNSS_UNLOCK(); + return(zERR_NO_MEMORY); + } + + if (COMN_GetVolumeName( &genMsg, volume, + as->pCD.u.VCO_getInfo.VGI_volumeName, + NELEMS( as->pCD.u.VCO_getInfo.VGI_volumeName ) ) != zOK) + { + status = GetErrno(&genMsg); + goto exit; + } + + COMN_USE_BEAST( &volume->VOLroot ); /* VOL_commandFunction inherits count */ + /* Ensure volume state does not change so that all + * objects report items from the same state. + * + * NOTE - the COMN Ops use to do this BUT it is illegal for + * a thread to get TWO shared latches(even if there are no yields). + * This comes about as the first shared latch may yield. If thread + * A has a Xlatch. Thread B must wait to get a Slatch. Thread C + * must wait to get a Xlatch. Thread A unlatches, Thread B gets + * a Slatch, but waits(deadlocks) for the 2nd Slatch, because + * Thread C requested a Xlatch. + */ + S_LATCH( &volume->stateLatch ); + as->pCD.u.VCO_getInfo.VGI_action = 0; + status = volume->VOLcomnVolOps.VOL_commandFunction( + &genMsg, volume, VCO_VOLUME_GET_INFO_NUMBER, &as->pCD, + parmLen, parm, + /*dataLen*/ 0, /*data*/ NULL, /*offset*/ 0, + sizeof( as->data ), as->data, &retLen); + UNS_LATCH( &volume->stateLatch ); + + if ( status != zOK ) + { +#if NSS_DEBUG IS_ENABLED +#ifdef USER_GPACHNER + DBG_DebugPrintf(CYAN,"%s VOL_commandFunction(%U) returned %ld from %s\n", + WHERE, as->pCD.u.VCO_getInfo.VGI_volumeName, + GetErrno( &genMsg ), GetErrnoSetter( &genMsg ) ); +#endif +#endif + status = GetErrno(&genMsg); + goto exit; + } + status = VIRT_AddResultData(virtInfo, as->data); + +exit: + free(as); + return status; +} /* End of volume_getInfo() */ + +#define COOKIE_BUF_SIZE 4096 +typedef struct INFControlCookie_s +{ + union + { + UserID_t uCursor; + Zid_t dCursor; + } u; + BOOL done; /* Is enumeration done? */ + SNINT resultLen; + BYTE resultBuf[COOKIE_BUF_SIZE]; +} INFControlCookie_s; + +#define TRUSTEE_COOKIE_ALLOC_SIZE 4096 +typedef struct TrusteeControlCookie_s +{ + Zid_t cursor; + BOOL done; /* Is enumeration done? */ + SNINT resultLen; + SNINT resultBufLen; + BYTE *resultBuf; +} TrusteeControlCookie_s; + +/**************************************************************************** + * Allocate a cookie structure for user info. + ****************************************************************************/ +STATUS allocateINFCookie( + VirtInfo_s *virtInfo, + BOOL isUser) +{ + INFControlCookie_s *cookie; + + /* If we have not allocated a cookie then do so. */ + if (virtInfo->memPtr == NULL) + { + cookie = zalloc(sizeof(INFControlCookie_s)); + if (cookie == NULL) + { + return zERR_NO_MEMORY; + } + virtInfo->memPtr = cookie; + virtInfo->closeFunc = NULL; + + if (isUser) + { + cookie->u.uCursor = zINVALID_USERID; + } + else + { + cookie->u.dCursor = zINVALID_ZID; + } + cookie->done = FALSE; + cookie->resultLen = 0; + } + return zOK; +} + +/**************************************************************************** + * Send whatever is in the cookie buffer. Return TRUE if we filled the + * output buffer. + ****************************************************************************/ +BOOL sendINFResult( + INFControlCookie_s *cookie, + NINT *bufBytesLeft, + BYTE **outBuf, + NINT *outLen) +{ + NINT retLen; + + if (cookie->resultLen > 0) + { + retLen = (*bufBytesLeft < cookie->resultLen) + ? *bufBytesLeft : cookie->resultLen; + if (retLen > 0) + { + memmove(*outBuf, cookie->resultBuf, retLen); + *outBuf += retLen; + *outLen += retLen; + *bufBytesLeft -= retLen; + cookie->resultLen -= retLen; + if (cookie->resultLen > 0) + { + memmove(cookie->resultBuf, (cookie->resultBuf + retLen), + cookie->resultLen); + } + } + } + return !(*bufBytesLeft); +} + +/**************************************************************************** + * Generate the user list for this volume. + * NOTE: This is a cookie type read function. + ****************************************************************************/ +/* VIRTUAL FILE -- READ FUNCTION */ +STATUS volume_userInfo( + NINT parmLen, + utf8_t *parm, + VirtInfo_s *virtInfo) +{ + enum + { + MAX_USER_INFO_ENTRIES = 16, + }; + + STATUS status; + Volume_s *volume; + GeneralMsg_s genMsg; + NINT numEntriesRequested; + NINT numEntriesObtained; + NINT i; + INFControlCookie_s *cookie; + NINT bufBytesLeft = virtInfo->resultBufferSize; + BYTE *outBuf = virtInfo->resultBuffer; + NINT *retLen = &virtInfo->resultEOF; + char id[GUID_FORMAT_SIZE]; + NINT ccode; +#ifndef __linux__ // LINUX_NetWareVol + int context; +#endif + Time_t timeNotFound; + NINT numberOfTimesNotFound; + char timeString[32]; + + struct + { + struct + { + unicode_t *namePtr; + unicode_t uniName[MAX_DN_CHARS+1]; + } name; + unicode_t uniName[MAX_DN_CHARS+1]; + BYTE volName[zMAX_COMPONENT_NAME]; + COMNUserRest_s userInfo[MAX_USER_INFO_ENTRIES]; + } *alloc = NULL; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + *retLen = 0; + + + if ((status = allocateINFCookie(virtInfo, TRUE)) != zOK) + { + goto done; + } + + cookie = (INFControlCookie_s *)virtInfo->memPtr; + /* + * Send anything that happens to be held in the cookie buffer. If this + * fills the output buffer then we are done with this request. + */ + if (sendINFResult(cookie, &bufBytesLeft, &outBuf, retLen)) + { + goto done; + } + + if (cookie->done) + { + goto done; + } + + if (LB_GUIDCompare(&cookie->u.uCursor, &zINVALID_USERID) == 0) + { + /* send out the start tag */ + strcpy(cookie->resultBuf, MSGNot("<"TAG_NSSREPLY">\n<" + TAG_USERINFO">\n")); + cookie->resultLen = strlen(cookie->resultBuf); + } + +#ifndef __linux__ // LINUX_NetWareVol + if (CHK_GetContext(&context) != zOK) + { + zASSERT("Error getting context for user info" == NULL); + status = zFAILURE; + goto sendRetcode; + } +#endif + + /* allocate memory for return data and for path */ + alloc = malloc(sizeof(*alloc)); + if (!alloc) + { + status = zERR_NO_MEMORY; + goto sendRetcode; + } + + /* Obtain the volume ptr */ + memcpy(alloc->volName, parm, parmLen); + alloc->volName[parmLen] = 0; + if ((status = findVolume(alloc->volName, &volume)) != zOK) + { + status = zERR_VOLUME_NOT_FOUND; + goto errorFree; + } + if (COMN_LockVolumeActive(&genMsg, volume, FALSE) != zOK) + { + status = GetErrno(&genMsg); + goto errorRelease; + } + + while (bufBytesLeft > 0 && !cookie->done) + { + numEntriesRequested = MAX_USER_INFO_ENTRIES; + if (volume->VOLcomnVolOps.VOL_browseUsersInVolume(&genMsg, volume, + MAX_USER_INFO_ENTRIES, &cookie->u.uCursor, alloc->userInfo, + &numEntriesObtained, BROWSE_USERS_GET_ALL) != zOK) + { + status = GetErrno(&genMsg); + goto errorUnlock; + } + if (numEntriesObtained == 0) + { + cookie->done = TRUE; + } + + for (i = 0; i < numEntriesObtained; ++i) + { +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LCYAN, "volume_userInfo:Validating user %x\n", alloc->userInfo[i].userID.timeLow); +#endif + (void)LB_GUIDToString(&alloc->userInfo[i].userID, GUID_FORMAT_SIZE, id); + /* put out standard user info */ + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("<" TAG_USER "><" TAG_ID ">%s<" + TAG_SPACEUSED ">%Ld<" + TAG_QUOTAAMOUNT ">%Ld\n"), + id, alloc->userInfo[i].usedAmount, alloc->userInfo[i].restrictionAmount); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + + /* + * Get the object's name and check to make sure the name can still + * be found in NDS. + */ + + if ((volume->VOLcomnVolOps.VOL_getObjectName(&genMsg, volume, + &alloc->userInfo[i].userID, alloc->uniName, &timeNotFound, + &numberOfTimesNotFound) != zOK) || + (alloc->uniName[0] == 0)) + { + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("<" TAG_NAME ">unknown\n")); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + } + else + { + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("<" TAG_NAME ">%U\n"), + alloc->uniName); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + #if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(YELLOW, + "volume_userInfo: Found User=%U\n", &alloc->uniName); + #endif +#ifdef __linux__ // LINUX_NetWareVol + ccode = zFAILURE; +#else + /* + * Check to make sure we can still look up this name. + */ + MPKNSS_UNLOCK(); + ccode = (*DDCNameToIDPtr)(context, DS_CREATE_ID, + &alloc->uniName); + MPKNSS_LOCK(); +#endif + if (ccode != 0) + { + /* + * Got an error looking up the name. Add "not found" tag. + */ + #if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED, "volume_userInfo: User %U not found in NDS.\n", alloc->uniName); + #endif + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("<" TAG_IDNOTFOUND "><" TAG_TIME "><" + TAG_UTC ">%d<" + TAG_STRING ">%s<" + TAG_NUMBEROFTIMES ">%d\n"), + timeNotFound, UTCTime2Str(timeNotFound, timeString), + numberOfTimesNotFound); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + } + } + #if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LCYAN, "user finished: %U\n", &alloc->uniName); + #endif + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("\n")); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + cookie->u.uCursor = alloc->userInfo[i].userID; + if (sendINFResult(cookie, &bufBytesLeft, &outBuf, retLen)) + { + break; + } + } + } +errorUnlock: + COMN_UnlockVolumeActive(volume, FALSE); +errorRelease: + COMN_Release(&volume); +errorFree: + free(alloc); + +sendRetcode: + if (status != zOK) + { + cookie->done = TRUE; + } + if (cookie->done) + { + /* send the status */ + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("\n")); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + MGMT_BuildResultNSS(status, + cookie->resultBuf + cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("\n")); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + sendINFResult(cookie, &bufBytesLeft, &outBuf, retLen); + } + +done: + MPKNSS_UNLOCK(); + return zOK; +} + +/**************************************************************************** + * Generate a list of directory quotas for the volume. + * NOTE: This is a cookie type read function. + ****************************************************************************/ +/* VIRTUAL FILE -- READ FUNCTION */ +STATUS volume_dirInfo( + NINT parmLen, + utf8_t *parm, + VirtInfo_s *virtInfo) +{ + enum + { + MAX_DIR_INFO_ENTRIES = 16, + }; + + STATUS status; + Volume_s *volume; + GeneralMsg_s genMsg; + NINT numEntriesRequested; + NINT numEntriesObtained; + NINT i; + INFControlCookie_s *cookie; + NINT bufBytesLeft = virtInfo->resultBufferSize; + BYTE *outBuf = virtInfo->resultBuffer; + NINT *retLen = &virtInfo->resultEOF; + unicode_t *path; + typedef struct Stack_s { + BYTE volName[zMAX_COMPONENT_NAME]; + COMNDirQuota_s dirInfo[MAX_DIR_INFO_ENTRIES]; + } Stack_s; + STACK_ALLOC(); + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + *retLen = 0; + + + if ((status = allocateINFCookie(virtInfo, FALSE)) != zOK) + { + goto done; + } + + cookie = (INFControlCookie_s *)virtInfo->memPtr; + /* + * Send anything that happens to be held in the cookie buffer. If this + * fills the output buffer then we are done with this request. + */ + if (sendINFResult(cookie, &bufBytesLeft, &outBuf, retLen)) + { + goto done; + } + + if (cookie->done) + { + goto done; + } + + if (cookie->u.dCursor == zINVALID_ZID) + { + /* send out the start tag */ + strcpy(cookie->resultBuf, MSGNot("<"TAG_NSSREPLY">\n<" + TAG_DIRINFO">\n")); + cookie->resultLen = strlen(cookie->resultBuf); + } + + /* allocate memory for return data and for path */ + path = malloc(zMAX_FULL_NAME * sizeof(unicode_t)); + if (!path) + { + status = zERR_NO_MEMORY; + goto sendRetcode; + } + + /* 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 errorFree; + } + if (COMN_LockVolumeActive(&genMsg, volume, FALSE) != zOK) + { + status = GetErrno(&genMsg); + goto errorRelease; + } + + while (bufBytesLeft > 0 && !cookie->done) + { + numEntriesRequested = MAX_DIR_INFO_ENTRIES; + if (volume->VOLcomnVolOps.VOL_browseDirsInVolume(&genMsg, volume, + MAX_DIR_INFO_ENTRIES, &cookie->u.dCursor, aStack->dirInfo, + &numEntriesObtained) != zOK) + { + status = GetErrno(&genMsg); + goto errorUnlock; + } + if (numEntriesObtained == 0) + { + cookie->done = TRUE; + } + + for (i = 0; i < numEntriesObtained; ++i) + { + if (COMN_GetFileNameFromZid(&genMsg, volume, aStack->dirInfo[i].dirZid, + zNSPACE_LONG, path, FALSE) != zOK) + { + status = GetErrno(&genMsg); + goto errorUnlock; + } + + /* put out standard directory quota info */ + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("<" TAG_DIRECTORY "><" + TAG_ZID ">%Lu<" + TAG_PATH ">%U<" + TAG_SPACEUSED ">%Ld<" + TAG_QUOTAAMOUNT ">%Ld" + "\n"), + aStack->dirInfo[i].dirZid, path, aStack->dirInfo[i].usedAmount, + aStack->dirInfo[i].quota); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + cookie->u.dCursor = aStack->dirInfo[i].dirZid; + if (sendINFResult(cookie, &bufBytesLeft, &outBuf, retLen)) + { + break; + } + } + } +errorUnlock: + COMN_UnlockVolumeActive(volume, FALSE); +errorRelease: + COMN_Release(&volume); +errorFree: + free(path); + +sendRetcode: + if (status != zOK) + { + cookie->done = TRUE; + } + if (cookie->done) + { + /* send the status */ + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("\n")); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + MGMT_BuildResultNSS(status, + cookie->resultBuf + cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("\n")); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + sendINFResult(cookie, &bufBytesLeft, &outBuf, retLen); + } + +done: + MPKNSS_UNLOCK(); + STACK_FREE(); + return zOK; +} + +/**************************************************************************** + * + * This function takes the numeric rights and produces rights tags. + * + ****************************************************************************/ +void convertRightsToTags( + NINT rights, + utf8_t *tags) +{ + utf8_t *pos = tags; + NINT bit; + NINT index; + static NINT bitsToCheck = ( + zAUTHORIZE_READ_CONTENTS | zAUTHORIZE_WRITE_CONTENTS | + zAUTHORIZE_CREATE_ENTRY | zAUTHORIZE_DELETE_ENTRY | + zAUTHORIZE_ACCESS_CONTROL | zAUTHORIZE_SEE_FILES | + zAUTHORIZE_MODIFY_METADATA | zAUTHORIZE_SUPERVISOR | + zAUTHORIZE_SALVAGE | zAUTHORIZE_SECURE); + + utf8_t rightsTags[16][20] = + { + {TAG_READ}, + {TAG_WRITE}, + {""}, + {TAG_CREATE}, + {TAG_ERASE}, + {TAG_ACCESSCONTROL}, + {TAG_FILESCAN}, + {TAG_MODIFY}, + {TAG_SUPERVISOR}, + {TAG_SALVAGE}, + {""}, + {""}, + {""}, + {""}, + {""}, + {TAG_SECURE} + }; + + rights &= bitsToCheck; + + /* Convert the mask to a list of tags */ + for (bit = 1, index = 0; bit != 0; bit <<= 1, index++) + { + if (rights & bit) + { + *(pos++) = '<'; + strcpy(pos, rightsTags[index]); + pos += strlen(rightsTags[index]); + *(pos++) = '/'; + *(pos++) = '>'; + *(pos) = '\0'; + } + } +} + +/**************************************************************************** + * + * This function takes the numeric rights and produces a character string. + * + ****************************************************************************/ +void convertRightsToChars( + NINT rights, + utf8_t *tags) +{ + utf8_t *pos = tags; + NINT bit; + NINT index; + static NINT bitsToCheck = ( + zAUTHORIZE_READ_CONTENTS | zAUTHORIZE_WRITE_CONTENTS | + zAUTHORIZE_CREATE_ENTRY | zAUTHORIZE_DELETE_ENTRY | + zAUTHORIZE_ACCESS_CONTROL | zAUTHORIZE_SEE_FILES | + zAUTHORIZE_MODIFY_METADATA | zAUTHORIZE_SUPERVISOR | + zAUTHORIZE_SALVAGE | zAUTHORIZE_SECURE); + + char rightsChars[16+1] = "rw\0ceafmsv\0\0\0\0\0x"; + + rights &= bitsToCheck; + + /* Convert the mask to a list of tags */ + for (bit = 1, index = 0; bit != 0; bit <<= 1, index++) + { + if (rights & bit) + { + *(pos++) = rightsChars[index]; + *(pos) = '\0'; + } + } +} + +/**************************************************************************** + * Release a cookie structure for trustee info. This is called as a close + * function from the virtual file system. + ****************************************************************************/ +void releaseTrusteeCookie( + VirtInfo_s *virtInfo) +{ + TrusteeControlCookie_s *cookie; + + /* If we have allocated a cookie then cleanup. */ + if (virtInfo->memPtr != NULL) + { + cookie = virtInfo->memPtr; + if (cookie->resultBuf != NULL) + { + free(cookie->resultBuf); + cookie->resultBuf = NULL; + } + } + return; +} + +/**************************************************************************** + * Allocate a cookie structure for trustee info. + ****************************************************************************/ +STATUS allocateTrusteeCookie( + VirtInfo_s *virtInfo) +{ + TrusteeControlCookie_s *cookie; + + /* If we have not allocated a cookie then do so. */ + if (virtInfo->memPtr == NULL) + { + cookie = zalloc(sizeof(TrusteeControlCookie_s)); + if (cookie == NULL) + { + return zERR_NO_MEMORY; + } + virtInfo->memPtr = cookie; + virtInfo->closeFunc = NULL; + + cookie->cursor = zINVALID_ZID; + cookie->done = FALSE; + cookie->resultLen = 0; + cookie->resultBuf = malloc(TRUSTEE_COOKIE_ALLOC_SIZE); + if (cookie->resultBuf == NULL) + { + return zFAILURE; + } + cookie->resultBufLen = TRUSTEE_COOKIE_ALLOC_SIZE; + virtInfo->closeFunc = releaseTrusteeCookie; + } + return zOK; +} + +/**************************************************************************** + * Send whatever is in the cookie buffer. Return TRUE if we filled the + * output buffer. + ****************************************************************************/ +BOOL sendTrusteeResult( + TrusteeControlCookie_s *cookie, + NINT *bufBytesLeft, + BYTE **outBuf, + NINT *outLen) +{ + NINT retLen; + + if (cookie->resultLen > 0) + { + retLen = (*bufBytesLeft < cookie->resultLen) + ? *bufBytesLeft : cookie->resultLen; + if (retLen > 0) + { + memmove(*outBuf, cookie->resultBuf, retLen); + *outBuf += retLen; + *outLen += retLen; + *bufBytesLeft -= retLen; + cookie->resultLen -= retLen; + if (cookie->resultLen > 0) + { + memmove(cookie->resultBuf, (cookie->resultBuf + retLen), + cookie->resultLen); + } + } + } + return !(*bufBytesLeft); +} + +/**************************************************************************** + * Insert a single trustee entry + *****************************************************************************/ +void insertEntry( + Volume_s *volume, + NINT rights, + UserID_t *userID, + TrusteeControlCookie_s *cookie) +{ + GeneralMsg_s genMsg; + typedef struct Stack_s { + unicode_t unicodeDName[MAX_DN_CHARS + 1]; + } Stack_s; + + STACK_ALLOC(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + sprintf(cookie->resultBuf + cookie->resultLen, "<" TAG_TRUSTEE "><" TAG_NAME ">"); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + if (OID_GetObjectName(&genMsg, volume, userID, aStack->unicodeDName) != zOK) + { + sprintf(cookie->resultBuf + cookie->resultLen, + "Unknown(%d)", GetErrno(&genMsg)); + } + else + { + uni2utf(aStack->unicodeDName, cookie->resultBuf + cookie->resultLen, + cookie->resultBufLen - cookie->resultLen); + } + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, "<" TAG_ID ">"); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + LB_GUIDToString(userID, cookie->resultBufLen - cookie->resultLen, + cookie->resultBuf + cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, + "<" TAG_RIGHTS " " ATR_VALUE "=\""); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + convertRightsToChars(rights, cookie->resultBuf + cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, "\">"); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + convertRightsToTags(rights, cookie->resultBuf + cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, "\n"); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + STACK_FREE(); + return; +} + +/**************************************************************************** + * Insert all trustees for a beast + *****************************************************************************/ +void insertTrustees( + GeneralMsg_s *genMsg, + Volume_s *volume, + File_s *beast, + TrusteeControlCookie_s *cookie) +{ + ZASAuthorizeInfo_s *authInfo; + ZasAclOverflowBeast_s *overflowBeast; + NINT i; + Zid_t overflowZid; + NINT entry; + BYTE *newBuf; + + authInfo = beast->FILEauthInfo.zas; + + if ((authInfo->p.inheritedRightsMask != 0xFFFFFFFF) && + (authInfo->p.inheritedRightsMask != 0xFFFF) && + (authInfo->p.inheritedRightsMask != 0x1FF)) + { + sprintf(cookie->resultBuf + cookie->resultLen, + "<" TAG_INHERITEDRIGHTSFILTER " " ATR_VALUE "=\""); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + convertRightsToChars(authInfo->p.inheritedRightsMask, + cookie->resultBuf + cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, "\">"); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + convertRightsToTags(authInfo->p.inheritedRightsMask, + cookie->resultBuf + cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, + "\n"); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + } + + if ((authInfo->p.numTrusteesAssigned == 0) && + (authInfo->p.trusteeOverflow == NULL)) + { + return; + } + + if (authInfo->p.numTrusteesAssigned) + { + /* search the main beast for the trustees */ + for (i = 0; i < authInfo->p.numTrusteesAssigned && i < 4; i++) + { + insertEntry(volume, authInfo->p.ACL[i].rights, + &authInfo->p.ACL[i].trusteeID, cookie); + } + } + + overflowZid = authInfo->p.trusteeOverflow; + if (overflowZid != zINVALID_ZID) + { + for (;;) + { /* find an overflow beast with an open entry */ + overflowBeast = COMN_LookupByZid(genMsg, beast->FILEvolume, + overflowZid, SLATCHED, FALSE); + if (overflowBeast == NULL) + { /* error */ + break; + } + for (entry=0; entry < overflowBeast->p.numEntries; entry++) + { + insertEntry(volume, overflowBeast->acl[entry].rights, + &overflowBeast->acl[entry].trusteeID, cookie); + if (cookie->resultLen + TRUSTEE_COOKIE_ALLOC_SIZE > + cookie->resultBufLen) + { + cookie->resultBufLen += TRUSTEE_COOKIE_ALLOC_SIZE; + newBuf = realloc(cookie->resultBuf, cookie->resultBufLen); + if (newBuf == NULL) + { + cookie->resultBufLen -= TRUSTEE_COOKIE_ALLOC_SIZE; + break; + } + cookie->resultBuf = newBuf; + } + } + overflowZid = overflowBeast->p.nextOverflowZid; + COMN_UnlatchAndRelease(&overflowBeast, SLATCHED); + } + } + + return; +} + +/**************************************************************************** + * Generate a list of trustees for the volume. + * NOTE: This is a cookie type read function. + ****************************************************************************/ +/* VIRTUAL FILE -- READ FUNCTION */ +STATUS volume_trusteeInfo( + NINT parmLen, + utf8_t *parm, + VirtInfo_s *virtInfo) +{ + enum + { + MAX_ZID_ENTRIES = 100, + }; + + NINT i; + STATUS status; + Volume_s *volume; + GeneralMsg_s genMsg; + NINT numEntriesRequested; + NINT numEntriesObtained; + TrusteeControlCookie_s *cookie; + NINT bufBytesLeft = virtInfo->resultBufferSize; + BYTE *outBuf = virtInfo->resultBuffer; + NINT *retLen = &virtInfo->resultEOF; + ZASAuthorizeInfo_s *authInfo; +#if zLINUX + NINT nameSpace = zNSPACE_UNIX; +#else + NINT nameSpace = zNSPACE_LONG; +#endif + unicode_t *uniPath = NULL; + typedef struct Stack_s { + BYTE volName[zMAX_COMPONENT_NAME]; + Zid_t zidArray[MAX_ZID_ENTRIES]; + } Stack_s; + STACK_ALLOC(); + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + *retLen = 0; + + + if ((status = allocateTrusteeCookie(virtInfo)) != zOK) + { + goto done; + } + + cookie = (TrusteeControlCookie_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 (sendTrusteeResult(cookie, &bufBytesLeft, &outBuf, retLen)) + { + goto done; + } + + if (cookie->done) + { + goto done; + } + + if (cookie->cursor == zINVALID_ZID) + { + /* send out the start tag */ + strcpy(cookie->resultBuf, MSGNot("<"TAG_NSSREPLY">\n<" + TAG_TRUSTEEINFO">\n")); + cookie->resultLen = strlen(cookie->resultBuf); + } + + /* allocate memory for return data and for path */ + uniPath = malloc((zMAX_FULL_NAME + 1) * sizeof(unicode_t)); + if (!uniPath) + { + status = zERR_NO_MEMORY; + goto sendRetcode; + } + + /* 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); + goto errorRelease; + } + + /* Make sure we have the correct auth module */ + if (volume->p.authModelID != zFTYPE_ZAS_AUTH_MODEL) + { + goto errorUnlock; + } + + while (bufBytesLeft > 0 && !cookie->done) + { + RootBeast_s *beast; + + numEntriesRequested = MAX_ZID_ENTRIES; + if (volume->VOLcomnVolOps.VOL_browseBeastsInVolume(&genMsg, volume, + SELECT_BEASTS_ALL, MAX_ZID_ENTRIES, &cookie->cursor, + aStack->zidArray, &numEntriesObtained) != zOK) + { + status = GetErrno(&genMsg); + goto errorUnlock; + } + if (numEntriesObtained == 0) + { + cookie->done = TRUE; + } + + for (i = 0; i < numEntriesObtained; ++i) + { + if ((beast = COMN_LookupByZid(&genMsg, volume, aStack->zidArray[i], + SLATCHED, TRUE)) == NULL) + { + ClearErrno(&genMsg); + continue; + } + + if (!COMN_IsDerivedFrom(beast, zFTYPE_FILE)) + { + COMN_UnlatchAndRelease(&beast, SLATCHED); + continue; + } + + /* if we hit a hardlink that has been deleted, don't process it */ + if( (((NamedBeast_s *)beast)->NAMEDattributes & zFA_HARDLINK) && + (((NamedBeast_s *)beast)->NAMEDfirstParentNameType == zNTYPE_DELETED_FILE)) + { + COMN_UnlatchAndRelease(&beast, SLATCHED); + continue; + } + + /* If this is a beast that is deleted but not purged - ignore */ + if (((NamedBeast_s *)beast)->NAMEDnameFlags & + NFL_ADDED_TO_SALVAGE_TREE) + { + COMN_UnlatchAndRelease(&beast, SLATCHED); + continue; + } + + authInfo = ((File_s *)beast)->FILEauthInfo.zas; + if ((authInfo->p.numTrusteesAssigned == 0) && + (authInfo->p.trusteeOverflow == NULL) && + ((authInfo->p.inheritedRightsMask == 0xFFFFFFFF) || + (authInfo->p.inheritedRightsMask == 0xFFFF) || + (authInfo->p.inheritedRightsMask == 0x1FF))) + { + COMN_UnlatchAndRelease(&beast, SLATCHED); + continue; + } + + if (COMN_GetFileNameFromZid(&genMsg, volume, aStack->zidArray[i], + nameSpace, uniPath, FALSE) != zOK) + { + unicpy(uniPath, L"***Error***\n"); + } + /* put out file name info */ + sprintf(cookie->resultBuf + cookie->resultLen, + "<" TAG_FILE ">\n<" + TAG_ZID ">%Lu<" + TAG_PATH ">", aStack->zidArray[i]); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + + uni2utf(uniPath, cookie->resultBuf + cookie->resultLen, + cookie->resultBufLen - cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + + /* put out file name info */ + sprintf(cookie->resultBuf + cookie->resultLen, "\n"); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + + /* put in the trustees */ + insertTrustees(&genMsg, volume, (File_s *)beast, cookie); + COMN_UnlatchAndRelease(&beast, SLATCHED); + + sprintf(cookie->resultBuf + cookie->resultLen, "\n" ); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + cookie->cursor = aStack->zidArray[i]; + if (sendTrusteeResult(cookie, &bufBytesLeft, &outBuf, retLen)) + { + break; + } + } + } +errorUnlock: + COMN_UnlockVolumeActive(volume, FALSE); +errorRelease: + COMN_Release(&volume); + +sendRetcode: + free(uniPath); + if (status != zOK) + { + cookie->done = TRUE; + } + if (cookie->done) + { + /* send the status */ + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("\n")); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + MGMT_BuildResultNSS(status, + cookie->resultBuf + cookie->resultLen); + cookie->resultLen += strlen(cookie->resultBuf + cookie->resultLen); + sprintf(cookie->resultBuf + cookie->resultLen, + MSGNot("\n")); + cookie->resultLen += strlen(cookie->resultBuf + + cookie->resultLen); + sendTrusteeResult(cookie, &bufBytesLeft, &outBuf, retLen); + } + +done: + MPKNSS_UNLOCK(); + STACK_FREE(); + return zOK; +} + +/**************************************************************************** + * Given a parameter (normally a file path) , find the general info of + * this pool. + ****************************************************************************/ +/* VIRTUAL FILE -- READ FUNCTION */ +STATUS volume_getInfo( + NINT parmLen, + utf8_t *parm, + VirtInfo_s *virtInfo) +{ + STATUS status; + Volume_s *volume = NULL; + typedef struct Stack_s { + BYTE volName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + MPKNSS_LOCK(); + + memcpy(aStack->volName, parm, parmLen); + aStack->volName[parmLen] = 0; + + if ((status = VIRT_AddResultTag(virtInfo, TAG_NSSREPLY, FALSE, TRUE)) + != zOK) + { + goto done; + } + + if ((status = findVolume(aStack->volName, &volume)) == zOK) + { + if ((status = VIRT_AddResultTag(virtInfo, TAG_VOLUMEINFO, FALSE, TRUE)) + != zOK) + { + goto done; + } + + if (volume->VOLpState == zVOL_PSTATE_DELETION) + { + if ((status = VIRT_AddResultData(virtInfo, "<"TAG_DELETEDVOLUME"/>\n")) + != zOK) + { + goto done; + } + } + /* + * put in what used to be called "extended info" including lss specific + * info. + */ + if ((status = + volume_getExtendedInfo(parmLen, parm, virtInfo, volume)) != zOK) + { + goto done; + } + /* + * put in the user usage statistics + */ + if ((status = volume_mountStatus(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = + VIRT_AddResultTag(virtInfo, TAG_USERIO, FALSE, TRUE)) != zOK) + { + goto done; + } + if ((status = volume_userReadSize(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_userReadCount(virtInfo, volume)) != zOK) + { + goto done; + } +#if NSS_DEBUG IS_ENABLED + if ((status = volume_userReadFailure(virtInfo, volume)) != zOK) + { + goto done; + } +#endif + if ((status = volume_userWriteSize(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_userWriteCount(virtInfo, volume)) != zOK) + { + goto done; + } +#if NSS_DEBUG IS_ENABLED + if ((status = volume_userWriteFailure(virtInfo, volume)) != zOK) + { + goto done; + } +#endif + if ((status = + VIRT_AddResultTag(virtInfo, TAG_USERIO, TRUE, TRUE)) != zOK) + { + goto done; + } +#if NSS_DEBUG IS_ENABLED + /* + * put in the system usage statistics + */ + if ((status = + VIRT_AddResultTag(virtInfo, TAG_SYSTEMIO, FALSE, TRUE)) != zOK) + { + goto done; + } + if ((status = volume_systemReadSize(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_systemReadCount(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_systemReadFailure(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_systemWriteSize(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_systemWriteCount(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_systemWriteFailure(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = + VIRT_AddResultTag(virtInfo, TAG_SYSTEMIO, TRUE, TRUE)) != zOK) + { + goto done; + } +#endif + /* + * put in the compression info + */ + if ((status = + VIRT_AddResultTag(virtInfo, TAG_COMPRESSION, FALSE, TRUE)) != zOK) + { + goto done; + } + if ((status = volume_compPreCompressedBytes(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_compCompressedBytes(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_compCompDeletedFiles(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_compUnableFiles(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = + VIRT_AddResultTag(virtInfo, TAG_COMPRESSION, TRUE, TRUE)) != zOK) + { + goto done; + } + /* + * put in the salvage info + */ + if ((status = VIRT_AddResultTag(virtInfo, TAG_SALVAGE, FALSE, + TRUE)) != zOK) + { + goto done; + } + if ((status = volume_salHighWaterMark(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_salLowWaterMark(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_salMaxKeepSeconds(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_salMinKeepSeconds(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_salFreeableSize(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_salNonFreeableSize(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_salDeletedFiles(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = VIRT_AddResultTag(virtInfo, TAG_SALVAGE, TRUE, + TRUE)) != zOK) + { + goto done; + } + /* + * put in the general information + */ + if ((status = volume_size(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_notInUseSize(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_blockSize(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_nextZid(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_attributes(virtInfo, volume, TRUE)) != zOK) + { + goto done; + } + if ((status = volume_attributes(virtInfo, volume, FALSE)) != zOK) + { + goto done; + } + if ((status = volume_nameSpaces(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_files(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_maxFileSize(virtInfo, volume)) != zOK) + { + goto done; + } +#if NSS_DEBUG IS_ENABLED + if ((status = volume_objects(virtInfo, volume)) != zOK) + { + goto done; + } +#endif + if ((status = volume_totalEntries(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_usedEntries(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_usedEntriesPercent(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_rebuildTimes(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_ndsID(virtInfo, volume)) != zOK) + { + goto done; + } + if ((status = volume_readAhead(virtInfo, volume)) != zOK) + { + goto done; + } +// being done in the extended info at the start +// if ((status = volume_poolName(virtInfo, volume)) != zOK) +// { +// goto done; +// } + if ((status = VIRT_AddResultTag(virtInfo, TAG_VOLUMEINFO, TRUE, TRUE)) + != zOK) + { + goto done; + } +done: + COMN_Release(&volume); + } + + if (status != zERR_NO_MEMORY) + { + MGMT_ReturnResultNSS(virtInfo, status); + VIRT_AddResultTag(virtInfo, TAG_NSSREPLY, TRUE, TRUE); + status = zOK; + } + MPKNSS_UNLOCK(); + STACK_FREE(); + return status; +} + +typedef struct VolAVFileInst_s +{ + BYTE *path; + BOOL isDir; + BOOL useCookieRead; + BOOL createNonPersistent; + BYTE *readFunctionName; + BYTE *writeFunctionName; + STATUS (*readFunction)(); + STATUS (*writeFunction)(); +}VolAVFileInst_s; + +VolAVFileInst_s VolumeInst[] = +{ + {NULL, TRUE, FALSE, TRUE, NULL, NULL, NULL, NULL}, + {NULL, FALSE, TRUE, TRUE, MSGNot("EFL_ControlReadFunc"), MSGNot("EFL_ControlWriteFunc"), EFL_ControlReadFunc, EFL_ControlWriteFunc}, + {NULL, FALSE, TRUE, TRUE, MSGNot("SBS_volumeMFLControlReadFunc"), MSGNot("SBS_volumeMFLControlWriteFunc"), SBS_volumeMFLControlReadFunc, SBS_volumeMFLControlWriteFunc}, + {NULL, FALSE, FALSE, TRUE, MSGNot("volume_getInfo"), NULL, volume_getInfo, NULL}, + {NULL, FALSE, TRUE, TRUE, MSGNot("volume_userInfo"), NULL, volume_userInfo, NULL}, + {NULL, FALSE, TRUE, TRUE, MSGNot("volume_dirInfo"), NULL, volume_dirInfo, NULL}, + {NULL, FALSE, TRUE, TRUE, MSGNot("volume_trusteeInfo"), NULL, volume_trusteeInfo, NULL}, + {0}, +}; + + +void initVolMgmtFile () +{ + NINT i; + + i = 0; + VolumeInst[i++].path = MSGNot("Volume\\%s"); + VolumeInst[i++].path = MSGNot("Volume\\%s\\FileEvents.xml"); + VolumeInst[i++].path = MSGNot("Volume\\%s\\ModifiedFilesList.xml"); + VolumeInst[i++].path = MSGNot("Volume\\%s\\VolumeInfo.xml"); + VolumeInst[i++].path = MSGNot("Volume\\%s\\UserInfo.xml"); + VolumeInst[i++].path = MSGNot("Volume\\%s\\DirInfo.xml"); + VolumeInst[i++].path = MSGNot("Volume\\%s\\TrusteeInfo.xml"); + + VolumeInstPathIsSetUp = TRUE; +} + +/*************************************************************************** + * Add loaded volume as management files * + ***************************************************************************/ +STATUS addVolumeMgmtFile( + GeneralMsg_s *genMsg, + unicode_t *volumeName) +{ + BYTE *pathStr; +// BYTE pathStr[zMAX_FULL_NAME]; + NINT i; + NINT createAttr; + STATUS status; + Key_t rootKey; + Key_t retKey; + typedef struct Stack_s { + BYTE name[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + if (VolumeInstPathIsSetUp == FALSE) + { + initVolMgmtFile(); + } + + /* + * FixFixFix -- when we get the automatic stack growth we can take the + * malloc out and use the stack. + */ + pathStr = malloc(zMAX_FULL_NAME); + if (pathStr == NULL) + { + goto errorExit; + } + + /* setup the root key for file operations */ + ZOS_zRootKey(status, 0, &rootKey); + if (status != zOK) + { + zASSERT("Error getting root key" == 0); + SetErrno(genMsg, status); + goto errorFree; + } + + strcpy((char *)pathStr, (char *)AVFileMgmtDir); + + if (VolumeBaseDirIsSetUp == FALSE) + { + strcpy(&pathStr[AVFileMgmtDirLen], MSGNot("Volume")); + + ZOS_zCreate(status, rootKey, zNO_TASK, 0, + zNSPACE_LONG | zMODE_UTF8, pathStr, zFILE_REGULAR, AVFILEDIRATTR, + zCREATE_OPEN_IF_THERE, zRR_WRITE_ACCESS, &retKey); + if (status != zOK) + { + zASSERT("Error creating volume admin directory" == 0); + SetErrno(genMsg, status); + goto errorClose; + } + + ZOS_zClose(status, retKey); + zASSERT(status == zOK); + + VolumeBaseDirIsSetUp = TRUE; + } + + LB_UnicodeToByte(NSS_UNI_CONVERSION_RAW, aStack->name, zMAX_COMPONENT_NAME, + volumeName, NULL); + + for(i = 0; VolumeInst[i].path != 0; i++) + { + /* + * If the persistent admin volume is not active then only create + * files that are flagged for non-persistent creation. + */ + if (!(VolumeInst[i].createNonPersistent || PersistAdminVolume)) + { + continue; + } + + sprintf(&pathStr[AVFileMgmtDirLen], VolumeInst[i].path, (BYTE *)aStack->name); + + if (VolumeInst[i].isDir) + { + createAttr = AVFILEDIRATTR; + } + else + { + createAttr = AVFILEFILEATTR; + } + + ZOS_zCreate(status, rootKey, zNO_TASK, 0, + zNSPACE_LONG | zMODE_UTF8, pathStr, zFILE_REGULAR, + createAttr, zCREATE_OPEN_IF_THERE, zRR_WRITE_ACCESS, &retKey); + if (status != zOK) + { + /* + * This check is here because of a bug in zCreate. It can be + * removed when zCreate opens an existing directory without + * an error. + */ + if (status != zERR_FILE_ALREADY_EXISTS) + { + SetErrno(genMsg, status); + zASSERT("Error during create" == 0); + goto errorClose; + } + ZOS_zOpen(status, rootKey, zNO_TASK, zNSPACE_LONG | zMODE_UTF8, + pathStr, zRR_WRITE_ACCESS, &retKey); + } + + if (!VolumeInst[i].isDir) + { + /* Write the transformation template to the file */ + if ((status = MGMTS_MakeFunctionVirtualFile(retKey, + VolumeInst[i].readFunctionName, aStack->name, + VolumeInst[i].writeFunctionName, aStack->name, + VolumeInst[i].useCookieRead)) != zOK) + { + zASSERT("Error writing transformation template" == 0); + SetErrno(genMsg, status); + ZOS_zClose(status, retKey); + goto errorClose; + } +#if zLINUX + if (MGMT_VolumeFunctionsRegistered == 0) + { + MPKNSS_UNLOCK(); + if (VolumeInst[i].readFunctionName) + { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)) + inter_module_register(VolumeInst[i].readFunctionName, + THIS_MODULE, VolumeInst[i].readFunction); +#else + nss_register_module(VolumeInst[i].readFunctionName, + VolumeInst[i].readFunction, THIS_MODULE ); +#endif + } + if (VolumeInst[i].writeFunctionName) + { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)) + inter_module_register(VolumeInst[i].writeFunctionName, + THIS_MODULE, VolumeInst[i].writeFunction); +#else + nss_register_module(VolumeInst[i].writeFunctionName, + VolumeInst[i].writeFunction, THIS_MODULE); +#endif + } + MPKNSS_LOCK(); + } +#endif + } + + ZOS_zClose(status, retKey); + zASSERT(status == zOK); + } + + MGMT_VolumeFunctionsRegistered++; + ZOS_zClose(status, rootKey); + zASSERT(status == zOK); + free(pathStr); + STACK_FREE(); + return zOK; + +errorClose: + ZOS_zClose(status, rootKey); + zASSERT(status == zOK); +errorFree: + free(pathStr); +errorExit: + STACK_FREE(); + return zFAILURE; +} + +/************************************************************************** + * Remove loaded volume as management files + ***************************************************************************/ +void removeVolumeMgmtFileByName( + GeneralMsg_s *genMsg, + unicode_t *volumeName) +{ + NINT i; + STATUS status; + Key_t rootKey; + + typedef struct Stack_s { + BYTE pathStr[zMAX_FULL_NAME]; + BYTE name[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + + LB_UnicodeToByte(NSS_UNI_CONVERSION_RAW, aStack->name, zMAX_COMPONENT_NAME, + volumeName, NULL); + memcpy(aStack->pathStr, AVFileMgmtDir, AVFileMgmtDirLen); + + i = 0; + while (VolumeInst[i].path != 0) + { + i++; + } + + ZOS_zRootKey(status, 0, &rootKey); + if (status != zOK) + { + zASSERT("Error getting root key" == 0); + SetErrno(genMsg, status); + goto errorExit; + } + + MGMT_VolumeFunctionsRegistered--; + for (; i > 0; i--) + { + sprintf(&aStack->pathStr[AVFileMgmtDirLen], VolumeInst[i - 1].path, aStack->name); + ZOS_zDelete(status, rootKey, 0, zNSPACE_LONG | zMODE_UTF8, + aStack->pathStr, zMATCH_ALL, zDELETE_FORCE_DELETE); +#if zLINUX + if (MGMT_VolumeFunctionsRegistered == 0) + { + MPKNSS_UNLOCK(); + if (VolumeInst[i].readFunctionName) + { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)) + inter_module_unregister(VolumeInst[i].readFunctionName); +#else + nss_unregister_module(VolumeInst[i].readFunctionName); +#endif + } + if (VolumeInst[i].writeFunctionName) + { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)) + inter_module_unregister(VolumeInst[i].writeFunctionName); +#else + nss_unregister_module(VolumeInst[i].writeFunctionName); +#endif + } + MPKNSS_LOCK(); + } +#endif + } + ZOS_zClose(status, rootKey); + zASSERT(status == zOK); + +errorExit: + STACK_FREE(); + return; +} + +/************************************************************************** + * Remove loaded volume as management files + ***************************************************************************/ +void removeVolumeMgmtFile( + GeneralMsg_s *genMsg, + void *volume) +{ + typedef struct Stack_s { + unicode_t vname[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + COMN_GetVolumeName(genMsg, (Volume_s *)volume, aStack->vname, NELEMS(aStack->vname)); + removeVolumeMgmtFileByName(genMsg, aStack->vname); + STACK_FREE(); + return; +} diff --git a/src/nwnss/comn/common/nameLookup.c b/src/nwnss/comn/common/nameLookup.c new file mode 100644 index 0000000..eb249ce --- /dev/null +++ b/src/nwnss/comn/common/nameLookup.c @@ -0,0 +1,872 @@ +/**************************************************************************** + | + | (C) Copyright 1995-1997 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-25 02:50:42 +0530 (Wed, 25 Jan 2006) $ + | + | $RCSfile$ + | $Revision: 1316 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | This looks up names + +-------------------------------------------------------------------------*/ +#include + +#include "comnPublics.h" + +#include /* NSS Library */ +#include +#include +#include +#include +#include + +#include "name.h" +#include "msgGen.h" +#include "msgName.h" +#include "comnBeasts.h" +#include "zParams.h" +#include "fullDirectoryInfo.h" +#include "nameSpace.h" +#include "comnBeastClass.h" +#include "pssStartup.h" +#include "nameScan.h" +#include "comnMacShortName.h" +/**************************************************************************** + * + *****************************************************************************/ +STATIC void NAME_HandleBeastlessName( + File_s *dir, + NameSpace_s *nameSpace, + NINT nameType, + unicode_t *name, + Zid_t badzid) +{ + Zid_t curZid; + GeneralMsg_s genMsg; +// cnt NINT nameUniquifier; + + typedef struct Stack_s { + FullDirectoryInfo_s dirInfo; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ASSERT_LATCH(&dir->FILEbeastLatch); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + /* try and look-up the entry again, but this time return the name. If we + * can't find it, something strange is going on, ignore it for now and + * move on. */ + if ((curZid = dir->FILEcomnOps.BST_lookupByNameInDirectory(&genMsg, + &dir->FILEnamed, + nameSpace,nameType,name,/* cnt zFNU_UNDEFINED, + &nameUniquifier,*/&aStack->dirInfo)) == zINVALID_ZID) + { + STACK_FREE(); + return; + } + + /* verify that it is the same bad ZID. if not, then something is changing + * and ignore this and skip the entry */ + if (curZid != badzid) + { + STACK_FREE(); + return; + } + + NAME_RemoveBeastlessNameFromDir(&genMsg,badzid,dir,nameSpace, + nameType,&aStack->dirInfo); + STACK_FREE(); +} + +/**************************************************************************** + * Given the specific ASCII name information, this function checks the ASCII + * name cache to see if the name is in the cache. If it is not there, this + * function returns a NULL. If it is there, this function reads in the + * beast and returns a pointer to it. + *****************************************************************************/ +void *NAME_FindNameInAsciiNameCache( + GeneralMsg_s *genMsg, + File_s *directory, + NameSpace_s *nameSpace, + NINT nameType, + NINT asciiNameLen, + char *asciiName, + NINT latchType, + BOOL dontDoVisibilityCheck +/* cnt, NINT *retNameUniquifier*/) +{ + Zid_t zid; + NamedBeast_s *beast; + QUAD count; + BOOL negativeEntryFound; + + ASSERT_LATCH(&directory->FILEbeastLatch); +//It is silly to try to lookup files if the parent is not a directory, but +//we should not assert here because the java stuff actually tries it. It +//just gets a "Not Found" error and keeps going happily on its way. +// zASSERT((directory->FILEattributes & zFA_SUBDIRECTORY) || +// (nameType == zNTYPE_DATA_STREAM) || +// (nameType == zNTYPE_EXTENDED_ATTRIBUTE)); + + if ((zid = NAME_GetNameFromCacheAscii(&directory->FILEvolume->VOLvolumeID, + directory->FILEzid, nameSpace, nameType, asciiNameLen, asciiName, + &negativeEntryFound, &count/* cnt, retNameUniquifier*/)) == zINVALID_ZID) + { /* if not in the name cache or a negative entry */ + if (negativeEntryFound) + { /* there is no beast by this name */ + SetErrno(genMsg, zERR_NAME_NOT_FOUND_IN_DIRECTORY); + return NULL; + } + /* no cache entry found */ + return(NULL); + } + + if ((beast = (NamedBeast_s *)COMN_LookupByZid(genMsg, directory->FILEvolume, + zid, latchType, dontDoVisibilityCheck)) == NULL) + { + if (GetErrno(genMsg) == zERR_ZID_NOT_FOUND) + { + /* Return as if the name was not found in the ASCII name cache. + * This will cause the name to be looked up in unicode. At that + * time, we can then properly call the NAME_HandleBeastlessName + * funciton to clean up the condition where we have a name that + * points to ZID that no longer exists + */ + ClearErrno(genMsg); + return(NULL); + } + return NULL; + } + return(beast); +} + + +/**************************************************************************** + * HexRadix + * Before calling, you MUST make sure uniChr is an ASCII HEX digit + *****************************************************************************/ +STATIC NINT HexRadix( unicode_t uniChr ) +{ + zASSERT( (uniChr < 128) && (LB_isxdigit(uniChr)) ); + + if (uniChr <= '9') + return(uniChr - '0'); + if (uniChr <= 'Z') + return(0x0a + (uniChr - 'A')); + return(0x0a + (uniChr - 'a')); +} + + +/**************************************************************************** + * This function is used to lookup specific names in a directory, in cases + * where the name should already exist. It does the following additional + * special checks: + * 1. If the name is not found and we just looked it up in the LONG + * namespace then try to look it up in the DOS name space. + * 2. If the name is still not found, check to see if it has any + * bracked special character syntax ... ie [xxxx], where there are + * exactly 4 hex digits surrounded by square brackets. If such + * syntax exists, convert each occurrence to a single unicode character + * and repeat the lookup steps. + * NOTE-NOTE-NOTE -- the caller is responsible to release the dosNameSpace + * pointer if it is filled in by this function. + *****************************************************************************/ +void *NAME_FindNameInDirSpecialRules( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + NameSpace_s **dosNameSpace, + BOOL negativeNameCacheFlag, + BOOL dontDoVisibilityCheck +/* cnt, NINT *retNameUniquifier*/) +{ + ScanComponentMsg_s *scanMsg = &nameMsg->scanMsg; + NamedBeast_s *nextBeast = NULL; + BOOL convertedHexConstants = FALSE; + BOOL strippedFFChars = FALSE; + unicode_t *saveUniBuffer = NULL; + unicode_t *src; + unicode_t *dest; + LONG mangledZid; + NINT retLen; + + typedef struct Stack_s { + unicode_t macName[zMAX_COMPONENT_NAME]; + } Stack_s; + STACK_ALLOC(); + +tryLookupAgain: + nextBeast = NAME_FindNameInDir(genMsg, nameMsg->curFile, + nameMsg->workNameSpace, nameMsg->workNameType, + scanMsg->retUnicodeComp, scanMsg->retAsciiCompLen, + scanMsg->retAsciiComp, nameMsg->latchType, + negativeNameCacheFlag, dontDoVisibilityCheck + /* cnt, retNameUniquifier*/); + if (nextBeast != NULL) + { + /* Just in case genMsg has an error because of an invalid path, + * clear it because even though the path may have been invalid, + * we located it anyway */ + if (GetErrno(genMsg) == zERR_INVALID_CHAR_IN_NAME) + { + ClearErrno(genMsg); + } + goto found; + } + + /* We have some clients which get confused and mix LONG names with + * "DOS-8.3" names in the same path string. To get around this problem, if + * a name is not found in the long name space, we always double check the + * DOS name space to see if it exists there. */ + if ((nameMsg->workNameSpaceID == zNSPACE_LONG) && + (nameMsg->parseFlags & NAMPFL_tryDosIfLongFails)) + { + if (*dosNameSpace == NULL) + { + *dosNameSpace = NSPACE_LOOKUP_NAMESPACE(genMsg, zNSPACE_DOS, + *dosNameSpace); + } + + if (*dosNameSpace != NULL) + { + /* Reset the error and look for the name in the DOS name space */ + ClearErrno(genMsg); + nextBeast = NAME_FindNameInDir(genMsg, nameMsg->curFile, + *dosNameSpace, nameMsg->workNameType, + scanMsg->retUnicodeComp, scanMsg->retAsciiCompLen, + scanMsg->retAsciiComp, nameMsg->latchType, + negativeNameCacheFlag, dontDoVisibilityCheck + /* cnt ,retNameUniquifier*/); + if (nextBeast != NULL) + { + /* Just in case genMsg has an error because of an invalid path, + * clear it because even though the path may have been invalid, + * we located it anyway */ + if (GetErrno(genMsg) == zERR_INVALID_CHAR_IN_NAME) + { + ClearErrno(genMsg); + } + nameMsg->retParseFlags |= NAMRETPFL_foundDOSNameWithLong; + goto found; + } + } + } + + /* Right here we do some extra work to allow for the user to type in a + * single unmappable unicode character in the form of a 6 character hex + * sequence of "[xxxx]", where "[xxxx]" is mapped to a single unicode + * character. We used to do this special character mapping in the + * AsciiToUnicode converter, but we discovered that some complications + * arose from that approach. Doing the mapping here allows for real file + * names to exist with the [xxxx] syntax as 6 actual file name characters + * rather than as a single char. */ + if ((!convertedHexConstants) && + (GetErrno(genMsg) == zERR_NAME_NOT_FOUND_IN_DIRECTORY) && + ((src = unichr(scanMsg->retUnicodeComp,L'[')) != NULL)) + { + /* We didn't find the name in the directory, and the name contains a + * '[' character. Start processing at the first '[' character. */ + dest = src; + + while (*src != 0) + { + if ((src[0] == L'[') && (src[5] == L']') && + (src[1]<128) && (LB_isxdigit(src[1])) && + (src[2]<128) && (LB_isxdigit(src[2])) && + (src[3]<128) && (LB_isxdigit(src[3])) && + (src[4]<128) && (LB_isxdigit(src[4]))) + { + if (!convertedHexConstants) + { + saveUniBuffer = malloc(zMAX_COMPONENT_NAME * 2); + if (saveUniBuffer != NULL) + { + unicpy( saveUniBuffer, scanMsg->retUnicodeComp ); + } + } + + /* This is a brute force conversion from 4 digit hex to unicode */ + *dest++ = ((HexRadix(src[1]) << 12) + + (HexRadix(src[2]) << 8) + + (HexRadix(src[3]) << 4) + + (HexRadix(src[4]) )); + src += 6; + convertedHexConstants = TRUE; + } + else /* not 4digit hex, skip to next char */ + { + *dest++ = *src++; + } + } + *dest++ = *src++; /* Copy final NULL */ + + if (convertedHexConstants) + { + /* IMPORTANT-IMPORTANT-IMPORTANT + * We must never add positive name cache entries where the unicode + * name has been converted, BUT the ascii name has not. It is much + * easier to just blow the unconverted ASCII name away here and + * this eliminates the problem. */ + scanMsg->retAsciiCompLen = 0; + scanMsg->retAsciiComp = NULL; + + ClearErrno(genMsg); + goto tryLookupAgain; + } + } + + /* + * If the NAME is a DOS name and it has extended ASCII characters in it, + * re-parse the ASCII component using original DOS rules and try to look + * it up again. + */ + if ((nameMsg->workNameSpaceID == zNSPACE_DOS) && + (scanMsg->retScanFlags & NSRETSFL_hasExtendedASCII)) + { + /* Note - only DOS sets this flag. We did not find the name, but the + * name contains extended ASCII characters. Reparse the path component + * using traditional NetWare uppercasing/legal character rules and then + * try to look it up one more time. + */ + if (NMSG_ReparseNameMsgDOSComponent(genMsg,nameMsg) == zOK) + { + COMN_SET_NAMING_MSG_CONTINUE_AFTER_ILLEGAL_CHARS(nameMsg); + ClearErrno(genMsg); + goto tryLookupAgain; + } + } + + /* + * If the NAME is a LONG name and it has at least one FF character, + * then strip extra FF characters and try it again one more time. + */ + if ((!strippedFFChars) && + (nameMsg->workNameSpaceID == zNSPACE_LONG) && + ((src = unichr(scanMsg->retUnicodeComp,NSSUnicodeFF)) != NULL)) + { + /* We didn't find the name in the directory, and the name contains at + * least one "FF" character. Start processing at the first "FF" + * character and strip pairs of "FF FF" chars to single "FF" chars. + */ + dest = src; + + while (*src != 0) + { + if ((src[0] == NSSUnicodeFF) && (src[1] == NSSUnicodeFF)) + { + if ((!strippedFFChars) && (saveUniBuffer == NULL)) + { + saveUniBuffer = malloc(zMAX_COMPONENT_NAME * 2); + if (saveUniBuffer != NULL) + { + unicpy( saveUniBuffer, scanMsg->retUnicodeComp ); + } + } + + *dest++ = NSSUnicodeFF; + src += 2; + strippedFFChars = TRUE; + } + else /* not "FF FF", skip to next char */ + { + *dest++ = *src++; + } + } + *dest++ = *src++; /* Copy final NULL */ + + if (strippedFFChars) + { + /* IMPORTANT-IMPORTANT-IMPORTANT + * We must never add positive name cache entries where the unicode + * name has been converted, BUT the ascii name has not. It is much + * easier to just blow the unconverted ASCII name away here and + * this eliminates the problem. */ + scanMsg->retAsciiCompLen = 0; + scanMsg->retAsciiComp = NULL; + + ClearErrno(genMsg); + goto tryLookupAgain; + } + } + + if (nameMsg->workNameSpaceID == zNSPACE_MAC) + { + // clear any previous error + ClearErrno(genMsg); + + mangledZid = COMN_GetZidFromMangledName(scanMsg->retUnicodeComp); + if (mangledZid < zFIRST_ALLOCATABLE_ZID) + { + // zid is not valid, can't be embedded zid + SetErrno(genMsg, zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto error; + } + // do comn_lookupbyzid and return beast ptr + + nextBeast = COMN_LookupByZid (genMsg, nameMsg->curvol, + (Zid_t) mangledZid, nameMsg->latchType, FALSE); + + ClearErrno(genMsg); // we may have to set it later + + if (nextBeast == NULL) + { + // lookup by zid failed, report not found + SetErrno(genMsg, zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto error; + } + // verify beast is right type + if ((!COMN_IsDerivedFrom(nextBeast, zFTYPE_NAMED_DATA_STREAM)) + || (nextBeast->NAMEDfirstParentNameType != nameMsg->workNameType)) + { + // no match, reject it + SetErrno(genMsg, zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto error; + } + + // does name match mangled name? + if (COMN_GetNameFromBeast(genMsg, nextBeast, /* cnt zFNU_FIRST_PARENT,*/ + zNSPACE_MAC, + zMAX_COMPONENT_NAME, + aStack->macName, &retLen) != zOK) + { + goto error; + } + + if (!COMN_VerifyMangledMacName (scanMsg->retUnicodeComp, + aStack->macName) ) + { + // we found a zid, but it doesn't match reject it + SetErrno(genMsg, zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto error; + } +// cnt *retNameUniquifier = zFNU_FIRST_PARENT; + goto found; + } +error: + if (nextBeast) + { + COMN_UnlatchAndRelease( &nextBeast, nameMsg->latchType); + } + if (saveUniBuffer) + { + /* We converted the string and didn't find the name, put the original + * name back */ + unicpy(scanMsg->retUnicodeComp, saveUniBuffer); + free(saveUniBuffer); + } + STACK_FREE(); + return(NULL); + +found: + if (saveUniBuffer) + { + free(saveUniBuffer); + } + STACK_FREE(); + return(nextBeast); +} + + +/**************************************************************************** + * Given the specific unicode name information, this will look in the name + * cache for the unicode name. If it doesn't find the name in the name cache + * it calls the BST_lookupByNameInDIrectory to ask the LSS to search the + * directory. If + * the name is found and it is not already in the name cache, it's unicode + * and ascii equivalents are added to the name cache. + *****************************************************************************/ +Zid_t NAME_FindZidForNameInDir( + GeneralMsg_s *genMsg, + void *_directory, + NameSpace_s *nameSpace, + NINT nameType, + unicode_t *uniName, + NINT asciiNameLen, + char *asciiName, + BOOL negativeNameCacheFlag /* INPUT: do we add negative entries to the cache? */ +/* cnt, NINT *retNameUniquifier*/) +{ + File_s *directory = _directory; + Zid_t zid; + QUAD count; + BOOL negativeEntryFound; + + ASSERT_MPKNSS_LOCK(); + ASSERT_LATCH(&directory->FILEbeastLatch); + zASSERT((directory->FILEattributes & zFA_SUBDIRECTORY) || + (nameType == zNTYPE_DATA_STREAM) || + (nameType == zNTYPE_EXTENDED_ATTRIBUTE)); + + if ((zid = NAME_GetNameFromCacheUnicode(&directory->FILEvolume->VOLvolumeID, + directory->FILEzid, nameSpace, nameType, uniName, &negativeEntryFound, + &count/* cnt, retNameUniquifier*/)) == zINVALID_ZID) + { /* if not in the name cache or a negative entry */ + if (negativeEntryFound) + { /* there is no beast by this name */ + SetErrno(genMsg, zERR_NAME_NOT_FOUND_IN_DIRECTORY); + goto errorExit; + } + /* no cache entry found */ + if ((zid = directory->FILEcomnOps. + BST_lookupByNameInDirectory(genMsg, &directory->FILEnamed, nameSpace, nameType, + uniName, /* cnt zFNU_UNDEFINED, retNameUniquifier,*/ + NULL)) == zINVALID_ZID) + { /* the beast was not found */ + if (negativeNameCacheFlag) + { /* add a negative cache entry if allowed */ + unicode_t *src; + BOOL skipNegativeAdd = FALSE; + + /* IMPORTANT-IMPORTANT-IMPORTANT + * We must never add a negative name cache entry that has + * [xxxx] syntax in it (see COMN_Lookup where it converts + * this syntax to a single unicode character). If we were + * to add such a string, it can really confuse the whole + * system. */ + src = uniName; + while ((src = unichr(src,L'[')) != NULL) + { + /* Found another starting '[' ... check it out */ + if ((src[0] == L'[') && (src[5] == L']') && + (src[1]<128) && (LB_isxdigit(src[1])) && + (src[2]<128) && (LB_isxdigit(src[2])) && + (src[3]<128) && (LB_isxdigit(src[3])) && + (src[4]<128) && (LB_isxdigit(src[4]))) + { + skipNegativeAdd = TRUE; + break; + } + ++src; + } + if (!skipNegativeAdd) + { + NAME_AddNameToCache(count, directory->FILEvolume, + directory->FILEzid, nameSpace, nameType, uniName, + asciiNameLen, asciiName, zINVALID_ZID + /* cnt,zFNU_INVALID_NAME_UNIQUIFIER*/); + } + } + goto errorExit; + } + /* the beast was found */ + NAME_AddNameToCache(count, directory->FILEvolume, + directory->FILEzid, nameSpace, nameType, uniName, + asciiNameLen, asciiName, zid/* cnt, *retNameUniquifier*/); + } + + if ( GetErrno( genMsg ) == zERR_ZID_NOT_FOUND ) + { /* By only clearing errno when zERR_ZID_NOT_FOUND + * we do not mess with wierd code that looks + * at errnos on NON-errors. Some of our callers + * only clearerrno if zERR_INVALID_CHAR_IN_NAME is + * set which worries me I.E. why not clear all + * the time if NO ONE is looking at it? + */ + ClearErrno( genMsg ); + } + +errorExit: + return zid; +} + +/**************************************************************************** + * Given the specific unicode name information, this will look in the name + * cache for the unicode name. If it doesn't find the name in the name cache + * it calls the BST_lookupByNameInDIrectory to ask the LSS to search the + * directory. If the name is found, the beast is read into memory. If + * the name is found and it is not already in the name cache, it's unicode + * and ascii equivalents are added to the name cache. + *****************************************************************************/ +void *NAME_FindNameInDir( + GeneralMsg_s *genMsg, + void *_directory, + NameSpace_s *nameSpace, + NINT nameType, + unicode_t *uniName, + NINT asciiNameLen, + char *asciiName, + NINT latchType, + BOOL negativeNameCacheFlag, /* INPUT: do we add negative entries to the cache? */ + BOOL dontDoVisibilityCheck +/* cnt NINT *retNameUniquifier*/) +{ + File_s *directory = _directory; + Zid_t zid; + NamedBeast_s *beast; + + ASSERT_MPKNSS_LOCK(); + ASSERT_LATCH(&directory->FILEbeastLatch); + zASSERT((directory->FILEattributes & zFA_SUBDIRECTORY) || + (nameType == zNTYPE_DATA_STREAM) || + (nameType == zNTYPE_EXTENDED_ATTRIBUTE)); + + if ((zid = NAME_FindZidForNameInDir(genMsg, _directory, nameSpace, nameType, + uniName, asciiNameLen, asciiName, + negativeNameCacheFlag + /* cnt, retNameUniquifier*/)) == zINVALID_ZID) + { + goto errorExit; + } + + if ((beast = (NamedBeast_s *)COMN_LookupByZid(genMsg, directory->FILEvolume, + zid, latchType, dontDoVisibilityCheck)) == NULL) + { + if (GetErrno(genMsg) == zERR_ZID_NOT_FOUND) + { + NAME_HandleBeastlessName(directory,nameSpace,nameType,uniName,zid); + ForceSetErrno(genMsg,zERR_NAME_NOT_FOUND_IN_DIRECTORY); + } + goto errorExit; + } + + return(beast); + +errorExit: + return NULL; +} + + +/************************************************************************** + * We have found a name in the directory and we could not find the + * associated beast for it. This is going to report an error and then + * delete the name. + ***************************************************************************/ +STATUS NAME_RemoveBeastlessNameFromDir( + GeneralMsg_s *genMsg, + Zid_t badzid, + void *_curdir, + NameSpace_s *nameSpace, + NINT nameType, + FullDirectoryInfo_s *nameInfo) +{ +#if (zGET_NAME_VARIABLE_DATA_SIZE < (zMAX_FULL_NAME*2)) + #error The zGET_NAME_VARIABLE_DATA_SIZE must be >= (zMAX_FULL_NAME * 2), + #error because we use it to get a full unicode path +#endif + NamedBeast_s *curdir = _curdir; + GetNameMsg_s gfnMsg; + unicode_t *fullName; + zGetName_s *fullNameBuf = NULL; + Xaction_s *xaction; + NINT latchType; + STATUS status; + NameSpace_s *pathNameSpace; + NINT pathNameType; + + typedef struct Stack_s { + NamingMsg_s noCleanupNameMsg; + } Stack_s; + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + ASSERT_LATCH(&curdir->NAMEDbeastLatch); /* make sure directory is latched */ + + COMN_INIT_NAMING_MSG(&aStack->noCleanupNameMsg); +/*--------------------------------------------------------------------------- + * Try and get the full name of the file. We do thing by getting the name + * of the DIR and the appending the filename to it. If we have a problem + * getting the full name, just give the file name. + *---------------------------------------------------------------------------*/ + /* get a buffer to return the full name into*/ + if ((fullNameBuf = COMN_GetPathNameWorkBuffer(genMsg)) == NULL) + { + fullName = nameInfo->name; + latchType = GET_LATCH_TYPE(&curdir->NAMEDbeastLatch); + } + else + { +/*--------------------------------------------------------------------------- + * Setup a nameMessage with all of the necessary beast/volume/nameSpace + * pointers --- BUT --- DO NOT do the extra use counts and latching normally + * required by a nameMsg. WE WILL NOT CLEANUP THE NAMEMSG. All of + * the pointers are already either inUse, latched or both. This is simply + * a method of setting up a temporary nameMsg to be used by COMN_GetName. + * All pointers are inuse/latched and cleaned up by the caller of this function. + *---------------------------------------------------------------------------*/ + /* Note, if the nameType/nameSpace is DataStream or Extended Attribute + * then we switch to the long name space to get the parent file's + * name. We cannot use these namespaces to get the whole path */ + if ((nameSpace->nSpaceID == zNSPACE_DATA_STREAM) || + (nameSpace->nSpaceID == zNSPACE_EXTENDED_ATTRIBUTE) || + (nameType == zNTYPE_DATA_STREAM) || + (nameType == zNTYPE_EXTENDED_ATTRIBUTE)) + { + pathNameType = zNTYPE_FILE; + pathNameSpace = COMN_NameSpaceIDLookup(genMsg, zNSPACE_LONG); + } + else + { + pathNameType = nameType; + pathNameSpace = nameSpace; + COMN_USE_BEAST(&pathNameSpace->NSPACEroot); + } + + latchType = GET_LATCH_TYPE(&curdir->NAMEDbeastLatch); + COMN_SETUP_NAMING_MSG_FILE_BEAST_PTR(&aStack->noCleanupNameMsg, + curdir->NAMEDvolume, + curdir->NAMEDfirstParentZid, +// cnt curdir->NAMEDfirstParentNameUniquifier, + (File_s *)curdir, + NAMPMODE_FullyResolveDirectory, + latchType, + pathNameSpace, + pathNameType, + NULL); + + /* get the full path name of the parent directory */ + COMN_STRUCT_INIT(gfnMsg); + COMN_SETUP_GET_NAME_MSG(&gfnMsg, + zGFN_INCLUDE_PATH|zGFN_INCLUDE_VOLUME, + GFN_NO_SEPARATOR_AFTER_VOLUME_COLON, + zPFMT_UNICODE, pathNameSpace->nSpaceID, + fullNameBuf, UNI_PATHWORKBUF_SIZE); + + if (COMN_GetName(genMsg,&aStack->noCleanupNameMsg,&gfnMsg) != zOK) + { + /* if we couldn't get it the full name, release the buffer */ + COMN_ReleasePathNameWorkBuffer(&fullNameBuf); + fullName = nameInfo->name; + + /* Some errors from COMN_GetName have released the latch. If this + * is the case, we must re-latch it */ + if (aStack->noCleanupNameMsg.latchType == NOTLATCHED) + { + switch(latchType) + { + case XLATCHED: + X_LATCH(&curdir->NAMEDbeastLatch); + break; + case SLATCHED: + S_LATCH(&curdir->NAMEDbeastLatch); + break; + } + } + else + { + zASSERT(aStack->noCleanupNameMsg.latchType == latchType); + } + } + else + { + NINT len; + NINT separatorLen; + unicode_t *separatorStr; + + if (pathNameSpace->nSpaceOps->getSeparator(genMsg,PATH_SEPARATOR, + &separatorStr, &separatorLen) != zOK) + { + zASSERT("Unable to get path sepatator, This should not happen\n" == NULL); + separatorLen = 1; + separatorStr = MSGNot(L"\\"); + } + + /* we have the directory name, add in the file name */ + fullName = fullNameBuf->name; + len = unilen(fullName); + if (len < UNI_PATHWORKBUF_SIZE-separatorLen) + { + unicpy(&fullName[len],separatorStr); + len += separatorLen; + } + unimcpy(&fullName[len],nameInfo->name,UNI_PATHWORKBUF_SIZE-len); + } + COMN_Release(&pathNameSpace); + } +/*--------------------------------------------------------------------------- + * Delete the spurious name. The directory that comes in is ALWAYS SLatched + * so we must upgrade the latch and then downgrade it after. + *---------------------------------------------------------------------------*/ + switch(latchType) + { + case XLATCHED: + break; + case SLATCHED: + UP_LATCH(&curdir->NAMEDbeastLatch); + break; + default: + zASSERT("Unknown latch type\n" == NULL); + break; + } + + xaction = COMN_BeginXLocal(curdir); + + NAME_RemoveNameFromCache(genMsg, curdir->NAMEDvolume, + curdir->NAMEDzid, nameInfo->nameSpaceMask, nameType, nameInfo->name, + 0); + + /* Call this again with "NAMEForcedUpper" to make sure we get a unix + * name cache entry. + */ + NAME_RemoveNameFromCache(genMsg, curdir->NAMEDvolume, + curdir->NAMEDzid, nameInfo->nameSpaceMask, nameType, nameInfo->name, + NAMEforcedUpper); + + status = curdir->NAMEDcomnOps.BST_removeNameFromDirectory(genMsg, + badzid, curdir,nameInfo->nameSpaceMask, + nameType,nameInfo->name,/* cnt zFNU_UNDEFINED,*/NF_UPDATE_NAME, + xaction,NULL); + + /* report the error message */ + if (status == zOK) + { +#if NSS_DEBUG IS_ENABLED + errPrintf(WHERE, Module, 624, + MSG("File object %d, whose name is \"%U\", could not be found.\n" + "The name has been removed! Couldn't find Beast. Run Verify.", 800), + (NINT)nameInfo->zid, fullName); +#endif + } + else + { + errPrintf(WHERE, Module, 625, + MSG("File object %d, whose name is \"%U\", " + "could not be found. The system was unable to " + "remove the name (status=%d)!\n", 801), /* Purposeful extra \n */ + (NINT)nameInfo->zid, fullName, GetErrno(genMsg)); + zASSERT("This is a nameTree corruption problem" == 0); + } + + COMN_EndXLocal(curdir,&xaction); + switch(latchType) + { + case XLATCHED: + break; + case SLATCHED: + DOWN_LATCH(&curdir->NAMEDbeastLatch); + break; + default: + zASSERT("Unknown latch type\n" == NULL); + break; + } + + if (fullNameBuf) + COMN_ReleasePathNameWorkBuffer(&fullNameBuf); + + STACK_FREE(); + return GetErrno(genMsg); +} diff --git a/src/nwnss/comn/common/ndpIdBrokerShared.c b/src/nwnss/comn/common/ndpIdBrokerShared.c new file mode 100644 index 0000000..e36e23e --- /dev/null +++ b/src/nwnss/comn/common/ndpIdBrokerShared.c @@ -0,0 +1,5 @@ +/**************************************************************************** + | MARS-NWE libnwnss import wrapper for NSS shared NDP idbroker source. + +-------------------------------------------------------------------------*/ + +#include diff --git a/src/nwnss/comn/common/sysimpUserland.c b/src/nwnss/comn/common/sysimpUserland.c new file mode 100644 index 0000000..526da36 --- /dev/null +++ b/src/nwnss/comn/common/sysimpUserland.c @@ -0,0 +1,66 @@ +/**************************************************************************** + | Userspace sysimp boundary for libnwnss. + | + | public_core/sharedsrc/sysimp.c.h is the real NSS sysimp implementation, but + | its Linux userspace branch depends on DDS/NDPS headers and runtime entry + | points that are outside the NSS userspace core import. Keep the exported + | sysimp state visible and inactive here until the eDirectory/DDS provider is + | deliberately wired in. + +-------------------------------------------------------------------------*/ + +#include +#include +#include + +BOOL NdsPublicsLoaded = FALSE; +LONG NdsPublicsHandle = 0; +int (*NDSRenameEventFunc)() = NULL; +int (*NDSDeleteEventFunc)() = NULL; +LONG NDSEventHandlerHandle = 0; +BOOL NDSEventRegistered = FALSE; + +int (*DDSGetLocalAgentInfoPtr)() = NULL; +int (*DDSGetLocalEntryNamePtr)() = NULL; +int (*DDCCreateContextPtr)() = NULL; +int (*DDCDuplicateContextPtr)() = NULL; +int (*DDCResolveNamePtr)() = NULL; +int (*DDCGetEntryInfoPtr)() = NULL; +void (*DDCFreeContextPtr)() = NULL; +int (*DDCSetContextFlagsPtr)() = NULL; +int (*DDCSetContextEntryIDPtr)() = NULL; +int (*DDCLoginPtr)() = NULL; +int (*DDSLoginAsServerPtr)() = NULL; +int (*DDCCreateEntryPtr)() = NULL; +int (*DDCRemoveEntryPtr)() = NULL; +int (*DDCRemoveAttributePtr)() = NULL; +int (*DDCGenerateKeyPairPtr)() = NULL; +int (*DDCLogoutPtr)() = NULL; +int (*DDCReadToBufferPtr)() = NULL; +int (*DDCReadToCBPtr)() = NULL; +int (*DDCListToBufferPtr)() = NULL; +int (*DDCModifyEntryPtr)() = NULL; +int (*DDCModifyRDNPtr)() = NULL; +int (*DDCGetServerNamePtr)() = NULL; +int (*DDCSetContextBaseDNPtr)() = NULL; +int (*DDCAuthenticateConnectionPtr)() = NULL; +int (*DDCGetEffectivePrivilegesPtr)() = NULL; +int (*DDCCheckConsoleOperatorPtr)() = NULL; +int (*DDCNameToIDPtr)() = NULL; +int (*DDCConnectToReferralPtr)() = NULL; +int (*DDCGetDefaultAddressPtr)() = NULL; +int (*DDCConnectToAddressPtr)() = NULL; +UINT32 (*DDCContextEntryIDPtr)() = NULL; +int (*DDCPingPtr)() = NULL; + +STATUS LB_ImportNDSPublics(LONG handle) +{ + (void)handle; + NdsPublicsLoaded = FALSE; + return zFAILURE; +} + +void LB_UnimportNDSPublics(LONG handle) +{ + (void)handle; + NdsPublicsLoaded = FALSE; +} diff --git a/src/nwnss/comn/common/volStartup.c b/src/nwnss/comn/common/volStartup.c new file mode 100644 index 0000000..e4ad563 --- /dev/null +++ b/src/nwnss/comn/common/volStartup.c @@ -0,0 +1,201 @@ +/**************************************************************************** + | + | (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) module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2005-08-10 01:03:51 +0530 (Wed, 10 Aug 2005) $ + | + | $RCSfile$ + | $Revision: 1177 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Manage VOLUME code + +-------------------------------------------------------------------------*/ +#include + +#include "comnPublics.h" + +#include +#include +#include +#include + +#include "volume.h" +#include "pssStartup.h" +#include "adminVolume.h" + +SEThead_t NSSMasterVolumeList = SET_STATIC_INIT(NSSMasterVolumeList); +SEThead_t NSSMasterPoolList = SET_STATIC_INIT(NSSMasterPoolList); + + +/************************************************************************** + * This initializes the VOLUME system + * + ***************************************************************************/ +STATUS VOLUME_Startup( + GeneralMsg_s *genMsg) +{ + return zOK; +} + + +/************************************************************************** + * This is called when + * 1) Someone downs the server (CMN_ServerDown()). + * 2) The NSS.NLM is exiting (CMN_GlobalShutdown() which is called + * by GenericExitRoutine() of NSS.NLM). + * + * In the first case, the NWSA (FixFixFix6 - put into COMN LYR) has the DOWN + * event hooked and prompts user if files are open on MOUNTed volumes. By + * the time this routine is called we are at a point where we have to + * deactivate even if files are open. + * In the 2nd case all non ADMIN volume's are already deactivated. + * + ***************************************************************************/ + +STATUS applyVolumeShutdown (SETlink_t *item, void *verbose) +{ + Volume_s *volume = STRUCT(item, Volume_s, masterVolLink); + + GeneralMsg_s genMsg; + STATUS status; + NINT errorcode; + NINT mode = (verbose ? VOLMODE_VERBOSE : 0); + + typedef struct Stack_s { + unicode_t vName[zMAX_COMPONENT_NAME]; + } Stack_s; + + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + /* + * We do not do internal volumes as the LSS is + * responsible for this. + * + * We skip the admin volume because it must be last and + * therefore we let ADMINVOL_Shutdown() do when + * BEAST_Shutdown() calls it from CMN_GlobalShutdown(). + * If we call here then admin volume rejects the + * state change, but we display that we are deactivating + * the volume. Therefore, when we really deactivate we + * display a SECOND deactivate message. + */ + if ( !VOL_ACCESSIBLE1(volume) || (volume == COMN_GetAdminVolume())) + { + STACK_FREE(); + return zOK; + } + COMN_GetVolumeName(&genMsg,volume,aStack->vName,NELEMS(aStack->vName)); + status = COMN_ChangeVolumeState( &genMsg, volume, zVOLSTATE_UNKNOWN, mode); + if (status != zOK) + { + /*- check if admin volume -*/ + errorcode = GetErrno( &genMsg); + errPrintf(WHERE, Module, 635, + MSG("Could not deactivate Volume %U, status=%d.", 196), + aStack->vName, errorcode); + zASSERT("Error deactivating volume" == 0); + } + STACK_FREE(); + return zOK; +} + + +void VOLUME_Shutdown( + BOOL verbose) +{ + SET_APPLY( &NSSMasterVolumeList, applyVolumeShutdown, (void *)verbose); +} + + +/************************************************************************** + * This initializes the POOL system + * + ***************************************************************************/ +STATUS POOL_Startup( + GeneralMsg_s *genMsg) +{ + return zOK; +} /* End of POOL_Startup() */ + + +/************************************************************************** + * This is called when + * 1) Someone downs the server (CMN_ServerDown()). + * 2) The NSS.NLM is exiting (CMN_GlobalShutdown() which is called + * by GenericExitRoutine() of NSS.NLM). + * + * In the first case, the NWSA (FixFixFix6 - put into COMN LYR) has the DOWN + * event hooked and prompts user if files are open on MOUNTed volumes. By + * the time this routine is called we are at a point where we have to + * deactivate even if files are open. + * In the 2nd case all non ADMIN volume's are already deactivated. + * + ***************************************************************************/ + +void POOL_Shutdown( + BOOL verbose) +{ + STATUS status; + NINT mode = (verbose ? VOLMODE_VERBOSE : 0); + Pool_s *pool; + GeneralMsg_s genMsg; + + typedef struct Stack_s { + unicode_t poolName[zMAX_COMPONENT_NAME]; + } Stack_s; + + STACK_ALLOC(); + + ASSERT_MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + SET_FOREACHBLOCKING(&NSSMasterPoolList, pool, Pool_s, masterPoolLink) + { /*** You MUST NOT use continue in this loop because the macro + *** SET_FOREACHBLOCKINGEND (at end of for loop) must be called + *** every time through the loop. Technically, you + *** can use a continue BEFORE any blocking calls. + ***/ + COMN_USE_BEAST( &pool->POOLroot ); + + COMN_GetPoolName( &genMsg, pool, aStack->poolName, NELEMS(aStack->poolName) ); + status = COMN_ChangePoolState( &genMsg, pool, zVOLSTATE_UNKNOWN, mode); + if (status != zOK) + { + errPrintf(WHERE, Module, -1, + MSG("Could not deactivate Pool %U, status=%d.", 176), + aStack->poolName, GetErrno(&genMsg)); + zASSERT("Error deactivating pool" == NULL); + } + COMN_Release( &pool ); + SET_FOREACHBLOCKINGEND(&NSSMasterPoolList, pool, Pool_s, masterPoolLink) + } + STACK_FREE(); +} /* End of POOL_Shutdown() */ diff --git a/src/nwnss/comn/comnModule.c b/src/nwnss/comn/comnModule.c index f3204cd..d192aef 100644 --- a/src/nwnss/comn/comnModule.c +++ b/src/nwnss/comn/comnModule.c @@ -1,3 +1,4 @@ +#include /**************************************************************************** * COMN module identity for userspace libnwnss. * @@ -6,3 +7,10 @@ * the identity local and explicit instead of leaving it in the temporary bridge. ****************************************************************************/ const char Module[] = "libnwnss"; + +/* Userspace libnwnss has no NetWare/Linux kernel module handle. Imported + * COMN sources pass this value through OS-service macros that are guarded in + * nwnssSourceCompat.h/nssOSAPIs.h. + */ +struct LoadDefinitionStructure; +struct LoadDefinitionStructure *CMN_ModuleHandle = NULL; diff --git a/src/nwnss/comn/compression/cmActivity.c b/src/nwnss/comn/compression/cmActivity.c new file mode 100644 index 0000000..9958f1c --- /dev/null +++ b/src/nwnss/comn/compression/cmActivity.c @@ -0,0 +1,593 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996-1999 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 + | + |*************************************************************************** + | + | NSS Compression Management module + | + |--------------------------------------------------------------------------- + | + | $Author: ying $ + | $Date: 2005-05-11 23:59:19 +0530 (Wed, 11 May 2005) $ + | + | $RCSfile$ + | $Revision: 976 $ + | + |--------------------------------------------------------------------------- + | Module Description: + | + +-------------------------------------------------------------------------*/ +#include + +#include "cmDefs.h" +#include "cmRuntime.h" +#include "cmAlgoMan.h" +#include "comnCompress.h" +#include "cmActivity.h" +#include "cmNSS.h" +#include "cmCompFile.h" +#include "cmControl.h" + +/* + * Called to indicate successful completion of a (de)compression activity. + */ +STATIC QUAD totalCompActivities = 0; +STATIC void CM_activityDone(CMActivity_s *activity) +{ + RootBeast_s *uncompBeast = activity->decompStream.beast; + RootBeast_s *compBeast = activity->compStream.beast; + CompressInfo_s *compInfo = BEAST_CM_INFO(uncompBeast); + GeneralMsg_s genMsg; + QUAD offset = activity->decompStream.beastOffset; + NINT newCompState; + NINT num; + Xaction_s *localXaction = NULL; + + + ASSERT_MPKNSS_LOCK(); + + XLATCH_BEAST(uncompBeast); + XLATCH_BEAST(compBeast); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + activity->state = CM_ACTIVITY_STATE_FINISHED; + if (activity->op == CM_ACTIVITY_OP_COMPRESS) + { + newCompState = COMP_STATUS_COMPRESSED; + if (activity->keepSrcChunk) + newCompState |= COMP_STATUS_UNCOMPRESSED; + if (compInfo->p.chunkSize > 0) + { + Buffer_s *cmbuf; + QUAD compChunkOffset; + CompChunkHdr_s *chunkHdr; + + if (getCompChunkOffset(&genMsg, compBeast, offset, + compInfo->p.chunkSize, &compChunkOffset) != zOK) + goto cleanupAndExit; + + /* Set compressed chunk size in chunk header */ + cmbuf = CM_fetchFileBlk(&genMsg, compBeast, + compChunkOffset >> compBeast->blkSizeShift, + CACHE_UPDATE, 0); + if (! cmbuf) + goto cleanupAndExit; + + mapBufferPage(cmbuf); + chunkHdr = (CompChunkHdr_s *) + (cmbuf->pBuf.data + (compChunkOffset & + ((1 << compBeast->blkSizeShift) - 1))); + chunkHdr->compChunkSize = activity->compStream.beastSize; + unmapBufferPage(cmbuf); + CACHE_DIRTY_RELEASE(cmbuf); + + (void) setCompChunkValidRange(&genMsg, + activity->compStream.beast, offset, + compInfo->p.chunkSize, + activity->compStream.beastOffset, + activity->compStream.beastSize); + (void) setChunkCompStatus(&genMsg, activity->compStream.beast, + offset, compInfo->p.chunkSize, newCompState); + UNXLATCH_BEAST(compBeast); + BST_flush(compBeast); + XLATCH_BEAST(compBeast); + if (! activity->keepSrcChunk) + { + /* + * create a hole in the uncompBeast in the range + * + * This step may not be possible with current NSS + * implementation. In case of whole file compression, truncate + * the beast. + * ??? to be filled in when fully supporting chunky compression. + */ + } + } + else + { + /* Set Compressed beast's new (logical) EOF, and flush compBeast */ + SET_DATASTREAM_SIZE(&genMsg, compBeast, + activity->compStream.beastOffset + + activity->compStream.beastSize); + COMN_MARK_BEAST_DIRTY(compBeast); + + UNXLATCH_BEAST(compBeast); + BST_flush(compBeast); + XLATCH_BEAST(compBeast); +#if 0 + if (! activity->keepSrcChunk) + { + /* Discard uncompressed data */ + /* + * XXX Shouldn't call BST_truncate to truncate the uncompBeast. + * BST_truncate in turn performs compression-related processing, + * which involves throwing away the compressed stream too. + * We should instead to a cacheTruncateMyCache followed by the + * bstTruncate LSS op. But for the moment, don't do anything. + */ + (void) TRUNCATE_BEAST(&genMsg, activity->decompStream.beast, + activity->decompStream.beastOffset); + } +#endif + compInfo->p.status &= + ~(COMP_STATUS_UNCOMPRESSED|COMP_STATUS_COMPRESSED); + compInfo->p.status |= newCompState; + } + + /* update the percentage space saved */ + { + totalCompActivities++; + zASSERT(totalCompActivities >= 1); + if (totalCompActivities == 0) + { + totalCompActivities = 1; + } + + num = activity->decompStream.beastSize - activity->compStream.beastSize; + + X_LATCH(&CM_curCompStatistics.latch); + + /* round the ratio */ + CM_curCompStatistics.percentSpaceSaved = + (100 * num + activity->decompStream.beastSize / 2)/activity->decompStream.beastSize; + + if (!CM_curCompStatistics.averageCompRatio) + { + /* we don't store averageCompRatio persistently, let's + * fake something if this is the first time + */ + CM_curCompStatistics.averageCompRatio + = CM_curCompStatistics.percentSpaceSaved; + + } + else + { + /* round the ratio */ + num = CM_curCompStatistics.percentSpaceSaved + + CM_curCompStatistics.averageCompRatio * (totalCompActivities - 1); + CM_curCompStatistics.averageCompRatio = + (num + totalCompActivities / 2)/totalCompActivities; + } + displayCompRatio(); + UNX_LATCH(&CM_curCompStatistics.latch); + } + + /* Update precious counts and cleanup the datastream if necessary. */ + localXaction = COMN_BeginXLocal(uncompBeast); + + ++ compInfo->p.Cprecious; + if (! activity->keepSrcChunk) + { + if (-- compInfo->p.UCprecious == 0) + { + /* remove activity from uncompBeast->CM_activities list. */ + DQ_RMV(activity, beastActivitiesChain); + + /* wakeup all threads waiting for this activity to finish */ + CM_signalEvent((ADDR)&compInfo->CM_activities, zOK); + + /* beast is fully compressed now, modify its compression related + * information + */ + setBeastCompAttr(uncompBeast, zFA_DATA_STREAM_IS_COMPRESSED, localXaction, FALSE); + setVolCompStats(uncompBeast, compBeast, localXaction, TRUE); + + if (compCleanup(&genMsg, uncompBeast, compBeast, FALSE, &localXaction) != zOK) + { + /* roll back compression related stats and attributes */ + if (localXaction == NULL) + { + localXaction = COMN_BeginXLocal(uncompBeast); + } + + compInfo->p.UCprecious++; + compInfo->p.status |= COMP_STATUS_UNCOMPRESSED; +// compInfo->p.Cprecious--; + setBeastCompAttr(uncompBeast, 0, localXaction, TRUE); + setVolCompStats(uncompBeast, compBeast, localXaction, FALSE); + + updateBeastPurgeableBlksCnt(&genMsg, + (NamedBeast_s *)uncompBeast, compBeast, TRUE, localXaction); + } + + goto releaseBeastsAndExit; + + } + } + } + else + { + newCompState = COMP_STATUS_UNCOMPRESSED; + if (activity->keepSrcChunk) + newCompState |= COMP_STATUS_COMPRESSED; + if (compInfo->p.chunkSize > 0) + { + /* reset compStream.beastOffset, beastSize to include the entire + * chunk (including chunk hdr) i.e., + * hdrSize = sizeof(CompChunkHdr_s); + * compStream.beastOffset -= hdrSize; + * compStream.beastSize += hdrSize; + * + * flush to disk, all uncompBeast blocks in the range + * . + * + * if uncompBeast is not marked for "Immediate Compression", + * { + * Throw away the compressed version of the chunk data: + * create a hole in the compBeast in the range + * + * This step may not be possible with current NSS + * implementation. In case of whole file compression, truncate + * the beast. + * } + */ + (void) setBeastChunkValidRange(&genMsg, + activity->decompStream.beast, + compInfo->p.chunkSize, + activity->decompStream.beastOffset, + activity->decompStream.beastSize); + setChunkCompStatus(&genMsg, activity->compStream.beast, offset, + compInfo->p.chunkSize, newCompState); + + /* Flush all modified data to disk */ + /* We must unlatch/latch compBeast/uncompBeast in order. + * The rule is if doing unlatching, unlatch compBeast before unlatching uncompBeast; + * if doing latching, latch uncompBeast before latching compBeast + */ + UNXLATCH_BEAST(compBeast); + UNXLATCH_BEAST(uncompBeast); +// BST_flush(compBeast); + BST_flush(uncompBeast); + XLATCH_BEAST(uncompBeast); + XLATCH_BEAST(compBeast); + } + else + { + /* We must unlatch/latch compBeast/uncompBeast in order. + * The rule is if doing unlatching, unlatch compBeast before unlatching uncompBeast; + * if doing latching, latch uncompBeast before latching compBeast + */ + UNXLATCH_BEAST(compBeast); + UNXLATCH_BEAST(uncompBeast); + BST_flush(uncompBeast); + XLATCH_BEAST(uncompBeast); + XLATCH_BEAST(compBeast); + + compInfo->p.status &= + ~(COMP_STATUS_UNCOMPRESSED|COMP_STATUS_COMPRESSED|COMP_STATUS_FAILURE); + compInfo->p.status |= newCompState; + + if (! activity->keepSrcChunk) + { +/* Seems it is not necessary. */ + /* Discard compressed data */ + (void) TRUNCATE_BEAST(&genMsg, activity->compStream.beast, + (activity->compStream.beastOffset + + activity->compStream.beastSize)); + } + } + + localXaction = COMN_BeginXLocal(uncompBeast); + + if (compInfo->p.UCprecious == 0) + { + /* beast was fully compressed previously, modify compression + * related information since its uncompressed version + * is presented now + */ + setBeastCompAttr(uncompBeast, 0, localXaction, FALSE); + setVolCompStats(uncompBeast, compBeast, localXaction, FALSE); + } + + /* Update precious counts and cleanup the datastream if necessary. */ + ++ compInfo->p.UCprecious; + if (! activity->keepSrcChunk) + { + if (-- compInfo->p.Cprecious == 0) + { + /* remove activity from uncompBeast->CM_activities list. */ + DQ_RMV(activity, beastActivitiesChain); + + /* wakeup all threads waiting for this activity to finish */ + CM_signalEvent((ADDR)&compInfo->CM_activities, zOK); + + if (decompCleanup(&genMsg, uncompBeast, compBeast, FALSE, localXaction) == zOK) + { + compBeast = 0; + } +/* compInfo will be released by decompCleanup */ +// else if ((compInfo = BEAST_CM_INFO(uncompBeast)) != NULL) +// { +// /* roll back the modified compression related information */ +// setBeastCompAttr(uncompBeast, zFA_DATA_STREAM_IS_COMPRESSED, localXaction, TRUE); +// setVolCompStats(uncompBeast, compBeast, localXaction, TRUE); +// } + goto releaseBeastsAndExit; + + } + } + } + + COMN_MARK_BEAST_XLOCAL(uncompBeast, localXaction); + if (COMN_ForceBeastWrite(&genMsg, uncompBeast, localXaction) != zOK) + { + zASSERT("COMN_ForceBeastWrite failed" == 0); + ClearErrno(&genMsg); + } + +cleanupAndExit: + /* remove activity from uncompBeast->CM_activities list. */ + DQ_RMV(activity, beastActivitiesChain); + if (DQ_EMPTY(&compInfo->CM_activities)) + updateBeastPurgeableBlksCnt(&genMsg, (NamedBeast_s *)uncompBeast, + compBeast, TRUE, localXaction); + + /* wakeup all threads waiting for this activity to finish */ + CM_signalEvent((ADDR)&compInfo->CM_activities, zOK); +releaseBeastsAndExit: + if (localXaction) + { + COMN_EndXLocal(uncompBeast, &localXaction); + } + + if (compBeast) + COMN_UnlatchAndRelease(&compBeast, XLATCHED); + COMN_UnlatchAndRelease(&uncompBeast, XLATCHED); +} + +STATIC void CM_activityAborted(CMActivity_s *activity, STATUS errCode) +{ + RootBeast_s *uncompBeast = activity->decompStream.beast; + RootBeast_s *compBeast = activity->compStream.beast; + CompressInfo_s *compInfo = BEAST_CM_INFO(uncompBeast); + QUAD offset = activity->decompStream.beastOffset; + NINT status; + GeneralMsg_s genMsg; + Xaction_s *localXaction = NULL; + + ASSERT_MPKNSS_LOCK(); + + XLATCH_BEAST(uncompBeast); + XLATCH_BEAST(compBeast); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + DQ_RMV(activity, beastActivitiesChain); + + activity->state = CM_ACTIVITY_STATE_FINISHED; + if (activity->op == CM_ACTIVITY_OP_COMPRESS) + { + status = COMP_STATUS_UNCOMPRESSED; + if (errCode != zERR_CM_ABORTED) + { + status |= COMP_STATUS_FAILURE; + } + + if (compInfo->p.chunkSize > 0) + { + /* + * reset compStream.beastOffset, beastSize to include the entire + * chunk (including hdr) i.e., + * hdrSize = sizeof(CompChunkHdr_s); + * compStream.beastOffset -= hdrSize; + * compStream.beastSize += hdrSize; + * + * * throw away the partially compressed chunk data + * create a hole in the compBeast in the range + * + * This step may not be possible with current NSS implementation. + * set chunk status to CantCompress; + */ + setChunkCompStatus(&genMsg, activity->compStream.beast, offset, + compInfo->p.chunkSize, status); + } + else + { + localXaction = COMN_BeginXLocal(uncompBeast); + + compInfo->p.status &= ~COMP_STATUS_COMPRESSED; + compInfo->p.status = status; + + if (errCode != zERR_CM_ABORTED) + { + setBeastCompAttr(uncompBeast, zFA_CANT_COMPRESS_DATA_STREAM, localXaction, FALSE); + } + } + + if (!(compInfo->p.action & COMP_ACTION_ENABLE_IO_WRITE) + && (compInfo->p.Cprecious == 0)) + { + /* Wakeup all threads waiting for this activity to finish. */ +// DQ_RMV(activity, beastActivitiesChain); + + CM_signalEvent((ADDR)&compInfo->CM_activities, errCode); + + /* we don't set up beast compression related attributes because we + * know it's cleaned up during compSetup. Also, we don't need to + * update volume comp blocks stats */ + + if (decompCleanup(&genMsg, uncompBeast, compBeast, FALSE, localXaction) == zOK) + { + compBeast = 0; + } + + goto releaseBeastsAndExit; + } + } + else + { + status = COMP_STATUS_COMPRESSED; + if (errCode != zERR_CM_ABORTED) + { + status |= COMP_STATUS_FAILURE; + } + + if (compInfo->p.chunkSize > 0) + { + /* + * throw away the partially decompressed chunk data + * create a hole in the uncompBeast in the range + * + * This step may not be possible with current NSS implementation. + * In case of whole file compression, truncate the beast. + */ + setChunkCompStatus(&genMsg, activity->compStream.beast, offset, + compInfo->p.chunkSize, status); + } + else + { + localXaction = COMN_BeginXLocal(uncompBeast); + + compInfo->p.status &= ~COMP_STATUS_UNCOMPRESSED; + compInfo->p.status |= status; + } + + if (compInfo->p.UCprecious == 0) + { + setBeastCompAttr(uncompBeast, zFA_DATA_STREAM_IS_COMPRESSED, localXaction, FALSE); + + /* we don't need to update volume comp blocks stats */ + compCleanup(&genMsg, uncompBeast, compBeast, FALSE, &localXaction); + } + + } + + if (localXaction) + { + COMN_MARK_BEAST_XLOCAL(uncompBeast, localXaction); + if (COMN_ForceBeastWrite(&genMsg, uncompBeast, localXaction) != zOK) + { + zASSERT("COMN_ForceBeastWrite failed" == 0); + ClearErrno(&genMsg); + } + } +// DQ_RMV(activity, beastActivitiesChain); + + if (DQ_EMPTY(&compInfo->CM_activities)) + { + updateBeastPurgeableBlksCnt(&genMsg, (NamedBeast_s *)uncompBeast, + compBeast, TRUE, localXaction); + } + + /* Wakeup all threads waiting for this activity to finish. */ + CM_signalEvent((ADDR)&compInfo->CM_activities, errCode); + +releaseBeastsAndExit: + if (localXaction) + { + COMN_EndXLocal(uncompBeast, &localXaction); + } + + if (compBeast) + { + COMN_UnlatchAndRelease(&compBeast, XLATCHED); + } + + COMN_UnlatchAndRelease(&uncompBeast, XLATCHED); +} + + +void CM_activityWorkToDoRun(FsmLite_s *workToDoFsm, ADDR unused) +{ + STATUS rc; + CMActivity_s *activity = STRUCT(workToDoFsm, CMActivity_s, fsm); + + ASSERT_MPKNSS_LOCK(); + + rc = ALGOMGR_invokeCompAlgo(activity); + if (rc != zOK) + CM_activityAborted(activity, rc); + else CM_activityDone(activity); + + zASSERT(NEXT(&activity->allActivitiesChain) != NULL); + + CM_threadExit(activity); +} + +void CM_activitySuspend(CMActivity_s *activity) +{ + ASSERT_MPKNSS_LOCK(); + + switch (activity->state) + { + case CM_ACTIVITY_STATE_RUNNABLE: + case CM_ACTIVITY_STATE_RUNNING: + activity->state = CM_ACTIVITY_STATE_SUSPENDED; + break; + default: + break; + } +} + +void CM_activityResume(CMActivity_s *activity) +{ + ASSERT_MPKNSS_LOCK(); + + switch (activity->state) + { + case CM_ACTIVITY_STATE_RUNNABLE: + case CM_ACTIVITY_STATE_RUNNING: + break; + case CM_ACTIVITY_STATE_SUSPENDED: + activity->state = CM_ACTIVITY_STATE_RUNNABLE; + CM_signalEvent((ADDR)activity, zOK); + break; + default: + break; + } +} + +void CM_activityAbort(CMActivity_s *activity, STATUS errCode, BOOL wait) +{ + ASSERT_MPKNSS_LOCK(); + + switch (activity->state) + { + case CM_ACTIVITY_STATE_RUNNABLE: + case CM_ACTIVITY_STATE_RUNNING: + activity->state = CM_ACTIVITY_STATE_ABORTING; + break; + case CM_ACTIVITY_STATE_SUSPENDED: + activity->state = CM_ACTIVITY_STATE_ABORTING; + CM_signalEvent((ADDR)activity, errCode); + break; + default: + break; + } +} diff --git a/src/nwnss/comn/compression/cmAlgoMan.c b/src/nwnss/comn/compression/cmAlgoMan.c new file mode 100644 index 0000000..dc0d45d --- /dev/null +++ b/src/nwnss/comn/compression/cmAlgoMan.c @@ -0,0 +1,568 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996-1999 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 + | + |*************************************************************************** + | + | NSS Compression Management module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2005-04-15 23:10:59 +0530 (Fri, 15 Apr 2005) $ + | + | $RCSfile$ + | $Revision: 937 $ + | + |--------------------------------------------------------------------------- + | Module Description: + | + +-------------------------------------------------------------------------*/ +#include "cmDefs.h" +#include "cmRuntime.h" +#include "cmActivity.h" +#include "cmAlgoMan.h" +#include "cmControl.h" +#include "comnCompress.h" + +typedef struct CompAlgo_s +{ + BYTE algoID; + BYTE state; +#define COMP_ALGO_STATE_UNREGISTERED 0 +#define COMP_ALGO_STATE_REGISTERED 1 +#define COMP_ALGO_STATE_UNREGISTERING 2 + CompAlgoIF_s *ops; +} CompAlgo_s; + +CompAlgo_s CompAlgoTable[NSS_MAX_COMP_ALGORITHMS] = +{ + {NSS_COMP_ALGO_ID_NETWARE, COMP_ALGO_STATE_UNREGISTERED, 0}, + {NSS_COMP_ALGO_ID_COPY, COMP_ALGO_STATE_UNREGISTERED, 0}, +}; + +void *ALGOMGR_malloc(size_t size) +{ + void *mem; + + MPKNSS_LOCK(); + mem = malloc(size); + MPKNSS_UNLOCK(); + + return mem; +} + +void ALGOMGR_free(void *mem) +{ + MPKNSS_LOCK(); + free(mem); + MPKNSS_UNLOCK(); +} + +/* + * Called by the algorithm after it is loaded. + */ +STATUS +ALGOMGR_registerCompAlgo(BYTE algoID, CompAlgoIF_s *algoIF) +{ + STATUS rc; + + MPKNSS_LOCK(); +tryAgain: ; + switch (CompAlgoTable[algoID].state) + { + case COMP_ALGO_STATE_REGISTERED: + return zERR_CM_COMP_ALGO_ALREADY_REGISTERED; + case COMP_ALGO_STATE_UNREGISTERING: + rc = CM_awaitEvent((ADDR)&CompAlgoTable[algoID]); + if (rc != zOK) + goto functionExit; + goto tryAgain; + case COMP_ALGO_STATE_UNREGISTERED: + break; + default: + break; + } + + CompAlgoTable[algoID].algoID = algoID; + CompAlgoTable[algoID].ops = algoIF; + + MPKNSS_UNLOCK(); + rc = CompAlgoTable[algoID].ops->init(); + MPKNSS_LOCK(); + if (rc != zOK) + goto functionExit; + CompAlgoTable[algoID].state = COMP_ALGO_STATE_REGISTERED; + +functionExit: ; + MPKNSS_UNLOCK(); + return rc; +} + +/* + * Called by NSS before unloading an algorithm + */ +STATUS +ALGOMGR_unregisterCompAlgo(BYTE algoID, BOOL abortOngoingActivities, BOOL wait) +{ +tryAgain: ; + switch (CompAlgoTable[algoID].state) + { + case COMP_ALGO_STATE_REGISTERED: + CompAlgoTable[algoID].state = COMP_ALGO_STATE_UNREGISTERING; + break; + case COMP_ALGO_STATE_UNREGISTERING: + if (wait) + { + (void) CM_awaitEvent((ADDR)&CompAlgoTable[algoID]); + goto tryAgain; + } + else return zOK; + case COMP_ALGO_STATE_UNREGISTERED: + return zOK; + default: + break; + } + + for (;;) + { + CMActivity_s *activity; + NINT waitCount = 0; + + DQ_FOREACH(&CM_activities, activity, CMActivity_s, allActivitiesChain) + { + switch (activity->state) + { + case CM_ACTIVITY_STATE_AVAILABLE: + case CM_ACTIVITY_STATE_ABORTED: + case CM_ACTIVITY_STATE_FINISHED: + continue; + default: + break; + } + if (abortOngoingActivities && (activity->algoID == algoID)) + activity->state = CM_ACTIVITY_STATE_ABORTING; + ++ waitCount; + } + + /* + * Wait till all the ongoing (de)compressions finish. + */ + if (waitCount == 0) + break; + else if (! wait) + return zOK; + (void) CM_awaitEvent((ADDR)&CompAlgoTable[algoID]); + } + + /* Call the algorithm's uninit() routine */ + MPKNSS_UNLOCK(); + CompAlgoTable[algoID].ops->uninit(); + MPKNSS_LOCK(); + + CompAlgoTable[algoID].ops = NULL; + CompAlgoTable[algoID].state = COMP_ALGO_STATE_UNREGISTERED; + + /* + * Signal any waiters that we are done. + */ + CM_signalEvent((ADDR)&CompAlgoTable[algoID], zOK); + return zOK; +} + +STATUS +ALGOMGR_init(void *voidVol) +{ + if (voidVol) + { + /* + * FixFixFix: + * Here we should check if all compression algorithms potentially used + * by the volume are loaded and if not, load them. + * But for the moment, who cares! + */ +// zASSERT("Hey this is not supported!" == NULL); + return zOK; + } + else if (CM_defaultAlgoStartupFn != NULL) + { + STATUS rc; + + MPKNSS_UNLOCK(); + rc = (* CM_defaultAlgoStartupFn)(); + MPKNSS_LOCK(); + return rc; + } + return zOK; +} + +void +ALGOMGR_uninit(void *voidVol, BOOL abortOngoingActivities, BOOL wait) +{ + SNINT i; + + if (voidVol) + { + /* + * FixFixFix: + * Here we should unload any algorithms that are only used by this + * volume. + */ +// zASSERT("Hey this is not supported yet!" == NULL); + } + else + { + for (i = 0; i < NSS_MAX_COMP_ALGORITHMS; ++ i) + ALGOMGR_unregisterCompAlgo(i, abortOngoingActivities, wait); + } +} + +#if zLINUX +#define LinuxCMStream_t (CMStream_t) +#else +#define LinuxCMStream_t +#endif + +STATUS +ALGOMGR_invokeCompAlgo(CMActivity_s *activity) +{ + BYTE algoID = activity->algoID; + BYTE algoVersion = activity->algoVersion; + BYTE minPercentGain = CM_curCompControlParams.minPercentGain; + STATUS rc; + + switch (CompAlgoTable[algoID].state) + { + case COMP_ALGO_STATE_REGISTERED: + break; + case COMP_ALGO_STATE_UNREGISTERED: + case COMP_ALGO_STATE_UNREGISTERING: + default: + return zERR_CM_COMP_ALGO_NOT_REGISTERED; + } + + MPKNSS_UNLOCK(); + if (activity->op == CM_ACTIVITY_OP_COMPRESS) + { + rc = CompAlgoTable[algoID].ops->compressStream(algoVersion, + LinuxCMStream_t &activity->decompStream, + LinuxCMStream_t &activity->compStream, + LinuxCMStream_t &activity->tmpStream, minPercentGain); + } + else + { + rc = CompAlgoTable[algoID].ops->uncompressStream(algoVersion, + LinuxCMStream_t &activity->compStream, + LinuxCMStream_t &activity->decompStream); + } + MPKNSS_LOCK(); + + if (rc != zOK) + activity->state = CM_ACTIVITY_STATE_ABORTING; + switch (activity->state) + { + case CM_ACTIVITY_STATE_ABORTING: + activity->state = CM_ACTIVITY_STATE_ABORTED; + break; + case CM_ACTIVITY_STATE_RUNNING: + activity->state = CM_ACTIVITY_STATE_FINISHED; + default: + break; + } + if (CompAlgoTable[algoID].state == COMP_ALGO_STATE_UNREGISTERING) + CM_signalEvent((ADDR)&CompAlgoTable[algoID], zOK); + return rc; +} + +STATUS +ALGOMGR_fetchStreamBuf( + CMStream_t streamHandle, + QUAD offset, + CMBuffer_t *cmbuf, /* out */ + LONG mode, + LONG sizeRequested, + BYTE **data, /* out; ptr to reqd data in the buffer */ + LONG *sizeReturned,/* out */ + LONG *isHole) /* out */ +{ + STATUS rc; + QUAD realOffset; + SQUAD realSize; + CMStream_s *stream; + CMActivity_s *activity; + Blknum_t realBlknum; + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + if (! ISVALID_HANDLE(streamHandle)) + { + rc = zERR_CM_INVALID_STREAM_HANDLE; + goto functionExit; + } + + stream = streamHandle.stream; + activity = stream->activity; + + /* Perform activity suspend/resume/abort control */ +tryAgain: ; + switch (activity->state) + { + case CM_ACTIVITY_STATE_ABORTING: + rc = zERR_CM_ABORTED; + goto functionExit; + case CM_ACTIVITY_STATE_SUSPENDED: + /* Block this thread on this activity; + * to be awakened when the activity is resumed */ + (void) CM_awaitEvent((ADDR) activity); + goto tryAgain; + default: + break; + } + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + /* Clip size to read against chunk size */ + *sizeReturned = sizeRequested; + realSize = stream->beastSize - offset; + if (realSize > sizeRequested) + realSize = sizeRequested; + + realOffset = stream->beastOffset + offset; + { + /* Clip realSize against actual readable size within the buffer */ + LONG readableSize = realOffset & + ((1 << stream->beast->blkSizeShift) - 1); + readableSize = (1 << stream->beast->blkSizeShift) - readableSize; + if (realSize > readableSize) + realSize = readableSize; + } + if (realSize <= 0) + { + *sizeReturned = 0; + rc = zERR_END_OF_FILE; + goto functionExit; + } + /* + * realSize bytes at realOffset in beast can be actually supplied to + * the caller. Now do the actual I/O. + */ + + if (mode == CACHE_READ) + { + SLATCH_BEAST(stream->beast); + } + else + { + XLATCH_BEAST(stream->beast); + } + + rc = zOK; + realBlknum = realOffset >> stream->beast->blkSizeShift; + if (mode == CACHE_READ) + { + if (stream->curHoleBlks > 0) + { + Blknum_t holeStart = (stream->streamOffset + stream->beastOffset) + >> stream->beast->blkSizeShift; + if ((realBlknum >= holeStart) && + (realBlknum < (holeStart + stream->curHoleBlks))) + *isHole = TRUE; + } + else + { + cmbuf->buffer = CM_fetchFileBlk(&genMsg, stream->beast, realBlknum, + mode, &stream->curHoleBlks); + if (! cmbuf->buffer) + { + rc = GetErrno(&genMsg); + goto unlatchBeastAndReturn; + } + if (stream->curHoleBlks > 0) + { + *isHole = TRUE; + CACHE_RELEASE(cmbuf->buffer); + } + } + if (*isHole) + { + INVALIDATE_HANDLE(*cmbuf); + *data = NULL; + *sizeReturned = realSize; + stream->streamOffset = offset + realSize; + -- stream->curHoleBlks; + } + } + else + { + if (activity->op == CM_ACTIVITY_OP_DECOMPRESS) + { + genMsg.flags |= DO_NOT_CHECK_SPACE_QUOTA; + } + + cmbuf->buffer = CM_fetchFileBlk(&genMsg, stream->beast, realBlknum, + mode, &stream->curHoleBlks); + if (! cmbuf->buffer) + rc = GetErrno(&genMsg); + *isHole = FALSE; + stream->curHoleBlks = 0; + } + + if (cmbuf->buffer) + { + mapBufferPage(cmbuf->buffer); + *data = cmbuf->buffer->pBuf.data + realOffset % + (1 << cmbuf->buffer->bufSizeShift); + *sizeReturned = realSize; + stream->streamOffset = offset + realSize; + } + +unlatchBeastAndReturn: ; + UNLATCH_BEAST(stream->beast); +functionExit: ; + MPKNSS_UNLOCK(); + return rc; +} + +STATUS +ALGOMGR_releaseStreamBuf( + CMStream_t streamHandle, + CMBuffer_t cmbuf, + BOOL isdirty) +{ + STATUS rc; + CMStream_s *stream; + CMActivity_s *activity; + + MPKNSS_LOCK(); + if (! ISVALID_HANDLE(streamHandle)) { + rc = zERR_CM_INVALID_STREAM_HANDLE; + goto functionExit; + } + + if (! ISVALID_HANDLE(cmbuf)) { + rc = zERR_CM_INVALID_BUFFER_HANDLE; + goto functionExit; + } + + stream = streamHandle.stream; + if (cmbuf.buffer) + { + unmapBufferPage(cmbuf.buffer); + if (isdirty) + CACHE_DIRTY_RELEASE(cmbuf.buffer); + else CACHE_RELEASE(cmbuf.buffer); + } + + /* Perform activity suspend/resume/abort control */ + activity = stream->activity; + + /* Update sizeDone (size of target stream already (de)compressed) */ + if (activity->op == CM_ACTIVITY_OP_DECOMPRESS) + { + if (stream == &activity->decompStream) + { + CompressInfo_s *compInfo = BEAST_CM_INFO(stream->beast); + + activity->sizeDone += (1 << stream->beast->blkSizeShift); + zASSERT(compInfo); + UNCOMP_DATA_AVAILABLE(&compInfo->dataWaiters, stream->beastOffset, + activity->sizeDone); + } + } + else + { + if (stream == &activity->compStream) + activity->sizeDone += (1 << stream->beast->blkSizeShift); + } + +tryAgain: ; + switch (activity->state) + { + case CM_ACTIVITY_STATE_ABORTING: + rc = zERR_CM_ABORTED; + goto functionExit; + case CM_ACTIVITY_STATE_SUSPENDED: + /* Block this thread on this activity; + * to be awakened when the activity is resumed */ + (void) CM_awaitEvent((ADDR) activity); + goto tryAgain; + default: + break; + } + rc = zOK; + +functionExit: ; + MPKNSS_UNLOCK(); + return rc; +} + +/* + * This operation truncates/pads the stream to given size. + * We delay the resizing till the end of the activity. + */ +STATUS +ALGOMGR_setStreamSize(CMStream_t streamHandle, QUAD size) +{ + CMStream_s *stream; + + MPKNSS_LOCK(); + stream = streamHandle.stream; + stream->beastSize = size; + MPKNSS_UNLOCK(); + return zOK; +} + +QUAD +ALGOMGR_getStreamSize(CMStream_t streamHandle) +{ + QUAD beastSize; + CMStream_s *stream; + + MPKNSS_LOCK(); + stream = streamHandle.stream; + beastSize = stream->beastSize; + MPKNSS_UNLOCK(); + return beastSize; +} + +STATUS +ALGOMGR_setStreamPosition(CMStream_t streamHandle, QUAD offset) +{ + CMStream_s *stream; + + MPKNSS_LOCK(); + stream = streamHandle.stream; + stream->streamOffset = offset; + stream->curHoleBlks = 0; + MPKNSS_UNLOCK(); + return zOK; +} + +QUAD +ALGOMGR_getStreamPosition(CMStream_t streamHandle) +{ + QUAD streamOffset; + CMStream_s *stream; + + MPKNSS_LOCK(); + stream = streamHandle.stream; + streamOffset = stream->streamOffset; + MPKNSS_UNLOCK(); + return streamOffset; +} diff --git a/src/nwnss/comn/compression/cmBgCompress.c b/src/nwnss/comn/compression/cmBgCompress.c new file mode 100644 index 0000000..8f54553 --- /dev/null +++ b/src/nwnss/comn/compression/cmBgCompress.c @@ -0,0 +1,537 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996-1999 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 + | + |*************************************************************************** + | + | NSS Compression Management module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2006-11-03 22:22:01 +0530 (Fri, 03 Nov 2006) $ + | + | $RCSfile$ + | $Revision: 1609 $ + | + |--------------------------------------------------------------------------- + | Module Description: + | + +-------------------------------------------------------------------------*/ +#include "cmDefs.h" +#include "cmControl.h" +#include "cmNSS.h" +#include "alarm.h" +#include "nssPubs.h" + +typedef struct CMBgCompressControl_s +{ + BOOL inProgress; /* Background compression currently in progress */ + BOOL scheduled; /* Background compression currently in progress */ + WORD reason; /* Who started the background compression */ + WORD unused; /* just for the alignment */ +#define CM_BG_COMPRESS_REASON_NONE 0 +#define CM_BG_COMPRESS_REASON_TIMER 1 +#define CM_BG_COMPRESS_REASON_USER_REQUEST 2 + OneShot_s alarm; /* Alarm for periodic background compression */ + FsmLite_s fsm; /* thread on which background compression happens */ +} CMBgCompressControl_s; +#define BG_COMPRESS_ABORTED(_bgCompress) (! (_bgCompress)->inProgress) +#define ABORT_BG_COMPRESS(_bgCompress) ((_bgCompress)->inProgress = FALSE) + +#define MAX_ZIDS_PER_SCOOP 100 +STATIC void CM_compressIdleFiles(Volume_s *volume, CMBgCompressControl_s *bgCompress) +{ + typedef struct Stack_s { + Zid_t beastZids[MAX_ZIDS_PER_SCOOP]; + } Stack_s; + Zid_t lastZidReturned; + GeneralMsg_s genMsg; + LONG i; + NINT numBeastsReturned; + NamedBeast_s *beast; + STATUS rc; + + STACK_ALLOC(); + ASSERT_MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + lastZidReturned = zINVALID_ZID; + + do + { + if (BG_COMPRESS_ABORTED(bgCompress)) + { + STACK_FREE(); + return; + } + + /* Make sure the volume is in active state */ + if (volume->v_statusFlag & VOL_SF_LEAVING_ACTIVE_STATE_CLEANUP) + { + STACK_FREE(); + return; + } + + /* Make sure compression is enabled on the volume */ + if ((! CM_curCompControlParams.compEnabled) || + (! (volume->VOLenabledAttributes & zATTR_COMPRESSION))) + { + STACK_FREE(); + return; + } + + if (volume->cmVolumeState.compActive != TRUE) + { + /* volume is deactivating */ + STACK_FREE(); + return; + } + + /* Obtain a scoop of ZIDs to examine */ + rc = volume->VOLcomnVolOps.VOL_browseBeastsInVolume(&genMsg, volume, + SELECT_BEASTS_FOR_COMPRESSION, MAX_ZIDS_PER_SCOOP, + &lastZidReturned, aStack->beastZids, &numBeastsReturned); + if (rc != zOK) + { + numBeastsReturned = 0; + ClearErrno(&genMsg); + } + + /* Process each of the above beasts in turn */ + for (i = 0; i < numBeastsReturned; ++ i) + { + if (volume->cmVolumeState.compActive != TRUE) + { + /* and if volume is deactivating */ + STACK_FREE(); + return; + } + + /* Obtain the beast */ + beast = (NamedBeast_s *)COMN_LookupByZid(&genMsg, volume, + aStack->beastZids[i], SLATCHED, TRUE); + + /* Ignore all errors */ + ClearErrno(&genMsg); + if (! beast) + continue; + + /* Compress only beasts satisfying the following criteria */ + if (COMN_IsDerivedFrom(beast, zFTYPE_NAMED_DATA_STREAM) && + ((beast->NAMEDattributes & + (zFA_SUBDIRECTORY|zFA_IS_LINK|zFA_DO_NOT_COMPRESS_FILE| + zFA_CANT_COMPRESS_DATA_STREAM)) == 0)) + { + if (beast->NAMEDattributes & zFA_COMPRESS_FILE_IMMEDIATELY) + { + if ((beast->NAMEDattributes & + (zFA_DATA_STREAM_IS_COMPRESSED | zFA_CANT_COMPRESS_DATA_STREAM)) != 0) + { + goto skipBeast; + } + } + else if (beast->NAMEDattributes & zFA_DO_NOT_COMPRESS_FILE) + { + goto skipBeast; + } + else if (beast->NAMEDnameFlags & NFL_ADDED_TO_SALVAGE_TREE) + { + switch (CM_curCompControlParams.compressDeletedFilesOption) + { + case COMP_DELETED_FILES_NEVER: + goto skipBeast; + case COMP_DELETED_FILES_NEXT_DAY: + if (COMN_IsDerivedFrom(beast, zFTYPE_FILE) && + (GetUTCTime() < + (((File_s *)beast)->FILEaccessedTime + + CM_curCompControlParams.minDeletedFileIdleTime))) + { + goto skipBeast; + } + break; + default: + break; + } + } + else if (COMN_IsDerivedFrom(beast, zFTYPE_FILE) && + (GetUTCTime() < + (((File_s *)beast)->FILEaccessedTime + + CM_curCompControlParams.minFileIdleTime))) + { + goto skipBeast; + } + + /* Check again if bgCompress is disabled by user. */ + if (BG_COMPRESS_ABORTED(bgCompress) || + (volume->cmVolumeState.compActive != TRUE)) + { + COMN_UnlatchAndRelease(&beast, SLATCHED); + STACK_FREE(); + return; + } + + /* if parent won't allow compression, skip this beast */ + if(!CM_checkParentDirForCompressOK(&genMsg, (File_s*)beast)) + { + goto skipBeast; + } + + /* + * Obtained a potential candidate for compression; + * Initiate its compression in the background and proceed. + */ + rc = CM_compressFileAsync(&genMsg, &beast->NAMEDroot, + SLATCHED, COMP_BACKGROUND); + if ((rc != zOK) && (GetErrno(&genMsg) == zERR_NO_MEMORY)) + { + /* + * Couldn't queue for compression due to low memory. + * wait for some ongoing compressions to finish + * and try again. + */ + ClearErrno(&genMsg); + COMN_UnlatchAndRelease(&beast, SLATCHED); + + LB_delay(100); // in milliseconds + + -- i; /* Retry compressing same beast. */ + continue; + } + } +skipBeast: ; + COMN_UnlatchAndRelease(&beast, SLATCHED); + + PERIODIC_YIELD(); + } + } while (numBeastsReturned == MAX_ZIDS_PER_SCOOP); + STACK_FREE(); +} + + +void CM_bgCompressCleanUp() +{ + CM_stopCompression(COMP_BACKGROUND); +} + +void CM_bgCompressRun(CMBgCompressControl_s *bgCompress) +{ + GeneralMsg_s dummyGenMsg; + Volume_s *prevVolume = NULL; + Volume_s *nextVolume; + + ASSERT_MPKNSS_LOCK(); + + COMN_SETUP_GENERAL_MSG_NOSA(&dummyGenMsg); + + /* Scan all known volumes for compression */ + while (! BG_COMPRESS_ABORTED(bgCompress)) + { + nextVolume = COMN_GetNextVolume(prevVolume); + if (prevVolume) + { + COMN_Release(&prevVolume); + } + + if (nextVolume == NULL) + { + break; + } + + prevVolume = nextVolume; + + /* Start background compression on this volume */ + if (COMN_LockVolumeActive(&dummyGenMsg, nextVolume, FALSE) == zOK) + { + CM_compressIdleFiles(nextVolume, bgCompress); + + COMN_UnlockVolumeActive(nextVolume, FALSE); + } + } + + if (prevVolume) + { + COMN_Release(&prevVolume); + } + + if (BG_COMPRESS_ABORTED(bgCompress)) + { + CM_bgCompressCleanUp(); + } + else + { + bgCompress->inProgress = FALSE; + } + + /* Set an alarm to start background compression at next interval */ + if (bgCompress->reason == CM_BG_COMPRESS_REASON_USER_REQUEST) + { + CM_bgCompressRestartStartTimer(FALSE); + } +} + + +/* Forward declarations */ +void CM_bgCompressStopTimerPopped(OneShot_s *alarm); +void CM_bgCompressStartTimerPopped(OneShot_s *alarm); + +/* + * Seconds to elapse before the specified time of day, + * Wraps to next day if needed. + */ +STATIC LONG +SecondsToTimeOfDay(LONG targetTimeOfDay) +{ + DOSTime_t dosTime = UTC2dosTime(GetUTCTime()); + NINT hour = ((dosTime >> 11) & 0x1f); + NINT min = ((dosTime >> 5) & 0x3f); + NINT sec = ((dosTime & 0x1f) << 1); + NINT secOfDay = (hour * 60 + min) * 60 + sec; + SLONG waitSecs = targetTimeOfDay - secOfDay; + + if (waitSecs < 0) + waitSecs += 24 * 60 * 60; + return (LONG) waitSecs; +} + +STATIC void +CM_bgCompressWorkerThread(FsmLite_s *workToDoFsm, ADDR startCompress) +{ + CMBgCompressControl_s *bgCompress = + STRUCT(workToDoFsm, CMBgCompressControl_s, fsm); + + ASSERT_MPKNSS_LOCK(); + + bgCompress->scheduled = FALSE; + if ((BOOL)startCompress) + { + CM_bgCompressRun(bgCompress); + } + else + { + /* clean up any queued request */ + CM_bgCompressCleanUp(); + } +} + +STATIC void +CM_startBgCompress(CMBgCompressControl_s *bgCompress) +{ + ASSERT_MPKNSS_LOCK(); + + if (! bgCompress->scheduled && ! bgCompress->inProgress) + { + bgCompress->inProgress = TRUE; + bgCompress->scheduled = TRUE; + WORK_Schedule(&bgCompress->fsm, CM_bgCompressWorkerThread, (ADDR)TRUE); + } +} + +STATIC void +CM_stopBgCompress(CMBgCompressControl_s *bgCompress) +{ + ASSERT_MPKNSS_LOCK(); + + if (bgCompress->inProgress) + { + ABORT_BG_COMPRESS(bgCompress); + } + else + { + if (! bgCompress->scheduled) + { + /* clean up any queued request */ + bgCompress->scheduled = TRUE; + WORK_Schedule(&bgCompress->fsm, CM_bgCompressWorkerThread, (ADDR)FALSE); + } + } + +} + +STATIC void +CM_bgCompressStartTimerPopped(OneShot_s *alarm) +{ + CMBgCompressControl_s *bgCompress = + STRUCT(alarm, CMBgCompressControl_s, alarm); + + ASSERT_MPKNSS_LOCK(); + + if (! bgCompress->inProgress) + { + LONG secsToStop = SecondsToTimeOfDay( + CM_curCompControlParams.dailyCheckStopTime); + + if (! secsToStop) + return; + + /* Set an alarm to stop background compression */ + secOneShot(&bgCompress->alarm, secsToStop, + CM_bgCompressStopTimerPopped); + + /* Start the background compression thread */ + bgCompress->reason = CM_BG_COMPRESS_REASON_TIMER; + CM_startBgCompress(bgCompress); + } +} + +STATIC void +CM_bgCompressStopTimerPopped(OneShot_s *alarm) +{ + CMBgCompressControl_s *bgCompress = + STRUCT(alarm, CMBgCompressControl_s, alarm); + + ASSERT_MPKNSS_LOCK(); + + if (bgCompress->reason == CM_BG_COMPRESS_REASON_TIMER) + { + LONG secsToStart = SecondsToTimeOfDay( + CM_curCompControlParams.dailyCheckStartTime); + + /* Don't stop compression if next interval has already started */ + if (! secsToStart) + return; + + /* Stop the background compression thread */ + CM_stopBgCompress(bgCompress); + + /* Set an alarm to start background compression at next interval */ + /* Cancel any previous timer */ + CANCEL_ALARM(bgCompress->alarm); + + secOneShot(&bgCompress->alarm, secsToStart, + CM_bgCompressStartTimerPopped); + } +} + +STATIC CMBgCompressControl_s CM_bgCompressControl = {0}; + +void CM_bgCompressRestartStartTimer(BOOL startup) +{ + LONG secsToStart = SecondsToTimeOfDay( + CM_curCompControlParams.dailyCheckStartTime); + + ASSERT_MPKNSS_LOCK(); + + // Change of start timer only affects when bgCompression is not on progress + if (startup) + { + secOneShot(&CM_bgCompressControl.alarm, + secsToStart, CM_bgCompressStartTimerPopped); + } + else if (!CM_bgCompressControl.inProgress) + { + /* Cancel any previous timer */ + if (ONESHOT_SET(CM_bgCompressControl.alarm)) + { + CANCEL_ALARM(CM_bgCompressControl.alarm); + } + + if (secsToStart > 0) + { + /* Set an alarm to start background compression at next interval */ + secOneShot(&CM_bgCompressControl.alarm, + secsToStart, CM_bgCompressStartTimerPopped); + } + else CM_bgCompressStartTimerPopped(&CM_bgCompressControl.alarm); + } + +} + +void CM_bgCompressRestartStopTimer(BOOL startup) +{ + LONG secsToStart = SecondsToTimeOfDay( + CM_curCompControlParams.dailyCheckStopTime); + + ASSERT_MPKNSS_LOCK(); + + // Change of stop timer only affects when bgCompression is on progress + if (!startup) + { + if (CM_bgCompressControl.inProgress) + { + /* Cancel any previous timer */ + if (ONESHOT_SET(CM_bgCompressControl.alarm)) + { + CANCEL_ALARM(CM_bgCompressControl.alarm); + } + + if (secsToStart > 0) + { + /* Set an alarm to start background compression at next interval */ + secOneShot(&CM_bgCompressControl.alarm, secsToStart, CM_bgCompressStopTimerPopped); + } + else CM_bgCompressStopTimerPopped(&CM_bgCompressControl.alarm); + } + } +} + +void +CM_bgCompressInit() +{ + ASSERT_MPKNSS_LOCK(); + + CM_bgCompressControl.inProgress = FALSE; + CM_bgCompressControl.scheduled = FALSE; + CM_bgCompressControl.reason = CM_BG_COMPRESS_REASON_NONE; + INIT_ONESHOT(CM_bgCompressControl.alarm); + FSMLITE_INIT(&CM_bgCompressControl.fsm, + "FSM for background compression/decompression", 1); +} + +/* + * Interface to explicitly request to start background compression. + */ +void +CM_bgCompressStartRequest() +{ + ASSERT_MPKNSS_LOCK(); + + CM_bgCompressControl.reason = CM_BG_COMPRESS_REASON_USER_REQUEST; + CM_startBgCompress(&CM_bgCompressControl); +} + +/* + * Interface to explicitly request to stop background compression. + */ +void +CM_bgCompressStopRequest() +{ + ASSERT_MPKNSS_LOCK(); + + CM_stopBgCompress(&CM_bgCompressControl); +} + + +/* + * When UTC is changed (cause by change of time zone), + * we need to recompute bgcompression start and stop time + */ +void CM_bgCompressResetTimer() +{ + ASSERT_MPKNSS_LOCK(); + + if (CM_bgCompressControl.inProgress) + { + CM_bgCompressRestartStopTimer(FALSE); + } + else + { + CM_bgCompressRestartStartTimer(FALSE); + } +} diff --git a/src/nwnss/comn/compression/cmControl.c b/src/nwnss/comn/compression/cmControl.c new file mode 100644 index 0000000..22417a1 --- /dev/null +++ b/src/nwnss/comn/compression/cmControl.c @@ -0,0 +1,161 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996-1999 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 + | + |*************************************************************************** + | + | NSS Compression Management module + | + |--------------------------------------------------------------------------- + | + | $Author: taysom $ + | $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $ + | + | $RCSfile$ + | $Revision: 465 $ + | + |--------------------------------------------------------------------------- + | Module Description: + | + +-------------------------------------------------------------------------*/ +#include "cmDefs.h" +#include "cmAlgoMan.h" +#include "cmActivity.h" +#include "cmRuntime.h" +#include "cmControl.h" +#include "cmNSS.h" + +CMCompControlParams_s CM_curCompControlParams = +{ + 0, + 0, + 5, + 10, + 0, + 24 * 60 * 60, + TRUE, + MAX_ZIDS_QUEUED_FOR_COMPRESSION, + 20, + DECOMP_OPTION_LEAVE_DECOMPRESSED_FOR_N_ACCESSES, + COMP_DELETED_FILES_NEXT_DAY, + 0, + 31 * 60 + 18, +}; + + +void CM_controlCompression(BOOL enable) +{ + /* Compression Enabled flag has changed */ + if (enable != CM_curCompControlParams.compEnabled) + { + CM_curCompControlParams.compEnabled = enable; + + if (enable) + { + /* + * Start all the pending requests. + */ + CM_startPendingCompressions(); + } + else + { + /* + * Even if compression is disabled on this server, we let all ongoing + * activities to finish, as otherwise they might hold up precious + * resources. + */ + } + } +} + +void CM_controlMaxConcurrentComp(NINT value) +{ + CM_curCompControlParams.maxCompressions = value; + CM_threadsChange(); + CM_activityPoolChange(); +} + +CMCompStatistics_s CM_curCompStatistics; +STATUS getCompStatistics(CMCompStatistics_s *stats) +{ + *stats = CM_curCompStatistics; + return zOK; +} + +STATIC VolumeCompAttr_s CM_defaultVolumeCompAttributes = +{ + NSS_COMP_IMPL_MAJOR_VERSION, + NSS_COMP_IMPL_MINOR_VERSION, + NSS_COMP_ALGO_ID_NETWARE, + NETWARE_COMP_ALGO_VERSION, + 0, + 0, + (1 << NSS_COMP_ALGO_ID_NETWARE) | (1 << NSS_COMP_ALGO_ID_COPY), +}; + + /* Check that sizes are still correct. Needed for our + * COMPILER_NO_INCOMPLETE_OFFSETOF compilers as they will not + * calculate items at compile time. + */ +BYTE CHECK_CompRequestScoop_s_1[ (3 == COMP_REQUEST_SCOOP_UNUSED_WORD) ? 1 : 0 ]; +BYTE CHECK_CompRequestScoop_s_2[ (510 == MAX_COMP_REQS_PER_SCOOP) ? 1 : 0 ]; +BYTE CHECK_CompRequestScoop_s_3[ (4096 == sizeof(CompRequestScoop_s)) ? 1 : 0 ]; + +void CM_resetVolumeCompState(Volume_s *volume) +{ + /* Initialize volume's persistent data */ + volume->VOLcompAttributes = CM_defaultVolumeCompAttributes; + + /* Initialize volume's logged persistent data */ + volume->VOLnumCompressedFiles = 0; + volume->VOLnumCompDelFiles = 0; + volume->VOLnumUncompressibleFiles = 0; + volume->VOLnumCompressedFileBlocks = 0; +} + +void CM_initVolumeCompState(Volume_s *volume) +{ + /* remember the compFlags setting, volume modify routines calls this function. + * compFlags is set by ZLSS level, if we don't remember the flags and set + * them back after reset volume's compression state, we won't have chance + * to do it later + */ + LONG compFlags = volume->VOLcompAttributes.compFlags & + (VOL_COMP_FLAGS_UPGRADE_START | VOL_COMP_FLAGS_UPGRADE_FINISHED); + + /* Initialize volume's persistent data */ + CM_resetVolumeCompState(volume); + + /* set back its previous compFlags setting */ + volume->VOLcompAttributes.compFlags |= compFlags; +} + +/* Interface to set Volume/file/directory Compression Attributes */ +STATUS volSetCompAttr(Volume_s *volume, VolumeCompAttr_s *newAttr) +{ + return zOK; +} + +STATUS +CM_controlInit() +{ + bzero(&CM_curCompStatistics, sizeof(CM_curCompStatistics)); + CM_bgCompressInit(); + return zOK; +} diff --git a/src/nwnss/comn/main/comnAudit.h b/src/nwnss/comn/main/comnAudit.h new file mode 100644 index 0000000..749435a --- /dev/null +++ b/src/nwnss/comn/main/comnAudit.h @@ -0,0 +1,68 @@ +/**************************************************************************** + | + | (C) Copyright 2001-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 Loadable Storage Services (LSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: $ + | $Date: $ + | + | $RCSfile$ + | $Revision: $ + | + |--------------------------------------------------------------------------- + | This module is used to: + +-------------------------------------------------------------------------*/ + +#ifndef _COMNAUDIT_H_ +#define _COMNAUDIT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AUDIT_KERNEL_OTHER +#define AUDIT_KERNEL_OTHER 1316 +#endif + +extern BOOL NSSLAF_AuditEnabled; + +extern void NSSLAF_LogTrusteeChange( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + LONG mode, + UserID_t *trustee, + NINT rights, + NINT attributes, + NINT inheritedRights); + +#define NSSLAF_MODE_ADD_TRUSTEE 1 +#define NSSLAF_MODE_REMOVE_TRUSTEE 2 +#define NSSLAF_MODE_SET_INHERITED_RIGHTS 3 + + +#ifdef __cplusplus +} +#endif + +#endif /* #ifdef _COMNAUDIT_H_ */ diff --git a/src/nwnss/comn/main/comnCmdline.c b/src/nwnss/comn/main/comnCmdline.c new file mode 100644 index 0000000..189cff7 --- /dev/null +++ b/src/nwnss/comn/main/comnCmdline.c @@ -0,0 +1,4364 @@ +/**************************************************************************** + | + | (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: cteerlink $ + | $Date: 2008-04-18 03:39:54 +0530 (Fri, 18 Apr 2008) $ + | + | $RCSfile$ + | $Revision: 2319 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | command line options for all input action + | + +-------------------------------------------------------------------------*/ +#include /* NetWare Include files*/ +#include +#include +#include +#include +#include + +#include "comnPublics.h" + +#include /* necessary with above changes */ + +#include /* NSS Library Includes*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +#include "comnCmdline.h" +#include "pssStartup.h" +#include "comnBeastClass.h" +#include "volume.h" +#include "zParams.h" +#include "zasAuthCache.h" +#include "name.h" +//#include "menuMain.h" +#include "repair.h" +#include "hmc.h" +#include "inst.h" +#include "cacheControl.h" +#include "adminVolume.h" +#include "mgmt.h" +#include "nssOSAPIs.h" +#include "msgName.h" +#include "dirQuotas.h" +#include "cmNSS.h" +#include "comnIO.h" +#include "nssPubs.h" +#include "objectIDStore.h" +#include "checker.h" +#include "seqUpdater.h" +#include "comnAuthorize.h" +#include "nfsLock.h" +#include "csa.h" +#include "utc.h" +#include "opLock.h" +#include "unixAuthModel.h" +#include "zPublics.h" +#include "comnAudit.h" + + +extern BOOL VIRT_PrintDebug; + +extern BOOL COMN_OldCreateRights; /* Enables the old broken create rights + * where we forced zRR_WRITE_ACCESS rights + * on everybody. + */ +extern BOOL COMN_IgnoreDoNotModifyMask; + +/*------------------------------------------------------------------------- + * Constant strings we use alot. + *-------------------------------------------------------------------------*/ +#define OnStr (MSG("ON", 874)) +#define OffStr (MSG("OFF", 875)) + + +NINT COMN_IncludeType = COMN_IT_DEFAULT; + /* BitMask of which type of volumes/pools + * a command is working on. Legal bits + * COMN_IT_LOCAL and COMN_IT_SHARED. This + * global is set by the /IncludeType switch. + */ + + +NINT COMN_OverrideType = COMN_OT_DEFAULT; + /* BitMask of overrides that a user can + * specify that modifies how a command works. + * Legal bits COMN_OT_SHARED, COMN_OT_CORRUPT + * and COMN_OT_QUESTIONS. This + * global is set by the /OverrrideType switch. + */ + +BOOL REZID_PoolLVolumes = FALSE; +BOOL REBUILD_PURGE_PoolLVolumes = FALSE; + +/************************************************************************** + * Display current NSS Options + ***************************************************************************/ +void DisplayNSSStatus() +{ +// wPause(stdout, -1); + + aprintf(LGREEN, MSG("Current " "NSS" " Status:\n", 876)); + + aprintf(LGRAY, MSG(" Current Buffer Cache Size = %uk (%u)\n", 877),(Config.cache.numPagesAllocated * 4),Config.cache.numPagesAllocated); + aprintf(LGRAY, MSG(" Current Private Cache Size = %uk (%u)\n", 0),(Config.cache.privateCachePages * (4096/1024)),Config.cache.privateCachePages); + aprintf(LGRAY, MSG(" Private Cache Size Limit = %uk (%u)\n", 0),(Config.cache.privateCachePageBuffers * (4096/1024)),Config.cache.privateCachePageBuffers); + aprintf(LGRAY, MSG(" High Memory Cache Type = %s\n", 0), HMC_CacheName()); + aprintf(LGRAY, MSG(" Minimum NSS Buffer Cache Size = %uk (%u)\n", 878),(Config.cache.numBuffers * 4),Config.cache.numBuffers); +// aprintf(LGRAY, MSG(" Minimum NetWare Buffer Cache Size = %uk (%u)\n", 879),(Config.cache.minOSFree * 4),Config.cache.minOSFree); + aprintf(LGRAY, MSG(" Cache Balance Percent = %u%%\n", 880),(Config.cache.usePercentMemory ? Config.cache.percentOfOSFree : 0)); + aprintf(LGRAY, MSG(" Cache Balance Timer = %u %s\n", 881),(Config.cache.usePercentMemory ? Config.cache.balanceTimerSecs : 0), + (Config.cache.balanceTimerSecs == 1)?MSG("second",882):MSG("seconds",883)); + aprintf(LGRAY, MSG(" Journal Flush Timer = %u %s\n", 0), + (int)Config.sec.journalGroupWriteTime, + (Config.sec.journalGroupWriteTime == 1) ? + MSG("second",885) : MSG("seconds",886) ); + aprintf(LGRAY, MSG(" Metadata Flush Timer = %u %s\n", 0), + (int)Config.sec.metadataGroupWriteTime, + (Config.sec.metadataGroupWriteTime == 1) ? + MSG("second",885) : MSG("seconds",886) ); + aprintf(LGRAY, MSG(" User Data Flush Timer = %u %s\n", 0), + (int)Config.sec.userDataGroupWriteTime, + (Config.sec.userDataGroupWriteTime == 1) ? + MSG("second",885) : MSG("seconds",886) ); + aprintf(LGRAY, MSG(" Current Metadata Group Write Size = %uk (%u)\n", 0), + (int)(Config.cache.metadataBlocksReadyForGroupWrite*(4096/1024)), + (int)Config.cache.metadataBlocksReadyForGroupWrite); + aprintf(LGRAY, MSG(" Metadata Block Group Write Limit = %uk (%u)\n", 0), + (int)(Config.cache.metadataBlocksReadyForGroupWriteLimit*(4096/1024)), + (int)Config.cache.metadataBlocksReadyForGroupWriteLimit); + + aprintf(LGRAY, MSG(" Open File Hash Table Size = %u entries\n", 887),(Config.bst.hashSize)); + aprintf(LGRAY, MSG(" Closed File Cache Size = %u files\n", 888),Config.bst.notInUseMax); + aprintf(LGRAY, MSG(" File Flush Timer = %u %s\n", 889),Config.sec.beast, + (Config.sec.beast == 1)?MSG("second",890):MSG("seconds",891)); + aprintf(LGRAY, MSG(" Name Cache Size = %u entries\n", 892),NameCache.maxEntries); + aprintf(LGRAY, MSG(" Authorization Cache Size = %u entries\n", 893),AuthCache.maxEntries); + aprintf(LGRAY, MSG(" Mailbox Size = %u entries\n", 894),Config.os.sizeMailbox); + aprintf(LGRAY, MSG(" Minimum Number of AsyncIOs = %u\n", 895),Config.cache.numAsyncios); + aprintf(LGRAY, MSG(" Minimum Number of Bonds = %u\n", 896),Config.cache.numBonds); + aprintf(LGRAY, MSG(" Minimum Number of WorkToDos = %u\n", 897),Config.os.workLimit); +} + + +/*======================================================================== + *======================================================================== + * Routines used to help process the command line. + *======================================================================== + *========================================================================*/ + +/************************************************************************** + * Change the minimum number of cache buffers allocated to NSS. + ***************************************************************************/ +STATUS doChangeCacheBuffers ( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + NINT newSize, maxSize; + struct sysinfo si; + + MPKNSS_LOCK(); + + newSize = *(NINT *)switchDef->ret_value; + if (newSize < MIN_NUM_BUFFERS) + { + if ( options & POPT_AT_STARTUP) + { + printk("<3>NSS: Size must be larger than %d.\n", MIN_NUM_BUFFERS); + } + else + { + aprintf(LRED, MSG("Size must be larger than %d.\n",0), MIN_NUM_BUFFERS); + } + goto exit; + } + si_meminfo(&si); + maxSize = ((si.totalram - si.totalhigh) / 100) * 80; + if (newSize > maxSize) + { + if ( options & POPT_AT_STARTUP) + { + printk("<3>NSS: Size must be smaller than %d.\n", maxSize); + } + else + { + aprintf(LRED, MSG("Size must be smaller than %d.\n",0), maxSize); + } + goto exit; + } + if ( !(options & POPT_AT_STARTUP) && + (Config.cache.hmcCacheType == HMC_CT_PRIVATE) && + (newSize >= Config.cache.privateCachePageBuffers) ) + { + aprintf(LRED, MSG("Size requested is larger than the private cache size.\nYou have to first increase the PrivateCacheSizeInBlocks.\n",0)); + goto exit; + } + + Config.cache.numBuffers = newSize; + + changeCacheBuffers(); +exit: + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Switch between cache balancing being turned off versus turned on. + ***************************************************************************/ +STATUS doCacheBalance ( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ +#ifndef __linux__ // LINUX_CacheBalance + MPKNSS_LOCK(); + cacheBalance(); + MPKNSS_UNLOCK(); +#endif + return zOK; +} + +#if zLINUX +/************************************************************************** + * Echo a line for NSSCON + **************************************************************************/ + STATUS doEchoString( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + if(switchDef->ret_value) + { + aprintf(WHITE, MSGNot("%U"),(unicode_t *)switchDef->ret_value); + } + return zOK; +} +#endif + +/************************************************************************** + * Resets some instrumentation data like total bytes read/written and + * cache hits/misses. + ***************************************************************************/ +STATUS doResetInst ( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + resetInst(); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * + ***************************************************************************/ +STATUS doStatusDisplay( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + DisplayNSSStatus(); + MPKNSS_UNLOCK(); + return zOK; +} + + +/* + * COMN_ChangeStateCommandLineSwitches() - + * Converts UI switches into the proper bits to the CPS API. + * The UI switches have already been parsed. This code uses + * MACROs to access GLOBAL variables to determine the VOLMODE_ to set. + * + * Notes - + * This routine must be called during the parseing of the command line + * because the GLOBALs that we reference are only valid during the + * parse of the command line. + */ + +NINT COMN_ChangeStateCommandLineSwitches() + +{ + NINT mode = 0; + + if ( COMN_CmdSwitchVerbose() ) + { /* User wishes to have verbose output. */ + mode |= VOLMODE_VERBOSE; + } + if ( COMN_CmdSwitchQuestions() ) + { /* User wishes to be able to abort CPS. */ + mode |= VOLMODE_USER_ABORTABLE; + } + if ( COMN_CmdSwitchCVSShared() ) + { /* User wishes to CPS pools that are SHARED even though + * clustering software is not loaded. + */ + mode |= VOLMODE_OVERRIDE_SHARED; + } + if ( COMN_CmdSwitchCVSCorrupt() ) + { /* User wishes to CPS pools that are corrupt even though + * this could lead to more corruption. + */ + mode |= VOLMODE_OVERRIDE; + } +// if ( COMN_CmdSwitchIncludeLocal() ) +// { /* User wishes to operate on LOCAL pools */ +// mode |= VOLMODE_INCLUDE_LOCAL; +// } +// if ( COMN_CmdSwitchIncludeShared() ) +// { /* User wishes to operate on SHARED pools */ +// mode |= VOLMODE_INCLUDE_SHARED; +// } +#if NSS_DEBUG IS_ENABLED + DBG_ScreenAPrintf( "COMN.Greg.CommandLine", WHERE, LRED,"CPS Mode is 0x%x\n",mode); +#endif + return(mode); + +} /* End of COMN_ChangeStateCommandLineSwitches() */ + +#if zNETWARE +/**************************************************************************** + * Prompt for a password and return it in a supplied buffer + * We assume that MPNSS_LOCK is already locked + ****************************************************************************/ + +void getEncryptedVolumePassword(unicode_t *password) +{ + struct ScreenStruct *screenID; + NINT bufsize = ENCRYPTED_VOLUME_PASSWORD_LENGTH +1; + BYTE buffer[ENCRYPTED_VOLUME_PASSWORD_LENGTH +1]; + NINT retval; + NINT charCount = 0; + WORD row; + WORD column; + BYTE *prompt = MSG("\r\n Enter Encrypted Volume Password:",87); + + MPKNSS_UNLOCK(); + + bufsize = sizeof(buffer); + screenID = GET_SCREENID(wStdin); + OutputToScreen( screenID, MSGNot("%s> "), prompt); + column = LB_strlen(prompt) + 2; + + GetOutputCursorPosition( screenID, &row, &column); + PositionOutputCursor(screenID, row, column); + PositionInputCursor(screenID, row, column); + + EnableInputCursor(screenID); + + /* Reserve room in buffer for trailing NULL */ + --bufsize; + + MPKNSS_LOCK(); + retval = LB_getchar(); + MPKNSS_UNLOCK(); + + /* Loop till or or illegal value */ + while ((retval != 0x0D) && (retval != 0x1B) && + (retval != 0x03) && (retval <= 0x000000FF)) + { + if (retval == 0x08) + { + /* Backspace */ + if (charCount > 0) + { + --charCount; + --column; + PositionInputCursor(screenID, row, column); + PositionOutputCursor(screenID, row, column); + buffer[charCount] = 0; + OutputToScreen(screenID, MSGNot(" ")); + } + } + else if (charCount < bufsize) + { + buffer[charCount++] = (BYTE)retval; + OutputToScreen( screenID, MSGNot(" ")); + ++column; + PositionInputCursor(screenID, row, column); + PositionOutputCursor(screenID, row, column); + } + + MPKNSS_LOCK(); + retval = LB_getchar(); + MPKNSS_UNLOCK(); + } + buffer[charCount] = 0; + OutputToScreen( screenID, MSGNot("\n\r")); + DisableInputCursor(screenID); + MPKNSS_LOCK(); + + utf2uni(buffer, password,(charCount+1) * sizeof(unicode_t)); + +} + +#endif + +/************************************************************************** + * Switch among the various states + ***************************************************************************/ +STATUS doChangeVolumeState( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + NINT mode = VOLMODE_VERBOSE; + GeneralMsg_s genMsg; + STATUS status; +#if zNETWARE + unicode_t password[ENCRYPTED_VOLUME_PASSWORD_LENGTH+1] = {0}; +#endif + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + mode |= COMN_ChangeStateCommandLineSwitches(); + +#if (0) + /* parse the command line for a volumename with attached password, if found, break it out and register it */ + foundPassword = FALSE; + p = (unicode_t *)switchDef->ret_value; + pEnd = p + unilen(p); + for(;p < pEnd; p++) + { + if(*p == L':') + { + *p = L'\0'; + for(p++; (p < pEnd) && (*p == L' ');p++); /* skip over leading spaces */ + uniupr((unicode_t *)switchDef->ret_value); /* upper case volname, but not the password */ + if(COMN_SVPW((unicode_t *)switchDef->ret_value, p) == zOK) /* any error here will show up later an EnableEncryptedVolume */ + { + foundPassword = TRUE; + } + break; + } + } +#endif + status = COMN_ChangeVolumeStateByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo, mode ); + +#if zNETWARE + /* if the change vol state failed, check to see if it was because of a missing password. If this is the case + * prompt for the password and try again. + */ + if((status != zOK) && (GetErrno( &genMsg ) == zERR_INVALID_VOLUME_PASSWORD)) + { + getEncryptedVolumePassword(password); /* accept whatever we get, it will be checked later */ + uniupr((unicode_t *)switchDef->ret_value); + COMN_SVPW((unicode_t *)switchDef->ret_value, password); /* any error here will show up later an EnableEncryptedVolume */ + ClearErrno(&genMsg); + COMN_ChangeVolumeStateByName(&genMsg,(unicode_t *)switchDef->ret_value, switchDef->userInfo, mode ); + } +#endif + + MPKNSS_UNLOCK(); + return zOK; +} + + +#if 1 +/************************************************************************** + * Switch among the various states + ***************************************************************************/ +STATUS doChangeVolumeStateForceDeact( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + COMN_ChangeVolumeStateByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo,VOLMODE_VERBOSE); + MPKNSS_UNLOCK(); + return zOK; +} +#endif + + +/************************************************************************** + * Switch among the various states + ***************************************************************************/ +STATUS doChangeVolumeSalvage( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeSalvageByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Switch among the various states + ***************************************************************************/ +STATUS doChangeVolumeHardlinks( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeHardlinksByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + + +/************************************************************************** + * Switch among the various states + ***************************************************************************/ +/* fixfixfix@nextMediaFormatChange begin */ +STATUS doChangeVolumeExtendedMac( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeExtendedMacByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} +/* fixfixfix@nextMediaFormatChange end */ + + +/************************************************************************** + * Switch among the various states + ***************************************************************************/ +STATUS doChangeVolumeTransaction( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeTransactionByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Switch among the various states + ***************************************************************************/ +STATUS doChangeVolumeMigration( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeMigrationByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + + +/************************************************************************** + * Switch among the various states + ***************************************************************************/ +STATIC STATUS doChangeVolumeCompression( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeCompressionByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +STATIC STATUS doChangeVolumeATime( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeATimeByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} +STATIC STATUS doToggleBGCompression( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + if (*(BOOL *)switchDef->ret_value) + { + CM_bgCompressStartRequest(); + } + else + { + CM_bgCompressStopRequest(); + } + MPKNSS_UNLOCK(); + return zOK; +} + +STATIC STATUS doStopNormalCompression( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + CM_stopCompression(COMP_NORMAL); + + MPKNSS_UNLOCK(); + return zOK; +} + +#if zLINUX +extern LONG NW_ClientFileCachingEnabledFlag; +NINT CompressionDailyCheckStartingHour = 0; +STATIC STATUS doCompressionDailyCheckStartingHour( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + SET_COMP_DAILY_CHECK_START_TIME(CompressionDailyCheckStartingHour * 60 * 60, FALSE); + + MPKNSS_UNLOCK(); + return zOK; +} + +NINT CompressionDailyCheckStopHour= 0; +STATIC STATUS doCompressionDailyCheckStopHour( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + SET_COMP_DAILY_CHECK_STOP_TIME(CompressionDailyCheckStopHour * 60 * 60, FALSE); + + MPKNSS_UNLOCK(); + return zOK; +} + +NINT DaylightSavingsTimeOffset = 0; +STATIC STATUS doDaylightSavingsTimeOffset( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) + +{ + MPKNSS_LOCK(); + + checkOrSetDSTConversionResults(-1,-1,DaylightSavingsTimeOffset); + BEASTHASH_InvalidateDOSTimes(); + CM_bgCompressResetTimer(); + + MPKNSS_UNLOCK(); + return zOK; +} + +NINT DecompressFreeSpaceWarningInterval=31; +STATIC STATUS doDecompressFreeSpaceWarningInterval( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) + +{ + SET_DECOMP_FREE_SPACE_WARN_INTERVAL(DecompressFreeSpaceWarningInterval*60); + return zOK; + +} + +NINT DaysUntouchedBeforeCompression = 0; +STATIC STATUS doDaysUntouchedBeforeCompression( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + SET_FILE_IDLE_TIME_FOR_COMP((QUAD)DaysUntouchedBeforeCompression * 24 * 60 * 60); + + MPKNSS_UNLOCK(); + return zOK; +} + +NINT EnableFileCompression = TRUE; +STATIC STATUS doEnableFileCompression( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) + +{ + MPKNSS_LOCK(); + + SET_COMP_ENABLED_FLAG(EnableFileCompression); + + MPKNSS_UNLOCK(); + return zOK; +} + + +char EDSTInfo[50] = "none"; +char EDSTSaved[50] = ""; +STATIC STATUS doEndOfDaylightSavingsTime( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + getDSTChangeRules(EDSTInfo, &DSTStopInfo); + if(DSTStopInfo.isOK) + { + checkOrSetDSTConversionResults(-1,-1,-1); + BEASTHASH_InvalidateDOSTimes(); + CM_bgCompressResetTimer(); + strcpy(EDSTSaved, EDSTInfo); + } + else + { + aprintf( LGRAY, MSGNot("\"%s\" is not a legal date/time or rule value.\n"), EDSTInfo ); + strcpy(EDSTInfo,EDSTSaved); + } + MPKNSS_UNLOCK(); + return zOK; +} + +char SDSTInfo[50] = "none"; +char SDSTSaved[50]=""; +STATIC STATUS doStartOfDaylightSavingsTime( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) + +{ + MPKNSS_LOCK(); + + getDSTChangeRules(SDSTInfo, &DSTStartInfo); + if(DSTStartInfo.isOK) + { + checkOrSetDSTConversionResults(-1,-1,-1); + BEASTHASH_InvalidateDOSTimes(); + CM_bgCompressResetTimer(); + strcpy(SDSTSaved, SDSTInfo); + } + else + { + aprintf( LGRAY, MSGNot("\"%s\" is not a legal date/time or rule value.\n"), SDSTInfo ); + strcpy(SDSTInfo,SDSTSaved); + } + + MPKNSS_UNLOCK(); + return zOK; +} + +NINT ImmediatePurgeOfDeletedFiles; +STATIC STATUS doImmediatePurgeOfDeletedFiles( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) + +{ + MPKNSS_LOCK(); + + if (ImmediatePurgeOfDeletedFiles) + { + if (!NW_PurgeImmediateFlag) + { + /* Purge Immediate was turned off */ + VOL_PurgeImmediateFlagSet(); + NW_PurgeImmediateFlag = TRUE; + } + } + else + { + NW_PurgeImmediateFlag = FALSE; + } + + MPKNSS_UNLOCK(); + return zOK; +} + + +NINT MaximumConcurrentCompressions; +STATIC STATUS doMaximumConcurrentCompressions( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + SET_MAX_CONCURRENT_COMPRESSIONS(MaximumConcurrentCompressions); + + MPKNSS_UNLOCK(); + return zOK; +} + +NINT MinimumCompressionPercentageGain; +STATIC STATUS doMinimumCompressionPercentageGain( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + SET_MIN_PERCENT_GAIN(MinimumCompressionPercentageGain); + + MPKNSS_UNLOCK(); + return zOK; +} + +NINT MinimumFileDeleteWaitTime; +STATIC STATUS doMinimumFileDeleteWaitTime( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + /* FixFixFix6 -- We need to fix this to work, but first we need to + * resolve how to keep nonpurgeableblocks and purgeableblocks + * counts accurate */ +// GeneralMsg_s genMsg; +// NW_MinimumFileDeleteWaitTime = MinimumFileDeleteWaitTime; +// +// COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); +// VOL_ChangeSalvageMinKeepSeconds(&genMsg, NW_MinimumFileDeleteWaitTime); + MPKNSS_UNLOCK(); + return zOK; +} +#endif + +STATIC STATUS doCompressionScreen( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + + CM_screenDisplay(); + + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Switch among the various states. Set the override switch which + * forces the state change even if the volume is corrupt. This + * really only applies to going to ACTIVE state. + ***************************************************************************/ +STATUS doChangeVolumeStateForce( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + + COMN_ChangeVolumeStateByName(&genMsg,(unicode_t *)switchDef->ret_value, + switchDef->userInfo,VOLMODE_VERBOSE|VOLMODE_USER_ABORTABLE|VOLMODE_OVERRIDE); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Change the state of user space restrictions on a volume + ***************************************************************************/ +STATUS doChangeVolumeUserSpaceRestrictions( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeUserSpaceRestrictionsByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Change the state of directory quotas on a volume + ***************************************************************************/ +STATUS doChangeVolumeDirectoryQuotas( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + DIRQ_ChangeVolumeDirectoryQuotasByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Fix the used amount of directory quotas on a volume + ***************************************************************************/ +STATUS doFixVolumeDirectoryQuotas( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + DIRQ_FixDirectoryQuotas(&genMsg, (unicode_t *)switchDef->ret_value); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Rebuild the visibility lists on a volume + ***************************************************************************/ +STATUS doVisibilityRebuild( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + ZAS_VisibilityRebuildByName(&genMsg, (unicode_t *)switchDef->ret_value); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Change the state of MFL maintenance on a volume + ***************************************************************************/ +STATUS doChangeVolumeMFL( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeMFLByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Change the state of data shredding on a volume + ***************************************************************************/ +STATUS doChangeVolumeDataShredding( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeDataShredByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Change the state of HIGH INTEGRITY on a volume + ***************************************************************************/ +STATUS doChangeVolumeHighIntegrity( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeHighIntegrityByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Change the state of CFS MASTER on a volume + ***************************************************************************/ +STATUS doChangeVolumeCFSMaster( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeCFSMasterByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Change the state of COW on a volume + ***************************************************************************/ +STATUS doChangeVolumeCOW( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeCOWByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + + +#if zLINUX +extern GUID_t MSAPServerId; +#endif + +#if zLINUX +/************************************************************************** + * Set the MSAP Id - Under NetWare this is stored in the registery so we do not need. + ***************************************************************************/ +STATUS doMSAPServerIdSet( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + STATUS status; + GUID_t userGuid; + + MPKNSS_LOCK(); + status = LB_GUIDFromUTF8( (utf8_t *)switchDef->ret_value, &userGuid ); + if ( status != zOK ) + { + aprintf(LRED,"Specified MSAP Server Id does not have correct form.\n"); + } + else + { + MSAPServerId = userGuid; // Structure copy + } + + MPKNSS_UNLOCK(); + return zOK; +} +#endif + +/************************************************************************** + * Display the MSAP Ids + ***************************************************************************/ +STATUS doMSAPIdDisplay( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GUID_t aGuid; + char aGuidString[GUID_FORMAT_SIZE]; + + MPKNSS_LOCK(); + COMN_ServerIDGet( &aGuid ); + (void)LB_GUIDToString( &aGuid, sizeof(aGuidString), aGuidString ); + printf("MSAP's server ID is %s\n",aGuidString); + COMN_ClusterIDGet( &aGuid ); + (void)LB_GUIDToString( &aGuid, sizeof(aGuidString), aGuidString ); + printf("MSAP's cluster ID is %s\n",aGuidString); + MPKNSS_UNLOCK(); + return zOK; +} + + +/************************************************************************** + * Change the state of LOCAL on a pool + ***************************************************************************/ +STATUS doChangePoolMSAP( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + POOL_ChangePoolMSAPByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + + + /************************************************************************** + * Change the high/low water marks on a pool + ***************************************************************************/ +STATUS doChangePoolWaterMarks( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + POOL_ChangePoolWaterMarksByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +///************************************************************************** +// * Change the state of data shredding on a volume +// ***************************************************************************/ +//STATUS doChangePoolShared( +// PCLSwitchDef_s *switchDef, +// NINT options, +// void *userParm) +//{ +// GeneralMsg_s genMsg; +// +// MPKNSS_LOCK(); +// COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); +// VOL_ChangePoolSharedByName( +// &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); +// MPKNSS_UNLOCK(); +// return zOK; +//} + +/************************************************************************** + * Change the state of user space restrictions on a volume + ***************************************************************************/ +STATUS doUpgradeBeastsOnVolume( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_UpgradeBeastsOnVolumeByName(&genMsg, + (unicode_t *)switchDef->ret_value); + MPKNSS_UNLOCK(); + return zOK; +} + +/************************************************************************** + * Perform specified administrative operation on the MFL + ***************************************************************************/ +STATUS doAdministerMFL( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_administerMFLByName( + &genMsg, (unicode_t *)switchDef->ret_value, switchDef->userInfo); + MPKNSS_UNLOCK(); + return zOK; +} + +void getBucketStats( + NINT *maxInBucket, + NINT *totalEntries, + NINT *numUsedBuckets, + DQhead_t *bucketHead, + NINT size) +{ + DQhead_t *bucket; + NINT i; + NINT numInBucket; + DQlink_t *next; + + *maxInBucket = 0; + *totalEntries = 0; + *numUsedBuckets = 0; + + ASSERT_MPKNSS_LOCK(); + if (bucketHead != NULL) + { + for (bucket = bucketHead, i = 0; i < size; ++bucket, ++i) + { + numInBucket = 0; + for (next = bucket->next; next != bucket; next = next->next) + { + ++(*totalEntries); + ++numInBucket; + } + if (numInBucket != 0) + { + ++(*numUsedBuckets); + } + if (numInBucket > *maxInBucket) + { + *maxInBucket = numInBucket; + } + } + } + return; +} + +/************************************************************************** + * Change the read ahead count on a volume + ***************************************************************************/ +STATUS doChangeVolumeReadAhead( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + VOL_ChangeVolumeReadAheadByName( + &genMsg, (unicode_t *)switchDef->ret_value); + MPKNSS_UNLOCK(); + return zOK; +} +/************************************************************************** + * display name cache statistics + ***************************************************************************/ +STATUS doDisplayNameCacheStats( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + NINT uniMaxInBucket; + NINT uniNumUsedBuckets; + NINT uniTotalEntries; + NINT asciiMaxInBucket; + NINT asciiNumUsedBuckets; + NINT asciiTotalEntries; + + MPKNSS_LOCK(); + S_LATCH(&NameCache.latch); + aprintf(YELLOW, MSG("***** Name Cache Statistics *****\n", 900)); + aprintf(LGREEN, MSG("Num hash buckets: %u\n", 901),NameCache.numHashEntries); + aprintf(LGREEN, MSG("Max cache entries: %u\n", 902),NameCache.maxEntries); + aprintf(LGREEN, MSG("Num entries in use: %u\n", 903),NameCache.numEntries); + aprintf(LGREEN, MSG("Num packet allocates: %Lu\n", 905),NameCache.numAllocs); + aprintf(LGREEN, MSG("Num unused packets freed: %Lu\n", 907),NameCache.numUnusedFrees); + aprintf(LGREEN, MSG("Change count(num adds): %Lu\n", 39),NameCache.changeCount); + aprintf(LGREEN, MSG("Num negative adds: %Lu\n", 40),NameCache.numNegativeAdds); + aprintf(LGREEN, MSG("Num victim selects: %Lu\n", 909),NameCache.numVictimSelected); + aprintf(LGREEN, MSG("Num removed entries: %Lu\n", 910),NameCache.numRemoved); + aprintf(YELLOW, MSG("*************************** Unicode Ascii\n", 911)); + aprintf(LGREEN, MSG("Num attempts on cache: %-12Lu %-12Lu\n", 912),NameCache.uniGets,NameCache.asciiGets); + aprintf(LGREEN, MSG("Num cache hits: %-12Lu %-12Lu\n", 913),NameCache.uniHits,NameCache.asciiHits); + aprintf(LGREEN, MSG("Cache hit percentage: %-12Lu %-12Lu\n", 914), + ((NameCache.uniGets != UI64_CONST(0)) ? ((NameCache.uniHits*UI64_CONST(100))/NameCache.uniGets) : UI64_CONST(0)), + ((NameCache.asciiGets != UI64_CONST(0)) ? ((NameCache.asciiHits*UI64_CONST(100))/NameCache.asciiGets) : UI64_CONST(0))); + aprintf(LGREEN, MSG("Num positive cache hits: %-12Lu %-12Lu\n", 915),NameCache.uniPositiveHits,NameCache.asciiPositiveHits); + aprintf(LGREEN, MSG("Num negative cache hits: %-12Lu %-12Lu\n", 916),NameCache.uniNegativeHits,NameCache.asciiNegativeHits); + + /* Calculate unicode bucket statistics */ + getBucketStats(&uniMaxInBucket, &uniTotalEntries, &uniNumUsedBuckets, + NameCache.uniHash, NameCache.numHashEntries); + + /* Calculate ascii bucket statistics */ + getBucketStats(&asciiMaxInBucket, &asciiTotalEntries, &asciiNumUsedBuckets, + NameCache.asciiHash, NameCache.numHashEntries); + + if (NameCache.numHashEntries != 0) + { + aprintf(LGREEN, MSG("Percent of buckets used: %-12u %-12u\n", 917), + (uniNumUsedBuckets*100)/NameCache.numHashEntries, + (asciiNumUsedBuckets*100)/NameCache.numHashEntries); + } + else + { + aprintf(LGREEN, MSG("Percent of buckets used: 0 0\n", 918)); + } + aprintf(LGREEN, MSG("Max entries in a bucket: %-12u %-12u\n", 919), + uniMaxInBucket, asciiMaxInBucket); + +#if NSS_DEBUG IS_ENABLED + aprintf(YELLOW, MSGNot("********** NAME CACHE OPTIMIZER **********\n")); + aprintf(LGREEN, MSGNot("Optimizer runs: %d, Resizes: %d ~ %d%%\n"), + NameCacheOptimizerStats.optimizeCount, + NameCacheOptimizerStats.resizeCount, + NameCacheOptimizerStats.optimizeCount > 0 ? (NameCacheOptimizerStats.resizeCount * 100) / NameCacheOptimizerStats.optimizeCount : 0); + aprintf(LGREEN, MSGNot("Max ~ Min cache size: %d ~ %d, Max ~ Min delta: %d ~ %d\n"), + NameCacheOptimizerStats.maxSize, + NameCacheOptimizerStats.minSize, + NameCacheOptimizerStats.maxChange, + NameCacheOptimizerStats.minChange); + aprintf(LGREEN, MSGNot("Max ~ Min Invalidate change: %d ~ %d, Max %%: %d\n"), + NameCacheOptimizerStats.maxInvalidateChange, + NameCacheOptimizerStats.minInvalidateChange, + NameCacheOptimizerStats.maxPctInvalidateChange); + aprintf(LGREEN, MSGNot("Max req'd node destroys: %d\n"), NameCacheOptimizerStats.maxReqdNodeDestroys); + aprintf(LGREEN, MSGNot("Last Invalidate size: %d\n"), NameCache. lastInvalidateSize); +#endif + + UNS_LATCH(&NameCache.latch); + MPKNSS_UNLOCK(); + return zOK; +} + + + +#if NSS_DEBUG IS_ENABLED +//rks/************************************************************************** +//rks * Dump the count in each bucket to the debug buffer +//rks ***************************************************************************/ +//rksvoid displayBucketCounts( +//rks DQhead_t *bucketHead, +//rks NINT size) +//rks{ +//rks DQhead_t *bucket; +//rks NINT i; +//rks NINT numInBucket; +//rks DQlink_t *next; +//rks +//rks ASSERT_MPKNSS_LOCK(); +//rks DBG_DebugPrintf(LMAGENTA, "Hash Dump of buckets with chain count\n"); +//rks if (bucketHead != NULL) +//rks { +//rks for (bucket = bucketHead, i = 0; i < size; ++bucket, ++i) +//rks { +//rks numInBucket = 0; +//rks for (next = bucket->next; next != bucket; next = next->next) +//rks { +//rks ++numInBucket; +//rks } +//rks DBG_DebugPrintf(LMAGENTA, "bucket #%d=%d\n", i, numInBucket); +//rks } +//rks } +//rks return; +//rks} +#endif + +/************************************************************************** + * Display beast cache statistics + ***************************************************************************/ +STATUS doDisplayBeastCacheStats( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + NINT maxInBucket; + NINT numUsedBuckets; + NINT totalEntries; + NINT scale; + QUAD misses; + QUAD hits; + QUAD total; + char suffix; + enum { A_ONE = 1, A_THOUSAND = 1000, A_MILLION = 1000000, + A_BILLION = 1000000000, A_TRILLION = UI64_CONST(1000000000000) }; + + MPKNSS_LOCK(); + UNUSED_PARAM(switchDef); + UNUSED_PARAM(options); + UNUSED_PARAM(userParm); + + /*** Harvest and then put totals in locals so that they match. ***/ + /*** I.E. Get totals before we may yield ***/ + harvestInst(); + hits = Inst.bst.hitTotal; + misses = Inst.bst.missTotal; + total = hits + misses; + + aprintf(YELLOW, MSG("***** File System Object Cache Statistics *****\n", 97)); + aprintf(LGREEN, MSG("Num file system objects: %d\n", 558), Config.bst.total); + aprintf(LGREEN, MSG("Num closed objects: %d\n", 559), Config.bst.notInUse); + aprintf(LGREEN, MSG("Num hash buckets: %d\n", 560), Config.bst.hashSize); + aprintf(LGREEN, MSG("Cache hit percentage: %d%%\n", 561), + (NINT)((total != 0) ? ((hits * 100)/total) : 0)); + + if (total > A_TRILLION) + { + scale = A_MILLION; + suffix = 'M'; + } + else if (total > A_BILLION) + { + scale = A_THOUSAND; + suffix = 'K'; + } + else + { + scale = A_ONE; + suffix = ' '; + } + aprintf(LGREEN, MSG("Cache hit: %d %c\n", 562), (NINT)(hits / scale), suffix); + aprintf(LGREEN, MSG("Cache miss: %d %c\n", 569), (NINT)(misses / scale), suffix); + + getBucketStats(&maxInBucket, &totalEntries, &numUsedBuckets, + RootBeastHash, Config.bst.hashSize); + + if (Config.bst.hashSize != 0) + { + aprintf(LGREEN, MSG("Percent of buckets used: %d%%\n", 570), + (numUsedBuckets*100) / Config.bst.hashSize); + } + else + { + aprintf(LGREEN, MSG("Percent of buckets used: 0%%\n", 572)); + } + aprintf(LGREEN, MSG("Max entries in a bucket: %d\n", 574), maxInBucket); + aprintf(LGREEN, MSG("Total entries: %d\n", 575), totalEntries); +#if NSS_DEBUG IS_ENABLED +//rks displayBucketCounts(RootBeastHash, Config.bst.hashSize); +#endif + + MPKNSS_UNLOCK(); + return zOK; +} + +/* A little structure for cleaner code */ +struct NSS_hitmiss_s +{ + QUAD hit; + QUAD miss; +}; + +/* + CacheHitMissPercent() - + Code to display cache hit/miss/percentage. +*/ +static void CacheHitMissPercent( const char *header, const struct NSS_hitmiss_s *facts ) +{ + NINT scale; + char suffix; + + enum { A_ONE = 1, A_THOUSAND = 1000, A_MILLION = 1000000, + A_BILLION = 1000000000, A_TRILLION = UI64_CONST(1000000000000) }; + + aprintf(LGREEN, MSG("%s\n",0), header ); + aprintf(LGREEN, MSG(" Cache hit percentage: %d%%\n", 0), + (NINT)((facts->hit + facts->miss != 0) ? + ((facts->hit * 100)/(facts->hit + facts->miss)) : 0)); + if ((facts->hit + facts->miss) > A_TRILLION) + { + scale = A_MILLION; + suffix = 'M'; + } + else if ((facts->hit + facts->miss) > A_BILLION) + { + scale = A_THOUSAND; + suffix = 'K'; + } + else + { + scale = A_ONE; + suffix = ' '; + } + aprintf(LGREEN, MSG(" Cache hit: %d %c\n", 0), (NINT)(facts->hit / scale), suffix); + aprintf(LGREEN, MSG(" Cache miss: %d %c\n", 0), (NINT)(facts->miss / scale), suffix); + return; +} + + +void CacheHashStatistics( + const char *header, + DQhead_t *bucketHead, + NINT hashSize ) +{ + NINT maxInBucket; + NINT numUsedBuckets; + NINT totalEntries; + + aprintf(LGREEN, MSG("%s\n",0), header ); + getBucketStats(&maxInBucket, &totalEntries, &numUsedBuckets, + bucketHead, hashSize); + aprintf(LGREEN, MSG(" Num hash buckets: %d\n", 0), hashSize); + if (hashSize != 0) + { + aprintf(LGREEN, MSG(" Percent of buckets used: %d%%\n", 0), + (numUsedBuckets*100) / hashSize); + } + else + { + aprintf(LGREEN, MSG(" Percent of buckets used: 0%%\n", 0)); + } + aprintf(LGREEN, MSG(" Max entries in a bucket: %d\n", 0), maxInBucket); + aprintf(LGREEN, MSG(" Total entries: %d\n", 0), totalEntries); + return; +} + + +/************************************************************************** + * Display buffer cache statistics + ***************************************************************************/ +STATUS doDisplayCacheStats( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + struct NSS_hitmiss_s lAll; /* Linux only cache totals (user and system blocks) */ + struct NSS_hitmiss_s lSystem; /* Linux only system blocks */ + struct NSS_hitmiss_s lUser; /* Linux only user blocks */ + + struct NSS_hitmiss_s ctAll; /* Complete Totals */ + struct NSS_hitmiss_s ctSystem; /* Complete System Totals */ + struct NSS_hitmiss_s ctUser; /* Complete User Totals */ + + struct NSS_hitmiss_s nAll; /* NSS only cache totals (user and system blocks) */ + struct NSS_hitmiss_s nSystem; /* NSS only system blocks */ + struct NSS_hitmiss_s nUser; /* NSS only user blocks */ + + MPKNSS_LOCK(); + UNUSED_PARAM(switchDef); + UNUSED_PARAM(options); + UNUSED_PARAM(userParm); + + /*** Harvest and then put totals in locals so that they match. ***/ + /*** I.E. Get totals before we may yield ***/ + harvestInst(); + lAll.hit = Inst.cache.ioHitLinuxUserSystemTotal; + lAll.miss = Inst.cache.ioMissLinuxUserSystemTotal; + lSystem.hit = Inst.cache.ioHitLinuxSystemTotal; + lSystem.miss = Inst.cache.ioMissLinuxSystemTotal; + lUser.hit = lAll.hit - lSystem.hit; + lUser.miss = lAll.miss - lSystem.miss; + + nAll.hit = Inst.cache.ioHitUserSystemTotal; + nAll.miss = Inst.cache.ioMissUserSystemTotal; + nSystem.hit = Inst.cache.ioHitSystemTotal; + nSystem.miss = Inst.cache.ioMissSystemTotal; + nUser.hit = nAll.hit - nSystem.hit; + nUser.miss = nAll.miss - nSystem.miss; + /* We must add up the old cache stats with the new Linux ones to get + a true total. Vandana wants these because her calculator is + broken:-) + Since a miss in the NSS cache always causes a lookup in the Linux + cache we only have to count the Linux miss in our totals:-) + */ + ctAll.hit = nAll.hit + lAll.hit; + ctAll.miss = /* nAll.miss */ + lAll.miss; + ctSystem.hit = nSystem.hit + lSystem.hit; + ctSystem.miss = /* nSystem.miss */ + lSystem.miss; + ctUser.hit = nUser.hit + lUser.hit; + ctUser.miss = /* nUser.miss + */ lUser.miss; + + aprintf(YELLOW, MSG("***** Buffer Cache Statistics *****\n", 920)); + aprintf(LGREEN, MSG("Min cache buffers: %d\n", 550), Config.cache.numBuffers); +// aprintf(LGREEN, MSG("Num hash buckets: %d\n", 922), Config.cache.hashSize); + aprintf(LGREEN, MSG("Min OS free cache buffers: %d\n", 923), Config.cache.minOSFree); + aprintf(LGREEN, MSG("Num cache pages allocated: %d\n", 924), Config.cache.numPagesAllocated); + + CacheHitMissPercent( MSG("Complete User/System Total",0), &ctAll ); + CacheHitMissPercent( MSG("Complete User Total",0), &ctUser ); + CacheHitMissPercent( MSG("Complete System Total",0), &ctSystem ); + + CacheHitMissPercent( MSG("NSS User/System Total",0), &nAll ); + CacheHitMissPercent( MSG("NSS User Total",0), &nUser ); + CacheHitMissPercent( MSG("NSS System Total",0), &nSystem ); + + CacheHitMissPercent( MSG("Linux User/System Total",0), &lAll ); + CacheHitMissPercent( MSG("Linux User Total",0), &lUser ); + CacheHitMissPercent( MSG("Linux System Total",0), &lSystem ); + + CacheHashStatistics( MSG("Buffer hash",0), Cache.bucket, Config.cache.hashSize ); + CacheHashStatistics( MSG("Metadata high memory hash",0), Cache.bucketPageBuffer, Config.cache.privateHashSize ); + + MPKNSS_UNLOCK(); + return zOK; +} + + +STATUS SetBeastLimit () +{ + if (Config.bst.notInUseLimit > Config.bst.notInUseMax) + { + Config.bst.notInUseLimit = Config.bst.notInUseMax; + } + return zOK; +} + +/**************************************************************************** + * NWSA_GetFileNameAndPath + * + * Given a volume and zid, get the path of the file + *****************************************************************************/ + STATUS comn_GetFileNameAndPath( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + unicode_t *fullPathBuffer, + NINT fullPathBufferSize) +{ +#if (PATHWORKBUF_SIZE < (zMAX_FULL_NAME*2)) + #error The PATHWORKBUF_SIZE >= (zMAX_FULL_NAME * 2), + #error because we use it to get a full unicode_t path +#endif + GetNameMsg_s gfnMsg; + zGetName_s *getNameBuf = NULL; + + if ((getNameBuf = COMN_GetPathNameWorkBuffer(genMsg)) == NULL) + { + goto cleanup_error; + } +/*--------------------------------------------------------------------------- + * Get the unicode_t name/path in a temporary buffer. Then translate it into + * the callers buffer. + *---------------------------------------------------------------------------*/ + COMN_STRUCT_INIT(gfnMsg); + COMN_SETUP_GET_NAME_MSG(&gfnMsg, zGFN_INCLUDE_PATH/*|zGFN_INCLUDE_VOLUME*/, + 0/*GFN_NO_SEPARATOR_AFTER_VOLUME_COLON|GFN_USE_OLD_DOS_PATH_SEPARATORS*/, + zPFMT_UNICODE, nameMsg->nameSpaceID, getNameBuf, + (PATHWORKBUF_SIZE - offsetof(zGetName_s,variableData)) ); + + if (COMN_GetName(genMsg,nameMsg,&gfnMsg) != zOK) + { + goto cleanup_error; + } + if ( fullPathBufferSize < + ( LB_unilen( getNameBuf->name ) * sizeof(unicode_t) + + (1 * sizeof(unicode_t)) ) ) + { + SetErrno( genMsg, zERR_BUFFER_TOO_SMALL ); + goto cleanup_error; + } + LB_unicpy( fullPathBuffer, getNameBuf->name ); + + COMN_ReleasePathNameWorkBuffer(&getNameBuf); + return zOK; + +cleanup_error: + if (getNameBuf) + { + COMN_ReleasePathNameWorkBuffer(&getNameBuf); + } + return zFAILURE; + +} /* End of comn_GetFileNameAndPath() */ + + +/************************************************************************** + * NWSA_SetupNameMsgFromDirBase + * + * This routine takes a legacy volume ID and directory entry and + * fills in the name message. + ***************************************************************************/ +STATUS comn_SetupNameMsgFromZID( + GeneralMsg_s *genMsg, + NamingMsg_s *nameMsg, + unicode_t *volumeName, + Zid_t zid, + NINT nameSpaceID, + NINT nType, + NINT pathType, + BYTE *pathString, + BYTE parseMode, + NINT latchType) +{ + VolumeID_t volumeID; + Volume_s *volume; + + ASSERT_MPKNSS_LOCK(); + /* this is here so it is safe to cleanup the naming message even on the error*/ + COMN_INIT_NAMING_MSG(nameMsg); + volume = COMN_VolumeNameLookup( genMsg, volumeName, TRUE, &volumeID ); + if ( volume == NULL ) + { + return zFAILURE; + } + if (COMN_LockVolumeActive( genMsg, volume, + (nameMsg->parseFlags & NAMPFL_dontLockVolumeActive)) != zOK) + { + COMN_Release(&volume); + return zFAILURE; + } + +#if 0 + /* This code if from REPAIR I used the code from CMD (MAPDIR) */ + COMN_INIT_NAMING_MSG(&nameMsg); + COMN_SETUP_NAMING_MSG_VOLUME_ZID( &nameMsg, + stats->pool->ZFSPOOLvolumeID /*ZFSPOOLzfsvollogged.LPZV_volumeID*/, + zFNU_FIRST_PARENT, zINVALID_ZID, zid, zid, SLATCHED, + nameSpaceID, nameType, NULL); + COMN_SET_NAMING_MSG_DONT_LOCK_VOLUME_ACTIVE(&nameMsg); + COMN_SET_NAMING_MSG_VOLUME(&nameMsg,COMN_VolumeIDLookup(genMsg, + &stats->pool->ZFSPOOLvolumeID /*ZFSPOOLzfsvollogged.LPZV_volumeID*/,FALSE)); + COMN_STRUCT_INIT(gfnMsg); + COMN_SETUP_GET_NAME_MSG(&gfnMsg, zGFN_INCLUDE_PATH, 0, zPFMT_ASCII, + nameSpaceID, &nameBuffer, sizeof(zGetName_s)); + ccode = zOK; + ccode = COMN_GetName(genMsg,&nameMsg,&gfnMsg); + COMN_CleanupNameMsg(genMsg, &nameMsg); +#endif + COMN_SETUP_NAMING_MSG_VOLUME_ZID_PATH(nameMsg, volumeID, // cnt zFNU_FIRST_PARENT, + zid, nType, pathString, pathType, parseMode, + latchType, nameSpaceID, nType, NULL, 0, NULL, NULL); + COMN_SET_NAMING_MSG_VOLUME(nameMsg, volume); + return zOK; + +} /* End of comn_SetupNameMsgFromZID() */ + + +/************************************************************************** + * + ***************************************************************************/ + +STATUS COMN_ReverseNameLookup( + GeneralMsg_s *genMsg, + unicode_t *volumeName, + Zid_t zid, + NINT nameSpaceId, + NINT nType, + unicode_t *fullNameBuffer, + NINT fullNameBufferLength ) + +{ + STATUS status; + NamingMsg_s nameMsg; + + ASSERT_MPKNSS_LOCK(); + status = comn_SetupNameMsgFromZID(genMsg, &nameMsg, + volumeName, zid, nameSpaceId, nType, + zPFMT_UNDEFINED, NULL, + NAMPMODE_FullyResolveAny, SLATCHED); + if ( status != zOK ) + { + COMN_CleanupNameMsg(genMsg, &nameMsg); + return( zFAILURE ); + } + + status = comn_GetFileNameAndPath( genMsg, &nameMsg, + fullNameBuffer,fullNameBufferLength); + if ( status != zOK) + { + COMN_CleanupNameMsg(genMsg, &nameMsg); + return( zFAILURE ); + } + COMN_CleanupNameMsg(genMsg, &nameMsg); + return( zOK ); + +} /* End of COMN_ReverseNameLookup() */ + + +unicode_t *ZIDToFileNameVolumeName = NULL; /* Volume Name of volume to do + * ZID to file name. + */ + +LONG ZIDToFileNameNameSpace = zNSPACE_LONG; + /* Volume Name of volume to do + * ZID to file name. + */ + +/************************************************************************** + * doZIDToFileNameNameSpace - Command line user interface for getting the + * name of a file given the file's ZID. This routine sets + * the name space to do the lookup on. + ***************************************************************************/ +NINT doZIDToFileNameNameSpace( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + + MPKNSS_LOCK(); + + if ( uniicmp(L"LONG",(unicode_t *)switchDef->ret_value) == 0 ) + { + ZIDToFileNameNameSpace = zNSPACE_LONG; + } + else if ( uniicmp(L"MAC",(unicode_t *)switchDef->ret_value) == 0 ) + { + ZIDToFileNameNameSpace = zNSPACE_MAC; + } + else if ( uniicmp(L"UNIX",(unicode_t *)switchDef->ret_value) == 0 ) + { + ZIDToFileNameNameSpace = zNSPACE_UNIX; + } + else if ( uniicmp(L"DOS",(unicode_t *)switchDef->ret_value) == 0 ) + { + ZIDToFileNameNameSpace = zNSPACE_DOS; + } + else + { + aprintf(LRED,MSG("Error - Invalid name space name\n",1111)); +// aprintf(LRED,MSGNot("Error - Invalid name space name of \"%U\"\n"), +// (unicode_t *)switchDef->ret_value ); + } + MPKNSS_UNLOCK(); + return zOK; + +} /* End of doZIDToFileNameNameSpace() */ + + +/************************************************************************** + * doZIDToFileNameVolumeName - Command line user interface for getting the + * name of a file given the file's ZID. This routine sets + * the name of the volume to do the lookup on. + ***************************************************************************/ +NINT doZIDToFileNameVolumeName( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + NINT size; + + MPKNSS_LOCK(); + free ( ZIDToFileNameVolumeName ); + ZIDToFileNameVolumeName = NULL; + /* Length + NULL Converted to size */ + size = (unilen( (unicode_t *)switchDef->ret_value ) + 1) * sizeof(unicode_t); + + ZIDToFileNameVolumeName = malloc( size ); + if ( ZIDToFileNameVolumeName != NULL ) + { + memcpy( ZIDToFileNameVolumeName, switchDef->ret_value, size ); + } + MPKNSS_UNLOCK(); + return zOK; +} + + +/************************************************************************** + * doZIDToFileName - Command line user interface for getting the + * name of a file given a file ZIDs. + ***************************************************************************/ +STATUS doZIDToFileName( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + STATUS status; + Zid_t zid; + unicode_t fullNameBuffer[zMAX_FULL_NAME]; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + COMN_INCLUDE_INTERNAL_VOLUMES( &genMsg ); + if ( ZIDToFileNameVolumeName == NULL ) + { + aprintf(LRED,MSG("Must set volume name first(see NSS /ZIDVolumeName)\n",1112) ); + MPKNSS_UNLOCK(); + return( zFAILURE ); + } + zid = *(QUAD *)switchDef->ret_value; + aprintf(CYAN,MSG("Volume \"%U\" ZID %Ld\n ",1113), + ZIDToFileNameVolumeName, zid ); + status = COMN_ReverseNameLookup( &genMsg, ZIDToFileNameVolumeName, + zid, ZIDToFileNameNameSpace, zNTYPE_FILE, fullNameBuffer, + sizeof(fullNameBuffer) ); + if ( status != zOK ) + { + switch ( GetErrno( &genMsg ) ) + { + case zERR_INVALID_PATH: + aprintf(YELLOW,MSG("Note - ZID is for a deleted file(%s).\n",143), + GetErrnoSetter(&genMsg) ); + status = COMN_ReverseNameLookup( &genMsg, + ZIDToFileNameVolumeName, zid, + ZIDToFileNameNameSpace, zNTYPE_DELETED_FILE, + fullNameBuffer, sizeof(fullNameBuffer) ); + if ( status == zOK ) + { + aprintf(YELLOW,MSG(" File name is \"%U\"\n",148), fullNameBuffer ); + } + else + { + aprintf(LRED,MSG("Error - %ld(%s).\n", 174 ), + (unsigned long)GetErrno(&genMsg), + GetErrnoSetter(&genMsg) ); + } + break; + case zERR_VOLUME_NOT_FOUND: + aprintf(LRED,MSG("Error - Volume not found or in ACTIVE state(%s).\n",1115), + GetErrnoSetter(&genMsg) ); + break; + default: + aprintf(LRED,MSG("Error - %ld(%s).\n",1116), + (unsigned long)GetErrno(&genMsg), + GetErrnoSetter(&genMsg) ); + } + MPKNSS_UNLOCK(); + return( zFAILURE ); + } + aprintf(CYAN,MSG("File name is \"%U\"\n",1117), fullNameBuffer ); + MPKNSS_UNLOCK(); + return zOK; + +} /* End of doZIDToFileName() */ + + +NINT doHMCTypeSet( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + STATUS status; + unicode_t *option; + + MPKNSS_LOCK(); + option = (unicode_t *)switchDef->ret_value; + if ( LB_uniicmp( option, MSGNot(L"private")) == 0 ) + { + status = HMC_TypeSetUI( HMC_CT_PRIVATE ); + } + else if ( LB_uniicmp( option, MSGNot(L"linux")) == 0 ) + { + status = HMC_TypeSetUI( HMC_CT_LINUX ); + } + else if ( LB_uniicmp( option, MSGNot(L"none")) == 0 ) + { + status = HMC_TypeSetUI( HMC_CT_NONE ); + } + else + { + aprintf( LRED, MSG("\"%U\" is not a legal '%s' value.\n" + " Legal values are \"private\", \"linux\" or \"none\"\n",0), option, switchDef->name ); + MPKNSS_UNLOCK(); + return(zFAILURE); + } + if ( status != zOK ) { + aprintf( LRED, MSG("Unable to change high memory cache type - %d.\n",0), status ); + } + MPKNSS_UNLOCK(); + return(zOK); +} /* End of doHMCTypeSet() */ + + +STATUS doHMCPrivateSizeSet( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + STATUS status; + + MPKNSS_LOCK(); + status = HMC_PrivateSizeSetUI(*(NINT *)switchDef->ret_value); + switch ( status ) { + case zOK: + aprintf( LGREEN, MSG("Private cache size set.\n",0) ); + break; + case zERR_HMC_LESS_THAN_TWICE_NSS_CACHE: + aprintf( LRED, MSG("Size must be at least twice current 'minbuffercachesize' setting.\n",0) ); + break; + default: + aprintf( LRED, MSG("Error in setting size - %d.\n",0), status ); + break; + } + MPKNSS_UNLOCK(); + return zOK; /* This indicates that the command was specified correctly. + It does NOT mean that the command was able to change + the setting. The command output reports that info. */ +} /* End of doHMCPrivateSizeSet() */ + + +/* + * doVolumeIncludeTypePre() - + * If the /IncludeType switch is specified then we require the + * user to specifies all the include types they wish to have. + * + * Returns + * zOK - Parsing should continue else zFAILURE. + * + * Notes - if this routine returns zFAILURE then doVolumeIncludeType + * will not be called (doVolumeIncludeTypePost will be called). + */ + +STATUS doVolumeIncludeTypePre( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + COMN_IncludeType = COMN_IT_PRESENT; /* Indicate that the switch is + * present just in case someone cares. + */ + MPKNSS_UNLOCK(); + return( zOK ); +} /* End of doVolumeIncludeTypePre() */ + + +/* + * doVolumeIncludeTypePost() - + * If the /IncludeType switch is not specified then we only do + * local volumes or pools. + */ +NINT doVolumeIncludeTypePost( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + COMN_IncludeType = COMN_IT_DEFAULT; + MPKNSS_UNLOCK(); + return( zOK ); +} /* End of doVolumeIncludeTypePost() */ + + +NINT doVolumeIncludeType( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + unicode_t itName[MAX_TOKEN]; + unicode_t *cmdLine = NULL; + + MPKNSS_LOCK(); + +// aprintf(CYAN,"In doVolumeIncludeType\n"); +// aprintf(CYAN,"COMN_IncludeType is 0x%x\n", COMN_IncludeType ); + cmdLine = (unicode_t *)switchDef->ret_value; + while(getNextNameFromCmdLineString(itName,sizeof(itName),&cmdLine) ==zOK) + { +#if NSS_DEBUG IS_ENABLED + DBG_ScreenAPrintf( "COMN.Greg.CommandLine", WHERE, CYAN, "doVolumeIncludeType ==>%U<==\n", itName ); +#endif + if ( LB_uniicmp( itName, MSGNot(L"SHARED")) == 0 ) + { + COMN_IncludeType |= COMN_IT_SHARED; + } + else if ( LB_uniicmp( itName, MSGNot(L"LOCAL")) == 0 ) + { + COMN_IncludeType |= COMN_IT_LOCAL; + } + else + { + aprintf( LRED, MSG("\"%U\" is not a legal include type value.\n" + " Legal values are \"LOCAL\" and \"SHARED\"\n",1093), itName ); + MPKNSS_UNLOCK(); + return(zFAILURE); + } + + } +#if NSS_DEBUG IS_ENABLED + DBG_ScreenAPrintf( "COMN.Greg.CommandLine", WHERE, CYAN,"COMN_IncludeType is 0x%x\n", COMN_IncludeType ); +#endif + MPKNSS_UNLOCK(); + return(zOK); +} /* End of doVolumeIncludeType() */ + + + +/* + * doVolumeOverrideTypePre() - + * If the /OverrideType switch is specified then we require the + * user to specifies all the override types they wish to have. + * + * Returns + * zOK - Parsing should continue else zFAILURE. + * + * Notes - if this routine returns zFAILURE then doVolumeOverrideType + * will not be called (doVolumeOverrideTypePost will be called). + */ + +NINT doVolumeOverrideTypePre( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + COMN_OverrideType = 0; + MPKNSS_UNLOCK(); + return( zOK ); +} /* End of doVolumeOverrideTypePre() */ + + +/* + * doVolumeOverrideTypePost() - + * If the /OverrideType switch is not specified then we only do + * local volumes or pools. + */ +NINT doVolumeOverrideTypePost( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + COMN_OverrideType = COMN_OT_DEFAULT; + MPKNSS_UNLOCK(); + return( zOK ); +} /* End of doVolumeOverrideTypePost() */ + + +NINT doVolumeOverrideType( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + unicode_t itName[MAX_TOKEN]; + unicode_t *cmdLine = NULL; + + MPKNSS_LOCK(); + + cmdLine = (unicode_t *)switchDef->ret_value; + while(getNextNameFromCmdLineString(itName,sizeof(itName),&cmdLine) ==zOK) + { + if ( LB_uniicmp( itName, MSGNot(L"QUESTIONS")) == 0 ) + { + COMN_OverrideType |= COMN_OT_QUESTIONS; + } + else if ( LB_uniicmp( itName, MSGNot(L"QUESTION")) == 0 ) + { + COMN_OverrideType |= COMN_OT_QUESTIONS; + } + else if ( LB_uniicmp( itName, MSGNot(L"SHARED")) == 0 ) + { + COMN_OverrideType |= COMN_OT_SHARED; + } + else if ( LB_uniicmp( itName, MSGNot(L"CORRUPT")) == 0 ) + { + COMN_OverrideType |= COMN_OT_CORRUPT; + } + else + { + aprintf( LRED, MSG("\"%U\" is not a legal override type value.\n" + " Legal values are \"QUESTIONS\", \"CORRUPT\" and \"SHARED\"\n",1095), itName ); + MPKNSS_UNLOCK(); + return(zFAILURE); + } + + } + MPKNSS_UNLOCK(); + return(zOK); +} /* End of doVolumeOverrideType() */ + +NINT doRebuildPurgePoolVolumesPost( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + REBUILD_PURGE_PoolLVolumes = FALSE; + MPKNSS_UNLOCK(); + return( zOK ); +} /* End of doRebuildPurgePoolVolumesPost() */ + + +NINT doReZidPoolVolumesPost( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + REZID_PoolLVolumes = FALSE; + MPKNSS_UNLOCK(); + return( zOK ); +} /* End of doReZidPoolVolumesPost() */ + + +#if NSS_DEBUG IS_ENABLED +/* + * doDebugScreen() - + * Implements the /DebugScreenSwitches command. Used to control + * what is displayed on the NSS Debug Screen. + * + */ +NINT doDebugScreen( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + unicode_t itName[MAX_TOKEN]; + unicode_t *cmdLine = NULL; + + MPKNSS_LOCK(); + + cmdLine = (unicode_t *)switchDef->ret_value; + while(getNextNameFromCmdLineString(itName,sizeof(itName),&cmdLine) ==zOK) + { +#if NSS_DEBUG IS_ENABLED + DBG_ScreenAPrintf( "COMN.Greg.CommandLine", WHERE, CYAN, "doDebugScreen ==>%U<==\n", itName ); +#endif + if ( LB_uniicmp( itName, MSGNot(L"WHERE")) == 0 ) + { + DBG_ScreenSwitches |= DBG_SS_WHERE; + } + else if ( LB_uniicmp( itName, MSGNot(L"NOWHERE")) == 0 ) + { + DBG_ScreenSwitches &= ~DBG_SS_WHERE; + } + else if ( LB_uniicmp( itName, MSGNot(L"UTC")) == 0 ) + { + DBG_ScreenSwitches |= DBG_SS_UTC; + } + else if ( LB_uniicmp( itName, MSGNot(L"NOUTC")) == 0 ) + { + DBG_ScreenSwitches &= ~DBG_SS_UTC; + } + else if ( LB_uniicmp( itName, MSGNot(L"MASK")) == 0 ) + { + DBG_ScreenSwitches |= DBG_SS_MASK; + } + else if ( LB_uniicmp( itName, MSGNot(L"NOMASK")) == 0 ) + { + DBG_ScreenSwitches &= ~DBG_SS_MASK; + } + else + { + aprintf( LRED, MSGNot("\"%U\" is not a legal value.\n"), itName ); + MPKNSS_UNLOCK(); + return(zFAILURE); + } + + } + DBG_ScreenAPrintf( "COMN.Greg.CommandLine", WHERE, + CYAN,"DBG_ScreenSwitches is 0x%x\n", DBG_ScreenSwitches ); + MPKNSS_UNLOCK(); + return(zOK); +} /* End of doDebugScreen() */ +#endif + +#if HISTOGRAM IS_ENABLED +NINT doPrintWriteStatistics( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + prHistogram(COMN_Resource.consoleScreenID, LGREEN, &WriteHistogram); + return zOK; +} + +NINT doResetWriteStatistics( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + bzero(&WriteHistogram, sizeof(Histogram_s)); + return zOK; +} +#endif + +NINT doResetDOSTimes( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + NSS_ResetTimeCaches(); + return zOK; +} + +NINT doResetIDCache( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + G2I_InvalidateCache(); + I2G_InvalidateCache(TRUE); + MPKNSS_UNLOCK(); + return zOK; +} + +NINT doIDCacheResetInterval( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + aprintf(WHITE, MSGNot("ID cache reset interval changed to %d\n"), + G2I_CacheInvalidateTime); + GUID_IDCacheResetInterval(G2I_CacheInvalidateTime); + MPKNSS_UNLOCK(); + return zOK; +} + +NINT doResetObjectIDStore( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + OID_InitObjectIDStoreByName(&genMsg, (unicode_t *)switchDef->ret_value, + TRUE, TRUE); + MPKNSS_UNLOCK(); + return zOK; +} + +NINT doUpdateObjectIDStore( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + OID_InitObjectIDStoreByName(&genMsg, (unicode_t *)switchDef->ret_value, + FALSE, TRUE); + MPKNSS_UNLOCK(); + return zOK; +} + + +NINT doCSAClean( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + + MPKNSS_LOCK(); + CSA_Clean_UI(); + MPKNSS_UNLOCK(); + return zOK; +} + + +NINT doCSAStatsDisplay( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + + MPKNSS_LOCK(); + CSA_StatsDisplay_UI(); + MPKNSS_UNLOCK(); + return zOK; +} + + +NINT doRemoveObjectIDStore( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + OID_InitObjectIDStoreByName(&genMsg, (unicode_t *)switchDef->ret_value, + TRUE, FALSE); + MPKNSS_UNLOCK(); + return zOK; +} + +NINT doStartBackgroundChecker( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + Config.Storage.forceChecker = TRUE; + CHK_Wakeup(); + return zOK; +} + +#if zLINUX +NINT doStartSecurityEquivUpdater( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + Config.SecEquiv.forceUpdater = TRUE; + SEQ_Wakeup(); + return zOK; +} + +NINT doUpdateSecurityEquivInterval( + struct PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + Config.SecEquiv.intervalChanged = TRUE; + SEQ_Wakeup(); + return zOK; +} +#endif + + +#if NSS_DEBUG IS_ENABLED +STATUS doDumpNameCache( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + MPKNSS_LOCK(); + S_LATCH(&NameCache.latch); + ZAS_DisplayNameCache(); + UNS_LATCH(&NameCache.latch); + MPKNSS_UNLOCK(); + return zOK; +} +#endif + + /* Command Line Recovery options */ +STATUS doFreePartitionDisplay( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + DisplayFreePartitions(); + return zOK; +} + +STATUS doSalvageSys( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + SalvageSys(); + return zOK; +} + +STATUS doChangeSysQuota( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + ChangeSysQuota(switchDef->ret_value); + return zOK; +} + +STATUS doExpandSys( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + ExpandSys(switchDef->ret_value); + return zOK; +} + +STATUS doRenameToSys( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + RenameToSys(switchDef->ret_value); + return zOK; +} + /* End Command Line Recovery options */ + +STATUS doSetFileFlushTime( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + Config.tick.beast = SEC2TICK(Config.sec.beast); + return zOK; +} + +extern BOOL WriteMessyBeasts; + +STATUS doResetEFLTree( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + resetVolumeEFLTree(&genMsg, (unicode_t *)switchDef->ret_value); + MPKNSS_UNLOCK(); + return zOK; +} + +STATUS doListHardLinks( + PCLSwitchDef_s *switchDef, + NINT options, + void *userParm) +{ + GeneralMsg_s genMsg; + STATUS status; + NamedBeast_s *beast; + Zid_t zid; + NINT nameNum = 0; + typedef struct Stack_s { + NamingMsg_s nameMsg; + unicode_t name[zMAX_FULL_NAME+1]; + } Stack_s; + STACK_ALLOC(); + + MPKNSS_LOCK(); + COMN_SETUP_GENERAL_MSG_NOSA(&genMsg); + COMN_INIT_NAMING_MSG(&aStack->nameMsg); + COMN_SETUP_NAMING_MSG_SIMPLE(&aStack->nameMsg, (unicode_t *)switchDef->ret_value, + zPFMT_UNICODE, NAMPMODE_FullyResolveAny, SLATCHED, + zNSPACE_LONG, zNTYPE_FILE, NULL ); + + status = COMN_Lookup(&genMsg,&aStack->nameMsg); + + if(status == zOK) + { + + if(aStack->nameMsg.curFile->FILEhardLinkZid != zINVALID_ZID) + { + aprintf(LGREEN, MSG("Primary beast ZID = 0x%08x, Links = %d \n", 690), (NINT)aStack->nameMsg.curFile->FILEzid, aStack->nameMsg.curFile->FILEnumParents); +#if NSS_DEBUG IS_ENABLED + aprintf(LGREEN, MSG(" Primary beast FirstParentZID = 0x%08x\n", 691),(NINT)aStack->nameMsg.curFile->FILEfirstParentZid ); + aprintf(LGREEN, MSG(" Primary beast FirstParent NameType = %d\n", 692),aStack->nameMsg.curFile->FILEfirstParentNameType ); +#endif + zid = aStack->nameMsg.curFile->FILEhardLinkZid; + COMN_UNLATCH_AND_RELEASE_NAMEMSG_BEASTS_KEEP_LATCHTYPE(&aStack->nameMsg); + + while(zid != zINVALID_ZID) + { + nameNum++; + beast = COMN_LookupByZid(&genMsg,aStack->nameMsg.curvol,zid,SLATCHED, TRUE); + if(beast != NULL) + { + + status = COMN_GetFileNameFromZid(&genMsg, aStack->nameMsg.curvol, zid, + zNSPACE_LONG, aStack->name, FALSE); + + if(status == zOK) + { + if(((HardLinkBeast_s*)beast)->HARDLhlFlags & zHL_FIRST_HLNAME) + { +#if NSS_DEBUG IS_ENABLED + aprintf(LGREEN, MSG("Zid=0x%08x, parentZid=0x%08x, PrimaryName=\"%U\" \n", 693), + (NINT)beast->NAMEDzid, (NINT)beast->NAMEDfirstParentZid, aStack->name ); +#else + aprintf(LGREEN, MSG("PrimaryName=\"%U\"\n", 694), aStack->name); +#endif + } + else + { +#if NSS_DEBUG IS_ENABLED + aprintf(LGREEN, MSG("Zid=0x%08x, parentZid=0x%08x, name%d=\"%U\" \n", 695), + (NINT)beast->NAMEDzid, (NINT)beast->NAMEDfirstParentZid, nameNum, aStack->name); +#else + aprintf(LGREEN, MSG(" name%d=\"%U\"\n", 696),nameNum, aStack->name); +#endif + + } + } + else + { + aprintf(LRED, MSG("Error getting filename for Zid=0x%08x. Status = %d\n", 697),(NINT)zid, GetErrno(&genMsg) ); + } + zid = beast->NAMEDhardLinkZid; + COMN_UnlatchAndRelease(&beast, SLATCHED); + } + else + { + aprintf(LRED, MSG("Lookup of hardlink beast failed for zid 0x%08x. Status=%d \n", 698), zid, GetErrno(&genMsg) ); + zid = zINVALID_ZID; + } + } + } + else + { + aprintf(LRED, MSG("File %U is not a HardLink.\n", 699),(unicode_t *)switchDef->ret_value ); + } + } + else + { + aprintf(LRED, MSG("File %U not found.\n", 700),(unicode_t *)switchDef->ret_value ); + } + COMN_CleanupNameMsg( &genMsg, &aStack->nameMsg); + MPKNSS_UNLOCK(); + STACK_FREE(); + return (GetErrno(&genMsg)); +} + +/* Not needed on Linux */ +// +//STATUS doCreateHardLink( +// PCLSwitchDef_s *switchDef, +// NINT options, +// void *userParm) +//{ +// STATUS rc; +// Key_t key,fileKey; +// unicode_t *linkFile=NULL; +// +// +// rc = zRootKey(0, &key); +// if (rc != zOK) +// { +// return zFAILURE; +// } +// +// +// if((linkFile = unichr((unicode_t *)switchDef->ret_value, '|')) == NULL) +// { +// rc = zFAILURE; +// goto done; +// } +// *linkFile = 0; +// linkFile++; +// rc = zOpen(key,0,zNSPACE_LONG, /*L"sys:tmp/primary.doc"*/(unicode_t *)switchDef->ret_value, 0, &fileKey); +// if(rc==zOK) +// { +// rc = zLink (fileKey,0,zNSPACE_LONG,/*L"sys:tmp/primary.doc"*/(unicode_t *)switchDef->ret_value +// ,0,zNSPACE_LONG,/*(unicode_t *)switchDef->ret_value*/linkFile,0); +// zClose(fileKey); +// } +//done: +// zClose(key); +// return rc; +//} + +/*========================================================================= + *========================================================================= + *========================================================================= + * Command line switch definitions + *========================================================================= + *========================================================================= + *=========================================================================*/ + +/*--------------------------------------------------------------------------- + * General command line switch table + *---------------------------------------------------------------------------*/ +PCLSwitchDef_s CMN_CommandLineSwitches[] = +{ + /*** Modifier type commands must be first as they need to + *** be called before the commands that they modify. Note + *** that commands are called in order listed here and + *** NOT by how they appear on command line. + *** + *** NOTE - that NSS commands are executed before the + *** COMN commands. Therefore these modifier commands + *** can not modify NSS commands. + ***/ + {MSGNot("IncludeType"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE, /* We allow at startup for /AutoPool... commands */ + 0,0, + (PCLFunction_t)doVolumeIncludeType,NULL, + {{0,0}},0,0, + StructMSG("Include local and/or shared(clustered) pools in the command.",1109), + (PCLFunction_t)doVolumeIncludeTypePre, + (PCLFunction_t)doVolumeIncludeTypePost + }, + + {MSGNot("OverrideType"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doVolumeOverrideType,NULL, + {{0,0}},0,0, + StructMSG("Override options in the specified command. Possible overrides are SHARED, CORRUPT, and QUESTIONS.",1198), + (PCLFunction_t)doVolumeOverrideTypePre, + (PCLFunction_t)doVolumeOverrideTypePost + }, + + {MSGNot("Rezid"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_RUNTIME_ONLY, + 0,0, + NULL,&REZID_PoolLVolumes, + {{0,0}},0,0, + StructMSG("Forces rebuild to rezid the volume(s) being rebuilt.",548), + NULL, + (PCLFunction_t)doReZidPoolVolumesPost + }, + + {MSGNot("Purge"), + NULL, + SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_RUNTIME_ONLY, + 0,0, + NULL,&REBUILD_PURGE_PoolLVolumes, + {{0,0}},0,0, + StructMSG("Forces rebuild to purge the pool.",640), + NULL, + (PCLFunction_t)doRebuildPurgePoolVolumesPost + }, + /*** + *** End of Modifier type commands + ***/ + + {MSGNot("Status"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doStatusDisplay,NULL, + {{0,0}},0,0, + StructMSG("Display current " "NSS" " status information.", 932) + }, + + /* volume status commands */ + {MSGNot("Volumes"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)VOL_DisplayVolumes,NULL, + {{0,0}},0,0, + StructMSG("Display all of the currently available NSS volumes.",933) + }, + +/*** CSA commands(start) ***/ + {MSGNot("CSAStatistics"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_RUNTIME_ONLY|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doCSAStatsDisplay,NULL, + {{0,0}},0,0, + StructMSGNot("Display CSA statistics.") + }, + + {MSGNot("CSAClean"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_NAME|SWOPT_RUNTIME_ONLY|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doCSAClean,NULL, + {{0,0}},0,0, + StructMSGNot("Tosses all not in use CSABeasts.") + }, +/*** CSA commands(end) ***/ + + /* volume status commands */ + {MSGNot("SpaceInformation"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)VOL_DisplaySpaceInfo,NULL, + {{0,0}},0,0, + StructMSG("Display space information for active pools & volumes.",1251) + }, + + {MSGNot("Activate"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY|SWOPT_NO_HELP_VALUE|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doChangeVolumeState,NULL, + {{0,0}},0,zVOLSTATE_ACTIVE, + StructMSG("Switch the given volume to the ACTIVE state.",1231) + }, + + {MSGNot("Deactivate"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY|SWOPT_NO_HELP_VALUE|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doChangeVolumeState,NULL, + {{0,0}},0,zVOLSTATE_DEACTIVE, + StructMSG("Switch the given volume to the DEACTIVE state.",1232) + }, + + {MSGNot("Maintenance"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY|SWOPT_NO_HELP_VALUE|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doChangeVolumeState,NULL, + {{0,0}},0,zVOLSTATE_MAINTENANCE, + StructMSG("Switch the given volume to the MAINTENANCE state.",1233) + }, + + /* We should make activate use the /OverrideType switch and remove the next two commands */ + {MSGNot("ForceActivate"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeStateForce,NULL, + {{0,0}},0,zVOLSTATE_ACTIVE, + StructMSG("Force the given volume to the ACTIVE state.",937) + }, + +#if 1 + {MSGNot("ForceDeactivate"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeStateForceDeact,NULL, + {{0,0}},0,zVOLSTATE_DEACTIVE, + StructMSG("Force the given volume to the DEACTIVE state. Do not prompt for open files.",222) + }, +#endif + + /* Pool/Volume Verify/Rebuild Switches */ + /*********************************************************************************/ + /* 11-07-00: The decision was made to remove the volume maintenence commands */ + /* and only support the pool maintenance commands. It was hoped that at some */ + /* time in the future we would support volume maintenance on LVs so the command */ + /* line functions were added early on. It is hoped that by removing volume */ + /* maintenance commands and only supporting pool maintenance commands, that less */ + /* confussion on the part of the user will result. */ + /*********************************************************************************/ +// {MSGNot("VolumeVerify"), +// NULL, +// SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS|SWOPT_RUNTIME_ONLY, +// 0, 0, +// (PCLFunction_t)doCheckSpecificVol,NULL, +// {{0,0}},0,0, +// StructMSG("Verify the specified volumes physical integrity.",938) +// }, +// +// {MSGNot("VolumeVerify"), +// NULL, +// SWTYPE_NAME|SWOPT_IGNORE_STATUS|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, +// 0, 0, +// (PCLFunction_t)doCheckSelectedVol,NULL, +// {{0,0}},0,0, +// StructMSG("Select volumes from a menu and VERIFY their physical integrity.",940) +// }, +// +// {MSGNot("VolumeRebuild"), +// NULL, +// SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS|SWOPT_RUNTIME_ONLY, +// 0, 0, +// (PCLFunction_t)doRepairSpecificVol,NULL, +// {{0,0}},0,0, +// StructMSG("Rebuild the specified volumes.",939) +// }, +// +// {MSGNot("VolumeRebuild"), +// NULL, +// SWTYPE_NAME|SWOPT_IGNORE_STATUS|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, +// 0, 0, +// (PCLFunction_t)doRepairSelectedVol,NULL, +// {{0,0}},0,0, +// StructMSG("Select volumes from a menu and REBUILD them.",74) +// }, + + /* This has been left in to be the same as NSS 2.70 - Use VolumeAutoActivate instead */ + {MSGNot("AutoActivateVolume"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS|SWOPT_NO_HELP_VALUE|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)AVOL_PolicySetLoadTimeActivateVolume,NULL, + {{0,0}},0,0, + StructMSG("",0) + }, + + /* This has been left in to be the same as NSS 2.70 - Use VolumeAutoDeactivate instead */ + {MSGNot("AutoDeactivateVolume"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS|SWOPT_NO_HELP_VALUE|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)AVOL_PolicySetLoadTimeDeactivateVolume,NULL, + {{0,0}},0,0, + StructMSG("",0) + }, + + /*********************************************************************************/ + /* 11-07-00: The decision was made to remove the volume maintenence commands */ + /* (see above comment from same date) */ + /*********************************************************************************/ +// {MSGNot("AutoVerifyVolume"), +// NULL, +// SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, +// 0, 0, +// (PCLFunction_t)AVOL_PolicySetLoadTimeVerifyVolume,NULL, +// {{0,0}},0,0, +// StructMSG("Verify the specified volumes physical integrity at startup time.",943) +// }, + + {MSGNot("LogicalVolumePurgeDelay"), + NULL, + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT, + SP_TYPE_NUMBER, 0, + NULL,&Config.lv.PurgeDelayAfterDeleteSeconds, + {{0,0}},0,0, + StructMSG("Seconds to delay logical volume purging after delete.", 839) + }, + + {MSGNot("LogicalVolumePurgeDelayAfterContinue"), + NULL, + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT, + SP_TYPE_NUMBER, 0, + NULL,&Config.lv.PurgeDelayAfterLastEntrySeconds, + {{0,0}},0,0, + StructMSG("Seconds to delay logical volume purging after a continue.", 993) + }, + + {MSGNot("LogicalVolumePurgeDelayAfterLoad"), + NULL, + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT, + SP_TYPE_NUMBER, 0, + NULL,&Config.lv.PurgeDelayAfterLoadSeconds, + {{0,0}},0,0, + StructMSG("Seconds to delay logical volume purging after NSS load.", 994) + }, + + /* Command Line Recovery options */ + {MSGNot("ListFreeSpace"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doFreePartitionDisplay,NULL, + {{0,0}},0,0, + StructMSG("Display partitions that have not been assigned to a pool.",563) + }, + + {MSGNot("SalvageSys"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doSalvageSys,NULL, + {{0,0}},0,0, + StructMSG("Salvage the SYS volume.",564) + }, + + {MSGNot("ChangeSysQuota"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_CHAR|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeSysQuota,NULL, + {{0,0}},0,0, + StructMSG("New quota (in megaBytes) for SYS volume.", 565) + }, + + {MSGNot("ExpandSys"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_CHAR|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doExpandSys,NULL, + {{0,0}},0,0, + StructMSG("PartitionID to use in expanding pool.", 566) + }, + + {MSGNot("RenameToSys"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_CHAR|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doRenameToSys,NULL, + {{0,0}},0,0, + StructMSG("Name of volume to rename to SYS.", 567) + }, + + {MSGNot("SYSHotFixSize"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT, + SP_TYPE_NUMBER, 0, + NULL,&SYSHotFixSize, + {{0,0}},0,0, + StructMSG("This switch is used in conjuction with the ExpandSYS command. Used to set the Hotfix size (in KB) of the new partition. Default = 100 KB, 0 = No Hotfix", 568) + }, + /* End Command Line Recovery options */ + + /* Storage thresholds */ + {MSGNot("StorageAlarmThreshold"), + MSGNot("NSS Low Volume Space Warning Threshold"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + NULL,&Config.Storage.alarmThreshold, + {{MIN_STORAGE_ALARM_THRESHOLD,MAX_STORAGE_ALARM_THRESHOLD}},0,0, + StructMSG("Set the threshold (in megaBytes) for a low storage space warning.", 944) + }, + + {MSGNot("StorageResetThreshold"), + MSGNot("NSS Low Volume Space Warning Reset Threshold"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + NULL,&Config.Storage.resetThreshold, + {{MIN_STORAGE_RESET_THRESHOLD,MAX_STORAGE_RESET_THRESHOLD}},0,0, + StructMSG("Set the threshold (in megabytes) to reset a low storage space warning.", 945) + }, + + {MSGNot("StorageAlertMessages"), + MSGNot("NSS Low Volume Space Alerts"), + SWHELP_CAT_STATUS|SWTYPE_BOOLEAN|SWVAL_BOOL, + SP_TYPE_BOOLEAN, 0, + NULL,&Config.Storage.sendAlert, + {{0,0}},0,0, + StructMSG("Turn ON/OFF sending of low storage messages to all users.", 946) + }, + +#if NSS_DEBUG IS_ENABLED + {MSGNot("DebugScreenSwitches"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_HIDDEN, + 0,0, + (PCLFunction_t)doDebugScreen,NULL, + {{0,0}},0,0, + StructMSGNot("Options for NSS debug screen - (NO)WHERE, (NO)UTC, (NO)MASK."), + NULL, + NULL + }, + +#if 0 + {MSGNot("AutoCheck"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL, + 0, 0, + NULL,&gAutoCheck, + {{0,0}},0,0, + StructMSGNot("No confirm prompt for REBUILD/VERIFY. VERIFY exits if no errors.") + }, +#endif + +#if 0 + {MSGNot("DebugVerifySynchronous"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL, + 0, 0, + NULL,&VOL_DebugVerifySynchronous, + {{0,0}},0,0, + StructMSGNot("Pools verified will be done synchronously.") + }, +#endif + +#endif + + /* NAME CACHE switches */ + {MSGNot("NameCacheSize"), + MSGNot("NSS Name Cache Size"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + NULL,&NameCache.maxSize, + {{MIN_NAME_CACHE_SIZE,MAX_NAME_CACHE_SIZE}},0,0, + StructMSG("Set the maximum number of Name Cache entries.", 81) + }, + + {MSGNot("NameCache"), + MSGNot("NSS Name Cache Enable"), + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_STARTUP_ONLY|SWOPT_HIDDEN, + SP_TYPE_BOOLEAN, SP_STARTUP_ONLY, + NULL,&NameCacheEnabled, + {{0,0}},0,0, + StructMSG("Set the name caching ON or OFF.", 82) + }, + + {MSGNot("AsciiNameCache"), + MSGNot("NSS ASCII Name Cache Enable"), + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_STARTUP_ONLY|SWOPT_HIDDEN, + SP_TYPE_BOOLEAN, SP_STARTUP_ONLY, + NULL,&AsciiNameCacheEnabled, + {{0,0}},0,0, + StructMSG("Set the ASCII name caching ON or OFF.", 83) + }, + + {MSGNot("NameCacheStats"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doDisplayNameCacheStats,NULL, + {{0,0}},0,0, + StructMSG("Show name caching statistics.", 84) + }, + +#if NSS_DEBUG IS_ENABLED + {MSGNot("NameCacheDump"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_NAME|SWOPT_RUNTIME_ONLY|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doDumpNameCache, NULL, + {{0, 0}}, 0, 0, + StructMSG("Show name cache contents.", 85) + }, +#endif + + + /* Authorization cache switches */ + {MSGNot("AuthCacheSize"), + MSGNot("NSS Auth Cache Size"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_STARTUP_ONLY|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, SP_STARTUP_ONLY, + NULL,&AuthCache.maxEntries, + {{MIN_AUTH_CACHE_SIZE,MAX_AUTH_CACHE_SIZE}},0,0, + StructMSG("Set the number of Authorization Cache entries.", 98) + }, + +//rks /* Beast Hash switches (Config.bst) */ +//rks {MSGNot("OpenFileHashShift"), +//rks MSGNot("NSS Open File Hash Shift"), +//rks SWTYPE_VALUE|SWVAL_NINT|SWOPT_STARTUP_ONLY|SWOPT_HAS_NUMERIC_RANGE, +//rks SP_TYPE_NUMBER, SP_STARTUP_ONLY, +//rks NULL,&Config.bst.hashShift, +//rks {MIN_BEAST_HASH_SHIFT,MAX_BEAST_HASH_SHIFT},0,0, +//rks StructMSG("Set the size of the Open File hash table (in powers of 2).", 86) +//rks }, + + {MSGNot("ClosedFileCacheSize"), + MSGNot("NSS Closed File Cache Size"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, SP_STARTUP_OR_LATER, + (PCLFunction_t)SetBeastLimit,&Config.bst.notInUseMax, + {{MIN_NOT_IN_USE_BEASTS,MAX_NOT_IN_USE_BEASTS}},0,0, + StructMSG("Set the number of closed files that can be cached in memory.", 650) + }, + + {MSGNot("FileFlushTimer"), + MSGNot("NSS File Flush Timer"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + (PCLFunction_t)doSetFileFlushTime,&Config.sec.beast, + {{MIN_SEC,MAX_SEC}},0,0, + StructMSG("Set the Flush Time in seconds for metadata controlling modified open files.", 88) + }, + + + /* Buffer Cache switches (Config.cache) */ + {MSGNot("MinBufferCacheSize"), + MSGNot("NSS Minimum Cache Buffers"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT, + SP_TYPE_NUMBER, 0, + (PCLFunction_t)doChangeCacheBuffers,0, + {{0,0}},0,0, + StructMSG("Set the minimum number of " "NSS" " Buffer Cache entries.", 89) + }, + + {MSGNot("MinOSBufferCacheSize"), + MSGNot("NSS Minimum OS Cache Buffers"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_HIDDEN, + SP_TYPE_NUMBER, 0, + NULL,&Config.cache.minOSFree, + {{MIN_OS_FREE_CACHE_BUFS,MAX_NUM_BUFFERS}},0,0, + StructMSG("This is a NetWare only setting.", 0) + }, + + {MSGNot("JournalGroupWriteTime"), + MSGNot("Journal Group Write Time"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + NULL,&Config.sec.journalGroupWriteTime, + {{MIN_SEC,MAX_SEC}},0,0, + StructMSG("Set the Flush Time for modified journal data in seconds.", 0) + }, + + {MSGNot("MetadataGroupWriteTime"), + MSGNot("Metadata Group Write Time"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + NULL,&Config.sec.metadataGroupWriteTime, + {{MIN_SEC,MAX_SEC}},0,0, + StructMSG("Set the Flush Time for modified metadata in seconds.", 0) + }, + + {MSGNot("UserDataGroupWriteTime"), + MSGNot("User Data Group Write Time"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + NULL,&Config.sec.userDataGroupWriteTime, + {{MIN_SEC,MAX_SEC}},0,0, + StructMSG("Set the Flush Time for modified user data in seconds.", 0) + }, + + {MSGNot("MetadataGroupWriteLimit"), + MSGNot("Metadata Group Write Limit"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT, + SP_TYPE_NUMBER, 0, + NULL,&Config.cache.metadataBlocksReadyForGroupWriteLimit, + {{0,0}},0,0, /* No Range on values! */ + StructMSG("Set the maximum metadata blocks to group before doing a write.", 0) + }, + + {MSGNot("CacheBalance"), + MSGNot("NSS Cache Balance Enable"), + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL, + SP_TYPE_BOOLEAN, 0, + (PCLFunction_t)doCacheBalance,&Config.cache.usePercentMemory, + {{0,0}},0,0, + StructMSG("Set the dynamic balancing of free memory for the " "NSS" " buffer cache ON or OFF.", 92) + }, + + {MSGNot("CacheBalance"), + MSGNot("NSS Cache Balance Percent"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + NULL,&Config.cache.percentOfOSFree, + {{1,99}},0,0, + StructMSG("Set what percentage of free memory " "NSS" " will use for its buffer cache.", 93) + }, + + {MSGNot("CacheBalanceTimer"), + MSGNot("NSS Cache Balance Timer"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_HIDDEN, + SP_TYPE_NUMBER, 0, + NULL,&Config.cache.balanceTimerSecs, + {{1,3600}},0,0, + StructMSG("Set the Cache Balance Timer in seconds.", 94) + }, + + {MSGNot("CacheBalanceMaxBuffersPerSession"), + MSGNot("NSS Maximum Cache Balance Buffers Per Session"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_HIDDEN, + SP_TYPE_NUMBER, 0, + NULL,&Config.cache.maxNumBuffersToAddPerBalance, + {{BALANCE_CACHE_MIN, MAX_NUM_BUFFERS}},0,0, + StructMSG("Every time we do a cache balance, limit the num buffers to this limit.", 95) + }, + + /* Cache Statistics */ + {MSGNot("FileCacheStats"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doDisplayBeastCacheStats,NULL, + {{0,0}},0,0, + StructMSG("Show file system object caching statistics.",576) + }, + + {MSGNot("CacheStats"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doDisplayCacheStats,NULL, + {{0,0}},0,0, + StructMSG("Show buffer caching statistics.",96) + }, + + {MSGNot("ResetStats"), + NULL, + SWHELP_CAT_TUNING|SWTYPE_NAME|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doResetInst,NULL, + {{0,0}},0,0, + StructMSGNot("Reset caching and file statistics.") + }, + + {MSGNot("CacheUserMaxPercent"), + NULL, + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0, 0, + NULL,&Config.cache.percentUserPages, + {{10,100}},0,0, + StructMSG("Set the maximum percentage of buffer cache that can be used for user data.", 141) + }, + + /* Miscelaneous system settings */ +/* fixfixfix@nextMediaFormatChange begin */ + {MSGNot("ExtendedMac"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeExtendedMac,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable extended Macintosh namespace on the given volume.",652) + }, + +// {MSGNot("NoExtendedMac"), +// NULL, +// SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, +// 0, 0, +// (PCLFunction_t)doChangeVolumeExtendedMac,NULL, +// {{0,0}},0,FALSE, +// StructMSG("Disable extended Macintosh namespace on the given volume.",653) +// }, +/* fixfixfix@nextMediaFormatChange end */ + {MSGNot("NumWorkToDos"), + MSGNot("NSS Work To Do Count"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_STARTUP_ONLY|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, SP_STARTUP_ONLY, + NULL,&Config.os.workLimit, + {{MIN_WORK_LIMIT,MAX_WORK_LIMIT}},0,0, + StructMSG("Set the number of WorkToDo entries which may be concurrently executing.", 100) + }, + + {MSGNot("Salvage"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeSalvage,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable salvage of deleted files on the given volume.",101) + }, + + {MSGNot("NoSalvage"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeSalvage,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable salvage of deleted files on the given volume.",102) + }, + + {MSGNot("Hardlinks"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeHardlinks,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable creation of Hardlinks on the given volume.",686) + }, + + {MSGNot("NoHardlinks"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeHardlinks,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable creation of Hardlinks on the given volume.",687) + }, + + {MSGNot("UserSpaceRestrictions"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeUserSpaceRestrictions,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable user space restrictions for the given volume.",103) + }, + + {MSGNot("NoUserSpaceRestrictions"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeUserSpaceRestrictions,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable user space restrictions for the given volume.",104) + }, + + {MSGNot("DirectoryQuotas"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeDirectoryQuotas,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable directory quotas for the given volume.",1151) + }, + + {MSGNot("NoDirectoryQuotas"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeDirectoryQuotas,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable directory quotas for the given volume.",1152) + }, + + {MSGNot("FixDirectoryQuotas"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doFixVolumeDirectoryQuotas,NULL, + {{0,0}},0,0, + StructMSG("Recompute used space for directory quotas for the given volume.",589) + }, + + {MSGNot("DataShredding"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeDataShredding,NULL, + {{0,0}},0,TRUE, + StructMSG("Specify [:] to enable data shredding for the given volume. Count (Default value = 1, Maximum value = 7) is the number of times you want to shred data.",1182) + }, + + {MSGNot("NoDataShredding"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeDataShredding,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable data shredding for the given volume.",1183) + }, + + {MSGNot("ResetObjectIDStore"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_HELP_ADD_SLASH|SWOPT_NO_HELP_VALUE|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doResetObjectIDStore,NULL, + {{0,0}},0,0, + StructMSGNot("Reset the entire object ID store for a volume (use with care).") + }, + + {MSGNot("UpdateObjectIDStore"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE, + 0, 0, + (PCLFunction_t)doUpdateObjectIDStore,NULL, + {{0,0}},0,0, + StructMSGNot("Scan and add all volume objects to an existing object store") + }, + + {MSGNot("RemoveObjectIDStore"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE, + 0, 0, + (PCLFunction_t)doRemoveObjectIDStore,NULL, + {{0,0}},0,0, + StructMSGNot("Remove the object store") + }, + + {MSGNot("BackgroundChecking"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_BOOLEAN|SWVAL_BOOL, + 0, 0, + NULL,&Config.Storage.checker, + {{0,0}},0,0, + StructMSG("Enable/Disable background file system checking.", 537) + }, + + {MSGNot("ForceBackgroundCheck"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doStartBackgroundChecker,NULL, + {{0,0}},0,0, + StructMSG("Force background file system checking to start.", 547) + }, + +#if zLINUX + {MSGNot("SecurityEquivalenceUpdating"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_BOOLEAN|SWVAL_BOOL, + 0, 0, + NULL,&Config.SecEquiv.updater, + {{0,0}},0,0, + StructMSG("Enable/Disable background user security equivalence updating.", 0) + }, + + {MSGNot("ForceSecurityEquivalenceUpdate"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doStartSecurityEquivUpdater,NULL, + {{0,0}},0,0, + StructMSG("Force user security equivalence background updating to start.", 0) + }, + + {MSGNot("UpdateSecurityEquivalenceInterval"), + MSGNot("NSS Security Equivalence Update Interval"), + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0, 0, + (PCLFunction_t)doUpdateSecurityEquivInterval,&Config.SecEquiv.updaterInterval, + {{(5*60),(90*24*60*60)}},0,0, + StructMSG("Set the Security Equivalence Update Interval in seconds.", 0) + }, +#endif + + {MSGNot("FlushFilesImmediately"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeHighIntegrity,NULL, + {{0,0}},0,TRUE, + StructMSG("Synchronously flush files when they are closed for the given volume.",842) + }, + + {MSGNot("NoFlushFilesImmediately"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeHighIntegrity,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable flushing files synchronously for the given volume.",1209) + }, + + {MSGNot("CFSMaster"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doChangeVolumeCFSMaster,NULL, + {{0,0}},0,TRUE, + StructMSG("Mark the given volume as a Cluster File System Master.",606) + }, + + {MSGNot("NoCFSMaster"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doChangeVolumeCFSMaster,NULL, + {{0,0}},0,FALSE, + StructMSG("Mark the given volume as no longer being a Cluster File System Master.",607) + }, + + {MSGNot("FileCopyOnWriteSnapshot"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeCOW,NULL, + {{0,0}},0,TRUE, + StructMSG("Create a copy of files when they are opened for write on the given volume.",1027) + }, + + {MSGNot("NoFileCopyOnWriteSnapshot"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeCOW,NULL, + {{0,0}},0,FALSE, + StructMSG("Do no create a copy of files when they are opened for write on the given volume.",1028) + }, + + {MSGNot("VisibilityRebuild"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doVisibilityRebuild,NULL, + {{0,0}},0,0, + StructMSG("Rebuild the authorization visibility lists for a volume",304) + }, + +// {MSGNot("SharedPool"), +// NULL, +// SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, +// 0, 0, +// doChangePoolShared,NULL, +// {{0,0}},0,TRUE, +// StructMSG("Mark the given pool as being shared in a cluster",0) +// }, +// +// {MSGNot("NoSharedPool"), +// NULL, +// SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, +// 0, 0, +// doChangePoolShared,NULL, +// {{0,0}},0,FALSE, +// StructMSG("Mark the given pool as being local and no longer part of a cluster.",0) +// }, + +#if NSS_DEBUG IS_ENABLED + {MSGNot("DirQuotaCache"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)DIRQ_DoDisplayCache,NULL, + {{0,0}},0,0, + StructMSG("Show directory quota cache.",1153) + }, +#endif + + {MSGNot("UpgradeObjectsOnVolume"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doUpgradeBeastsOnVolume,NULL, + {{0,0}},0,0, + StructMSG("Upgrade the objects for the given volumes to the current version.",1170) + }, + + {MSGNot("Transaction"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeTransaction,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable transactioned writes in files on the given volumes.",984) + }, + + {MSGNot("NoTransaction"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeTransaction,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable transactioned writes in files on the given volumes.",985) + }, + + {MSGNot("Migration"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeMigration,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable Migration of files on the given volumes.",1181) + }, + + {MSGNot("NoMigration"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeMigration,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable Migration of files on the given volumes.",1192) + }, + + /* Maximum value is defined by zMAX_READ_AHEAD_COUNT in comnvol.c */ + {MSGNot("ReadAheadBlks"), + NULL, + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeReadAhead,NULL, + {{0,0}},0,TRUE, + StructMSG("Specify : to set the read ahead block count, for the specified volume. Count (Default value = 2 (most types of volumes), Maximum value = 1024) is the number of 4K blocks to read ahead. Count of zero implies no read ahead",622) + }, + + {MSGNot("AllocAheadBlks"), + NULL, + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0, 0, + NULL,&Config.Storage.allocAhead, + {{MIN_ALLOC_AHEAD_WRITE,MAX_ALLOC_AHEAD_WRITE}},0,0, + StructMSG("Set the number of blks that we alloc ahead on writes.",105) + }, + + {MSGNot("HighMemoryCacheType"), + MSGNot("Type of high memory cache to use - private, Linux or none"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_UNICODE, + SP_TYPE_NUMBER, 0, + (PCLFunction_t)doHMCTypeSet,NULL, + {{0,0}},0,0, + StructMSG("Set the type of high memory cache to use. Valid values are NONE, PRIVATE, and LINUX.", 0) + }, + + {MSGNot("PrivateCacheSizeInBlocks"), + MSGNot("Total number of metadata blocks to cache outside of Linux's Caching System"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT, + SP_TYPE_NUMBER, 0, + (PCLFunction_t)doHMCPrivateSizeSet,NULL, + {{0,0}},0,0, + StructMSG("Set the number of metadata blocks to cache.", 0) + }, + + {MSGNot("Compression"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeCompression,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable File Compression on the given volumes. It cannot be turned off once it's enabled",106) + }, + +// {MSGNot("NoCompression"), +// NULL, +// SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, +// 0, 0, +// (PCLFunction_t)doChangeVolumeCompression,NULL, +// {{0,0}},0,FALSE, +// StructMSG("Disable File Compression on the given volumes.",107) +// }, + + {MSGNot("BGCompression"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doToggleBGCompression,NULL, + {{0,0}},0,0, + StructMSG("Start/Stop background Compression. Stop BGCompression will stop and clear all the enqueued background compression request.",108) + }, + + {MSGNot("StopNormalCompression"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doStopNormalCompression,NULL, + {{0,0}},0,0, + StructMSG("Stop normal Compression. It will stop and clear all the enqueued normal compression request.",623) + }, + + {MSGNot("CompScreen"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_IGNORE_STATUS|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doCompressionScreen,NULL, + {{0,0}},0,0, + StructMSG("Start the NSS Compression Statistics Screen.", 221) + }, + + {MSGNot("ATime"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeATime,NULL, + {{0,0}},0,TRUE, + StructMSGNot("Enable File Access time of the given volumes.") + }, + + {MSGNot("NoATime"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeATime,NULL, + {{0,0}},0,FALSE, + StructMSGNot("Disable File Access time of the given volumes.") + }, + /** + * Pool Status command. This is similar to the Volume status command + */ + {MSGNot("Pools"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)POOL_DisplayPools,NULL, + {{0,0}},0,0, + StructMSG("Display all of the currently available NSS pools.",207) + }, + + /** + * These 3 commands set POLICIES for pools. Volume's have their own + * commands that are similarly named. + */ + + {MSGNot("PoolAutoActivate"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)AVOL_PolicySetLoadTimeActivatePool,NULL, + {{0,0}},0,0, + StructMSG("Places specified pools in ACTIVE state at pool load time.",208) + }, + + {MSGNot("PoolAutoDeactivate"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)AVOL_PolicySetLoadTimeDeactivatePool,NULL, + {{0,0}},0,0, + StructMSG("Leave specified pools in DEACTIVE state at pool load time.",1234) + }, + + {MSGNot("PoolAutoDisplay"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)AVOL_PolicyDisplayLoadTimePool,NULL, + {{0,0}},0,0, + StructMSG("Displays current pool load time policies.",1235) + }, + + {MSGNot("PoolAutoMaintenance"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)AVOL_PolicySetLoadTimeMaintenancePool,NULL, + {{0,0}},0,0, + StructMSG("Places specified pools in MAINTENANCE state at pool load time.",1236) + }, + + {MSGNot("PoolAutoVerify"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)AVOL_PolicySetLoadTimeVerifyPool,NULL, + {{0,0}},0,0, + StructMSG("Verify the specified pools physical integrity at startup time.",1229) + }, + +#if zLINUX + {MSGNot("MSAPServerId"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_CHAR, + 0, 0, + (PCLFunction_t)doMSAPServerIdSet,NULL, + {{0,0}},0,0, + StructMSG("Sets the ID for MSAP to use to uniquely identify the server.",0) + }, +#endif + + {MSGNot("MSAPIdDisplay"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)doMSAPIdDisplay,NULL, + {{0,0}},0,0, + StructMSG("Displays current IDs used by MSAP.",0) + }, + + {MSGNot("PoolMSAP"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangePoolMSAP,NULL, + {{0,0}},0,TRUE, + StructMSG("Enables feature to prevent accidental activations of a pool on more than one server at a time.",42) + }, + + {MSGNot("NoPoolMSAP"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangePoolMSAP,NULL, + {{0,0}},0,FALSE, + StructMSG("Disables feature to prevent accidental activations of a pool on more than one server at a time.",601) + }, + + {MSGNot("PoolRebuild"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doRepairSpecificPool,NULL, + {{0,0}},0,0, + StructMSG("Rebuild the specified pools.",201) + }, + + {MSGNot("PoolRebuild"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_NAME|SWOPT_IGNORE_STATUS|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doRepairSelectedPool,NULL, + {{0,0}},0,0, + StructMSG("Select pools from a menu and REBUILD them.",202) + }, + + {MSGNot("PoolVerify"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doCheckSpecificPool,NULL, + {{0,0}},0,0, + StructMSG("Verify the specified pools physical integrity.",203) + }, + + {MSGNot("PoolVerify"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_NAME|SWOPT_IGNORE_STATUS|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doCheckSelectedPool,NULL, + {{0,0}},0,0, + StructMSG("Select pools from a menu and VERIFY their physical integrity.",204) + }, + + {MSGNot("MFL"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeMFL,NULL, + {{0,0}},0,TRUE, + StructMSG("Enable MFL maintenance for the given volumes.",1086) + }, + + {MSGNot("NoMFL"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeMFL,NULL, + {{0,0}},0,FALSE, + StructMSG("Disable MFL maintenance for the given volumes.",1087) + }, + + {MSGNot("MFLVerify"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doAdministerMFL,NULL, + {{0,0}},0,VOL_MFL_ADMIN_VERIFY_OP, + StructMSG("Compares MFL with the file system and reports any inconsistencies.",99) + }, + + {MSGNot("FixMFL"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doAdministerMFL,NULL, + {{0,0}},0,VOL_MFL_ADMIN_FIX_OP, + StructMSG("Fixes MFL to be consistent with file system.",557) + }, + + {MSGNot("GetMFLStatus"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doAdministerMFL,NULL, + {{0,0}},0,VOL_MFL_ADMIN_GET_STATUS_OP, + StructMSG("Get the status of MFL maintenance for the given volumes.",1090) + }, + + {MSGNot("VolumeActivate"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeState,NULL, + {{0,0}},0,zVOLSTATE_ACTIVE, + StructMSG("Switch the given volume to the ACTIVE state.",934) + }, + + {MSGNot("VolumeAutoActivate"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, + 0, 0, + (PCLFunction_t)AVOL_PolicySetLoadTimeActivateVolume,NULL, + {{0,0}},0,0, + StructMSG("Places specified volumes in ACTIVE state at volume load time.",941) + }, + + {MSGNot("VolumeAutoDeactivate"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, + 0, 0, + (PCLFunction_t)AVOL_PolicySetLoadTimeDeactivateVolume,NULL, + {{0,0}},0,0, + StructMSG("Leave specified volumes in DEACTIVE state at volume load time.",942) + }, + + {MSGNot("VolumeAutoDisplay"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)AVOL_PolicyDisplayLoadTimeVolume,NULL, + {{0,0}},0,0, + StructMSG("Displays current volume load time policies.",1237) + }, + + {MSGNot("VolumeDeactivate"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeState,NULL, + {{0,0}},0,zVOLSTATE_DEACTIVE, + StructMSG("Switch the given volume to the DEACTIVE state.",935) + }, + + {MSGNot("VolumeMaintenance"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangeVolumeState,NULL, + {{0,0}},0,zVOLSTATE_MAINTENANCE, + StructMSG("Switch the given volume to the MAINTENANCE state.",936) + }, + + /* + * The ZID commands allows the user to lookup the name of a file + * given the file's ZID. This is needed because some ALERTs + * report the ZID and not the file's name. This is done because + * NSS does not have a station number with a Buffer_s. + */ + {MSGNot("ZIDNameSpace"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)doZIDToFileNameNameSpace, NULL, + {{0,0}},0,0, + StructMSG("The name space(DOS,LONG,MAC,or UNIX) the command /ZIDToFileName should use.", 1118) + }, + + {MSGNot("ZIDVolumeName"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_IGNORE_STATUS, + 0,0, + (PCLFunction_t)doZIDToFileNameVolumeName,NULL, + {{0,0}},0,0, + StructMSG("The volume name the command /ZIDToFileName should use.", 1119) + }, + + /* ZIDToFileName is after the other TWO ZID commands because the command + * line parser executes command line options in order that they + * appear in this table. By being after other two we can allow + * the user to specify all three items on a single line in any + * order. It would be nice if HELP displayed items in SORTED order. + */ + {MSGNot("ZIDToFileName"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_QUAD, + 0, 0, + (PCLFunction_t)doZIDToFileName,NULL, + {{0,0}},0,0, + StructMSG("Converts a ZID into its full path(see also /ZIDVolumeName and /ZIDNameSpace).", 1120) + }, + +#if HISTOGRAM IS_ENABLED + {MSGNot("WriteStatistics"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_NAME|SWOPT_RUNTIME_ONLY|SWOPT_NO_HELP_VALUE|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doPrintWriteStatistics,NULL, + {{0,0}},0,0, + StructMSGNot("Print write statistics.") + }, + + {MSGNot("ResetWriteStatistics"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_NAME|SWOPT_RUNTIME_ONLY|SWOPT_NO_HELP_VALUE|SWOPT_HIDDEN, + 0, 0, + (PCLFunction_t)doResetWriteStatistics,NULL, + {{0,0}},0,0, + StructMSGNot("Reset write statistics.") + }, +#endif + + {MSGNot("ResetCachedTimes"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_NAME|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doResetDOSTimes,NULL, + {{0,0}},0,0, + StructMSG("Reset the various system caching for time conversions.", 175) + }, + + {MSGNot("ResetIDCache"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_NAME|SWOPT_HELP_ADD_SLASH|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doResetIDCache,NULL, + {{0,0}},0,0, + StructMSGNot("Reset the various NDS caches.") + }, + + {MSGNot("IDCacheResetInterval"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0, 0, + (PCLFunction_t)doIDCacheResetInterval,&G2I_CacheInvalidateTime, + {{0,200000000}},0,0, + StructMSGNot("Set the number of seconds between invalidation of the ID cache.") + }, + + {MSGNot("ResetEFLTree"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doResetEFLTree,NULL, + {{0,0}},0,0, + StructMSG("Reset EFL tree on the given volume.", 577) + }, + + {MSGNot("PoolHighWaterMark"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangePoolWaterMarks,NULL, + {{0,0}},0,TRUE, + StructMSG("Set the purge high water mark to this percentage for one or ALL Pools. Usage: /PoolHighWaterMark=POOL:PERCENT", 644) + }, + + {MSGNot("PoolLowWaterMark"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0, 0, + (PCLFunction_t)doChangePoolWaterMarks,NULL, + {{0,0}},0,FALSE, + StructMSG("Set the purge low water mark to this percentage for one or ALL Pools. Usage: /PoolLowWaterMark=POOL:PERCENT", 645) + + }, + + {MSGNot("VFSDisplay"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_HIDDEN, + 0,0, + NULL,&VIRT_PrintDebug, + {{0,0}},0,0, + StructMSG("Display the virtual file system debug", 646) + }, + + {MSGNot("QuotaChecking"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_HIDDEN, + 0,0, + NULL,&COMN_CheckQuotas, + {{0,0}},0,0, + StructMSG("Display the checking of user and directory quotas", 647) + }, + + {MSGNot("InitialUnixRights"), + MSGNot("Initial Unix File Mode"), + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER,0, + NULL,&UX_InitialMode, + {{0,1911}},0,0, + StructMSG("Set the initial mode for files created with Unix type authorization", 651) + }, + + {MSGNot("BuffersPerEncryptedVolume"), + MSGNot("Number of buffers reserved per Encrypted Volume"), + SWHELP_CAT_TUNING|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + SP_TYPE_NUMBER, 0, + NULL,&Pages_Per_Encrypted_Volume, + {{MIN_BUFS_PER_ENCRYPTED_VOLUME,MAX_BUFS_PER_ENCRYPTED_VOLUME}},0,0, + StructMSG("Set the number of buffers to reserve for each encrypted volume.", 652) + }, + + {MSGNot("OldCreateRights"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_HIDDEN, + 0,0, + NULL,&COMN_OldCreateRights, + {{0,0}},0,0, + StructMSG("Or's in WRITE_ACCESS when creating a new file",653) + }, + +/* Not needed on Linux */ +// {MSGNot("CreateHardLink"), +// NULL, +// SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, +// 0,0, +// (PCLFunction_t)doCreateHardLink,NULL, +// {{0,0}},0,0, +// StructMSG("Creates a HardLink. Syntax is NSS /CreateHardLink=PrimaryFilePath|HardLinkFilePath",676) +// }, + + {MSGNot("ListHardLinks"), + NULL, + SWHELP_CAT_STATUS|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doListHardLinks,NULL, + {{0,0}},0,0, + StructMSG("Lists all HardLinks associated with the filename provided. Syntax is NSS /ListHardLinks=Path/Filename",701) + }, + +#ifdef ONE_OFF_FOR_KEIPPER + {MSGNot("UpgradeCurrentVersion3MediaFormat"), + NULL, + SWHELP_CAT_MAINT|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY|SWOPT_HIDDEN, + 0,0, + NULL,NULL, + {{0,0}},0,0, + StructMSG("Forces a conversion of Beta Version 3 Beasts to shipping Version 3 beasts.",688), + NULL, + (PCLFunction_t)doUpgradeVersion3Beasts + }, +#endif + +#if zLINUX + {MSGNot("ClientFileCaching"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL, + 0,0, + NULL,&NW_ClientFileCachingEnabledFlag, + {{0,0}},0,0, + StructMSG("Enable/Disable client side caching of opened file.", 649) + }, + + {MSGNot("CompressionDailyCheckStartingHour"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doCompressionDailyCheckStartingHour,&CompressionDailyCheckStartingHour, + {{0,23}},0,0, + StructMSG("The hour (0=midnight, 23=11p.m.) when the file compressor starts scanning each" + " enabled volume for files that need to be compressed.", 654) + }, + + {MSGNot("CompressionDailyCheckStopHour"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doCompressionDailyCheckStopHour,&CompressionDailyCheckStopHour, + {{0,23}},0,0, + StructMSG("The hour (0=midnight, 23=11p.m.) when the file compressor ends scanning each" + " enabled volume for files that need to be compressed. If CompressionDailyCheckStopHour" + " is equal to CompressionDailyStartingHour then start checking every day at CompressionDailyStartingHour" + " and run as long as necessary to finish all files meeting the compressible criteria.", 655) + }, + + {MSGNot("ConvertCompressedToUncompressedOption"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0,0, + NULL,&CM_curCompControlParams.decompOption, + {{0,2}},0,0, + StructMSG("What to do to the uncompressed version when the server uncompresses a file." + " (0= always leave compressed version, 1= if compressed file is read only once (within the time fram defined" + " by DaysUntouchedBeforeCompression) then leave the file compressed (on second access leave uncompressed)," + " 2= always change to the uncompressed version)", 656) + }, + + {MSGNot("DaylightSavingsTimeOffset"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_HAS_NUMERIC_RANGE|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doDaylightSavingsTimeOffset,&DaylightSavingsTimeOffset, + {{0,23}},0,0, + StructMSG("The offset applied in time calculations when daylight savings time is in effect. The default is +1" + " (one hour). Issuing this command causes UTC time to be recalculated from local time.", 657) + }, + + {MSGNot("DaysUntouchedBeforeCompression"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_FINISHOFSTARTUP, + 0,0, + (PCLFunction_t)doDaysUntouchedBeforeCompression,&DaysUntouchedBeforeCompression, + {{0,100000}},0,0, + StructMSG("The number of days to wait after a file was last accessed before automatically compressing it.", 668) + }, + + {MSGNot("DecompressFreeSpaceWarningInterval"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0,0, + (PCLFunction_t)doDecompressFreeSpaceWarningInterval,&DecompressFreeSpaceWarningInterval, + {{0,720}},0,0, + StructMSG("The time interval (in minutes) between displaying warning alerts when the file system is not" + " permanently changing compressed files to uncompressed files due to insufficient free disk space" + " (setting the interval to 0 turns off the alert).", 669) + }, + + {MSGNot("DecompressPercentDiskSpaceFreeToAllowCommit"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0,0, + NULL,&CM_curCompControlParams.minFreeSpaceToDecompress, + {{0,75}},0,0, + StructMSG("The percentage of disk space on a volume that is required to be free in order for file decompression" + " to permanently change the compressed file version to uncompressed, which prevents newly uncompressed fils from" + " entirely filling up the volume. (compressed files that are written to are always left uncompressed)", 670) + }, + + {MSGNot("DeletedFilesCompressionOption"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0,0, + NULL,&CM_curCompControlParams.compressDeletedFilesOption, + {{0,2}},0,0, + StructMSG("How to compress deleted files. (0=don't, 1=compress next day, 2=compress immediately.", 671) + }, + + {MSGNot("EnableFileCompression"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doEnableFileCompression,&EnableFileCompression, + {{0,0}},0,0, + StructMSG("Allow file compression to occur on compression enabled volumes. If disabled, no compression will" + " take place. Immediate compress requests will be queued until compression is allowed.", 672) + }, + + {MSGNot("EndOfDaylightSavingsTime"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_CHAR|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doEndOfDaylightSavingsTime,&EDSTInfo, + {{0,0}},0,0, + StructMSG("Local date and time when the switch off of daylight savings time should occur. Formats include a simple" + " date and time enclosed in quotes, or rules, enclosed in quotes and parenthesis. For example," + " \"October 31 2004 2:0:0 am\", \"(October Sunday <= 31 2:0:0 am)\", or \"(October Sunday Last 2:0:0 am)\". Only" + " rules cause rescheduling for the next year. You must set both the start and end dates before either will be scheduled.", 673) + }, + + {MSGNot("ImmediatePurgeOfDeletedFiles"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + doImmediatePurgeOfDeletedFiles,&ImmediatePurgeOfDeletedFiles, + {{0,0}},0,0, + StructMSG("Purge all files immediately upon deletion.", 674) + }, + + {MSGNot("Level2OpLocksEnabled"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL, + 0,0, + NULL,&NW_Level2OpLocksEnabledFlag, + {{0,0}},0,0, + StructMSG("Allow or Disallow level 2 (shared) oplocks.", 675) + }, + + {MSGNot("MaximumConcurrentCompressions"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doMaximumConcurrentCompressions,&MaximumConcurrentCompressions, + {{1,8}},0,0, + StructMSG("The number of simultaneous compressions allowed by the system (simultaneous compressions can only occur" + " if there are multiple volumes).", 676) + }, + + + {MSGNot("MinimumCompressionPercentageGain"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doMinimumCompressionPercentageGain,&MinimumCompressionPercentageGain, + {{0,50}},0,0, + StructMSG("The minimum percentage a file must compress in order to remain compressed.", 677) + }, + +/* The code to implement this above currently does nothing. When the code is completed, this structure will call it + {MSGNot("MinimumFileDeleteWaitTime"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_NINT|SWOPT_HAS_NUMERIC_RANGE, + 0,0, + (PCLFunction_t)doMinimumFileDeleteWaitTime,&MinimumFileDeleteWaitTime, + {{0,0}},0,0, + StructMSG("Minimum time to wait (in seconds) after a file is deleted before purging it.", 677) + }, +*/ + + {MSGNot("StartOfDaylightSavingsTime"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_CHAR|SWOPT_FINISHOFSTARTUP|SWOPT_RUNTIME_ONLY, + 0,0, + (PCLFunction_t)doStartOfDaylightSavingsTime,&SDSTInfo, + {{0,0}},0,0, + StructMSG("Local date and time when the switch onto daylight savings time should occur. Formats include a simple" + " date and time, enclosed in quotes, or rules, enclosed in quotes and parenthesis. For example," + " \"April 1 2004 2:0:0 am\", \"(April Sunday > 1 2:0:0 am)\", or \"(April Sunday First 2:0:0 am)\". Only rules cause" + " rescheduling for the next year. You must set both the start and end dates before either will be scheduled.", 678) + }, + + {MSGNot("Echo"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_VALUE|SWVAL_UNICODE|SWOPT_RUNTIME_ONLY|SWOPT_HIDDEN, + 0,0, + (PCLFunction_t)doEchoString, NULL, + {{0,0}},0,0, + StructMSG("Echo a character string",000) + }, +#endif + + {MSGNot("WriteMessyBeasts"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL, + 0,0, + NULL,&WriteMessyBeasts, + {{0,0}},0,0, + StructMSGNot("Enable/Disable messy file flushing.") + }, + + {MSGNot("LAFAuditTrustee"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL, + 0,0, + NULL,&NSSLAF_AuditEnabled, + {{0,0}},0,0, + StructMSGNot("Enable/Disable generating audit messages via LAF for NSS trustee changes.") + }, + + {MSGNot("IgnoreDoNotModifyMask"), + NULL, + SWHELP_CAT_CONTROL|SWTYPE_BOOLEAN|SWVAL_BOOL|SWOPT_HIDDEN, + 0,0, + NULL,&COMN_IgnoreDoNotModifyMask, + {{0,0}},0,0, + StructMSGNot("Only enable when fixing broken file atributes.") + }, + + {PCMDLINE_ENDOFLIST} +}; + +///************************************************************************** +// * ACTIVATE/DEACTIVATE switches +// ***************************************************************************/ +//STATIC unicode_t ActivateNameBuf[64]; +// +//PCLSwitchDef_s activateSwitches[] = +//{ +// {MSGNot("Volume"), +// SWTYPE_REQUIRED|SWVAL_UNICODE, +// NULL,ActivateNameBuf, +// {unisizeof(ActivateNameBuf),0},0,0, +// StructMSG("Activate the given volume.", 0) +// }, +// +// {PCMDLINE_ENDOFLIST} +//}; +// +//PCLSwitchDef_s deactivateSwitches[] = +//{ +// {MSGNot("Volume"), +// SWTYPE_REQUIRED|SWVAL_UNICODE, +// NULL,ActivateNameBuf, +// {unisizeof(ActivateNameBuf),0},0,0, +// StructMSG("Deactyivate the given volume.", 0) +// }, +// +// {PCMDLINE_ENDOFLIST} +//}; diff --git a/src/nwnss/comn/main/seqUpdater.h b/src/nwnss/comn/main/seqUpdater.h new file mode 100755 index 0000000..94d83cb --- /dev/null +++ b/src/nwnss/comn/main/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/library/misc/lbVolume.c b/src/nwnss/library/misc/lbVolume.c new file mode 100644 index 0000000..20c0005 --- /dev/null +++ b/src/nwnss/library/misc/lbVolume.c @@ -0,0 +1,527 @@ +/**************************************************************************** + | + | (C) Copyright 1995-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) module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2006-12-30 03:27:16 +0530 (Sat, 30 Dec 2006) $ + | + | $RCSfile$ + | $Revision: 1799 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Implements Logical Volumes/Volume/Pools library routines. Contains + | routines that deal with the names of pools and volumes. + +-------------------------------------------------------------------------*/ +#include /* NetWare */ +#include /* NetWare */ +#include + +#include /* NSS Library */ +#include +#include +#include +#include +#include +#include +#include "mal.h" /* For POOL_MAXNAME */ +#include "nssPubs.h" + + /* ASCII numeric to unicode numeric table */ +STATIC unicode_t *LB_UnicodeDigit[] = { + L"0", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L"7", + L"8", + L"9" +}; + + +/* + * LB_VolumeNameToNewName() - + * Takes a current name (usually a volume name) and converts it + * to a snapshot name. + * + * Conversion examples (assumes posfixBase is L"_SV") - + * volName="NameName", uniSize=30, mangleKey = 0 then "NameName_SV" + * volName="NameName", uniSize=30, mangleKey = 1 then "NameName_SV001" + * volName="NameName", uniSize=10, mangleKey = 0 then "NameNa_SV" + * volName="NameName", uniSize=10, mangleKey = 1 then "Nam_SV001" + * volName="NameName", uniSize=10, mangleKey = 2 then "Nam_SV002" + * volName="NameNameName", uniSize=10, mangleKey = 0 then zERR_BUFFER_TOO_SMALL + * volName="Name", uniSize=8, mangleKey = 0 then zERR_BUFFER_TOO_SMALL + * + * + * Returns - + * zOK on success with mangleKey and newName changed. + * zERR_BUFFER_TOO_SMALL on failure with mangleKey and newName + * undefined. Can only get this error if newName is + * too small. Too small is either less than 7 unicode + * characters OR smaller than the passed in name. + */ + +STATUS LB_VolumeNameToNewName( + CONST unicode_t *volName, /* Current volume name */ + CONST unicode_t *postfixBase, /* Base 3 unicode length string to post fix */ + NINT *mangleKey, /* (input/output)Mangle key pointer, must point to 0 on first call */ + NINT uniSize, /* Number of unicode newName can hold */ + unicode_t *newName ) /* (output)New mangled name */ + +{ + NINT addedLen, location; + unicode_t postfixToAdd[10]; + + if ( unilen( postfixBase ) != 3 ) + { + zASSERT("Illegal parameter passed to LB_VolumeNameToNewName()" == NULL ); + return( zERR_BAD_PARAMETER_VALUE ); + } + if ( uniSize < 7 ) /* Minimum requirement is to hold L"'postfixBase'xxx" */ + { + return( zERR_BUFFER_TOO_SMALL ); + } + if ( unilen( volName ) >= uniSize ) + { + return( zERR_BUFFER_TOO_SMALL ); + } + + /** + * Normally, append postfixBase to current volume name to obtain new name. + * If this creates a name too long then the postfixBase will replace some + * of the end characters. The user can rename the new name if they + * wish. + * + * Mangle code changes postfixBase to 'postfixBase'xxx where xxx is a + * number starting at 1. The caller is responsible for determining a name + * clash and must then call us back with the mangle key we returned to + * them. We use 3 digits because 1000 attempts at a name is enough. + */ + if ( (*mangleKey) != 0 ) + { + NINT index100, index10, index1; + + unicpy( &postfixToAdd[0], postfixBase ); + index100 = (*mangleKey)/100; + unicat( &postfixToAdd[0], LB_UnicodeDigit[ index100 % 10 ] ); + index10 = ((*mangleKey) - index100 * 100 ) / 10; + unicat( &postfixToAdd[0], LB_UnicodeDigit[ index10 ] ); + index1 = (*mangleKey) % 10; + unicat( &postfixToAdd[0], LB_UnicodeDigit[ index1 ] ); + } + else + { + unicpy( &postfixToAdd[0], postfixBase ); + } + addedLen = unilen( postfixToAdd ); + /* Verify that we did not ZAP past the end of our internal buffer */ + zASSERT( addedLen < ( sizeof( postfixToAdd )/ sizeof( postfixToAdd[0] )) ); + + if ( (unilen( volName ) + addedLen) < uniSize ) + { + location = unilen( volName ); + } + else + { + location = uniSize - addedLen - 1; + } + + unicpy( newName, volName ); + unicpy( &newName[location], &postfixToAdd[0] ); + ++(*mangleKey); +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED,"Converted volume name is %U\r\n",newName); +#endif + return( zOK ); + +} /* End of LB_VolumeNameToNewName() */ + + +/* + * LB_VolumeNameToSnapshotName() - + * Takes a current name (usually a volume name) and converts it + * to a snapshot name. + * + * Returns - + * zOK on success with mangleKey and snapName changed. + * zERR_BUFFER_TOO_SMALL on failure with mangleKey and snapName + * undefined. Can only get this error if snapName is + * too small. Too small is either less than 7 unicode + * characters OR smaller than the passed in name. + */ + +STATUS LB_VolumeNameToSnapshotName( + CONST unicode_t *volName, /* Current volume name */ + NINT *mangleKey, /* (input/output)Mangle key pointer, must point to 0 on first call */ + NINT uniSize, /* Number of unicode snapName can hold */ + unicode_t *snapName ) /* (output)New mangled name */ + +{ + STATUS status; + + status = LB_VolumeNameToNewName( volName, L"_SV", mangleKey, uniSize, snapName ); + return( status ); + +} /* End of LB_VolumeNameToSnapshotName() */ + + +/* See comments for LB_VolumeNameToSnapshotName */ +STATUS LB_VolumeNameToQSName( + CONST unicode_t *volName, /* Current volume name */ + NINT *mangleKey, /* (input/output)Mangle key pointer, must point to 0 on first call */ + NINT uniSize, /* Number of unicode newName can hold */ + unicode_t *newName ) /* (output)New mangled name */ + +{ + STATUS status; + + status = LB_VolumeNameToNewName( volName, L"_QS", mangleKey, uniSize, newName ); + return( status ); + +} /* End of LB_VolumeNameToQSName() */ + + +/* + * LB_VolumeNameToAutoRenameName() - + * Takes a current name (usually a volume name) and converts it + * to a AutoRename name. + * + * Returns - + * zOK on success with mangleKey and AutoRename Name changed. + * zERR_BUFFER_TOO_SMALL on failure with mangleKey and AutoRename + * Name undefined. Can only get this error if AutoRename + * Name is too small. Too small is either less than 7 + * unicode characters OR smaller than the passed in name. + */ + +STATUS LB_VolumeNameToAutoRenameName( + CONST unicode_t *volName, /* Current volume name */ + NINT *mangleKey, /* (input/output)Mangle key pointer, must point to 0 on first call */ + NINT uniSize, /* Number of unicode AutoRename Name can hold */ + unicode_t *autoRenameName ) /* (output)New mangled name */ + +{ + STATUS status; + + status = LB_VolumeNameToNewName( volName, L"_AR", mangleKey, uniSize, autoRenameName ); + return( status ); + +} /* End of LB_VolumeNameToAutoRenameName() */ + + + /* + * LB_VolumeNameToPoolName() - + * Takes a current name (usually a volume name) and converts it + * to a pool name. + * + * Conversion examples - + * volName="NameName", uniSize=30, mangleKey = 0 then "NameName_Pool" + * volName="NameName", uniSize=30, mangleKey = 1 then "NameName_Pool001" + * volName="NameName", uniSize=10, mangleKey = 0 then "Name_Pool" + * volName="NameName", uniSize=10, mangleKey = 1 then "N_Pool001" + * volName="NameName", uniSize=10, mangleKey = 2 then "N_Pool002" + * volName="NameNameName", uniSize=10, mangleKey = 0 then zERR_BUFFER_TOO_SMALL + * volName="Name", uniSize=8, mangleKey = 0 then zERR_BUFFER_TOO_SMALL + * + * + * Returns - + * zOK on success with mangleKey and poolName changed. + * zERR_BUFFER_TOO_SMALL on failure with mangleKey and poolName + * undefined. Can only get this error if poolName is + * too small. Too small is either less than 9 unicode + * characters OR smaller than the passed in name. + */ + +STATUS LB_VolumeNameToPoolName( + CONST unicode_t *volName, /* Current pool name */ + NINT *mangleKey, /* (input/output)Mangle key pointer, must point to 0 on first call */ + NINT uniSize, /* Number of unicode poolName can hold */ + unicode_t *poolName ) /* (output)New mangled name */ + +{ +#if 0 + NINT addedLen, location; + unicode_t postfixToAdd[10]; +#endif + + if ( uniSize < 9 ) /* Minimum requirement is to hold L"_POOLxxx" */ + { + return( zERR_BUFFER_TOO_SMALL ); + } + if ( unilen( volName ) >= uniSize ) + { + return( zERR_BUFFER_TOO_SMALL ); + } + /** + * For now we will be keeping the same names for the POOL and + * VOLUME. Too much code assumes names from the MAL are VOLUME + * names. For example, NWCONFIG. + */ + unicpy( poolName, volName ); + +#if 0 + /** + * Normally, append _POOL to current volume name to obtain pool's name. + * If this creates a name too long then the _POOL will replace some + * of the end characters. The user can rename the POOL name if they + * wish. Note that NSS/ZLSS requires that the POOL and VOLUME + * names be different. + * + * Mangle code changes _POOL to _POOLxxx where xxx is a number starting + * at 1. The caller is responsible for determining a name clash + * and must then call us back with the mangle key we returned to + * them. We use 3 digits because NetWare has a 255 Volume limit. + */ + if ( (*mangleKey) != 0 ) + { + NINT index100, index10, index1; + + unicpy( &postfixToAdd[0], L"_POOL" ); + index100 = (*mangleKey)/100; + unicat( &postfixToAdd[0], LB_UnicodeDigit[ index100 % 10 ] ); + index10 = ((*mangleKey) - index100 * 100 ) / 10; + unicat( &postfixToAdd[0], LB_UnicodeDigit[ index10 ] ); + index1 = (*mangleKey) % 10; + unicat( &postfixToAdd[0], LB_UnicodeDigit[ index1 ] ); + } + else + { + unicpy( &postfixToAdd[0], L"_POOL" ); + } + addedLen = unilen( postfixToAdd ); + /* Verify that we did not ZAP past the end of our internal buffer */ + zASSERT( addedLen < ( sizeof( postfixToAdd )/ sizeof( postfixToAdd[0] )) ); + + if ( (unilen( volName ) + addedLen) < uniSize ) + { + location = unilen( volName ); + } + else + { + location = uniSize - addedLen - 1; + } + + unicpy( poolName, volName ); + unicpy( &poolName[location], &postfixToAdd[0] ); + ++(*mangleKey); +#endif +#if NSS_DEBUG IS_ENABLED + DBG_DebugPrintf(LRED,"Converted pool name is %U\r\n",poolName); +#endif + return( zOK ); + +} /* End of LB_VolumeNameToPoolName() */ + + + /*** + *** These defines bound the length of a volume name. They were + *** taken from the NSS Menu code. + ***/ +#define LB_VOLUME_NAME_SIZE_MIN 2 +#define LB_VOLUME_NAME_SIZE_MAX 15 + + + /*** + *** This is a list of the valid characters that can be in a volume + *** name. This was taken from the NSS Menu code. + ***/ +STATIC char LB_VolumeCharsValid[] = + MSGNot("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_!@#$%&()"); + + + /*** + *** This is a list of volumes that can not be renamed. + ***/ +STATIC unicode_t *LB_VolumeNamesRenameNo[] = +{ + AVOL_PERSISTENT_ADMIN_VOLUME_UNICODE, + AVOL_ADMIN_VOLUME_UNICODE, + NULL /* Must be last - indicates end of List */ +}; + + /*** + *** This is a list of reserved volume names. This was taken from the + *** NSS Menu code. + ***/ +STATIC char *LB_VolumeNamesReserved[] = +{ + MSGNot("NUL"), + MSGNot("CON"), + MSGNot("AUX"), + MSGNot("PRN"), + MSGNot("COM1"), + MSGNot("COM2"), + MSGNot("COM3"), + MSGNot("COM4"), + MSGNot("LPT1"), + MSGNot("LPT2"), + MSGNot("LPT3"), + MSGNot("NETQ"), + MSGNot("PIPE"), + MSGNot("CLOCK"), + AVOL_ADMIN_VOLUME, /* Added because current name of NSS_Admin volume */ + MSGNot("NSS_ADMIN"), + MSGNot("ALL"), /* Added to list since NSS likes to use 'ALL' + * in commands like "nss /act=all" to specify + * all volumes - Greg + */ + NULL /* Must be last - indicates end of List */ +}; + + +/* + * LB_VolumeNameValid() - + * Determines if a volume name is syntactically valid. + * + * This function performs numerous checks on the name to determine + * if the volume name is syntactically valid. This following tests are + * performed. + * + * 1). Name has valid characters (See LB_VolumeCharsValid global). + * 2). Not a reserved name (See LB_VolumeNamesReserved global). + * 3). At least 2 character long, but not more than 15. + * 4). Does not start or end with a underscore. + * 5). Does not contain consecutive underscores. + * + * Returns - + * zOK if name is syntactically valid else specific error code. + * + * Note - + * This code was taken from the menu code. Why the abovve tests + * are required are not known! + */ + +STATUS LB_VolumeNameValid( unicode_t *volumeName ) + +{ + + NINT namelen; + char name[POOL_MAXNAME]; + NINT retNameSize; + BOOL validName = FALSE; + NINT i,j; + + + /* The persistent admin volume is a special case because + * it starts with a '_' and is still LEGAL. + */ + if (unicmp(volumeName, AVOL_PERSISTENT_ADMIN_VOLUME_UNICODE) == 0) + { + return zOK; + } + + bzero(name, sizeof(name)); + LB_UnicodeToByte(NSS_UNI_CONVERSION_RAW, name, POOL_MAXNAME, volumeName, &retNameSize); + namelen = strlen(name); + if ( namelen < LB_VOLUME_NAME_SIZE_MIN ) + { + return( zERR_BAD_VOLUME_NAME_SIZE_SHORT ); + } + if ( namelen > LB_VOLUME_NAME_SIZE_MAX ) + { + return( zERR_BAD_VOLUME_NAME_SIZE_LONG ); + } + + for (i = 0; i < namelen; i++) + { + validName = FALSE; + for (j = 0; j < sizeof(LB_VolumeCharsValid); j++) + { + if (name[i] == LB_VolumeCharsValid[j]) + { + validName = TRUE; + break; + } + } + if (!validName) + { + break; + } + } + if (!validName) + { + return ( zERR_BAD_VOLUME_NAME_CHARACTER ); + } + + if ((name[0] == '_') || (name[namelen - 1] == '_')) + { + return (zERR_BAD_VOLUME_NAME_UNDERSCORE); + } + + for (i = 0; i < (namelen - 1); i++) + { + if ((name[i] == '_') && (name[i+1] == '_')) + { + return (zERR_BAD_VOLUME_NAME_TWO_UNDERSCORES); + } + } + + i = 0; + while (LB_VolumeNamesReserved[i] != NULL) + { + /* Note - we ignore case here */ + if (stricmp(name, LB_VolumeNamesReserved[i]) == 0) + { + return( zERR_RESERVED_VOLUME_NAME ); + } + i++; + } + + return( zOK ); +} + + +/* + * LB_VolumeRenameOK() - + * Determines if a volume can be renamed based on the volume's + * current name. Simply checks if the volume is one of the + * volume names that are not allowed to be renamed. + * + * Returns - + * zOK if volume can be renamed else specific error code. + * + */ + +STATUS LB_VolumeRenameOK( unicode_t *currentVolumeName ) + +{ + NINT i; + + i = 0; + while (LB_VolumeNamesRenameNo[i] != NULL) + { /* Note - we 'ignore case' here */ + if (uniicmp(currentVolumeName, LB_VolumeNamesRenameNo[i]) == 0) + { + return( zERR_VOLUME_RENAME_NOT_ALLOWED ); + } + i++; + } + return( zOK ); + +} /* End of LB_VolumeRenameOK() */ diff --git a/src/nwnss/library/os/currentTime.c b/src/nwnss/library/os/currentTime.c new file mode 100644 index 0000000..7ccf13c --- /dev/null +++ b/src/nwnss/library/os/currentTime.c @@ -0,0 +1,27 @@ +/**************************************************************************** + | Userspace COMN time boundary for imported NSS sources. + | + | public_core/nsslnxlib/nssLnxDummy.c implements GetCurrentTime() as Linux + | jiffies for the kernel-oriented NSS Linux support library. libnwnss runs + | in userspace, so expose the same NSS symbol using a monotonic clock tick + | counter rather than importing the full kernel nssLnxDummy.c shim. + +-------------------------------------------------------------------------*/ + +#include +#include + +LONG GetCurrentTime(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + return 0; + } + + return (LONG)(ts.tv_sec * 100UL + ts.tv_nsec / 10000000UL); +} + +LONG GetHighResolutionTimer(void) +{ + return GetCurrentTime(); +} diff --git a/src/nwnss/nssStartupNameGlobals.c b/src/nwnss/nssStartupNameGlobals.c new file mode 100644 index 0000000..5cde957 --- /dev/null +++ b/src/nwnss/nssStartupNameGlobals.c @@ -0,0 +1,14 @@ +/**************************************************************************** + | Selected NSS startup name globals for userspace libnwnss. + | + | These definitions are copied from public_core/nss/nssStartup.c. The full + | startup module owns NetWare/kernel module lifecycle, event registration and + | command-line machinery that is not part of the default userspace library + | boundary. Keep only the data globals required by the real COMN/AdminVolume + | imports until the full NSS startup block is imported deliberately. + +-------------------------------------------------------------------------*/ + +#include + +unicode_t *PersistAdminVolUnicodeName = (unicode_t *)L"_ADMIN_P"; +NINT AdminVolNameLen = 0; diff --git a/src/nwnss/nwnssSourceCompat.h b/src/nwnss/nwnssSourceCompat.h index 67100e6..5154cff 100644 --- a/src/nwnss/nwnssSourceCompat.h +++ b/src/nwnss/nwnssSourceCompat.h @@ -11,6 +11,9 @@ #include #include +LONG GetCurrentTime(void); +LONG GetHighResolutionTimer(void); + #ifdef wPause #undef wPause #define wPause(_file, _mode) LB_wPause((WFile_s *)(void *)(_file), (_mode)) @@ -66,6 +69,28 @@ typedef LONG UINT32; do { (void)(_producer); (void)(_event); } while (0) #endif + + +#ifndef ZOS_StartThread +#define ZOS_StartThread(_thread, _name, _func, _stack, _prio, _arg) \ + do { (void)(_name); (void)(_func); (void)(_stack); (void)(_prio); (void)(_arg); (_thread) = 0; } while (0) +#endif + +#ifndef ZOS_StartThreadWithModuleHandle +#define ZOS_StartThreadWithModuleHandle(_thread, _name, _func, _stack, _prio, _arg, _module) \ + do { (void)(_module); ZOS_StartThread((_thread), (_name), (_func), (_stack), (_prio), (_arg)); } while (0) +#endif + +#ifndef ZOS_RegisterConsumer +#define ZOS_RegisterConsumer(_reg) \ + do { (void)(_reg); } while (0) +#endif + +#ifndef ZOS_UnRegisterConsumer +#define ZOS_UnRegisterConsumer(_consumer, _event) \ + do { (void)(_consumer); (void)(_event); } while (0) +#endif + #ifndef ZOS_ImportPublicSymbol #define ZOS_ImportPublicSymbol(_target, _module, _name) \ do { (void)(_module); (void)(_name); (_target) = NULL; } while (0) diff --git a/src/nwnss/sharedsrc/ndp_idbroker.c.h b/src/nwnss/sharedsrc/ndp_idbroker.c.h new file mode 100644 index 0000000..7c20b66 --- /dev/null +++ b/src/nwnss/sharedsrc/ndp_idbroker.c.h @@ -0,0 +1,3379 @@ +/**************************************************************************** + | + | (C) Copyright 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 + | + |*************************************************************************** + | + | Novell's User/Kernel Data Portal (NDP) ID Broker proxy program file. + | + |--------------------------------------------------------------------------- + | + | $Author: blarsen $ + | $Date: 2007-02-16 05:36:20 +0530 (Fri, 16 Feb 2007) $ + | + | $RCSfile$ + | $Revision: 1869 $ + | + |--------------------------------------------------------------------------- + | This file is used to: + | ... + +-------------------------------------------------------------------------*/ + +#ifdef BUILD_NDP_IDBROKER + +#include + +#ifdef __KERNEL__ +# include +# include +//# include +# include +# include +#else +/* NOTE: ndp_comn.h needs included before anything else in application land */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include /* dlerror(), dlopen(), dlsym(), dlclose() */ +# include +#endif + +/* Timeout(s) specified in seconds */ +#define ndpIdBrokerHandlerTIMEOUT 15 +#define ndpIdBrokerReadTIMEOUT (60*5) + +//#include +#define ERR_INSUFFICIENT_BUFFER -649 /* 0xFFFFFD77 */ +//end + +#include +#include +#include + +#define HEXGUIDSIZE ((2*sizeof(GUID_t))+1) + +QUAD NDP_namGetUserFDNfromUID_count = 0; +QUAD NDP_NCPMapDNToGUID_count = 0; +QUAD NDP_NCPLocalTreeName_count = 0; +QUAD NDP_NCPMapDNToSEV_count = 0; +QUAD NDP_NCPMapGUIDToMgtLevel_count = 0; +QUAD NDP_NCPMapGUIDToDN_count = 0; +QUAD NDP_NCPMapGUIDToUID_count = 0; +QUAD NDP_NCPMapUIDToGUID_count = 0; +QUAD NDP_GetUIDFromName_count = 0; +QUAD NDP_GenerateData_count = 0; +QUAD NDP_ExtractData_count = 0; +#ifdef __KERNEL__ +EXPORT_SYMBOL(NDP_namGetUserFDNfromUID_count); +EXPORT_SYMBOL(NDP_NCPMapDNToGUID_count); +EXPORT_SYMBOL(NDP_NCPLocalTreeName_count); +EXPORT_SYMBOL(NDP_NCPMapDNToSEV_count); +EXPORT_SYMBOL(NDP_NCPMapGUIDToMgtLevel_count); +EXPORT_SYMBOL(NDP_NCPMapGUIDToDN_count); +EXPORT_SYMBOL(NDP_NCPMapGUIDToUID_count); +EXPORT_SYMBOL(NDP_NCPMapUIDToGUID_count); +EXPORT_SYMBOL(NDP_GetUIDFromName_count); +EXPORT_SYMBOL(NDP_GenerateData_count); +EXPORT_SYMBOL(NDP_ExtractData_count); +#endif + +/*** Declare external variables *********************************************/ + +//extern int ndp_debug; + +extern ndpContext_t *ndpContext; + +/****************************************************************************** +* Declare the NDP ID Broker Thread Conext Type +******************************************************************************/ + +typedef struct idBrokerThreadContext_t idBrokerThreadContext_t; +struct idBrokerThreadContext_t { + int functionIndex; /* NDP ID Broker Function Index */ + void *idBrokerInfo; /* Pointer to the associated ndpIdBrokerInfo */ + /* See below */ +}; + +#ifdef __KERNEL__ +#define NULLTHREADID NULL +#else +#define NULLTHREADID 0 +#endif + +/***************************************************************************** +**************************** NDP ID Broker GUIDs ***************************** +************************* and associated information ************************* +*****************************************************************************/ + +/* Define offset into array of ID Broker Guids */ +/* An associated value will also be placed in node[5] of copy of base guid */ + +#define IDBG_base 0 +/***** Mod2App *****/ +#define IDBG_namGetUserFDNfromUID 1 +#define IDBG_NCPMapDNToGUID 2 +#define IDBG_NCPLocalTreeName 3 +#define IDBG_NCPMapDNToSEV 4 +#define IDBG_NCPMapGUIDToMgtLevel 5 +#define IDBG_NCPMapGUIDToDN 6 +#define IDBG_NCPMapGUIDToUID 7 +#define IDBG_NCPMapUIDToGUID 8 +#define IDBG_GetUIDFromName 9 +#define IDBG_GenerateVolumeKeyInfo 10 +#define IDBG_ExtractVolumeKeyInfo 11 +/***** App2Mod *****/ +#define IDBG_NCPNotifyDNChange 12 /* THIS EXACT SAME DEFINE IS IN + * ndp_msg.c. IF YOU CHANGE THIS, + * IT MUST BE CHANGED THERE TOO. */ +#define IDBG_NCPNotifySEVChange 13 /* THIS EXACT SAME DEFINE IS IN + * ndp_msg.c. IF YOU CHANGE THIS, + * IT MUST BE CHANGED THERE TOO. */ +#define ndpIdBrokerGuidCount 14 + +typedef struct ndpIdBrokerInfo_t ndpIdBrokerInfo_t; +struct ndpIdBrokerInfo_t { + GUID_t guid; /* guid = guid[base] + node[5]=index */ + GUID_t guidPrime; /* guidPrime filled at runtime */ + int mod2app; /* app2mod=0, mod2app=1, N/A=-1 */ + /* app2mod == Application initiates activity */ + /* mod2app == Module initiates activity */ +#ifdef __KERNEL__ + THREAD thread; +#else + pthread_t thread; +#endif + idBrokerThreadContext_t threadContext; + char *name; /* name */ +}; + +static ndpIdBrokerInfo_t ndpIdBrokerInfo[] = +{ + { /* 0 = NDP ID Broker Base */ + /* C2EBF816-9B2C-4D53-984C-7474FE42C396 */ + { 0xC2EBF816, 0x9B2C, 0x4D53, 0x98, 0x4C, { 0x74, 0x74, 0xFE, 0x42, 0xC3, 0x00 } }, + {0}, /* guidPrime filled at runtime */ + -1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NDP ID Broker" /* name */ + }, + { /* 1 = namGetUserFDNfromUID */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "namGetUserFDNfromUID" /* name */ + }, + { /* 2 = NCPMapDNToGUID */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPMapDNToGUID" /* name */ + }, + { /* 3 = NCPLocalTreeName */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPLocalTreeName" /* name */ + }, + { /* 4 = NCPMapDNToSEV */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPMapDNToSEV" /* name */ + }, + { /* 5 = NCPMapGUIDToMgtLevel */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPMapGUIDToMgtLevel" /* name */ + }, + { /* 6 = NCPMapGUIDToDN */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPMapGUIDToDN" /* name */ + }, + { /* 7 = NCPMapGUIDToUID */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPMapGUIDToUID" /* name */ + }, + { /* 8 = NCPMapUIDToGUID */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPMapUIDToGUID" /* name */ + }, + { /* 9 = GetUIDFromName */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "GetUIDFromName" /* name */ + }, + { /* 10 = GenerateVolumeKeyInfo */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "GenerateData" /* name - Generic name on purpose*/ + }, + { /* 11 = ExtractVolumeKeyInfo */ + {0}, /* guid = guid[base] + node[5]=index */ + {0}, /* guidPrime filled at runtime */ + 1, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "ExtractData" /* name - Generic name on purpose */ + }, + { /* 12 = NCPNotifyDNChange */ + {0}, /* guid propogated from base */ + {0}, /* guidPrime filled at runtime */ + 0, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPNotifyDNChange" /* name */ + }, + { /* 13 = NCPNotifySEVChange */ + {0}, /* guid propogated from base */ + {0}, /* guidPrime filled at runtime */ + 0, /* app2mod=0, mod2app=1, N/A=-1 */ + NULLTHREADID, /* thread (ID) */ + {0}, /* threadContext */ + "NCPNotifySEVChange" /* name */ + } +}; + +/***************************************************************************** +* Unless otherwise stated, DNs are in: +* unicode +* dot (preceeding dot, trailing dot) +* include tree name +* right rooted +****************************************************************************** +* Errors will mostly be edir errors +*****************************************************************************/ + +/****************************************************************************** +* The NDP ID Broker Message Handling Routine +* These routines run in their own threads... +******************************************************************************/ +#ifdef __KERNEL__ +void *ndp_idBroker_messagehandler( + THREAD thread, + void *_threadContext) +{ + idBrokerThreadContext_t *threadContext; + int functionIndex = 0; + ndpIdBrokerInfo_t *idBrokerInfo; + GUID_t srcGuid; + int sts = -1; + LONG length; + unsigned char *data; + + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(Enter)\n"); + /* + * Code to handle any Application initiated conversations + * with the KERNEL World (APP->MOD) + */ + threadContext = (idBrokerThreadContext_t *)_threadContext; + if (threadContext) { + functionIndex = threadContext->functionIndex; + idBrokerInfo = threadContext->idBrokerInfo; + } + if (threadContext) for ( ; ; ) { + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(%s)(top of loop)\n", + idBrokerInfo->name); + /* + * Loop until we have something + * At a minimum, check every N seconds + */ + sts = -1; + while (sts) { + /* + * Call schedule() to give the system time to look at things + * just in case we are in a very tight read loop. + * This will give the user some response to kill the app. + */ +//Commented out because ndp_readFromGuidUntilTimeout has it's own schedule. +// schedule(); +// current->state = TASK_INTERRUPTIBLE; + + sts = ndp_readFromGuidUntilTimeout(2, + &idBrokerInfo->guidPrime, + &srcGuid, &length, &data, ndpIdBrokerHandlerTIMEOUT); + } + if (sts == 0) { + /* The message destinations are defined by their GUID */ + /* In this case, specifically by their node[5] value */ + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(function=%d, node[5]=%d)\n", functionIndex, srcGuid.node[5]); + ndp_dumpDataInHex(3, "ndp_idBroker_messagehandler(data)", length, data); + switch (functionIndex) { /* == srcGuid.node[5] */ +// MOD->APP Only +// case IDBG_namGetUserFDNfromUID: +// break; +// MOD->APP Only +// case IDBG_NCPMapDNToGUID: +// break; +// MOD->APP Only +// case IDBG_NCPLocalTreeName: +// break; +// MOD->APP Only +// case IDBG_NCPMapDNToSEV: +// break; +// MOD->APP Only +// case IDBG_NCPMapGUIDToMgtLevel: +// break; +// MOD->APP Only +// case IDBG_NCPMapGUIDToDN: +// break; +// MOD->APP Only +// case IDBG_NCPMapGUIDToUID: +// break; +// MOD->APP Only +// case IDBG_NCPMapUIDToGUID: +// break; +// MOD->APP Only +// case IDBG_GetUIDFromName: +// break; +// MOD->APP Only +// case IDBG_GenerateVolumeKeyInfo: +// break; +// MOD->APP Only +// case IDBG_ExtractVolumeKeyInfo: +// break; + case IDBG_NCPNotifyDNChange: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPNotifyDNChange)\n"); + ndp_NCPNotifyDNChange_handler(&srcGuid, length, data); + break; + case IDBG_NCPNotifySEVChange: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPNotifySEVChange)\n"); + ndp_NCPNotifySEVChange_handler(&srcGuid, length, data); + break; + default: + /* Ignore errant messages for now */ + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(node[5]=%02X: IGNORED)\n", srcGuid.node[5]); + break; + } + if (data) { + ndpFree(data); + } + } + } + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(Leave)\n"); + //return(retval); + return(0); +} /* ndp_idBroker_messagehandler() */ +#else +void *ndp_idBroker_messagehandler( + void *_threadContext) +{ + idBrokerThreadContext_t *threadContext; + int functionIndex = 0; + ndpIdBrokerInfo_t *idBrokerInfo; + GUID_t srcGuid; + int sts = -1; + LONG length; + unsigned char *data; + pid_t childPid; + int childStat; + + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(Enter)\n"); + /* + * Code to handle any Kernel initiated conversations + * with the Application World (MOD->APP) + */ + threadContext = (idBrokerThreadContext_t *)_threadContext; + if (threadContext) { + functionIndex = threadContext->functionIndex; + idBrokerInfo = threadContext->idBrokerInfo; + } + if (threadContext) for ( ; ; ) { + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(%s)(top of loop)\n", + idBrokerInfo->name); + /* + * Loop until we have something + * At a minimum, check every N seconds + */ + sts = -1; + while (sts) { + /* + * First, cleanup any child processes that have died. + */ + do { + childPid = waitpid(-1, &childStat, WNOHANG); + if (childPid == 0) { + break; /* No children have died, exit this loop */ + } else if (childPid == -1) { + if (errno != 10) { /* 10 == no child processes */ + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(error waiting for terminated child, errno=%d\n",errno); + } + } else { + if (WIFEXITED(childStat)) { + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(Child %d exited normally, stat=%d)\n", + childPid, WEXITSTATUS(childStat)); + } else if (WIFSTOPPED(childStat)) { + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(Child %d stopped, stat=%d)\n", + childPid, WSTOPSIG(childStat)); + } else if (WIFSIGNALED(childStat)) { + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(Child %d signaled, stat=%d)\n", + childPid, WTERMSIG(childStat)); + } + } + } while (childPid > 0); + /* + * Now, read more input. + */ + sts = ndp_readFromGuidUntilTimeout(2, + &idBrokerInfo->guidPrime, + &srcGuid, &length, &data, ndpIdBrokerHandlerTIMEOUT); + } + if (sts == 0) { + /* The message destinations are defined by their GUID */ + /* In this case, specifically by their node[5] value */ + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(function=%d, node[5]=%d)\n", functionIndex, srcGuid.node[5]); + switch (functionIndex) { /* == srcGuid.node[5] */ + case IDBG_namGetUserFDNfromUID: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(namGetUserFDNfromUID)\n"); + ndp_namGetUserFDNfromUID_handler( + &srcGuid, length, data); + break; + case IDBG_NCPMapDNToGUID: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPMapDNToGUID)\n"); + ndp_NCPMapDNToGUID_handler( + &srcGuid, length, data); + break; + case IDBG_NCPLocalTreeName: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPLocalTreeName)\n"); + ndp_NCPLocalTreeName_handler( + &srcGuid, length, data); + break; + case IDBG_NCPMapDNToSEV: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPMapDNToSEV)\n"); + ndp_NCPMapDNToSEV_handler( + &srcGuid, length, data); + break; + case IDBG_NCPMapGUIDToMgtLevel: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPMapGUIDToMgtLevel)\n"); + ndp_NCPMapGUIDToMgtLevel_handler( + &srcGuid, length, data); + break; + case IDBG_NCPMapGUIDToDN: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPMapGUIDToDN)\n"); + ndp_NCPMapGUIDToDN_handler( + &srcGuid, length, data); + break; + case IDBG_NCPMapGUIDToUID: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPMapGUIDToUID)\n"); + ndp_NCPMapGUIDToUID_handler( + &srcGuid, length, data); + break; + case IDBG_NCPMapUIDToGUID: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(NCPMapUIDToGUID)\n"); + ndp_NCPMapUIDToGUID_handler( + &srcGuid, length, data); + break; + case IDBG_GetUIDFromName: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(GetUIDFromName)\n"); + ndp_GetUIDFromName_handler( + &srcGuid, length, data); + break; + case IDBG_GenerateVolumeKeyInfo: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(GenerateData)\n"); + ndp_GenerateVolumeKeyInfo_handler( + &srcGuid, length, data); + break; + case IDBG_ExtractVolumeKeyInfo: + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(ExtractData)\n"); + ndp_ExtractVolumeKeyInfo_handler( + &srcGuid, length, data); + break; +// APP->MOD Only +// case IDBG_NCPNotifyDNChange: +// break; +// APP->MOD Only +// case IDBG_NCPNotifySEVChange: +// break; + default: + /* Ignore errant messages for now */ + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(node[5]=%02X: IGNORED)\n", srcGuid.node[5]); + break; + } + if (data) { + ndpFree(data); + } + } + } + ndpDbgPrintf(2, "ndp_idBroker_messagehandler(Leave)\n"); + return(0); +} /* ndp_idBroker_messagehandler() */ +#endif + +/***************************************************************************** +* Dynamically linked libraries & functions we need +*****************************************************************************/ + +#ifndef __KERNEL__ + +/* The following is a deriviation of info from Alexander Danoyan */ +#ifdef __x86_64__ +#define PAM_NAM_LIBRARY "/lib64/security/pam_nam.so" +#else +#define PAM_NAM_LIBRARY "/lib/security/pam_nam.so" +#endif +void *pam_nam_handle = NULL; +static int (*namGetUserFDNfromUID) + (int uid, char *userFDN) = NULL; + +/* The following is a deriviation of ncpServLib.h from DeeAnne Higley */ +/*************************************** +* dn's are in the form: unicode, full dot +* (including tree name, preceeding +* and trailing dot, right rooted +***************************************/ +#define IDBROKER_LIBRARY "libncpid.so" +void *idbroker_handle = NULL; + +static int ncpservlib = -1; /* Note: OpenNCPServLib() returns 0 if OK */ +static int (*OpenNCPServLib) + (void) = NULL; +static void (*CloseNCPServLib) + (void) = NULL; +static int (*NCPMapDNToGUID) + (const int create, const unicode_t *dn, GUID_t *guid) = NULL; +static int (*NCPLocalTreeName) + (const size_t treeNameSize, unicode_t *treename) = NULL; +static int (*NCPMapDNToSEV) + (const unicode_t *dn, size_t *guidSEVCount, GUID_t *guidSEV, + int *isSupervisor) = NULL; +static int (*NCPMapGUIDToMgtLevel) + (const size_t numAuthenticatedIDs, const GUID_t *authenticatedIDs, + const GUID_t *objectID, int *managementLevel) = NULL; +static int (*NCPMapGUIDToDN) + (const GUID_t *guid, const size_t dnSize, unicode_t *dn) = NULL; +static int (*NCPMapGUIDToUID) + (const GUID_t *guid, LONG *uid) = NULL; +static int (*NCPMapUIDToGUID) + (const LONG uid, GUID_t *guid) = NULL; + +#endif /* ! __KERNEL__ */ + +/***************************************************************************** +* Bind dynamically linked libraries & functions we need +*****************************************************************************/ +void ndp_bind_idbroker_functions() +{ +#ifndef __KERNEL__ + char *error; + + ndpDbgPrintf(2, "ndp_bind_idbroker_functions(Enter)\n"); + /* + * Bind the PAM/NAM library and the functions we use + */ + if (pam_nam_handle == NULL) { + dlerror(); /* Clear any existing error */ + pam_nam_handle = dlopen(PAM_NAM_LIBRARY, RTLD_NOW); + if (pam_nam_handle == NULL) { + ndpErrPrintf("%s\n", dlerror()); + } + } + if (pam_nam_handle) { + if (namGetUserFDNfromUID == NULL) { + dlerror(); /* Clear any existing error */ + namGetUserFDNfromUID = dlsym(pam_nam_handle, + "namGetUserFDNfromUID"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + } + /* + * Bind the ncpserv library and the functions we use + */ + if (idbroker_handle == NULL) { + dlerror(); /* Clear any existing error */ + idbroker_handle = dlopen(IDBROKER_LIBRARY, RTLD_NOW); + if (idbroker_handle == NULL) { + ndpErrPrintf("%s\n", dlerror()); + } + } + if (idbroker_handle) { + if (OpenNCPServLib == NULL) { + dlerror(); /* Clear any existing error */ + OpenNCPServLib = dlsym(idbroker_handle, + "OpenNCPServLib"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + if ((ncpservlib != 0) && (OpenNCPServLib)) { + ndpDbgPrintf(2, "ndp_bind_idbroker_functions:OpenNCPServLib\n"); + ncpservlib = (*OpenNCPServLib)(); + if (ncpservlib != 0) { + ndpErrPrintf("ndp_bind_idbroker_functions:OpenNCPServLib:%d\n", + ncpservlib); + } + } + if (ncpservlib == 0) { + if (CloseNCPServLib == NULL) { + dlerror(); /* Clear any existing error */ + CloseNCPServLib = dlsym(idbroker_handle, + "CloseNCPServLib"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + if (NCPMapDNToGUID == NULL) { + dlerror(); /* Clear any existing error */ + NCPMapDNToGUID = dlsym(idbroker_handle, + "NCPMapDNToGUID"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + if (NCPLocalTreeName == NULL) { + dlerror(); /* Clear any existing error */ + NCPLocalTreeName = dlsym(idbroker_handle, + "NCPLocalTreeName"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + if (NCPMapDNToSEV == NULL) { + dlerror(); /* Clear any existing error */ + NCPMapDNToSEV = dlsym(idbroker_handle, + "NCPMapDNToSEV"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + if (NCPMapGUIDToMgtLevel == NULL) { + dlerror(); /* Clear any existing error */ + NCPMapGUIDToMgtLevel = dlsym(idbroker_handle, + "NCPMapGUIDToMgtLevel"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + if (NCPMapGUIDToDN == NULL) { + dlerror(); /* Clear any existing error */ + NCPMapGUIDToDN = dlsym(idbroker_handle, + "NCPMapGUIDToDN"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + if (NCPMapGUIDToUID == NULL) { + dlerror(); /* Clear any existing error */ + NCPMapGUIDToUID = dlsym(idbroker_handle, + "NCPMapGUIDToUID"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + if (NCPMapUIDToGUID == NULL) { + dlerror(); /* Clear any existing error */ + NCPMapUIDToGUID = dlsym(idbroker_handle, + "NCPMapUIDToGUID"); + if ((error = dlerror()) != NULL) { + ndpErrPrintf("%s\n", error); + } + } + } + } + + ndpDbgPrintf(2, "ndp_bind_idbroker_functions(Leave)\n"); +#endif /* ! __KERNEL__ */ + return; +} /* ndp_bind_idbroker_functions() */ + +/***************************************************************************** +* Unbind dynamically linked libraries & functions we needed +*****************************************************************************/ +void ndp_unbind_idbroker_functions() +{ +#ifndef __KERNEL__ + ndpDbgPrintf(2, "ndp_unbind_idbroker_functions(Enter)\n"); + /* + * Unbind the PAM/NAM library and the functions we use + */ + namGetUserFDNfromUID = NULL; + if (pam_nam_handle) { + dlclose(pam_nam_handle); + } + /* + * Unbind the ncpserv library and the functions we use + */ + if ((ncpservlib == 0) && (CloseNCPServLib)) { + ndpDbgPrintf(2, "ndp_bind_idbroker_functions:CloseNCPServLib\n"); + (*CloseNCPServLib)(); + ncpservlib = -1; /* Note: OpenNCPServLib() returns 0 if OK */ + } + OpenNCPServLib = NULL; + CloseNCPServLib = NULL; + NCPMapDNToGUID = NULL; + NCPLocalTreeName = NULL; + NCPMapDNToSEV = NULL; + NCPMapGUIDToMgtLevel = NULL; + NCPMapGUIDToDN = NULL; + NCPMapGUIDToUID = NULL; + NCPMapUIDToGUID = NULL; + if (idbroker_handle) { + dlclose(idbroker_handle); + } + ndpDbgPrintf(2, "ndp_unbind_idbroker_functions(Leave)\n"); +#endif /* ! __KERNEL__ */ + return; +} /* ndp_unbind_idbroker_functions() */ + +/***************************************************************************** +* Initialize the ID Broker wrapper code +* Make it run in its own thread. +*****************************************************************************/ +int ndp_init_idBroker(void) +{ + int retval = 0; /* WAS = -EINVAL; */ + int g; + int dothis; + + ndpDbgPrintf(1, "ndp_init_idBroker(Enter)\n"); + /* Bind dynamically linked libraries & functions we need */ + ndp_bind_idbroker_functions(); + /* + * Propogate the base guid changing node[5] to be the associated index + */ + for (g = 1; g < ndpIdBrokerGuidCount; g++) { + memcpy(&(ndpIdBrokerInfo[g].guid), + &(ndpIdBrokerInfo[0].guid), + sizeof(GUID_t)); + ndpIdBrokerInfo[g].guid.node[5] = (char)g; + } + /* + * Register all of our guids (functions) on the receiving end only + * (Mod2App functions get registered on the App side) + * (App2Mod functions get registered on the Mod side) + */ + for (g = 1; g < ndpIdBrokerGuidCount; g++) { +#ifdef __KERNEL__ + dothis = (ndpIdBrokerInfo[g].mod2app == 0); +#else + dothis = (ndpIdBrokerInfo[g].mod2app == 1); +#endif + if (dothis) { + retval = ndp_registerGuid( + &ndpIdBrokerInfo[g].guid, + &ndpIdBrokerInfo[g].guidPrime, + ndpIdBrokerInfo[g].name); + } + } + /* + * Start a thread per guid (function) on the receiving end only + * (Mod2App functions get a thread on the App side) + * (App2Mod functions get a thread on the Mod side) + */ + for (g = 1; g < ndpIdBrokerGuidCount; g++) { +#ifdef __KERNEL__ + dothis = (ndpIdBrokerInfo[g].mod2app == 0); +#else + dothis = (ndpIdBrokerInfo[g].mod2app == 1); +#endif + if (dothis) { + ndpIdBrokerInfo[g].threadContext.functionIndex = g; + ndpIdBrokerInfo[g].threadContext.idBrokerInfo = + (void *)&ndpIdBrokerInfo[g]; +#ifdef __KERNEL__ + { + ndpIdBrokerInfo[g].thread = NULL; + mpkEnter(); + ndpIdBrokerInfo[g].thread = kStartThread( + "ndp_idBroker_messagehandler", + ndp_idBroker_messagehandler, + NULL, + 0L, + &ndpIdBrokerInfo[g].threadContext); + mpkExit(); + } +#else + { + int sts = -1; + sts = pthread_create( + &ndpIdBrokerInfo[g].thread, + NULL, + ndp_idBroker_messagehandler, + &ndpIdBrokerInfo[g].threadContext); +// if (sts) { +// /* Thread Creation Error */ +// } + } +#endif + } + } + ndpDbgPrintf(1, "ndp_init_idBroker(Leave:%d)\n", retval); + return(retval); +} /* ndp_init_idBroker() */ + +/***************************************************************************** +* Cleanup the ID Broker wrapper code +*****************************************************************************/ +int ndp_cleanup_idBroker(void) +{ + int retval = -EINVAL; + int g; + int dothis; + + ndpDbgPrintf(1, "ndp_cleanup_idBroker(Enter)\n"); + /* + * Stop our thread per guid (function) on the receiving end only + * (Mod2App functions get a thread on the App side) + * (App2Mod functions get a thread on the Mod side) + */ + for (g = 1; g < ndpIdBrokerGuidCount; g++) { +#ifdef __KERNEL__ + dothis = (ndpIdBrokerInfo[g].mod2app == 0); +#else + dothis = (ndpIdBrokerInfo[g].mod2app == 1); +#endif + if (dothis) { +#ifdef __KERNEL__ + (void) kDestroyThread(ndpIdBrokerInfo[g].thread); +#else + /* I'm not sure what needs done here */ +#endif + } + } + /* + * Deregister all of our guids (functions) on the receiving end only + * (Mod2App functions get registered on the App side) + * (App2Mod functions get registered on the Mod side) + */ + for (g = 1; g < ndpIdBrokerGuidCount; g++) { +#ifdef __KERNEL__ + dothis = (ndpIdBrokerInfo[g].mod2app == 0); +#else + dothis = (ndpIdBrokerInfo[g].mod2app == 1); +#endif + if (dothis) { + ndp_deregisterGuid(&ndpIdBrokerInfo[g].guidPrime); + } + } + /* Unbind dynamically linked libraries & functions we needed */ + ndp_unbind_idbroker_functions(); + ndpDbgPrintf(1, "ndp_cleanup_idBroker(Leave)\n"); + return(retval); +} /* ndp_cleanup_idBroker() */ + +/***************************************************************************** +* uid To FDN +* K2U nnn +* U2K nnnnnnccc +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_namGetUserFDNfromUID( + int uid, + unicode_t **userFDN) +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0L; + utf8_t *utf8FDN = NULL; + int lenUni; + + NDP_namGetUserFDNfromUID_count++; + + ndpDbgPrintf(1, "ndp_namGetUserFDNfromUID(Enter:%d)\n", uid); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "namGetUserFDNfromUID"); + + /* Construct and send the command */ + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_namGetUserFDNfromUID].guid, + "%d", uid); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID(sts:%d)\n", sts); + retval = sts; + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueLong("uid", data, length, &retUID); + status = ndp_getXmlTagValueString("fdn", data, length, + (unsigned char **)&utf8FDN); + + lenUni = (strlen(utf8FDN) + 1) * sizeof(unicode_t); + *userFDN = ndpMalloc(lenUni, GFP_KERNEL); + if (*userFDN == NULL) { + retval = -ENOMEM; + } else { + if (utf2uni(utf8FDN, *userFDN, lenUni) == -1) { + retval = -1; + } else { + retval = 0; + } + } + ndpFree(utf8FDN); + } + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_namGetUserFDNfromUID(Leave)\n"); + return(retval); +} /* ndp_namGetUserFDNfromUID() */ +EXPORT_SYMBOL(ndp_namGetUserFDNfromUID); +#else +int ndp_namGetUserFDNfromUID_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + LONG uid = 0; +# define FDNSIZE 768 /* 256 * 3 utf8 chars per uni char */ + char fdnLDAP[FDNSIZE + 2]; + char fdnEDir[FDNSIZE + 2]; + char *ldapPtr; + char *eDirPtr; + int fdnLen; + int status; + int sts = -1; + unicode_t localTreeName[128 + 1]; + utf8_t utf8TreeName[128 + 1]; /* Same as unicode because only 7-bit ASCII */ + int utf8Len; + BOOL skippedEquals; + + ndpDbgPrintf(1, "ndp_namGetUserFDNfromUID_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueLong("uid", (utf8_t *)data, length, &uid); + + /* Get the requested data */ + fdnLDAP[0] = '\0'; + fdnEDir[0] = '\0'; + if ((namGetUserFDNfromUID == NULL) || (NCPLocalTreeName == NULL)) { + ndp_bind_idbroker_functions(); + } + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + + /* In case we use "multiple messages" for the response, increment + * the multipleID to make it unique for this instance. + * We do this in the parent before the fork, so the child will have + * a unique value to work with. + */ + sem_wait(&ndpmsg_multipleIDsem); + ++ndpmsg_multipleID; + + ndpDbgPrintf(1, "ndp_namGetUserFDNfromUID_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + /* Let go of the parent semaphore now */ + sem_post(&ndpmsg_multipleIDsem); + ndpDbgPrintf(1, "ndp_namGetUserFDNfromUID_handler(parent process exiting)\n"); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* The child now has a semaphore which it needs to let go of and destroy */ + sem_post(&ndpmsg_multipleIDsem); + sem_destroy(&ndpmsg_multipleIDsem); + + /* Only the child process will call library functions */ + if (namGetUserFDNfromUID) { + /* This function returns a utf8 fdn */ + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler(calling namGetUserFDNfromUID)\n"); + sts = (*namGetUserFDNfromUID)((int)uid, fdnLDAP); + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler(back from namGetUserFDNfromUID, sts=%d, uid=%d)\n", sts, uid); + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler(back from namGetUserFDNfromUID, fdn=%s)\n", fdnLDAP); + } + } + + /* NOTE - The fdn returned is an LDAP format fdn. We need to + * convert it to a standard eDir format name, with a leading + * period, and a trailing ".." on the end. + */ + if (sts == 0) { + + /* Convert the LDAP characters and escape sequences to be eDir format, + * with a leading period and a trailing .. on the end. */ + ldapPtr = fdnLDAP; + eDirPtr = fdnEDir; + + /* Insert a leading ".", and strip any leading "," from LDAP */ + *eDirPtr++ = '.'; + if (*ldapPtr == ',') { + ++ldapPtr; /* skip leading comma */ + } + + /* Copy the LDAP string to the eDir string, one character at a time. + * Converting any special char escape sequences to eDir syntax. + */ + skippedEquals = FALSE; + while (*ldapPtr != 0) { + switch (*ldapPtr) { + case '\\': + /* If the next character is not one of ".+=\" then + * strip the '\' and leave the next character untouched, + */ + switch (*(ldapPtr+1)) { + case '.': + case '+': + case '\\': + /* Copy both characters to eDir -- unchanged */ + *eDirPtr++ = *ldapPtr++; + *eDirPtr++ = *ldapPtr++; + break; + + case '=': + /* Copy both characters to eDir -- unchanged. + * Also, flag that we saw an '=' in this element. + */ + *eDirPtr++ = *ldapPtr++; + *eDirPtr++ = *ldapPtr++; + break; + + default: + /* Strip the '\' and copy the next character. + * The LDAP RFC talks about a \nn syntax, where + * the next two characters could be a hex constant, + * but we don't see that from our LDAP implementation + * so we don't deal with it here. What we see in + * our LDAP implementation is that slashes before + * all non-special characters are simply stripped + * and ignored. + */ + ++ldapPtr; + *eDirPtr++ = *ldapPtr++; + break; + } + break; + + case '.': + case '+': + /* These characters, if not escaped in LDAP, DO need to + * be escaped in eDir. Add a leading '\' to them. + */ + *eDirPtr++ = '\\'; + *eDirPtr++ = *ldapPtr++; + break; + + case '=': + /* The equal char is not handled properly by our LDAP + * implementation. It comes through without a leading + * '\' character. Therefore it is hard for us to know if + * the '=' is on a cn=xxx string, or if it is embedded in + * an actual name. As a kludge, we ignore all occurrences + * of first '=' chars in an element, and we insert a '\' + * in front of all subsequent '=' chars. + */ + if (skippedEquals) { + /* Already skipped first '='. Put '\' in front of this*/ + *eDirPtr++ = '\\'; + *eDirPtr++ = *ldapPtr++; + } else { + /* This is the first '='. Don't add '\' in front */ + *eDirPtr++ = *ldapPtr++; + skippedEquals = TRUE; + } + break; + + case ',': + /* Convert all comma separators to periods */ + ++ldapPtr; + *eDirPtr++ = '.'; + skippedEquals = FALSE; + break; + + default: + /* just copy any other characters straight across */ + *eDirPtr++ = *ldapPtr++; + break; + } + } + *eDirPtr = 0; + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler(eDir name before adding tree = %s)\n", fdnEDir); + + /* Now, make sure the eDir string has a trailing tree name. */ + fdnLen = strlen(fdnEDir); + + if (eDirPtr[fdnLen-1] != '.') + { + /* Doesn't end in a period. Add the tree to the end */ + if ((NCPLocalTreeName) && (pid == 0)) { + /* Only the child process will call library functions */ + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler: calling NCPLocalTreeName\n"); + sts = (*NCPLocalTreeName)( sizeof(localTreeName), localTreeName ); + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler: got local tree name, sts=%d\n", sts); + } else { + sts = -1; + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler: couldn't call local tree name\n"); + } + + if (sts == 0) { + if (uni2utf( localTreeName, utf8TreeName, sizeof(utf8TreeName)) == -1) { + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler: failed uni2utf\n"); + sts = -1; + } + } + if (sts == 0) { + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler: tree name = %s\n", utf8TreeName); + utf8Len = strlen(utf8TreeName); + if ((fdnLen + utf8Len + 2) > FDNSIZE) { + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler: lengths too big %d + %d\n", fdnLen, utf8Len); + sts = -1; + } else { + strcat(eDirPtr, "."); + strcat(eDirPtr, utf8TreeName); + strcat(eDirPtr, "."); + ndpDbgPrintf(2, "ndp_namGetUserFDNfromUID_handler: returned fdn = %s\n", fdnEDir); + } + } + } + } + + /* Construct and return the results */ + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_namGetUserFDNfromUID].guidPrime, + srcGuid, + "%d%d%s", + sts, uid, (sts == 0 ? fdnEDir : NULL) ); + + if (pid == 0) { + ndpDbgPrintf(1, "ndp_namGetUserFDNfromUID_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_namGetUserFDNfromUID_handler(Leave)\n"); + return(retval); +} /* ndp_namGetUserFDNfromUID_handler() */ +#endif + +/***************************************************************************** +* DN To GUID - with create flag +* K2U nnnccc +* U2K nnnccchex +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPMapDNToGUID( + int create, + unicode_t *dn, + GUID_t *guid) +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + unsigned char *hexguid; /* [HEXGUIDSIZE] */ + LONG sts = 0L; + int lenUtf8; + utf8_t *dnUtf8 = NULL; + + NDP_NCPMapDNToGUID_count++; + + ndpDbgPrintf(1, "ndp_NCPMapDNToGUID(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "NCPMapDNToGUID"); + + /* Construct and send the command */ + lenUtf8 = (unilen(dn) * 3) + 1; + dnUtf8 = ndpMalloc( lenUtf8, GFP_KERNEL); + if (dnUtf8 == NULL) { + retval = -ENOMEM; + goto functionExit; + } + uni2utf( dn, dnUtf8, lenUtf8 ); + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_NCPMapDNToGUID].guid, + "%d%s", + create, dnUtf8); + + /* Free the utf8 buffer */ + ndpFree(dnUtf8); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + ndpDbgPrintf(2, "ndp_NCPMapDNToGUID(sts:%d)\n",sts); + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueString("dn", data, length, &retDn); + status = ndp_getXmlTagValueString("guid", data, length, &hexguid); + ndp_hex2guid(hexguid, guid); + ndpFree(hexguid); + retval = 0; + } + } +functionExit: + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_NCPMapDNToGUID(Leave:%d)\n",retval); + return(retval); +} /* ndp_NCPMapDNToGUID() */ +EXPORT_SYMBOL(ndp_NCPMapDNToGUID); +#else +int ndp_NCPMapDNToGUID_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + LONG create = 1; + utf8_t *dnUtf8 = NULL; + unicode_t *dn = NULL; + GUID_t guid; + unsigned char hexguid[HEXGUIDSIZE]; + int status; + int lenUni; + + ndpDbgPrintf(1, "ndp_NCPMapDNToGUID_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueLong("create", (utf8_t *)data, length, &create); + status = ndp_getXmlTagValueString("dn", (utf8_t *)data, length, + (unsigned char **)&dnUtf8); + + lenUni = (strlen(dnUtf8) + 1) * sizeof(unicode_t); + dn = (unicode_t *)ndpMalloc( lenUni, GFP_KERNEL); + if (dn == NULL) { + sts = -ENOMEM; + goto SendResponse; + } + utf2uni (dnUtf8, dn, lenUni); + + /* Get the requested data */ + if (NCPMapDNToGUID == NULL) { + ndp_bind_idbroker_functions(); + } + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + ndpDbgPrintf(1, "ndp_NCPMapDNToGUID_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (dn) { + ndpFree(dn); + } + if (dnUtf8) { + ndpFree(dnUtf8); + } + ndpDbgPrintf(1, "ndp_NCPMapDNToGUID_handler(parent process exiting)\n"); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_NCPMapDNToGUID_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* Only the child process will call library functions */ + if (NCPMapDNToGUID) { + //ndp_dumpDataInHex(2, "DN before NCPMapDNToGUID", ((unilen(dn)+1) * 2), (unsigned char *)dn); + //ndpDbgPrintf(2, "create = %d\n",create); + ndpDbgPrintf(2, "ndp_NCPMapDNToGUID_handler(calling NCPMapDNToGUID)\n"); + sts = (*NCPMapDNToGUID)((int)create, dn, &guid); + ndpDbgPrintf(2, "ndp_NCPMapDNToGUID_handler(sts=%d)\n",sts); + } + } + + /* Construct and return the results */ +SendResponse: + ndp_guid2hex(&guid, hexguid); + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_NCPMapDNToGUID].guidPrime, + srcGuid, + "%d%s%s", + sts, dnUtf8, (sts == 0 ? hexguid : NULL)); + + if (dn) { + ndpFree(dn); + } + if (dnUtf8) { + ndpFree(dnUtf8); + } + if (pid == 0) { + ndpDbgPrintf(1, "ndp_NCPMapDNToGUID_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_NCPMapDNToGUID_handler(Leave)\n"); + return(retval); +} /* ndp_NCPMapDNToGUID_handler() */ +#endif + +/***************************************************************************** +* Return Tree Name (unicode) +* K2U nnn +* U2K nnnccc +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPLocalTreeName( + size_t treeNameSize, /* This is buffer size in bytes */ + unicode_t *treeName) +{ + int retval = -1; + utf8_t *utf8TreeName = NULL; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0; + + NDP_NCPLocalTreeName_count++; + + ndpDbgPrintf(1, "ndp_NCPLocalTreeName(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "NCPLocalTreeName"); + + /* Construct and send the command */ + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_NCPLocalTreeName].guid, + "%d", + treeNameSize); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + ndpDbgPrintf(2, "ndp_NCPLocalTreeName(sts=%d)\n", sts); + } else { + status = ndp_getXmlTagValueString("name", data, length, + (unsigned char **)&utf8TreeName); + if (status == zOK) { + ndpDbgPrintf(2, "ndp_NCPLocalTreeName(treeName=%s)\n", utf8TreeName); + if (utf2uni(utf8TreeName, treeName, treeNameSize) == -1) { + retval = -1; + } else { + retval = 0; + } + ndpFree(utf8TreeName); + } else { + /* Unknown error. NCP eDir did not return an error, but + * we couldn't read the name + */ + retval = -1; + } + } + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_NCPLocalTreeName(Leave)\n"); + return(retval); +} /* ndp_NCPLocalTreeName() */ +EXPORT_SYMBOL(ndp_NCPLocalTreeName); +#else +int ndp_NCPLocalTreeName_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + LONG nameSize; + unicode_t *localTreeName; + utf8_t *utf8TreeName = NULL; + int utf8Len; + int status; + + ndpDbgPrintf(1, "ndp_NCPLocalTreeName_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueLong("namesize", (utf8_t *)data, length, &nameSize); + localTreeName = (unicode_t *)ndpMalloc(nameSize, GFP_KERNEL); + if (localTreeName == NULL) { + sts = -ENOMEM; + goto SendResponse; + } + + /* Get the requested data */ + if (NCPLocalTreeName == NULL) { + ndp_bind_idbroker_functions(); + } + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + ndpDbgPrintf(1, "ndp_NCPLocalTreeName_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (localTreeName) { + ndpFree(localTreeName); + } + ndpDbgPrintf(1, "ndp_NCPLocalTreeName_handler(parent process exiting)\n"); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_NCPLocalTreeName_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* Only the child process will call library functions */ + if (NCPLocalTreeName) { + ndpDbgPrintf(2, "ndp_NCPLocalTreeName_handler(calling NCPLocalTreeName)\n"); + sts = (*NCPLocalTreeName)( nameSize, localTreeName ); + ndpDbgPrintf(2, "ndp_NCPLocalTreeName_handler(back from NCPLocalTreeName, sts=%d)\n", sts); + } + } + + /* Construct and return the results */ + utf8Len = (unilen(localTreeName) * 3) + 1; + utf8TreeName = ndpMalloc( utf8Len, GFP_KERNEL); + if (utf8TreeName == NULL) { + sts = -ENOMEM; + } else { + if (uni2utf( localTreeName, utf8TreeName, utf8Len ) == -1) + { + sts = -1; + } + } + +SendResponse: + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_NCPLocalTreeName].guidPrime, + srcGuid, + "%d%s", + sts, (sts==0)?utf8TreeName:"error"); + + /* Free the local name buffer */ + if (localTreeName) { + ndpFree(localTreeName); + } + if (utf8TreeName) { + ndpFree(utf8TreeName); + } + + if (pid == 0) { + ndpDbgPrintf(1, "ndp_NCPLocalTreeName_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_NCPLocalTreeName_handler(Leave)\n"); + return(retval); +} /* ndp_NCPLocalTreeName_handler() */ +#endif + +/***************************************************************************** +* DN To SEV (sev in guids) +* guidSevCount is an IN/OUT parameter. The in tells us how big (in number of +* guids) your guidSEV buffer is. We will return up to that amount. If the +* buffer is not big enough we will return a truncated list with the error +* ERR_INSUFFICIENT_BUFFER. guidSevCount will be the count of guids which +* exist. +* K2U ccc +* U2K nnncccnnn +* hex,... +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPMapDNToSEV( + unicode_t *dn, + size_t *_guidSEVCount, + GUID_t *_guidSEV[], + BOOL *_isSupervisor) +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0L; + LONG isSupervisor = 0L; + LONG guidSEVCount = 0L; + GUID_t *guidSEV = NULL; + unsigned char *hexguids; /* [(n * HEXGUIDSIZE) + 1] */ + utf8_t *utf8Dn; + int utf8Len; + + NDP_NCPMapDNToSEV_count++; + + ndpDbgPrintf(1, "ndp_NCPMapDNToSEV(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "NCPMapDNToSEV"); + + /* Construct and send the command */ + utf8Len = (unilen(dn) * 3) + 1; + utf8Dn = ndpMalloc(utf8Len, GFP_KERNEL); + if (utf8Dn == NULL) { + retval = -ENOMEM; + goto functionExit; + } + uni2utf( dn, utf8Dn, utf8Len ); + + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_NCPMapDNToSEV].guid, + "%s", utf8Dn); + ndpFree(utf8Dn); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV(sts:%d)\n", sts); + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueString("dn", data, length, &retDn); + status = ndp_getXmlTagValueLong("issupervisor", data, length, &isSupervisor); + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV(isSupervisor:%d)\n", isSupervisor); + *_isSupervisor = (isSupervisor != 0) ? TRUE : FALSE; + + status = ndp_getXmlTagValueLong("guidsevcount", data, length, &guidSEVCount); + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV(guidSEVCount:%d)\n", guidSEVCount); + *_guidSEVCount = (size_t)guidSEVCount; + retval = 0; + if (guidSEVCount > 0) { + guidSEV = (GUID_t *)ndpMalloc + (guidSEVCount * sizeof(GUID_t), GFP_KERNEL); + if (guidSEV) { + int i; + + /* Save the pointer to the GUIDs */ + *_guidSEV = guidSEV; + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV(guidSEV:0x%08x)\n", *_guidSEV); + + /* + * The code is not currently checking for the delimiting ',' + * but merely expecting things to be "right". + */ + status = ndp_getXmlTagValueString("guidsev", data, length, &hexguids); + for ( i = 0; i < guidSEVCount; i++) { + ndp_hex2guid(&hexguids[i * HEXGUIDSIZE], &guidSEV[i]); + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV(GUID (%d) - ", i+1); + ndpDbgPrintf(2, "%08lx-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x\n", + (&guidSEV[i])->timeLow, (&guidSEV[i])->timeMid, + (&guidSEV[i])->timeHighAndVersion, + (&guidSEV[i])->clockSeqHighAndReserved, + (&guidSEV[i])->clockSeqLow, + (&guidSEV[i])->node[0], (&guidSEV[i])->node[1], + (&guidSEV[i])->node[2], (&guidSEV[i])->node[3], + (&guidSEV[i])->node[4], (&guidSEV[i])->node[5] ); + } + ndpFree(hexguids); + } else { + /* ERROR */ + retval = -ENOMEM; + } + } + } + } + +functionExit: + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_NCPMapDNToSEV(Leave:%d)\n",retval); + return(retval); +} /* ndp_NCPMapDNToSEV() */ +EXPORT_SYMBOL(ndp_NCPMapDNToSEV); +#else +int ndp_NCPMapDNToSEV_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + unicode_t *dn = NULL; + utf8_t *utf8Dn = NULL; + int lenUni; + size_t guidSEVCount; + GUID_t *guidSEV = NULL; + unsigned char *hexguids = NULL; /* [(n * HEXGUIDSIZE) + 1]; */ + int status; + int isSupervisor = 0; + + ndpDbgPrintf(1, "ndp_NCPMapDNToSEV_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueString("dn", (utf8_t *)data, length, (unsigned char **)&utf8Dn); + lenUni = (strlen(utf8Dn) + 1) * sizeof(unicode_t); + dn = ndpMalloc(lenUni, GFP_KERNEL); + if (dn == NULL) { + sts = -ENOMEM; + goto SendResult; + } + utf2uni(utf8Dn, dn, lenUni); + + /* Get the requested data */ + if (NCPMapDNToSEV == NULL) { + ndp_bind_idbroker_functions(); + } + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + + /* In case we use "multiple messages" for the response, increment + * the multipleID to make it unique for this instance. + * We do this in the parent before the fork, so the child will have + * a unique value to work with. + */ + sem_wait(&ndpmsg_multipleIDsem); + ++ndpmsg_multipleID; + + ndpDbgPrintf(1, "ndp_NCPMapDNToSEV_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (dn) { + ndpFree(dn); + } + if (utf8Dn) { + ndpFree(utf8Dn); + } + /* Let go of the parent semaphore now */ + sem_post(&ndpmsg_multipleIDsem); + ndpDbgPrintf(1, "ndp_NCPMapDNToSEV_handler(parent process exiting)\n"); + return(retval); + } + + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV_handler(fork done, PID=%d)\n",pid); + + guidSEVCount = 20; + guidSEV = ndpMalloc((guidSEVCount * sizeof(GUID_t)), GFP_KERNEL); + if (guidSEV == NULL) { + sts = -ENOMEM; + goto SendResult; + } + if (pid == 0) { + /* The child now has a semaphore which it needs to let go of and destroy */ + sem_post(&ndpmsg_multipleIDsem); + sem_destroy(&ndpmsg_multipleIDsem); + + /* Only the child process will call library functions */ + if (NCPMapDNToSEV) { + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV_handler calling NCPMapDNToSEV, dn=%s)\n", utf8Dn); + sts = (*NCPMapDNToSEV)(dn, &guidSEVCount, guidSEV, &isSupervisor); + if (sts == ERR_INSUFFICIENT_BUFFER) + { + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV_handler allocating bigger buffer for %d entries", guidSEVCount); + ndpFree(guidSEV); + guidSEV = ndpMalloc((guidSEVCount * sizeof(GUID_t)), GFP_KERNEL); + if (guidSEV == NULL) { + sts = -ENOMEM; + goto SendResult; + } + sts = (*NCPMapDNToSEV)(dn, &guidSEVCount, guidSEV, &isSupervisor); + } + ndpDbgPrintf(2, "ndp_NCPMapDNToSEV_handler back from NCPMapDNToSEV, sts = %d, count=%d\n", sts, guidSEVCount); + ndp_dumpDataInHex(4, "guidSEV buffer:", (guidSEVCount * 16), (unsigned char *)&guidSEV[0]); + } + } else { + guidSEVCount = 0; /* ??? JMG ??? */ + } + + if (guidSEVCount > 0) { + int i; + hexguids = (unsigned char *)ndpMalloc + (((guidSEVCount * HEXGUIDSIZE) + 1), GFP_KERNEL); + if (hexguids) { + for ( i = 0; i < guidSEVCount; i++) { + ndp_guid2hex(&guidSEV[i], &hexguids[i * HEXGUIDSIZE]); + hexguids[((i + 1) * HEXGUIDSIZE) - 1] = ','; + } + hexguids[((guidSEVCount * HEXGUIDSIZE))] = '\0'; + } + } + + /* Construct and return the results */ +SendResult: + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_NCPMapDNToSEV].guidPrime, + srcGuid, + "%d%s%d%d%s", + sts, utf8Dn, isSupervisor, guidSEVCount, hexguids); + + if (guidSEV) { + ndpFree(guidSEV); + } + if (hexguids) { + ndpFree(hexguids); + } + if (dn) { + ndpFree(dn); + } + if (utf8Dn) { + ndpFree(utf8Dn); + } + if (pid == 0) { + ndpDbgPrintf(1, "ndp_NCPMapDNToSEV_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_NCPMapDNToSEV_handler(Leave)\n"); + return(retval); +} /* ndp_NCPMapDNToSEV_handler() */ +#endif + +/***************************************************************************** +* GUID To Management Level +* K2U nnn +* hex,...hex +* U2K nnnhex +* nnn +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPMapGUIDToMgtLevel( + size_t numAuthenticatedIDs, + GUID_t *authenticatedIDs, + GUID_t *objectID, + NINT *_managementLevel) +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0L; + LONG managementLevel = 0L; + unsigned char *hexguids = NULL; /* [(n * HEXGUIDSIZE) + 1] */ + unsigned char objhexguid[HEXGUIDSIZE]; + + NDP_NCPMapGUIDToMgtLevel_count++; + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToMgtLevel(Enter, numAuthenticatedIDs=%d, objectID=%08lx-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x\n", + numAuthenticatedIDs, + objectID->timeLow, objectID->timeMid, + objectID->timeHighAndVersion, + objectID->clockSeqHighAndReserved, + objectID->clockSeqLow, + objectID->node[0], objectID->node[1], + objectID->node[2], objectID->node[3], + objectID->node[4], objectID->node[5] ); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "NCPMapGUIDToMgtLevel"); + + if (numAuthenticatedIDs > 0) { + int i; + hexguids = (unsigned char *)ndpMalloc + (((numAuthenticatedIDs * HEXGUIDSIZE) + 1), GFP_KERNEL); + if (hexguids) { + for ( i = 0; i < numAuthenticatedIDs; i++) { + ndpDbgPrintf(2, "ndp_NCPMapGUIDToMgtLevel(authID(%d): %08lx-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x)\n", + i, + (&authenticatedIDs[i])->timeLow, (&authenticatedIDs[i])->timeMid, + (&authenticatedIDs[i])->timeHighAndVersion, + (&authenticatedIDs[i])->clockSeqHighAndReserved, + (&authenticatedIDs[i])->clockSeqLow, + (&authenticatedIDs[i])->node[0], (&authenticatedIDs[i])->node[1], + (&authenticatedIDs[i])->node[2], (&authenticatedIDs[i])->node[3], + (&authenticatedIDs[i])->node[4], (&authenticatedIDs[i])->node[5] ); + ndp_guid2hex(&authenticatedIDs[i], &hexguids[i * HEXGUIDSIZE]); + hexguids[((i + 1) * HEXGUIDSIZE) - 1] = ','; + } + hexguids[((numAuthenticatedIDs * HEXGUIDSIZE))] = '\0'; + } + } + ndp_guid2hex(objectID, objhexguid); + + /* Construct and send the command */ + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_NCPMapGUIDToMgtLevel].guid, + "%d" + "%s%s", + numAuthenticatedIDs, hexguids, objhexguid); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + } else { + /* Return value of not used - yet */ + /*status = ndp_getXmlTagValueString("objid", data, length, &retDn); */ + status = ndp_getXmlTagValueLong("managementLevel", data, length, &managementLevel); + *_managementLevel = managementLevel; + retval = 0; + } + } + + if (hexguids) { + ndpFree(hexguids); + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToMgtLevel(Leave, retval=%d)\n",retval); + return(retval); +} /* ndp_NCPMapGUIDToMgtLevel() */ +EXPORT_SYMBOL(ndp_NCPMapGUIDToMgtLevel); +#else +int ndp_NCPMapGUIDToMgtLevel_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + int managementLevel = 0; + int status; + unsigned char *hexguids; /* [(n * HEXGUIDSIZE) + 1] */ + unsigned char *objhexguid = NULL;/* [HEXGUIDSIZE] */ + LONG numAuthenticatedIDs; + GUID_t *authenticatedIDs = NULL;/* points to an array of guids */ + GUID_t objectID; + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToMgtLevel_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueLong("authidcount", (utf8_t *)data, length, + &numAuthenticatedIDs); + ndpDbgPrintf(2, "ndp_NCPMapGUIDToMgtLevel_handler(numAuthIds=%d)\n",numAuthenticatedIDs); + if (numAuthenticatedIDs > 0) { + authenticatedIDs = (GUID_t *)ndpMalloc + (numAuthenticatedIDs * sizeof(GUID_t), GFP_KERNEL); + if (authenticatedIDs) { + int i; + /* + * The code is not currently checking for the delimiting ',' + * but merely expecting things to be "right". + */ + status = ndp_getXmlTagValueString("authid", (utf8_t *)data, length, &hexguids); + + for ( i = 0; i < numAuthenticatedIDs; i++) { + ndp_hex2guid(&hexguids[i * HEXGUIDSIZE], &authenticatedIDs[i]); + ndpDbgPrintf(2, "ndp_NCPMapGUIDToMgtLevel_handler(authID(%d): %08lx-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x)\n", + i, + (&authenticatedIDs[i])->timeLow, (&authenticatedIDs[i])->timeMid, + (&authenticatedIDs[i])->timeHighAndVersion, + (&authenticatedIDs[i])->clockSeqHighAndReserved, + (&authenticatedIDs[i])->clockSeqLow, + (&authenticatedIDs[i])->node[0], (&authenticatedIDs[i])->node[1], + (&authenticatedIDs[i])->node[2], (&authenticatedIDs[i])->node[3], + (&authenticatedIDs[i])->node[4], (&authenticatedIDs[i])->node[5] ); + } + ndpFree(hexguids); + } else { + /* ERROR */ + sts = -ENOMEM; + goto SendResult; + } + } + status = ndp_getXmlTagValueString("objid", (utf8_t *)data, length, &objhexguid); + ndp_hex2guid(objhexguid, &objectID); + + /* Get the requested data */ + if (NCPMapGUIDToMgtLevel == NULL) { + ndp_bind_idbroker_functions(); + } + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + ndpDbgPrintf(1, "ndp_NCPMapGUIDToMgtLevel_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (objhexguid) { + ndpFree(objhexguid); + } + if (authenticatedIDs) { + ndpFree(authenticatedIDs); + } + ndpDbgPrintf(1, "ndp_NCPMapGUIDToMgtLevel_handler(parent process exiting)\n"); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_NCPMapGUIDToMgtLevel_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* Only the child process will call library functions */ + if (NCPMapGUIDToMgtLevel) { + ndpDbgPrintf(2, "ndp_NCPMapGUIDToMgtLevel_handler(calling NCPMapGUIDToMgtLevel)\n"); + ndpDbgPrintf(2, "ndp_NCPMapGUIDToMgtLevel_handler(numAuthenticatedIDs=%d)\n",numAuthenticatedIDs); + ndpDbgPrintf(2, "ndp_NCPMapGUIDToMgtLevel_handler(objectID=%08lx-%04x-%04x-%02x-%02x-%02x%02x%02x%02x%02x%02x\n", + objectID.timeLow, objectID.timeMid, + objectID.timeHighAndVersion, + objectID.clockSeqHighAndReserved, + objectID.clockSeqLow, + objectID.node[0], objectID.node[1], + objectID.node[2], objectID.node[3], + objectID.node[4], objectID.node[5] ); + sts = (*NCPMapGUIDToMgtLevel)(numAuthenticatedIDs, + authenticatedIDs, &objectID, &managementLevel); + ndpDbgPrintf(2, "ndp_NCPMapGUIDToMgtLevel_handler(back from NCPMapGUIDToMgtLevel, sts=%d, mgtLevel=%d)\n", sts, managementLevel); + } + } + + /* Construct and return the results */ +SendResult: + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_NCPMapGUIDToMgtLevel].guidPrime, + srcGuid, + "%d%s%d", + sts, objhexguid, managementLevel); + + if (objhexguid) { + ndpFree(objhexguid); + } + if (authenticatedIDs) { + ndpFree(authenticatedIDs); + } + + if (pid == 0) { + ndpDbgPrintf(1, "ndp_NCPMapGUIDToMgtLevel_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_NCPMapGUIDToMgtLevel_handler(Leave)\n"); + return(retval); +} /* ndp_NCPMapGUIDToMgtLevel_handler() */ +#endif + +/***************************************************************************** +* Map GUID To DN +* K2U hexnnn +* U2K nnnhexccc +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPMapGUIDToDN( + GUID_t *guid, + size_t dnSize, + unicode_t *dn) +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + unsigned char hexguid[HEXGUIDSIZE]; + LONG sts = 0L; + utf8_t *utf8Dn; + + NDP_NCPMapGUIDToDN_count++; + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToDN(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "NCPMapGUIDToDN"); + + /* Construct and send the command */ + ndp_guid2hex(guid, hexguid); + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_NCPMapGUIDToDN].guid, + "%s%d", + hexguid, dnSize); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueString("guid", data, length, &hexguid); + //ndp_hex2guid(hexguid, guid); + //ndpFree(hexguid); + status = ndp_getXmlTagValueString("dn", data, length, + (unsigned char **)&utf8Dn); + if (utf2uni(utf8Dn, dn, dnSize) != -1) { + retval = 0; + } + ndpFree(utf8Dn); + } + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToDN(Leave)\n"); + return(retval); +} /* ndp_NCPMapGUIDToDN() */ +EXPORT_SYMBOL(ndp_NCPMapGUIDToDN); +#else +int ndp_NCPMapGUIDToDN_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + unsigned char *hexguid = NULL; /* [HEXGUIDSIZE] */ + GUID_t guid; + unicode_t *dn = NULL; + utf8_t *utf8Dn = NULL; + int lenUtf8; + int status; + LONG dnSize; + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToDN_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueLong("dnsize", (utf8_t *)data, length, &dnSize); + dn = (unicode_t *)ndpMalloc(dnSize, GFP_KERNEL); + if (dn == NULL) { + sts = -ENOMEM; + goto SendResult; + } + + status = ndp_getXmlTagValueString("guid", (utf8_t *)data, length, (unsigned char **)&hexguid); + ndp_hex2guid(hexguid, &guid); + + /* Get the requested data */ + if (NCPMapGUIDToDN == NULL) { + ndp_bind_idbroker_functions(); + } + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + + /* In case we use "multiple messages" for the response, increment + * the multipleID to make it unique for this instance. + * We do this in the parent before the fork, so the child will have + * a unique value to work with. + */ + sem_wait(&ndpmsg_multipleIDsem); + ++ndpmsg_multipleID; + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToDN_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (dn) { + ndpFree(dn); + } + if (hexguid) { + ndpFree(hexguid); + } + /* Let go of the parent semaphore now */ + sem_post(&ndpmsg_multipleIDsem); + ndpDbgPrintf(1, "ndp_NCPMapGUIDToDN_handler(parent process exiting, child PID=%d)\n", pid); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_NCPMapGUIDToDN_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* The child now has a semaphore which it needs to let go of and destroy */ + sem_post(&ndpmsg_multipleIDsem); + sem_destroy(&ndpmsg_multipleIDsem); + + /* Only the child process will call library functions */ + if (NCPMapGUIDToDN) { + ndpDbgPrintf(2, "ndp_NCPMapGUIDToDN_handler(calling NCPMapGUIDToDN)\n"); + sts = (*NCPMapGUIDToDN)(&guid, dnSize, dn); + ndpDbgPrintf(2, "ndp_NCPMapGUIDToDN_handler(back from NCPMapGUIDToDN, sts=%d)\n", sts); + } + } + + /* Construct and return the results */ + lenUtf8 = (unilen(dn) * 3) + 1; + utf8Dn = ndpMalloc( lenUtf8, GFP_KERNEL ); + if (utf8Dn == NULL) { + sts = -ENOMEM; + } else { + if (uni2utf(dn, utf8Dn, lenUtf8) == -1) { + sts = -1; + } + } +SendResult: + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_NCPMapGUIDToDN].guidPrime, + srcGuid, + "%d%s%s", + sts, hexguid, utf8Dn); + + /* Free the allocated memory */ + if (dn) { + ndpFree(dn); + } + if (utf8Dn) { + ndpFree(utf8Dn); + } + if (hexguid) { + ndpFree(hexguid); + } + + if (pid == 0) { + ndpDbgPrintf(1, "ndp_NCPMapGUIDToDN_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_NCPMapGUIDToDN_handler(Leave)\n"); + return(retval); +} /* ndp_NCPMapGUIDToDN_handler() */ +#endif + +/***************************************************************************** +* GUID To UID +* K2U hex +* U2K nnnhexnnn +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPMapGUIDToUID( + GUID_t *guid, + LONG *uid) +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0L; + unsigned char hexguid[HEXGUIDSIZE]; + + NDP_NCPMapGUIDToUID_count++; + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToUID(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "NCPMapGUIDToUID"); + + /* Construct and send the command */ + ndp_guid2hex(guid, hexguid); + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_NCPMapGUIDToUID].guid, + "%s", hexguid); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + *uid = -1; + ndpDbgPrintf(2, "ndp_NCPMapGUIDToUID(sts:%d,uid=0x%08x)\n",sts,*uid); + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueString("guid", data, length, &retGuid); + status = ndp_getXmlTagValueLong("uid", data, length, uid); + ndpDbgPrintf(2, "ndp_NCPMapGUIDToUID(sts:%d,uid=0x%08x)\n",sts,*uid); + retval = 0; + } + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToUID(Leave:%d)\n",retval); + return(retval); +} /* ndp_NCPMapGUIDToUID() */ +EXPORT_SYMBOL(ndp_NCPMapGUIDToUID); +#else +int ndp_NCPMapGUIDToUID_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + unsigned char *hexguid = NULL; /* [HEXGUIDSIZE] */ + GUID_t guid; + LONG uid; + int status; + + ndpDbgPrintf(1, "ndp_NCPMapGUIDToUID_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueString("guid", (utf8_t *)data, length, (unsigned char **)&hexguid); + ndp_hex2guid(hexguid, &guid); + + /* Get the requested data */ + if (NCPMapGUIDToUID == NULL) { + ndp_bind_idbroker_functions(); + } + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + ndpDbgPrintf(1, "ndp_NCPMapGUIDToUID_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (hexguid) { + ndpFree(hexguid); + } + ndpDbgPrintf(1, "ndp_NCPMapGUIDToUID_handler(parent process exiting)\n"); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_NCPMapGUIDToUID_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* Only the child process will call library functions */ + if (NCPMapGUIDToUID) { + ndpDbgPrintf(2, "ndp_NCPMapGUIDToUID_handler(calling NCPMapGUIDToUID)\n"); + sts = (*NCPMapGUIDToUID)(&guid, &uid); + ndpDbgPrintf(2, "ndp_NCPMapGUIDToUID_handler(sts=%d, uid=%d)\n",sts,uid); + } + } + + /* Construct and return the results */ + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_NCPMapGUIDToUID].guidPrime, + srcGuid, + "%d%s%d", + sts, hexguid, (sts == 0 ? uid : -1)); + + /* Free the allocated memory */ + if (hexguid) { + ndpFree(hexguid); + } + + if (pid == 0) { + ndpDbgPrintf(1, "ndp_NCPMapGUIDToUID_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_NCPMapGUIDToUID_handler(Leave)\n"); + return(retval); +} /* ndp_NCPMapGUIDToUID_handler() */ +#endif + +/***************************************************************************** +* UID To GUID +* K2U nnn +* U2K nnnnnnhex +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPMapUIDToGUID( + LONG uid, + GUID_t *guid) +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0L; + unsigned char *hexguid; + + NDP_NCPMapUIDToGUID_count++; + + ndpDbgPrintf(1, "ndp_NCPMapUIDToGUID(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "NCPMapUIDToGUID"); + + /* Construct and send the command */ + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_NCPMapUIDToGUID].guid, + "%d", uid); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + ndpDbgPrintf(2, "ndp_NCPMapUIDToGUID(sts:%d)\n",sts); + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueLong("uid", data, length, &retUid); + status = ndp_getXmlTagValueString("guid", data, length, &hexguid); + ndp_hex2guid(hexguid, guid); + ndpFree(hexguid); + retval = 0; + } + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_NCPMapUIDToGUID(Leave:%d)\n",retval); + return(retval); +} /* ndp_NCPMapUIDToGUID() */ +EXPORT_SYMBOL(ndp_NCPMapUIDToGUID); +#else +int ndp_NCPMapUIDToGUID_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + unsigned char hexguid[HEXGUIDSIZE]; + GUID_t guid; + LONG uid; + int status; + + ndpDbgPrintf(1, "ndp_NCPMapUIDToGUID_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueLong("uid", (utf8_t *)data, length, &uid); + + /* Get the requested data */ + if (NCPMapUIDToGUID == NULL) { + ndp_bind_idbroker_functions(); + } + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + ndpDbgPrintf(1, "ndp_NCPMapUIDToGUID_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + ndpDbgPrintf(1, "ndp_NCPMapUIDToGUID_handler(parent process exiting)\n"); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_NCPMapUIDToGUID_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* Only the child process will call library functions */ + if (NCPMapUIDToGUID) { + ndpDbgPrintf(2, "ndp_NCPMapUIDToGUID_handler(calling NCPMapUIDToGUID)\n"); + sts = (*NCPMapUIDToGUID)(uid, &guid); + ndpDbgPrintf(2, "ndp_NCPMapUIDToGUID_handler(sts=%d, uid=%d)\n",sts,uid); + } + } + + /* Construct and return the results */ + ndp_guid2hex(&guid, hexguid); + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_NCPMapUIDToGUID].guidPrime, + srcGuid, + "%d%d%s", + sts, uid, (sts == 0 ? hexguid : NULL)); + + if (pid == 0) { + ndpDbgPrintf(1, "ndp_NCPMapUIDToGUID_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_NCPMapUIDToGUID_handler(Leave)\n"); + return(retval); +} /* ndp_NCPMapUIDToGUID_handler() */ +#endif + +/***************************************************************************** +* Get UID From Name +* K2U ccc +* U2K nnncccnnn +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_GetUIDFromName( + unsigned char *name, + LONG *uid) +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0L; + + NDP_GetUIDFromName_count++; + + ndpDbgPrintf(1, "ndp_GetUIDFromName(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, + "GetUIDFromName"); + + /* Construct and send the command */ + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_GetUIDFromName].guid, + "%s", name); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + *uid = 0; + ndpDbgPrintf(2, "ndp_GetUIDFromName(sts:%d,uid=0x%08x)\n",sts,*uid); + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueString("name", data, length, &retName); + status = ndp_getXmlTagValueLong("uid", data, length, uid); + ndpDbgPrintf(2, "ndp_GetUIDFromName(sts:%d,uid=0x%08x)\n",sts,*uid); + retval = 0; + } + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_GetUIDFromName(Leave:%d)\n",retval); + return(retval); +} /* ndp_GetUIDFromName() */ +EXPORT_SYMBOL(ndp_GetUIDFromName); +#else +int ndp_GetUIDFromName_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + struct passwd *pwd; + char *name = NULL; + LONG uid = 0; + int status; + + ndpDbgPrintf(1, "ndp_GetUIDFromName_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueString("name", (utf8_t *)data, length, (unsigned char **)&name); + + /* There is no dynamic function to import/bind */ + + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + ndpDbgPrintf(1, "ndp_GetUIDFromName_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (name) { + ndpFree(name); + } + ndpDbgPrintf(1, "ndp_GetUIDFromName_handler(parent process exiting)\n"); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_GetUIDFromName_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* Only the child process will call library functions */ + ndpDbgPrintf(2, "ndp_GetUIDFromName_handler(calling getpwdnam)\n"); + pwd = getpwnam( name ); + if (pwd == NULL) + { + sts = -1; + uid = 0; + } + else + { + sts = 0; + uid = pwd->pw_uid; + } + ndpDbgPrintf(2, "ndp_GetUIDFromName_handler(sts=%d, uid=%d)\n",sts,uid); + } + + /* Construct and return the results */ + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_GetUIDFromName].guidPrime, + srcGuid, + "%d%s%d", + sts, name, uid); + + if (name) { + ndpFree(name); + } + + if (pid == 0) { + ndpDbgPrintf(1, "ndp_GetUIDFromName_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_GetUIDFromName_handler(Leave)\n"); + return(retval); +} /* ndp_GetUIDFromName_handler() */ +#endif + +/**************************************************************************** + * ndp_MangleBuffer + * Make the buffer unreadable so debug logging won't be able to easily see it. + * This algorithm is reversible -- a simple XOR of an arbitrary pattern. + * NOTE - This is not a secure algorithm ... it simply makes it inconvenient + * to see the data in the XML logging. + *****************************************************************************/ +void ndp_MangleBuffer( + unsigned char *key, + int buflen) +{ + int idx,idx2; + char *xorPattern = "arbitraryValue"; /* Arbitrary value here */ + int idx2Reset = strlen(xorPattern)-1; + + /* XOR every character with a character from the word "debug" */ + for (idx=0,idx2=0; idx= idx2Reset) { + idx2 = 0; + } + } +} + +/**************************************************************************** + * ndp_ManglePassword + * Make the password unreadable so debug logging won't be able to easily + * see it. + * This allocates the return buffer, and the caller must free it. + * NOTE - This is not a secure algorithm ... it simply makes it inconvenient + * to see the password in the XML logging. + *****************************************************************************/ +unsigned char *ndp_ManglePassword( + utf8_t *utf8Pw) +{ + int utf8len; + unsigned char *hexdata = NULL; + + utf8len = strlen(utf8Pw); + hexdata = ndpMalloc((utf8len+1)*2, GFP_KERNEL); + if (utf8Pw == NULL) { + return(NULL); + } + + /* XOR every character with a character from the word "debug" */ + ndp_MangleBuffer((unsigned char *)utf8Pw, utf8len); + + /* Convert the utf8 string to null terminated ascii-hex */ + ndp_buf2hex((unsigned char *)utf8Pw, utf8len, hexdata); + return(hexdata); +} + +/**************************************************************************** + * ndp_ManglePassword + * Make the password unreadable so debug logging won't be able to easily + * see it. + * This allocates the return buffer, and the caller must free it. + * NOTE - This is not a secure algorithm ... it simply makes it inconvenient + * to see the password in the XML logging. + *****************************************************************************/ +utf8_t *ndp_UnManglePassword( + unsigned char *hexdata) +{ + int hexlen; + int utf8len; + utf8_t *utf8Pw = NULL; + + hexlen = strlen((char *)hexdata); + utf8len = hexlen / 2; + utf8Pw = ndpMalloc((utf8len+1), GFP_KERNEL); + if (utf8Pw == NULL) { + return(NULL); + } + + /* Convert the ascii-hex buffer back to utf8 */ + ndp_hex2buf(hexdata, utf8len, (unsigned char *)utf8Pw); + utf8Pw[utf8len] = 0; + + /* XOR every character with a character from the word "debug" */ + ndp_MangleBuffer((unsigned char *)utf8Pw, utf8len); + + return(utf8Pw); +} + +/***************************************************************************** +* ndp_GenerateVolumeKeyInfo - Given a password, generate a new key for an +* encrypted volume, and generate the persistent portion of the VolumeKey_s +* structure. +* This persistent portion includes a version, flags, salt value, and an +* encrypted key. Then the entire persistent portion is signed and shrouded into +* a MAC value that is stored at the end of it. This persistent portion is +* stored in the volume data block. +* +* K2U ccc +* U2K nnnccchex

hex

+*
+*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_GenerateVolumeKeyInfo( + unicode_t *volumePassword, + BYTE *retKey, /* ptr to 16 byte buffer to receive the new key */ + BYTE *retP) /* ptr to 128 byte buffer to receive the new persistent key info */ +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0L; + unsigned char *hexdata; + utf8_t *utf8Pw = NULL; + int utf8Len; + + NDP_GenerateData_count++; + + ndpDbgPrintf(1, "ndp_GenerateData(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime, "GenerateData"); + + /* Construct and send the command */ + utf8Len = (unilen(volumePassword) * 3) + 1; + utf8Pw = ndpMalloc(utf8Len, GFP_KERNEL); + if (utf8Pw == NULL) { + retval = -ENOMEM; + goto functionExit; + } + uni2utf( volumePassword, utf8Pw, utf8Len ); + + /* Convert the utf8 password into a re-arranged hex buffer */ + hexdata = ndp_ManglePassword(utf8Pw); + if (hexdata == NULL) { + retval = -ENOMEM; + goto functionExit; + } + + ndp_printfToGuid(3, /* Don't log this message because it contains a password */ + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_GenerateVolumeKeyInfo].guid, + "%s", hexdata); + memset(hexdata, 0, strlen(hexdata)); + ndpFree(hexdata); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + ndpDbgPrintf(2, "ndp_GenerateData(sts:%d)\n", sts); + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueString("w", data, length, &retPw); + + /* Get the 16 byte key. The caller passes in a 16 byte buffer, + * and this code assumes the ndpApp code returns exactly 16 bytes. + * (Use debugLevel == -1 so this tag won't show up in debug) + */ + status = ndp_getXmlTagValueString("y", data, length, &hexdata); + ndp_hex2buf(hexdata, 16, retKey); + ndp_MangleBuffer(retKey, 16); /* restore the "real" key */ + memset(hexdata, 0, strlen(hexdata)); + ndpFree(hexdata); + + /* Get the 128 byte "p". The caller passes in a 128 byte buffer, + * and this code assumes the ndpApp code returns exactly 128 bytes. + */ + status = ndp_getXmlTagValueString("p", data, length, &hexdata); + ndp_hex2buf(hexdata, 128, retP); + ndpFree(hexdata); + + retval = 0; + } + } + +functionExit: + + if (utf8Pw) { + memset(utf8Pw, 0, strlen(utf8Pw)); + ndpFree(utf8Pw); + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_GenerateData(Leave:%d)\n",retval); + return(retval); +} /* ndp_NCPMapDNToSEV() */ +EXPORT_SYMBOL(ndp_GenerateVolumeKeyInfo); +#else +int ndp_GenerateVolumeKeyInfo_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + unicode_t *pw = NULL; + utf8_t *utf8Pw = NULL; + int lenUni; + VolumeKey_s key; + unsigned char *hexdata = NULL; + unsigned char hexKey[(16*2)+1]; + unsigned char hexP[(128*2)+1]; + int status; + + ndpDbgPrintf(1, "ndp_GenerateData_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueString("w", (utf8_t *)data, length, (unsigned char **)&hexdata); + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + if (daemonize) + { + ndpDbgPrintf(1, "ndp_GenerateData_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (hexdata) { + ndpFree(hexdata); + } + ndpDbgPrintf(1, "ndp_GenerateData_handler(parent process exiting)\n"); + return(retval); + } + } + + utf8Pw = ndp_UnManglePassword(hexdata); + lenUni = (strlen(utf8Pw) + 1) * sizeof(unicode_t); + pw = ndpMalloc(lenUni, GFP_KERNEL); + if (pw == NULL) { + sts = -ENOMEM; + goto SendResult; + } + utf2uni(utf8Pw, pw, lenUni); + + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_GenerateData_handler(fork done, PID=%d)\n",pid); + + if ((!daemonize) || (pid == 0)) { + /* Only the child process will call library functions */ + sts = COMN_GenerateVolumeCrypto(&key, pw); + } + + /* encrypt and format the "real" key for transmission */ + ndp_MangleBuffer((unsigned char *)&key.key, 16); + ndp_buf2hex((unsigned char *)&key.key, 16, hexKey); + memset(&key.key, 0, 16); + + /* Format the persistent volume portion for transmission */ + ndp_buf2hex((unsigned char *)&key.p, 128, hexP); + + /* Construct and return the results */ +SendResult: + ndpmsgsnd_printfToGuid(3, /* Use -1 do this won't go in debug log w/password or key */ + &ndpIdBrokerInfo[IDBG_NCPMapDNToSEV].guidPrime, + srcGuid, + "%d%s%s

%s

", + sts, hexdata, hexKey, hexP); + + if (pw) { + ndpFree(pw); + } + if (utf8Pw) { + memset(utf8Pw, 0, strlen(utf8Pw)); + ndpFree(utf8Pw); + } + if (hexdata) { + memset(hexdata, 0, strlen((char *)hexdata)); + ndpFree(hexdata); + } + if ((daemonize) && (pid == 0)) { + ndpDbgPrintf(1, "ndp_GenerateData_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_GenerateData_handler(Leave)\n"); + return(retval); +} /* ndp_GenerateVolumeKeyInfo_handler() */ +#endif + +/***************************************************************************** +* ndp_ExtractVolumeKeyInfo - Given a password, and the persistent portion of +* a VolumeKey_s structure, verify the structure and extract the unencrypted key. +* +* K2U ccc

hex

+* U2K nnnccchex +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_ExtractVolumeKeyInfo( + unicode_t *volumePassword, + BYTE *volP, /* ptr to 128 byte persistent portion of VolumeKey_s */ + BYTE *retKey) /* ptr to 16 byte buffer to receive the extracted key */ +{ + int retval = -1; + GUID_t sidGuid; + GUID_t sidGuidPrime; + GUID_t srcGuid; + LONG length = 0; + unsigned char *data = NULL; + int status; + LONG sts = 0L; + unsigned char *hexdata; + utf8_t *utf8Pw = NULL; + int utf8Len; + unsigned char *hexP = NULL; + + NDP_ExtractData_count++; + + ndpDbgPrintf(1, "ndp_ExtractData(Enter)\n"); + + /* Generate a new random Guid (for this session) & register it */ + sts = ndp_registerRandomGuid(&sidGuid, &sidGuidPrime,"ExtractData"); + + /* Construct and send the command */ + utf8Len = (unilen(volumePassword) * 3) + 1; + utf8Pw = ndpMalloc(utf8Len, GFP_KERNEL); + if (utf8Pw == NULL) { + retval = -ENOMEM; + goto functionExit; + } + hexP = ndpMalloc( ((128*2)+1), GFP_KERNEL); + if (hexP == NULL) { + retval = -ENOMEM; + goto functionExit; + } + + uni2utf( volumePassword, utf8Pw, utf8Len ); + + /* Convert the utf8 password into a re-arranged hex buffer */ + hexdata = ndp_ManglePassword(utf8Pw); + if (hexdata == NULL) + { + retval = -ENOMEM; + goto functionExit; + } + + ndp_buf2hex((unsigned char *)volP, 128, hexP); + + ndp_printfToGuid(3, + &sidGuidPrime, + &ndpIdBrokerInfo[IDBG_ExtractVolumeKeyInfo].guid, + "%s

%s

", + hexdata,hexP); + memset(hexdata, 0, strlen(hexdata)); + ndpFree(hexdata); + + /* Read until we have data or timeout */ + status = ndp_readFromGuidUntilTimeout(1, + &sidGuidPrime, &srcGuid, &length, &data, ndpIdBrokerReadTIMEOUT); + + /* Parse the data returned to us */ + if (status == 0) { + /* We have something */ + status = ndp_getXmlTagValueLong("sts", data, length, &sts); + if (sts) { + retval = sts; + ndpDbgPrintf(2, "ndp_ExtractData(sts:%d)\n", sts); + } else { + // Return value of not used - yet */ + //status = ndp_getXmlTagValueString("w", data, length, &retPw); + + /* Get the 16 byte key. The caller passes in a 16 byte buffer, + * and this code assumes the ndpApp code returns exactly 16 bytes. + */ + status = ndp_getXmlTagValueString("y", data, length, &hexdata); + ndp_hex2buf(hexdata, 16, retKey); + ndp_MangleBuffer(retKey,16); /* restore the "real" key */ + memset(hexdata, 0, strlen(hexdata)); + ndpFree(hexdata); + + retval = 0; + } + } + +functionExit: + + if (utf8Pw) { + memset(utf8Pw, 0, strlen(utf8Pw)); + ndpFree(utf8Pw); + } + if (hexP) { + ndpFree(hexP); + } + + /* DeRegister our random Guid (for this session) */ + ndp_deregisterGuid(&sidGuidPrime); + + ndpDbgPrintf(1, "ndp_ExtractData(Leave:%d)\n",retval); + return(retval); +} /* ndp_NCPMapDNToSEV() */ +EXPORT_SYMBOL(ndp_ExtractVolumeKeyInfo); +#else +int ndp_ExtractVolumeKeyInfo_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = 0; + pid_t pid = -1; + int sts = -1; + unicode_t *pw = NULL; + utf8_t *utf8Pw = NULL; + int lenUni; + VolumeKey_s key; + unsigned char *hexdata = NULL; + unsigned char hexKey[(16*2)+1]; + unsigned char *hexP = NULL; + int status; + + ndpDbgPrintf(1, "ndp_ExtractData_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueString("w", (utf8_t *)data, length, (unsigned char **)&hexdata); + utf8Pw = ndp_UnManglePassword(hexdata); + lenUni = (strlen(utf8Pw) + 1) * sizeof(unicode_t); + pw = ndpMalloc(lenUni, GFP_KERNEL); + if (pw == NULL) { + sts = -ENOMEM; + goto SendResult; + } + utf2uni(utf8Pw, pw, lenUni); + + memset(&key, 0, sizeof(key)); + status = ndp_getXmlTagValueString("p", (utf8_t *)data, length, &hexP); + if (hexP) { + ndp_hex2buf(hexP, 128, (unsigned char *)&key.p); + ndpFree(hexP); + } + + /* + * From here on, we fork and operate as a separate process + * so if the library function crashes, ndpapp is immune. + * As a result, we need to send the data back to the sender + * using msgop functions. + */ + ndpDbgPrintf(1, "ndp_ExtractData_handler(forking new child process)\n"); + pid = fork(); + if (pid > 0) { + /* Parent Process */ + if (pw) { + ndpFree(pw); + } + if (utf8Pw) { + memset(utf8Pw, 0, strlen(utf8Pw)); + ndpFree(utf8Pw); + } + if (hexdata) { + ndpFree(hexdata); + } + ndpDbgPrintf(1, "ndp_ExtractData_handler(parent process exiting)\n"); + return(retval); + } + /* + * NOTE: We let thru both + * the Child Process, and the parent process when we have an error forking + * so the parent when error'ing out can send a message back indicating + * a failure occured. This allows the receiving process/thread to + * continue without waiting for a timeout condition. + */ + ndpDbgPrintf(2, "ndp_ExtractData_handler(fork done, PID=%d)\n",pid); + + if (pid == 0) { + /* Only the child process will call library functions */ + sts = COMN_ProcessVolumeCrypto(&key, pw); + } + + /* encrypt and format the "real" key for transmission */ + ndp_MangleBuffer((unsigned char *)&key.key, 16); + ndp_buf2hex((unsigned char *)&key.key, 16, hexKey); + memset(&key.key, 0, 16); + + /* Construct and return the results */ +SendResult: + ndpmsgsnd_printfToGuid(3, + &ndpIdBrokerInfo[IDBG_NCPMapDNToSEV].guidPrime, + srcGuid, + "%d%s%s", + sts, hexdata, hexKey); + + if (pw) { + ndpFree(pw); + } + if (utf8Pw) { + memset(utf8Pw, 0, strlen(utf8Pw)); + ndpFree(utf8Pw); + } + if (hexdata) { + memset(hexdata, 0, strlen((char *)hexdata)); + ndpFree(hexdata); + } + if (pid == 0) { + ndpDbgPrintf(1, "ndp_ExtractData_handler(exiting - PID==0)\n"); + exit(retval); /* The child process needs to exit */ + } + /* The parent process error'ing out while forking needs to return */ + ndpDbgPrintf(1, "ndp_ExtractData_handler(Leave)\n"); + return(retval); +} /* ndp_ExtractVolumeKeyInfo_handler() */ +#endif + +/***************************************************************************** +* KERNEL/MODULE Registration of function to call when +* Notification If DN Has Been Renamed Or Deleted +* Return Value: if properly registered (0), +* if already registered (-2) +* if invalid function pointer (-1) +*****************************************************************************/ +#ifdef __KERNEL__ +void (*ndp_NCPNotifyDNChange)(unicode_t *oldDN, unicode_t *newDN) = NULL; + +int ndp_register_NCPNotifyDNChange( + void (*NCPNotifyDNChange)(unicode_t *oldDN, unicode_t *newDN) ) +{ + int retval = -1; + + ndpDbgPrintf(1, "ndp_register_NCPNotifyDNChange(Enter)\n"); + if (NCPNotifyDNChange) { + if (ndp_NCPNotifyDNChange == NULL) { + ndp_NCPNotifyDNChange = NCPNotifyDNChange; + retval = 0; + } else { + retval = -2; + } + } else { + retval = -1; + } + ndpDbgPrintf(1, "ndp_register_NCPNotifyDNChange(Leave)\n"); + return(retval); +} +EXPORT_SYMBOL(ndp_register_NCPNotifyDNChange); +#endif + +/***************************************************************************** +* Notification If DN Has Been Renamed Or Deleted +* If newDN is 0, the object has been deleted +* K2U ... N/A (no return value) ... +* U2K cccccc +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPNotifyDNChange_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = -1; + int status; + utf8_t *utf8FDN = NULL; + int lenUni; + int lenUtf8; + unicode_t *oldDN = NULL; + unicode_t *newDN = NULL; + + ndpDbgPrintf(1, "ndp_NCPNotifyDNChange_handler(Enter)\n"); + /* Parse the input data */ + status = ndp_getXmlTagValueString("olddn", data, length, + (unsigned char **)&utf8FDN); + if ((status != 0) || (utf8FDN == NULL)) { + ndpWrnPrintf("ndp_NCPNotifyDNChange_handler(Invalid old DN)\n"); + } else { + lenUni = (strlen(utf8FDN) + 1) * sizeof(unicode_t); + oldDN = (unicode_t *)ndpMalloc(lenUni, GFP_KERNEL); + utf2uni (utf8FDN, oldDN, lenUni); + ndpFree(utf8FDN); + } + status = ndp_getXmlTagValueString("newdn", data, length, + (unsigned char **)&utf8FDN); + if ((status == 0) || (utf8FDN != NULL)) { + /* + * We don't check for errors here, because + * if newDN is 0, the object has been deleted + */ + if ((lenUtf8 = strlen(utf8FDN)) != 0) + { + lenUni = (lenUtf8 + 1) * sizeof(unicode_t); + newDN = (unicode_t *)ndpMalloc(lenUni, GFP_KERNEL); + utf2uni (utf8FDN, newDN, lenUni); + } + ndpFree(utf8FDN); + } + if (oldDN) { + if (ndp_NCPNotifyDNChange) { + (*ndp_NCPNotifyDNChange)(oldDN, newDN); + /* + * NOTE: No return value is expected by the APP side of this... + */ + } + } + if (oldDN) { + ndpFree(oldDN); + } + if (newDN) { + ndpFree(newDN); + } + ndpDbgPrintf(1, "ndp_NCPNotifyDNChange_handler(Leave)\n"); + return(retval); +} /* ndp_NCPNotifyDNChange_handler() */ +#endif + +/***************************************************************************** +* KERNEL/MODULE Registration of function to call when +* Notification If SEV (Security Equivalence Vector) Has Been Changed. +* Return Value: if properly registered (0), +* if already registered (-2) +* if invalid function pointer (-1) +*****************************************************************************/ +#ifdef __KERNEL__ +void (*ndp_NCPNotifySEVChange)(GUID_t *changedGUID) = NULL; + +int ndp_register_NCPNotifySEVChange( + void (*NCPNotifySEVChange)(GUID_t *changedGUID) ) +{ + int retval = -1; + + ndpDbgPrintf(1, "ndp_register_NCPNotifySEVChange(Enter)\n"); + if (NCPNotifySEVChange) { + if (ndp_NCPNotifySEVChange == NULL) { + ndp_NCPNotifySEVChange = NCPNotifySEVChange; + retval = 0; + } else { + retval = -2; + } + } else { + retval = -1; + } + ndpDbgPrintf(1, "ndp_register_NCPNotifySEVChange(Leave)\n"); + return(retval); +} +EXPORT_SYMBOL(ndp_register_NCPNotifySEVChange); +#endif + +/***************************************************************************** +* Notification If SEV (Security Equivalence Vector) Has Been Changed. +* K2U ... N/A (no return value) ... +* U2K hex +*****************************************************************************/ +#ifdef __KERNEL__ +int ndp_NCPNotifySEVChange_handler( + GUID_t *srcGuid, + LONG length, + unsigned char *data) +{ + int retval = -1; + int status; + unsigned char *hexguid = NULL; /* [HEXGUIDSIZE] */ + GUID_t guid; + + ndpDbgPrintf(1, "ndp_NCPNotifySEVChange_handler(Enter)\n"); + + /* Parse the input data */ + status = ndp_getXmlTagValueString("guid", data, length, (unsigned char **)&hexguid); + if ((status != 0) || (hexguid == NULL)) { + ndpWrnPrintf("ndp_NCPNotifySEVChange_handler(Invalid GUID)\n"); + } else { + ndp_hex2guid(hexguid, &guid); + ndpFree(hexguid); + + if (ndp_NCPNotifySEVChange) { + (*ndp_NCPNotifySEVChange)(&guid); + /* + * NOTE: No return value is expected by the APP side of this... + */ + } + } + ndpDbgPrintf(1, "ndp_NCPNotifySEVChange_handler(Leave)\n"); + return(retval); +} /* ndp_NCPNotifySEVChange_handler() */ +#endif + +#endif /* BUILD_NDP_IDBROKER */