690 lines
21 KiB
C++
690 lines
21 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();
|
|
// --------------------------------------------------------
|
|
}
|
|
|