Windows2003-3790/inetsrv/query/cicat/acinotfy.cxx

689 lines
22 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1998.
//
// File: acinotfy.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 2-26-96 srikants Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <tgrow.hxx>
#include <ffenum.hxx>
#include <docstore.hxx>
#include <lcase.hxx>
#include <eventlog.hxx>
#include <cievtmsg.h>
#include "acinotfy.hxx"
#include "cicat.hxx"
CWorkQueue TheFrameworkClientWorkQueue( 0,
CWorkQueue::workQueueFrmwrkClient );
//+---------------------------------------------------------------------------
//
// Function: CCiSyncProcessNotify::CCiSyncProcessNotify
//
// Synopsis: Constructor
//
// Arguments: [cicat] -- Catalog
// [scanMgr] -- Scan thread manager
// [pbChange] -- Change buffer
// [wcsRoot] -- Root dir for notifications
// [fAbort] -- Abort ?
//
// History: 20-Mar-96 SitaramR Added header
//
//----------------------------------------------------------------------------
CCiSyncProcessNotify::CCiSyncProcessNotify( CiCat & cicat,
CCiScanMgr & scanMgr,
BYTE const * pbChanges,
WCHAR const * wcsRoot,
BOOL & fAbort )
:_cicat(cicat),
_scanMgr(scanMgr),
_changeQueue(pbChanges),
_rootLen(0),
_fAbort(fAbort),
_nUpdates(0)
{
_lowerFunnyPath.SetPath( wcsRoot, _rootLen = wcslen( wcsRoot ) );
Win4Assert( (_lowerFunnyPath.GetActualPath())[_rootLen-1] == L'\\' );
}
//+---------------------------------------------------------------------------
//
// Member: CCiSyncProcessNotify::DoIt
//
// Synopsis: Processes changes notifications
//
// History: 3-07-96 srikants Created
//
//----------------------------------------------------------------------------
void CCiSyncProcessNotify::DoIt()
{
FILETIME ftNow;
GetSystemTimeAsFileTime( &ftNow );
NTSTATUS status = STATUS_SUCCESS;
TRY
{
CDirNotifyEntry const * pNotify = _changeQueue.First();
//
// Iterate through changes
//
for ( ;
0 != pNotify;
pNotify = _changeQueue.Next() )
{
if ( _fAbort )
break;
_nUpdates++;
_relativePathLen = pNotify->PathSize() / sizeof(WCHAR);
Win4Assert( _relativePathLen > 0 );
_lowerFunnyPath.Truncate( _rootLen );
_lowerFunnyPath.AppendPath( pNotify->Path(), _relativePathLen );
switch ( pNotify->Change() )
{
case FILE_ACTION_MODIFIED:
case FILE_ACTION_ADDED_STREAM:
case FILE_ACTION_REMOVED_STREAM:
case FILE_ACTION_MODIFIED_STREAM:
{
ciDebugOut(( DEB_FSNOTIFY, "Updating file %ws. Change code 0x%X\n",
_lowerFunnyPath.GetActualPath(), pNotify->Change() ));
ULONG ulFileAttrib = GetFileAttributes( _lowerFunnyPath.GetPath() );
//
// If we got an error value for file attributes, then substitute zero
// because we don't want the directory bit to be turned on
//
if ( ulFileAttrib == 0xFFFFFFFF )
ulFileAttrib = 0;
if ( IsShortName() )
{
ciDebugOut(( DEB_IWARN, "Converting %ws to long filename ",
_lowerFunnyPath.GetActualPath() ));
if ( ConvertToLongName() )
{
ciDebugOut(( DEB_IWARN | DEB_NOCOMPNAME, "\t%ws\n",
_lowerFunnyPath.GetActualPath() ));
}
else
{
ciDebugOut(( DEB_WARN,
"Couldn't convert short filename %ws. Scope will be scanned.\n",
_lowerFunnyPath.GetActualPath() ));
RescanCurrentPath();
break;
}
}
_cicat.Update( _lowerFunnyPath, FALSE, ftNow, ulFileAttrib ); // Not a deletion
break;
}
case FILE_ACTION_ADDED:
{
ULONG ulFileAttrib = GetFileAttributes( _lowerFunnyPath.GetPath() );
if ( IsShortName() )
{
ciDebugOut(( DEB_IWARN, "Converting %ws to long filename ",
_lowerFunnyPath.GetActualPath() ));
if ( ConvertToLongName() )
{
ciDebugOut(( DEB_IWARN | DEB_NOCOMPNAME, "\t%ws\n",
_lowerFunnyPath.GetActualPath() ));
}
else
{
ciDebugOut(( DEB_WARN,
"Couldn't convert short filename %ws. Scope will be scanned.\n",
_lowerFunnyPath.GetActualPath() ));
RescanCurrentPath();
break;
}
}
if ( ulFileAttrib == 0xFFFFFFFF )
{
ciDebugOut(( DEB_FSNOTIFY,
"Adding file %ws. Change code 0x%X\n",
_lowerFunnyPath.GetActualPath(),
pNotify->Change() ));
ulFileAttrib = 0;
_cicat.Update( _lowerFunnyPath, FALSE, ftNow, ulFileAttrib );
}
else
{
if ( ulFileAttrib & FILE_ATTRIBUTE_DIRECTORY )
{
ciDebugOut(( DEB_FSNOTIFY,
"Adding directory %ws. Change code 0x%X\n",
_lowerFunnyPath.GetActualPath(),
pNotify->Change() ));
//
// Append '\' and convert to lower case
//
_lowerFunnyPath.AppendBackSlash();
_scanMgr.DirAddNotification( _lowerFunnyPath.GetActualPath() );
}
else
{
ciDebugOut(( DEB_FSNOTIFY,
"Adding file %ws. Change code 0x%X\n",
_lowerFunnyPath.GetActualPath(),
pNotify->Change() ));
_cicat.Update( _lowerFunnyPath, FALSE, ftNow, ulFileAttrib );
}
}
break;
}
case FILE_ACTION_REMOVED:
{
if ( IsShortName() )
{
//
// File is in the index with a long name. Need to rescan scope.
// Still worth trying the immediate delete as well.
//
ciDebugOut(( DEB_WARN,
"Missed deletion of short filename %ws. Scope will be scanned.\n",
_lowerFunnyPath.GetActualPath() ));
Report8Dot3Delete();
RescanCurrentPath();
}
if ( _cicat.IsDirectory( &_lowerFunnyPath, 0 ) )
{
ciDebugOut(( DEB_FSNOTIFY,
"Deleting directory %ws. Change code 0x%X\n",
_lowerFunnyPath.GetActualPath(),
pNotify->Change() ));
_lowerFunnyPath.AppendBackSlash();
_scanMgr.RemoveScope( _lowerFunnyPath.GetActualPath() );
}
else
{
ciDebugOut(( DEB_FSNOTIFY,
"Deleting file %ws. Change code 0x%X\n",
_lowerFunnyPath.GetActualPath(),
pNotify->Change() ));
_cicat.Update( _lowerFunnyPath, TRUE, ftNow, 0 );
}
break;
}
case FILE_ACTION_RENAMED_OLD_NAME:
{
if ( IsShortName() )
{
ciDebugOut(( DEB_WARN,
"Old file \"%ws\" is a short name. Scope will be rescanned.\n",
_lowerFunnyPath.GetActualPath() ));
RescanCurrentPath();
break;
}
//
// Look at next notification entry (don't advance) to see if
// it is a renamed notification
//
CDirNotifyEntry const *pNotifyNext = _changeQueue.NextLink();
if ( pNotifyNext &&
pNotifyNext->Change() == FILE_ACTION_RENAMED_NEW_NAME )
{
//
// Advance to next notification entry and get the new name
//
pNotify = _changeQueue.Next();
ULONG relativeNewPathLen = pNotify->PathSize()/sizeof( WCHAR );
Win4Assert( relativeNewPathLen > 0 );
CLowerFunnyPath lcaseFunnyNewName( _lowerFunnyPath );
lcaseFunnyNewName.Truncate( _rootLen );
lcaseFunnyNewName.AppendPath( pNotify->Path(), relativeNewPathLen );
if ( _cicat.IsDirectory( &_lowerFunnyPath, &lcaseFunnyNewName ) )
{
ciDebugOut(( DEB_FSNOTIFY,
"Renaming directory %ws. Change code 0x%X\n",
_lowerFunnyPath.GetActualPath(),
pNotify->Change() ));
_lowerFunnyPath.AppendBackSlash();
lcaseFunnyNewName.AppendBackSlash();
_scanMgr.DirRenameNotification( _lowerFunnyPath.GetActualPath(),
lcaseFunnyNewName.GetActualPath() );
}
else
{
//
// Delete old file
//
ciDebugOut(( DEB_FSNOTIFY,
"Deleting file %ws. Change code 0x%X\n",
_lowerFunnyPath.GetActualPath(),
pNotify->Change() ));
_cicat.Update( _lowerFunnyPath, TRUE, ftNow, 0 );
//
// Add new file
//
ULONG ulFileAttrib = GetFileAttributes( lcaseFunnyNewName.GetPath() );
if ( ulFileAttrib == 0xFFFFFFFF )
ulFileAttrib = 0;
ciDebugOut(( DEB_FSNOTIFY,
"Adding file %ws. Change code 0x%X\n",
lcaseFunnyNewName.GetActualPath(),
pNotify->Change() ));
_cicat.Update( lcaseFunnyNewName, FALSE, ftNow, ulFileAttrib );
}
}
else
{
ciDebugOut(( DEB_ERROR,
"Renaming directory %ws, file_action_renamed_new_name notification not found\n",
_lowerFunnyPath.GetActualPath() ));
}
break;
}
case FILE_ACTION_RENAMED_NEW_NAME:
//
// We might have skipped the old path because it is too big or
// because it was a short name.
// A later scan will pick up the file if appropriate.
//
break;
default:
ciDebugOut(( DEB_ERROR, "Unknown modification type 0x%X\n",
pNotify->Change() ));
Win4Assert( !"Unknown modification type" );
break;
}
}
}
CATCH( CException, e )
{
ciDebugOut(( DEB_ERROR,
"CCiSyncProcessNotify::DoIt - Error 0x%X while processing changes\n",
e.GetErrorCode() ));
status = e.GetErrorCode();
}
END_CATCH
if ( !_fAbort )
{
if ( STATUS_SUCCESS == status )
{
_cicat.IncrementUpdateCount( _nUpdates );
}
else
{
_cicat.HandleError( status );
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CCiSyncProcessNotify::IsShortName, private
//
// Returns: TRUE if current file is potentially a short (8.3) name for
// a file with a long name.
//
// History: 06-Jan-98 KyleP Created
//
//----------------------------------------------------------------------------
BOOL CCiSyncProcessNotify::IsShortName()
{
//
// First, see if this is possibly a short name (has ~ in final component).
//
BOOL fTwiddle = FALSE;
unsigned ccFN = 0;
unsigned cDot = 0;
const WCHAR * const pwcsFullPath = _lowerFunnyPath.GetActualPath();
for ( int i = _rootLen + _relativePathLen; i >= 0 && ccFN < 13; i-- )
{
//
// Note: Ed Lau tested to confirm that we don't have to all ~ at the beginning
//
if ( pwcsFullPath[i] == L'~' && pwcsFullPath[i-1] != L'\\' )
fTwiddle = TRUE;
else if ( pwcsFullPath[i] == L'.' )
{
// max extension length is 3
// valid short names don't start with '.' (except . and ..)
if ( ccFN > 3 || pwcsFullPath[i-1] == L'\\' )
return FALSE;
cDot++;
}
else if ( pwcsFullPath[i] == L'\\' )
break;
ccFN++;
}
if (fTwiddle)
{
// short names can't have more than 1 '.'
// max filename size if no extension is 8
if (cDot >= 2 || cDot == 0 && ccFN > 8)
return FALSE;
// check for min (e.g., EXT~1 for .ext) and max lengths
if (ccFN >= 5 && ccFN <= 12)
return TRUE;
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Member: CCiSyncProcessNotify::ConvertToLongName, private
//
// Synopsis: Converts current filename from a short name to a long name.
//
// Returns: TRUE if conversion was successful.
//
// History: 06-Jan-98 KyleP Created
//
//----------------------------------------------------------------------------
BOOL CCiSyncProcessNotify::ConvertToLongName()
{
return _lowerFunnyPath.ConvertToLongName();
}
//+---------------------------------------------------------------------------
//
// Member: CCiSyncProcessNotify::RescanCurrentPath, private
//
// Synopsis: Rescans directory
//
// History: 06-Jan-98 KyleP Created
//
//----------------------------------------------------------------------------
void CCiSyncProcessNotify::RescanCurrentPath()
{
//
// Rescan whole directory.
//
WCHAR wcTemp;
WCHAR * pwcsFullPath = (WCHAR*)_lowerFunnyPath.GetActualPath();
for ( int i = _rootLen + _relativePathLen; i >= 0; i-- )
{
if ( pwcsFullPath[i] == L'\\' )
{
i++;
wcTemp = pwcsFullPath[i];
pwcsFullPath[i] = 0;
break;
}
}
_cicat.ReScanPath( pwcsFullPath, // Path
TRUE ); // Delayed
pwcsFullPath[i] = wcTemp;
}
//+---------------------------------------------------------------------------
//
// Member: CCiSyncProcessNotify::Report8Dot3Delete, private
//
// Synopsis: Writes event log message identifying slow rescan due to
// short filename delete.
//
// History: 06-Jan-98 KyleP Created
//
//----------------------------------------------------------------------------
void CCiSyncProcessNotify::Report8Dot3Delete()
{
TRY
{
CEventLog eventLog( NULL, wcsCiEventSource );
CEventItem item( EVENTLOG_WARNING_TYPE,
CI_SERVICE_CATEGORY,
MSG_CI_DELETE_8DOT3_NAME,
1 );
item.AddArg( _lowerFunnyPath.GetActualPath() );
eventLog.ReportEvent( item );
}
CATCH( CException, e )
{
ciDebugOut(( DEB_ERROR,
"Exception 0x%X while writing to event log\n",
e.GetErrorCode() ));
}
END_CATCH
}
//+---------------------------------------------------------------------------
//
// Member: ~ctor of CCiAsyncProcessNotify
//
// Synopsis: Primes the changequeue member with the given data.
//
// Arguments: [cicat] -
// [pbChanges] - Pointer to the list of changes.
// [cbChanges] - Number of bytes in pbChanges.
// [wcsRoot] - Root of the scope for changes.
//
// History: 2-28-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
CCiAsyncProcessNotify::CCiAsyncProcessNotify( CWorkManager & workMan,
CiCat & cicat,
CCiScanMgr & scanMgr,
XArray<BYTE> & xChanges,
WCHAR const * wcsRoot )
: CFwAsyncWorkItem( workMan, TheFrameworkClientWorkQueue),
_changes( cicat,
scanMgr,
xChanges.GetPointer(),
wcsRoot ,
_fAbort )
{
_pbChanges = xChanges.Acquire();
}
//+---------------------------------------------------------------------------
//
// Member: CCiAsyncProcessNotify::DoIt
//
// Synopsis: Processes the changes in the change buffer.
//
// Arguments: [pThread] -- Thread actually completing request.
//
// History: 2-26-96 srikants Created
//
//----------------------------------------------------------------------------
void CCiAsyncProcessNotify::DoIt( CWorkThread * pThread )
{
// ====================================
{
CLock lock(_mutex);
_fOnWorkQueue = FALSE;
}
// ====================================
// --------------------------------------------------------
AddRef();
_changes.DoIt();
Done();
Release();
// --------------------------------------------------------
}
//+---------------------------------------------------------------------------
//
// Member: CIISVRootAsyncNotify::DoIt
//
// Synopsis: Process IIS VRoot change notification.
//
// Arguments: [pThread] -
//
// History: 4-11-96 srikants Created
//
//----------------------------------------------------------------------------
void CIISVRootAsyncNotify::DoIt( CWorkThread * pThread )
{
// ====================================
{
CLock lock(_mutex);
_fOnWorkQueue = FALSE;
}
// ====================================
// --------------------------------------------------------
AddRef();
ciDebugOut(( DEB_WARN, "Processing IIS vroot change...\n" ));
_cicat.SynchWithIIS();
Done();
Release();
// --------------------------------------------------------
}
//+---------------------------------------------------------------------------
//
// Member: CRegistryScopesAsyncNotify::DoIt
//
// Synopsis: Process registry scopes registry change notification.
//
// Arguments: [pThread] -
//
// History: 4-11-96 srikants Created
//
//----------------------------------------------------------------------------
void CRegistryScopesAsyncNotify::DoIt( CWorkThread * pThread )
{
// ====================================
{
CLock lock(_mutex);
_fOnWorkQueue = FALSE;
}
// ====================================
// --------------------------------------------------------
AddRef();
ciDebugOut(( DEB_WARN, "Processing registry scopes change...\n" ));
_cicat.SynchWithRegistryScopes();
Done();
Release();
// --------------------------------------------------------
}
//+---------------------------------------------------------------------------
//
// Member: CStartFilterDaemon::DoIt
//
// Synopsis: Starts the filter daemon process.
//
// Arguments: [pThread] - A worker thread pointer.
//
// History: 12-23-96 srikants Created
//
//----------------------------------------------------------------------------
void CStartFilterDaemon::DoIt( CWorkThread * pThread )
{
// ====================================
{
CLock lock(_mutex);
_fOnWorkQueue = FALSE;
}
// ====================================
// --------------------------------------------------------
AddRef();
_docStore._StartFiltering();
Done();
Release();
// --------------------------------------------------------
}