|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
HookCmmn.c
Abstract:
The purpose of this module is to have a common source for many routines used by the hook on win95 and on NT. In this way, there'll be only one place to change even if there's some code uglyness (ifdefs, etc.)
Initially, i (jll) have not actually removed any routines from the win95 hook....i have just made copies of them here. accordingly, everything is initially under ifdef-NT. the rule that is being used is that anything that requires visibility of the Rx Fcb structures will not be included here; rather, it'll be in the minirdr part. the following are steps that need to be accomplished:
1. ensure that the win95 shadow vxd can be built from these sources. 1a. juggle the win95 vxd compile to use precomp and stdcall. 2. juggle the record manager structs so that we'll be RISCable 3. remove any routines from hook.h that are actually here. 4. remove a number of other routines that i splated around from hook.c under NT-ifdef and place them here.
Author:
Shishir Pardikar [Shishirp] 01-jan-1995
Revision History:
Joe Linn [JoeLinn] 10-mar-97 Initial munging for NT
--*/
#include "precomp.h"
#pragma hdrstop
#pragma code_seg("PAGE")
#undef RxDbgTrace
#define RxDbgTrace(a,b,__d__) {qweee __d__;}
#ifdef DEBUG
//cshadow dbgprint interface
#define HookCmmnKdPrint(__bit,__x) {\
if (((HOOKCMMN_KDP_##__bit)==0) || FlagOn(HookCmmnKdPrintVector,(HOOKCMMN_KDP_##__bit))) {\ KdPrint (__x);\ }\ } #define HOOKCMMN_KDP_ALWAYS 0x00000000
#define HOOKCMMN_KDP_BADERRORS 0x00000001
#define HOOKCMMN_KDP_ISSPECIALAPP 0x00000002
#define HOOKCMMN_KDP_INITDATABASE 0x00000004
#define HOOKCMMN_KDP_TUNNELING 0x00000008
#define HOOKCMMN_KDP_GOOD_DEFAULT (HOOKCMMN_KDP_BADERRORS \
| 0)
ULONG HookCmmnKdPrintVector = HOOKCMMN_KDP_GOOD_DEFAULT; ULONG HookCmmnKdPrintVectorDef = HOOKCMMN_KDP_GOOD_DEFAULT; #else
#define HookCmmnKdPrint(__bit,__x) {NOTHING;}
#endif
//this is just for editing ease......
//#ifdef CSC_RECORDMANAGER_WINNT
//#endif //ifdef CSC_RECORDMANAGER_WINNT
#ifdef CSC_RECORDMANAGER_WINNT
BOOL fInitDB = FALSE; // Database Initialized
BOOL fReadInit = FALSE; // Init values have been read
BOOL fSpeadOpt = TRUE; // spead option, reads the cached files even when
// locks are set on the share
GLOBALSTATUS sGS; // Global status used for communicating with ring3
// Semaphore used to synchronize in memory structures
VMM_SEMAPHORE semHook;
// This strucutre is used as temporary I/O buffer only within Shadow critical
// section
WIN32_FIND_DATA vsFind32;
// Agent Info, obtained through IoctlRegisterAgent
ULONG hthreadReint=0; // Thred ID
ULONG hwndReint=0; // windows handle.
ULONG heventReint;
// upto 16 threads can temporarily enable and disable shadowing
ULONG rghthreadTemp[16];
// Reintegration happens one share at a time. If it is going on, then BeginReint
// in ioctl.c sets hShareReint to the share on which we are doing reint
// if vfBlockingReint is TRUE, then all operations on that share will fail
// when the share is reintegrating.
// If vfBlockingReint is not true, then if the dwActivityCount is non-zero
// the ioctls to change any state on any of the descendents of this share fail
// causing the agent to aboort reintegration
// The acitvycount is incremented based on a trigger from the redir/hook, when
// any namespace mutating operation is performed.
HSHARE hShareReint=0; // Share that is currently being reintegrated
BOOL vfBlockingReint = TRUE; DWORD vdwActivityCount = 0; //from shadow.asm ---------------------------------------------------
int fShadow = 0;
#if defined(_X86_)
int fLog = 1; #else
int fLog = 0; #endif
//tunnel cache
SH_TUNNEL rgsTunnel[10] = {0};
#ifdef DEBUG
ULONG cntReadHits=0; tchar pathbuff[MAX_PATH+1]; #endif
BOOL FindTempAgentHandle( ULONG hthread) { int i;
for (i=0; i < (sizeof(rghthreadTemp)/sizeof(ULONG)); ++i) { if (rghthreadTemp[i]==hthread) { return TRUE; } } return FALSE;
}
BOOL RegisterTempAgent( VOID ) { int i; ULONG hthread;
hthread = GetCurThreadHandle();
for (i=0; i< (sizeof(rghthreadTemp)/sizeof(ULONG)); ++i) { if (!rghthreadTemp[i]) { rghthreadTemp[i] = hthread; return TRUE; } } return FALSE; }
BOOL UnregisterTempAgent( VOID ) { int i; ULONG hthread;
hthread = GetCurThreadHandle();
for (i=0; i < (sizeof(rghthreadTemp)/sizeof(ULONG)); ++i) { if (rghthreadTemp[i]==hthread) { rghthreadTemp[i] = 0; return TRUE; } }
return FALSE; }
BOOL IsSpecialApp ( VOID ) { ULONG hthread;
hthread = GetCurThreadHandle(); if ((hthread==hthreadReint) || FindTempAgentHandle(hthread)) { HookCmmnKdPrint(ISSPECIALAPP,("This is our Special App \r\n")); return TRUE; } return FALSE; }
#define SetHintsFromList(a,b) ((-1))
int InitShadowDB(VOID) { //for NT, we don't have all this hint stuff....just return success
return(1); #if 0
VMMHKEY hKeyShadow; int iSize = sizeof(int), iRet = -1; DWORD dwType; extern char vszExcludeList[], vszIncludeList[]; BOOL fOpen = FALSE; char rgchList[128]; if (_RegOpenKey(HKEY_LOCAL_MACHINE, REG_KEY_SHADOW, &hKeyShadow) == ERROR_SUCCESS) { fOpen = TRUE; iSize = sizeof(rgchList); if (_RegQueryValueEx(hKeyShadow, vszExcludeList, NULL, &dwType, rgchList, &iSize)==ERROR_SUCCESS) { if (SetHintsFromList(rgchList, TRUE) < 0) goto bailout; } iSize = sizeof(rgchList); if (_RegQueryValueEx(hKeyShadow, vszIncludeList, NULL, &dwType, rgchList, &iSize)==ERROR_SUCCESS) { if (SetHintsFromList(rgchList, FALSE) < 0) goto bailout; }
iRet = 1; } bailout: if (fOpen) { _RegCloseKey(hKeyShadow); } return (iRet); #endif //0
}
int ReinitializeDatabase( LPSTR lpszLocation, LPSTR lpszUserName, DWORD nFileSizeHigh, DWORD nFileSizeLow, DWORD dwClusterSize ) { BOOL fDBReinited = FALSE; if(OpenShadowDB(lpszLocation, lpszUserName, nFileSizeHigh, nFileSizeLow, dwClusterSize, TRUE, &fDBReinited) >= 0) { if (InitShadowDB() >= 0) { Assert(fDBReinited == TRUE); fInitDB = 1; } else { CloseShadowDB(); } } if (fInitDB != 1) { fInitDB = -1; fShadow = 0; }
return (fInitDB); }
int InitDatabase( LPSTR lpszLocation, LPSTR lpszUserName, DWORD nFileSizeHigh, DWORD nFileSizeLow, DWORD dwClusterSize, BOOL fReformat, BOOL *lpfNew ) { int iRet = 1; BOOL fDBReinited = FALSE; LPSTR PrefixedLocation = NULL;
HookCmmnKdPrint(INITDATABASE,("Opening database at %s for %s with size %d \r\n", lpszLocation, lpszUserName, nFileSizeLow));
//
// When CSC is started by the kernel as part of a remote boot, the input path
// will already be in NT format.
//
if (( _strnicmp(lpszLocation,"\\Device\\Harddisk",strlen("\\Device\\Harddisk")) != 0 ) && ( _strnicmp(lpszLocation,"\\ArcName",strlen("\\ArcName")) != 0 )) {
//this would be NT only..........
PrefixedLocation = AllocMem(strlen(lpszLocation)+sizeof(NT_DB_PREFIX));
if (!PrefixedLocation) { return -1; }
strcpy(PrefixedLocation, NT_DB_PREFIX); strcat(PrefixedLocation, lpszLocation); HookCmmnKdPrint(INITDATABASE,("Opening database at %s changing to %s \r\n", lpszLocation, PrefixedLocation));
//fortunately, this is call-by-value....so i can just overwrite the input parameter
lpszLocation = PrefixedLocation; }
// Do onetime init
if (!fReadInit) { ReadInitValues(); memset(rghthreadTemp, 0, sizeof(rghthreadTemp)); fReadInit = TRUE; }
// check if the database is not already initialized
if (!fInitDB) { // open/create it
iRet = OpenShadowDB( lpszLocation, lpszUserName, nFileSizeHigh, nFileSizeLow, dwClusterSize, fReformat, &fDBReinited );
// open/create DB succeeded?
if (iRet < 0) { //no
HookCmmnKdPrint(ALWAYS,("Error Opening/Createing shadow database \r\n")); fInitDB = -1; fShadow = 0; } else { *lpfNew = fDBReinited;
// did it exist in the first place?
if (fDBReinited) { // no it didn't, let use create things like the filters and such
iRet = InitShadowDB(); }
if (iRet >= 0) { fInitDB = 1; } else { CloseShadowDB(); } } }
if (PrefixedLocation) { FreeMem(PrefixedLocation); } return (iRet); }
int CloseDatabase( VOID ) { if (fInitDB) { CloseShadowDB(); fInitDB = FALSE; return (1); } return (0); }
BOOL IsBusy ( HSHADOW hShadow ) { DeclareFindFromShadowOnNtVars()
if (PFindFdbFromHShadow(hShadow)) return TRUE; return FALSE; }
int PRIVATE DeleteShadowHelper ( BOOL fMarkDeleted, HSHADOW hDir, HSHADOW hNew ) { int iRet = -1;
if (!fMarkDeleted) { if (DeleteShadow(hDir, hNew) < SRET_OK) goto bailout; } else { if (TruncateDataHSHADOW(hDir, hNew) < SRET_OK) goto bailout; // ACHTUNG!! other people depend on status being SHADOW_DELETED
if (SetShadowInfo(hDir, hNew, NULL, SHADOW_DELETED, SHADOW_FLAGS_OR) < SRET_OK) goto bailout; } iRet = 0;
bailout:
return (iRet); }
/*+-------------------------------------------------------------------------*/ /* @doc INTERNAL HOOK
@func BOOL | InsertTunnelInfo | 2.0
The <f InsertTunnelInfo> function inserts file names in a tunnelling table. These entries are considered useful only for STALE_TUNNEL_INFO seconds. Tunnelling is used to retain LPOTHERINFO for files that get renamed/deleted and some other file is renamed to it. This typically done by editors, spreadsheets and such while saving things.
@parm HSHADOW | hDir | Directory to which this guy belongs @parm LPPE | lppe | PathELement for the file to be tunnelled @parm LPOTHERINFO | lpOI | Info to be kept with the tunnelled entry
@comm >>comment_text, <p parm> etc...
@rdesc This function returns TRUE if successful. Otherwise the return value is FALSE. @xref >><f related_func>, <t RELATEDSTRUCT> ... */
BOOL InsertTunnelInfo( HSHADOW hDir, USHORT *lpcFileName, USHORT *lpcAlternateFileName, // assume 14 USHORTs
LPOTHERINFO lpOI ) { int i, iHole = -1; ULONG uTime = IFSMgr_Get_NetTime(), cbFileName;
cbFileName = (wstrlen(lpcFileName)+1)*sizeof(USHORT); ASSERT(hDir!=0);
FreeStaleEntries(); for (i=0;i< (sizeof(rgsTunnel)/sizeof(SH_TUNNEL)); ++i) { if (!rgsTunnel[i].hDir && (iHole < 0)) { iHole = i; } if ((rgsTunnel[i].hDir==hDir) && (!wstrnicmp(lpcFileName, rgsTunnel[i].lpcFileName, MAX_PATH*sizeof(USHORT))|| !wstrnicmp( lpcFileName, rgsTunnel[i].cAlternateFileName, sizeof(rgsTunnel[i].cAlternateFileName))) ) { FreeEntry(&rgsTunnel[i]); iHole = i; break; } } if (iHole >=0) { if (!(rgsTunnel[iHole].lpcFileName = (USHORT *)AllocMem(cbFileName))) { return (FALSE); } rgsTunnel[iHole].uTime = uTime; rgsTunnel[iHole].hDir = hDir; rgsTunnel[iHole].ubHintFlags = (UCHAR)(lpOI->ulHintFlags); rgsTunnel[iHole].ubHintPri = (UCHAR)(lpOI->ulHintPri); rgsTunnel[iHole].ubIHPri = (UCHAR)(lpOI->ulIHPri); rgsTunnel[iHole].ubRefPri = (UCHAR)(lpOI->ulRefPri);
// copy without the NULL, we know that allocmem will have a NULL at the end
memcpy(rgsTunnel[iHole].lpcFileName, lpcFileName, cbFileName-sizeof(USHORT));
// assumes 14 USHORTS
memcpy( rgsTunnel[iHole].cAlternateFileName, lpcAlternateFileName, sizeof(rgsTunnel[iHole].cAlternateFileName));
HookCmmnKdPrint(TUNNELING,("InsertTunnelInfo: Inserting %ws/%ws, Hintpri=%d, HintFlags=%d RefPri=%d \r\n", lpcFileName,lpcAlternateFileName, lpOI->ulHintPri, lpOI->ulHintFlags, lpOI->ulRefPri ));
return (TRUE); } return (FALSE); }
/*+-------------------------------------------------------------------------*/ /* @doc INTERNAL HOOK
@func BOOL | RetrieveTunnelInfo | 2.0
The <f RetrieveTunnelInfo> function returns to the caller OTHERINFO structure containing priorities and such about files which have been recently renamed or deleted. Entries which are older than STALE_TUNNEL_INFO seconds are thrown out.
@parm HSHADOW | hDir | Directory to which this guy belongs @parm ushort *| lpcFileName| name of the file whose info is needed @parm LPOTHERINFO | lpOI | Info to be retrieved from the tunnelled entry
@comm >>comment_text, <p parm> etc...
@rdesc This function returns TRUE if successful. Otherwise the return value is FALSE. @xref >><f related_func>, <t RELATEDSTRUCT> ... */
#ifndef MRXSMB_BUILD_FOR_CSC_DCON
BOOL RetrieveTunnelInfo( #else
RETRIEVE_TUNNEL_INFO_RETURNS RetrieveTunnelInfo( #endif
HSHADOW hDir, USHORT *lpcFileName, WIN32_FIND_DATA *lpFind32, // if NULL, get only otherinfo
LPOTHERINFO lpOI ) { int i; #ifdef MRXSMB_BUILD_FOR_CSC_DCON
RETRIEVE_TUNNEL_INFO_RETURNS RetVal; #endif
ASSERT(hDir!=0); FreeStaleEntries(); for (i=0;i< (sizeof(rgsTunnel)/sizeof(SH_TUNNEL)); ++i) { #ifndef MRXSMB_BUILD_FOR_CSC_DCON
if (rgsTunnel[i].hDir && (!wstrnicmp(lpcFileName, rgsTunnel[i].lpcFileName, MAX_PATH*sizeof(USHORT))|| !wstrnicmp( lpcFileName, rgsTunnel[i].cAlternateFileName, sizeof(rgsTunnel[i].cAlternateFileName))) ) { #else
if (rgsTunnel[i].hDir==hDir) { if (!wstrnicmp(lpcFileName, rgsTunnel[i].cAlternateFileName, sizeof(rgsTunnel[i].cAlternateFileName)) ) { RetVal = TUNNEL_RET_SHORTNAME_TUNNEL; } else if ( !wstrnicmp(lpcFileName, rgsTunnel[i].lpcFileName, MAX_PATH*sizeof(USHORT)) ){ RetVal = TUNNEL_RET_LONGNAME_TUNNEL; } else { continue; }
#endif
InitOtherInfo(lpOI);
lpOI->ulHintFlags = (ULONG)(rgsTunnel[i].ubHintFlags); lpOI->ulHintPri = (ULONG)(rgsTunnel[i].ubHintPri); lpOI->ulIHPri = (ULONG)(rgsTunnel[i].ubIHPri);
// don't copy the reference priority, it is assigned by the record manager
// lpOI->ulRefPri = (ULONG)(rgsTunnel[i].ubRefPri);
HookCmmnKdPrint(TUNNELING,("RetrieveTunnelInfo: %ws found, Hintpri=%d, HintFlags=%d RefPri=%d \r\n", lpcFileName, lpOI->ulHintPri, lpOI->ulHintFlags, lpOI->ulRefPri ));
if (lpFind32) { memcpy( lpFind32->cFileName, rgsTunnel[i].lpcFileName, (wstrlen(rgsTunnel[i].lpcFileName)+1)*sizeof(USHORT) ); memcpy( lpFind32->cAlternateFileName, rgsTunnel[i].cAlternateFileName, sizeof(rgsTunnel[i].cAlternateFileName) ); HookCmmnKdPrint(TUNNELING,("Recovered LFN %ws/%ws \r\n", lpFind32->cFileName, lpFind32->cAlternateFileName)); }
FreeEntry(&rgsTunnel[i]); #ifndef MRXSMB_BUILD_FOR_CSC_DCON
return (TRUE); } } return (FALSE); #else
return (RetVal); } } return (TUNNEL_RET_NOTFOUND); #endif
}
VOID FreeStaleEntries() { int i; ULONG uTime = IFSMgr_Get_NetTime();
for (i=0;i< (sizeof(rgsTunnel)/sizeof(SH_TUNNEL)); ++i) { if (rgsTunnel[i].lpcFileName && ((uTime- rgsTunnel[i].uTime)>STALE_TUNNEL_INFO)) { FreeEntry(&rgsTunnel[i]); } }
}
void FreeEntry(LPSH_TUNNEL lpshTunnel) { FreeMem(lpshTunnel->lpcFileName); memset(lpshTunnel, 0, sizeof(SH_TUNNEL)); }
//got this from hook.c...not the same because w95 looks at the
//resource flags directly
BOOL IsShadowVisible( #ifdef MRXSMB_BUILD_FOR_CSC_DCON
BOOLEAN Disconnected, #else
PRESOURCE pResource, #endif //ifdef MRXSMB_BUILD_FOR_CSC_DCON
DWORD dwAttr, ULONG uShadowStatus ) { BOOL fVisible = 1;
// To a filesystem API the shadow is never visible when it is marked
// as being deleted
if (mShadowDeleted(uShadowStatus)) return (0);
#ifdef MRXSMB_BUILD_FOR_CSC_DCON
if (Disconnected) #else
if (mIsDisconnected(pResource)) #endif //ifdef MRXSMB_BUILD_FOR_CSC_DCON
{ if (IsFile(dwAttr)) { #ifdef OFFLINE
#ifdef CSC_RECORDMANAGER_WINNT
ASSERT(FALSE); #endif //ifdef CSC_RECORDMANAGER_WINNT
if (mIsOfflineConnection(pResource)) { // offline connection
if (!mShadowOutofSync(uShadowStatus)) { fVisible = 0; } } else #endif //OFFLINE
{// pure disconnected state
// ignore sparse files
if (mShadowSparse(uShadowStatus)) { fVisible = 0; } } } } else { // connected state, bypass all out of ssync files, doesn't include
// stale, because we can handle staleness during open
if (IsFile(dwAttr)) { if (mShadowOutofSync(uShadowStatus)) { fVisible = 0; } } else if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) { // and locallycreated or orphaned directories
if (mQueryBits(uShadowStatus, SHADOW_LOCALLY_CREATED|SHADOW_ORPHAN)) { fVisible = 0; } } } return (fVisible); }
//got this from hook.c...not the same because w95 looks at the
//resource flags directly
//CODE.IMPROVEMENT we should define a common header for RESOURCE and FDB so that most stuff
// would just work.
int MarkShareDirty( PUSHORT ShareStatus, ULONG hShare ) {
if (!mQueryBits(*ShareStatus, SHARE_REINT)) { SetShareStatus(hShare, SHARE_REINT, SHADOW_FLAGS_OR); mSetBits(*ShareStatus, SHARE_REINT); } return SRET_OK; }
#endif //ifdef CSC_RECORDMANAGER_WINNT
|