906 lines
27 KiB
C++
906 lines
27 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1991 - 2000.
|
|
//
|
|
// File: UPDATE.CXX
|
|
//
|
|
// Contents: Content Index Update
|
|
//
|
|
// History: 19-Mar-92 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <imprsnat.hxx>
|
|
#include <pathpars.hxx>
|
|
#include <cifrmcom.hxx>
|
|
#include <lcase.hxx>
|
|
|
|
#include "cicat.hxx"
|
|
#include "update.hxx"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CImpersonatedFindFirst
|
|
//
|
|
// Purpose: A class that is capable of repeatedly trying to do a find
|
|
// first until there is success or is not retryable any more.
|
|
// Changes impersonation between attempts.
|
|
//
|
|
// History: 7-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CImpersonatedFindFirst: public PImpersonatedWorkItem
|
|
{
|
|
|
|
public:
|
|
|
|
CImpersonatedFindFirst( const CFunnyPath & funnyPath, HANDLE & h )
|
|
: PImpersonatedWorkItem( funnyPath.GetActualPath() ),
|
|
_funnyPath( funnyPath ),
|
|
_h(h)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
BOOL OpenFindFirst( CImpersonateRemoteAccess & remoteAccess );
|
|
|
|
BOOL DoIt(); // virtual
|
|
|
|
private:
|
|
|
|
HANDLE & _h;
|
|
const CFunnyPath & _funnyPath;
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonatedFindFirst::OpenFindFirst
|
|
//
|
|
// Synopsis: Opens the first first handle, impersonating as necessary.
|
|
//
|
|
// Arguments: [remoteAccess] -
|
|
//
|
|
// Returns: TRUE if successful; FALSE o/w
|
|
//
|
|
// History: 7-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CImpersonatedFindFirst::OpenFindFirst(
|
|
CImpersonateRemoteAccess & remoteAccess )
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
|
|
TRY
|
|
{
|
|
ImpersonateAndDoWork( remoteAccess );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "OpenFindFirst (%ws) failed with error (0x%X)\n",
|
|
_funnyPath.GetPath(), e.GetErrorCode() ));
|
|
fSuccess = FALSE;
|
|
}
|
|
END_CATCH
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CImpersonatedFindFirst::DoIt
|
|
//
|
|
// Synopsis: The worker method that does the work in the context of
|
|
// impersonation.
|
|
//
|
|
// Returns: TRUE if successful; FALSE if should be retried; THROWS
|
|
// otherwise.
|
|
//
|
|
// History: 7-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CImpersonatedFindFirst::DoIt()
|
|
{
|
|
//
|
|
// Open directory
|
|
//
|
|
|
|
NTSTATUS Status =
|
|
CiNtOpenNoThrow( _h,
|
|
_funnyPath.GetPath(),
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
|
|
|
|
if ( !NT_SUCCESS(Status) )
|
|
{
|
|
if ( IsRetryableError( Status ) )
|
|
return FALSE;
|
|
else
|
|
{
|
|
THROW( CException( Status ) );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
} //DoIt
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTraverse::CTraverse
|
|
//
|
|
// Synopsis: Constructor of the CTraverse class.
|
|
//
|
|
// Arguments: [fAbort] - A reference to an abort triggering variable.
|
|
//
|
|
// History: 3-15-96 srikants Split from CUpdate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CTraverse::CTraverse( CiCat & cat,
|
|
BOOL & fAbort,
|
|
BOOL fProcessRoot )
|
|
: _cat( cat ),
|
|
_fAbort(fAbort),
|
|
_fProcessRoot(fProcessRoot),
|
|
_cProcessed( 0 ),
|
|
_xbBuf( FINDFIRST_SIZE ),
|
|
_pCurEntry( 0 ),
|
|
_status( STATUS_SUCCESS )
|
|
{
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTraverse::DoIt
|
|
//
|
|
// Synopsis: Traverses the tree from the given root and invokes the
|
|
// "ProcessFile" method on all the files found. Also, before
|
|
// starting to traverse a directory, it calls the
|
|
// "IsEligibleForTraversal()" method on that.
|
|
//
|
|
// Arguments: [lcaseFunnyRootPath] - The path to traverse.
|
|
//
|
|
// History: 3-15-96 srikants Split from CUpdate constructor
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CTraverse::DoIt( const CLowerFunnyPath & lcaseFunnyRootPath )
|
|
{
|
|
Push( lcaseFunnyRootPath );
|
|
|
|
if ( _fProcessRoot )
|
|
{
|
|
Win4Assert( 0 == _pCurEntry );
|
|
|
|
// Note this is a bit of a hack. Only the attributes field is valid.
|
|
|
|
_pCurEntry = (CDirEntry *)_xbBuf.GetPointer();
|
|
|
|
ULONG ulAttrib = 0;
|
|
|
|
if ( CImpersonateRemoteAccess::IsNetPath( lcaseFunnyRootPath.GetActualPath() ) )
|
|
{
|
|
CImpersonateRemoteAccess remote( _cat.GetImpersonationTokenCache() );
|
|
CImpersonatedGetFileAttr getAttr( lcaseFunnyRootPath );
|
|
|
|
getAttr.DoWork( remote );
|
|
ulAttrib = getAttr.GetAttr();
|
|
}
|
|
else
|
|
{
|
|
ulAttrib = GetFileAttributes( lcaseFunnyRootPath.GetPath() );
|
|
}
|
|
|
|
_pCurEntry->SetAttributes( ulAttrib );
|
|
|
|
//
|
|
// 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 ( INVALID_FILE_ATTRIBUTES == _pCurEntry->Attributes() )
|
|
_pCurEntry->SetAttributes( 0 );
|
|
|
|
if ( !ProcessFile( lcaseFunnyRootPath ) )
|
|
return;
|
|
}
|
|
|
|
CImpersonateRemoteAccess remote( _cat.GetImpersonationTokenCache() );
|
|
|
|
for (;;)
|
|
{
|
|
XPtr<CLowerFunnyPath> xLowerFunnyPath;
|
|
|
|
if ( !Pop( xLowerFunnyPath ) )
|
|
break;
|
|
|
|
if ( !Traverse(xLowerFunnyPath, remote))
|
|
break;
|
|
}
|
|
} //DoIt
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTraverse::Traverse
|
|
//
|
|
// Synopsis: Traverses the specified directory.
|
|
//
|
|
// Arguments: [dir] -
|
|
//
|
|
// History: 3-15-96 srikants Split from CUpdate::Traverse
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CTraverse::Traverse (XPtr<CLowerFunnyPath> & xLowerFunnyPath, CImpersonateRemoteAccess & remote )
|
|
{
|
|
if ( !IsEligibleForTraversal( xLowerFunnyPath.GetReference() ) )
|
|
{
|
|
ciDebugOut (( DEB_ITRACE, "Traverse skipping %ws\n", xLowerFunnyPath->GetActualPath() ));
|
|
return TRUE;
|
|
}
|
|
|
|
TraversalIdle();
|
|
|
|
CFullPath fullPath( xLowerFunnyPath->GetActualPath(), xLowerFunnyPath->GetActualLength() );
|
|
|
|
ciDebugOut (( DEB_ITRACE, "Traversing %ws\n", fullPath.GetBuf()));
|
|
|
|
ULONG cSkip = 0;
|
|
|
|
HANDLE h;
|
|
|
|
if ( CImpersonateRemoteAccess::IsNetPath( xLowerFunnyPath->GetActualPath() ) )
|
|
{
|
|
CImpersonatedFindFirst findFirst( fullPath.GetFunnyPath(), h );
|
|
|
|
if ( !findFirst.OpenFindFirst( remote ) )
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Open directory
|
|
//
|
|
|
|
NTSTATUS Status =
|
|
CiNtOpenNoThrow( h,
|
|
xLowerFunnyPath->GetPath(),
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
|
|
|
|
if ( !NT_SUCCESS(Status) )
|
|
return TRUE;
|
|
}
|
|
|
|
SHandle xHandle(h);
|
|
|
|
//
|
|
// First enumeration
|
|
//
|
|
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS Status;
|
|
|
|
Status = NtQueryDirectoryFile( h, // File
|
|
0, // Event
|
|
0, // APC routine
|
|
0, // APC context
|
|
&IoStatus, // I/O Status
|
|
_xbBuf.GetPointer(), // Buffer
|
|
_xbBuf.SizeOf(), // Buffer Length
|
|
FileBothDirectoryInformation,
|
|
0, // Multiple entry
|
|
0, // Filename
|
|
1 ); // Restart scan
|
|
|
|
if ( NT_SUCCESS(Status) )
|
|
Status = IoStatus.Status;
|
|
|
|
//
|
|
// If there are no more files or we don't have access to any more files
|
|
// in this branch of the tree, just continue traversing. Otherwise throw.
|
|
//
|
|
|
|
if ( !NT_SUCCESS(Status) )
|
|
{
|
|
if ( STATUS_NO_MORE_FILES == Status ||
|
|
STATUS_NO_SUCH_FILE == Status ||
|
|
STATUS_ACCESS_DENIED == Status )
|
|
return TRUE;
|
|
|
|
THROW( CException( Status ) );
|
|
}
|
|
|
|
_pCurEntry = (CDirEntry *)_xbBuf.GetPointer();
|
|
BOOL fMore = TRUE;
|
|
|
|
ULONG ulScanBackoff = _cat.GetRegParams()->GetScanBackoff();
|
|
|
|
do
|
|
{
|
|
//
|
|
// Sleep for a while to let other I/O get through if appropriate.
|
|
//
|
|
// For reference, with 105,000 files on a free build, here are the
|
|
// scan times ( for mod of 50 and sleep(200) * ulScanBackoff )
|
|
//
|
|
// ScanBackoff Time (min:sec)
|
|
// ----------- --------------
|
|
// 0 8:40
|
|
// 1 18:03
|
|
// 3 43:11
|
|
//
|
|
|
|
if ( 0 != ulScanBackoff )
|
|
{
|
|
if ( ulScanBackoff > CI_SCAN_BACKOFF_MAX_RANGE )
|
|
{
|
|
//
|
|
// These values are reserved for future use.
|
|
//
|
|
}
|
|
else if ( ( _cProcessed % 50 ) == 0 )
|
|
{
|
|
for ( unsigned i = 0; !_fAbort && i < ulScanBackoff; i++ )
|
|
Sleep( 100 );
|
|
|
|
//
|
|
// If we're running ahead of filtering, then let's take a break.
|
|
// What's the point in running up a big change log for no reason?
|
|
//
|
|
// Attempt to keep primary and secondary store pages in memory.
|
|
// The primary store keeps 1489 records per 64k page and the
|
|
// secondary by default keeps 140. By keeping the scan
|
|
// thread only a little ahead of the filter thread we
|
|
// thrash less.
|
|
//
|
|
|
|
unsigned cLoops = 0;
|
|
|
|
while ( !_fAbort )
|
|
{
|
|
CI_STATE State;
|
|
State.cbStruct = sizeof State;
|
|
|
|
SCODE sc = _cat.CiState( State );
|
|
|
|
if ( FAILED(sc) ||
|
|
( (State.cDocuments - State.cSecQDocuments) < 200 &&
|
|
( 0 == (State.eState & ( CI_STATE_HIGH_IO |
|
|
CI_STATE_LOW_MEMORY |
|
|
CI_STATE_USER_ACTIVE ) ) ) ) )
|
|
break;
|
|
|
|
//
|
|
// Only call TraverseIdle if filtering has been stalled
|
|
// for a long time -- every 60 seconds or so.
|
|
//
|
|
|
|
cLoops++;
|
|
|
|
if ( 0 == ( cLoops % 30 ) )
|
|
TraversalIdle( TRUE ); // TRUE --> Stalled (not scanning)
|
|
|
|
//
|
|
// Sleep for a few of seconds, checking for abort.
|
|
//
|
|
|
|
for ( unsigned i = 0; !_fAbort && i < 3; i++ )
|
|
Sleep( 100 );
|
|
}
|
|
}
|
|
}
|
|
|
|
_cProcessed++;
|
|
|
|
//
|
|
// Get out?
|
|
//
|
|
|
|
if ( _fAbort )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "Aborting scan in the middle\n" ));
|
|
break;
|
|
}
|
|
|
|
fullPath.MakePath( _pCurEntry->Filename(), _pCurEntry->FilenameSize() / sizeof(WCHAR) );
|
|
|
|
BOOL fSkipFile = FALSE;
|
|
|
|
// If it's a directory and not a reparse point, push it on the stack
|
|
|
|
if ( ( 0 != ( _pCurEntry->Attributes() & FILE_ATTRIBUTE_DIRECTORY ) ) &&
|
|
( 0 == ( _pCurEntry->Attributes() & FILE_ATTRIBUTE_REPARSE_POINT ) ) )
|
|
{
|
|
if ( _pCurEntry->Filename()[0] == L'.' &&
|
|
( _pCurEntry->FilenameSize() == sizeof(WCHAR) ||
|
|
(_pCurEntry->Filename()[1] == L'.' && _pCurEntry->FilenameSize() == sizeof(WCHAR) * 2 ) ) )
|
|
{
|
|
fSkipFile = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Neither "." nor ".." directories
|
|
|
|
Push( fullPath.GetFunnyPath() );
|
|
}
|
|
}
|
|
|
|
if ( !fSkipFile )
|
|
if ( !ProcessFile( fullPath.GetFunnyPath() ) )
|
|
{
|
|
_status = HRESULT_FROM_WIN32( GetLastError() );
|
|
return FALSE;
|
|
}
|
|
|
|
_pCurEntry = _pCurEntry->Next();
|
|
|
|
if ( 0 == _pCurEntry )
|
|
{
|
|
Status = NtQueryDirectoryFile( h, // File
|
|
0, // Event
|
|
0, // APC routine
|
|
0, // APC context
|
|
&IoStatus, // I/O Status
|
|
_xbBuf.GetPointer(), // Buffer
|
|
_xbBuf.SizeOf(), // Buffer Length
|
|
FileBothDirectoryInformation,
|
|
0, // Multiple entry
|
|
0, // Filename
|
|
0 ); // Continue scan
|
|
|
|
if ( NT_SUCCESS(Status) )
|
|
Status = IoStatus.Status;
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
_pCurEntry = (CDirEntry *)_xbBuf.GetPointer();
|
|
else
|
|
fMore = FALSE;
|
|
}
|
|
} while ( fMore );
|
|
|
|
if ( !_fAbort )
|
|
{
|
|
if ( STATUS_NO_SUCH_FILE == Status )
|
|
Status = STATUS_NO_MORE_FILES;
|
|
|
|
_status = Status;
|
|
|
|
return STATUS_NO_MORE_FILES == _status;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CUpdate::CUpdate, public
|
|
//
|
|
// Synopsis: Perform update of scope. All work done from constructor.
|
|
//
|
|
// Arguments: [cat] -- Catalog
|
|
// [lcaseFunnyRootPath] -- Root of scope
|
|
// [PartId] -- Partition id
|
|
// [fIncrem] -- TRUE if this is an incremental update
|
|
//
|
|
// History: 04-Jan-96 KyleP Added header
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
CUpdate::CUpdate ( CiCat& cat,
|
|
ICiManager & ciManager,
|
|
const CLowerFunnyPath & lcaseFunnyRootPath,
|
|
PARTITIONID PartId,
|
|
BOOL fIncrem,
|
|
BOOL fDoDeletions,
|
|
BOOL & fAbort,
|
|
BOOL fProcessRoot )
|
|
: CTraverse( cat, fAbort, fProcessRoot ),
|
|
_ciManager(ciManager),
|
|
_cDoc(0),
|
|
_PartId(PartId),
|
|
_fIncrem(fIncrem),
|
|
_fDoDeletions(fDoDeletions)
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "CUpdate::CUpdate root: '%ws', fAbort: %d\n",
|
|
lcaseFunnyRootPath.GetActualPath(), fAbort ));
|
|
|
|
BOOL fRootDeleted = FALSE;
|
|
|
|
//
|
|
// If the rootPath is a network path, it is possible that the connection
|
|
// is down. _cat.StartUpdate() is a fairly expensive operation because it
|
|
// involves scanning the whole property store.
|
|
// Before doing any further processing, just check if we can
|
|
// open the path and get some information on it.
|
|
//
|
|
// Also, check that the root of the scope exists. If not, delete the
|
|
// files in the scope
|
|
//
|
|
|
|
if ( CImpersonateRemoteAccess::IsNetPath( lcaseFunnyRootPath.GetActualPath() ) )
|
|
{
|
|
CImpersonateRemoteAccess remote( _cat.GetImpersonationTokenCache() );
|
|
|
|
TRY
|
|
{
|
|
CImpersonatedGetAttr getAttr( lcaseFunnyRootPath );
|
|
getAttr.DoWork( remote );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"CUpdate::CUpdate(a) can't get attrinfo: %#x, for %ws\n",
|
|
e.GetErrorCode(), lcaseFunnyRootPath.GetActualPath()));
|
|
if ( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) != e.GetErrorCode() ||
|
|
HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) != e.GetErrorCode())
|
|
RETHROW();
|
|
|
|
fRootDeleted = TRUE;
|
|
}
|
|
END_CATCH;
|
|
}
|
|
else
|
|
{
|
|
DWORD dw = GetFileAttributes( lcaseFunnyRootPath.GetPath() );
|
|
if ( 0xffffffff == dw )
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
ciDebugOut(( DEB_WARN,
|
|
"CUpdate::CUpdate(b) can't get attrinfo: %d, for %ws\n",
|
|
dwErr, lcaseFunnyRootPath.GetPath()));
|
|
if ( ERROR_FILE_NOT_FOUND == dwErr || ERROR_PATH_NOT_FOUND == dwErr )
|
|
fRootDeleted = TRUE;
|
|
}
|
|
}
|
|
|
|
_docList.SetPartId ( _PartId );
|
|
_cat.StartUpdate( &_timeLastUpd, lcaseFunnyRootPath.GetActualPath(), fDoDeletions, eScansArray );
|
|
|
|
// Make sure EndProcessing deletes all the files in the scope
|
|
|
|
if ( fRootDeleted )
|
|
{
|
|
_status = STATUS_NO_MORE_FILES;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// This is a bit of a kludge. If we're doing an incremental update, we
|
|
// will not *update* the root, but we need to mark it as seen so it
|
|
// won't get deleted.
|
|
//
|
|
|
|
if ( _fDoDeletions )
|
|
{
|
|
WORKID wid = _cat.PathToWorkId( lcaseFunnyRootPath, eScansArray, fileIdInvalid );
|
|
|
|
//
|
|
// Workid is invalid for root, such as f:\
|
|
//
|
|
//NOTE: LokSetSeen is called by PathToWorkId
|
|
//if ( wid != widInvalid )
|
|
// _cat.Touch( wid, eScansArray );
|
|
}
|
|
|
|
# if CIDBG == 1
|
|
SYSTEMTIME time;
|
|
RtlZeroMemory( &time, sizeof(time) );
|
|
FileTimeToSystemTime( &_timeLastUpd, &time );
|
|
|
|
TIME_ZONE_INFORMATION tzinfo;
|
|
GetTimeZoneInformation( &tzinfo );
|
|
|
|
SYSTEMTIME timeLocal;
|
|
SystemTimeToTzSpecificLocalTime( &tzinfo, &time, &timeLocal );
|
|
|
|
ciDebugOut(( DEB_ITRACE, "Begin update. Last update %4d/%02d/%02d %02d:%02d:%02d.%d\n",
|
|
timeLocal.wYear,
|
|
timeLocal.wMonth,
|
|
timeLocal.wDay,
|
|
timeLocal.wHour,
|
|
timeLocal.wMinute,
|
|
timeLocal.wSecond,
|
|
timeLocal.wMilliseconds ));
|
|
# endif
|
|
|
|
DoIt( lcaseFunnyRootPath );
|
|
} //CUpdate
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CUpdate::EndProcessing, public
|
|
//
|
|
// Synopsis: Flush final updates to catalog.
|
|
//
|
|
// History: 04-Jan-96 KyleP Added header
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CUpdate::EndProcessing()
|
|
{
|
|
ciDebugOut(( DEB_ITRACE,
|
|
"CUpdate::EndProcessing, _fAbort: %d, _status %#x\n",
|
|
_fAbort,
|
|
_status ));
|
|
if ( !_fAbort )
|
|
{
|
|
if ( _cDoc != 0 )
|
|
{
|
|
_docList.LokSetCount ( _cDoc );
|
|
_cat.AddDocuments( _docList );
|
|
_docList.LokClear();
|
|
_docList.SetPartId ( _PartId );
|
|
_cDoc = 0;
|
|
}
|
|
|
|
if ( STATUS_NO_MORE_FILES == _status )
|
|
{
|
|
_cat.EndUpdate( _fDoDeletions, eScansArray );
|
|
}
|
|
else if ( STATUS_SUCCESS != _status )
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Error %#x while traversing\n",
|
|
_status ));
|
|
THROW( CException( _status ) );
|
|
}
|
|
}
|
|
} //EndProcessing
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUpdate::ProcessFile
|
|
//
|
|
// Synopsis: Processes the given file and adds it to the list of changed
|
|
// documents if necessary.
|
|
//
|
|
// Arguments: [lcaseFunnyPath] - Path of the file to be processed.
|
|
//
|
|
// Returns: TRUE if successful; FALSE o/w
|
|
//
|
|
// History: 3-15-96 srikants Split from CUpdate::Traverse
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CUpdate::ProcessFile( const CLowerFunnyPath & lcaseFunnyPath )
|
|
{
|
|
if (lcaseFunnyPath.IsRemote())
|
|
{
|
|
// Need to impersonate only for the remote case
|
|
CImpersonateSystem impersonate;
|
|
|
|
return ProcessFileInternal(lcaseFunnyPath);
|
|
}
|
|
else
|
|
return ProcessFileInternal(lcaseFunnyPath);
|
|
} //ProcessFile
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUpdate::ProcessFileInternal
|
|
//
|
|
// Synopsis: Processes the given file and adds it to the list of changed
|
|
// documents if necessary.
|
|
//
|
|
// Arguments: [lcaseFunnyPath] - Path of the file to be processed.
|
|
//
|
|
// Returns: TRUE if successful; FALSE o/w
|
|
//
|
|
// History: 3-15-96 srikants Split from CUpdate::Traverse
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CUpdate::ProcessFileInternal( const CLowerFunnyPath & lcaseFunnyPath )
|
|
{
|
|
//
|
|
// Add path without committing it
|
|
//
|
|
|
|
FILETIME ftLastSeen = { 0,0 };
|
|
BOOL fNew;
|
|
WORKID wid = _cat.PathToWorkId( lcaseFunnyPath,
|
|
TRUE,
|
|
fNew,
|
|
_fIncrem ? &ftLastSeen : 0,
|
|
eScansArray,
|
|
fileIdInvalid );
|
|
|
|
if (wid == widInvalid)
|
|
return TRUE;
|
|
|
|
//
|
|
// Decide if file has been updated.
|
|
//
|
|
|
|
LONG result = -1;
|
|
|
|
if ( _fIncrem && !fNew && !CiCat::IsMaxTime( ftLastSeen ) )
|
|
{
|
|
//
|
|
// Use the bigger of the last seen time and time of last update
|
|
// to compare the current time of the file.
|
|
//
|
|
|
|
if ( ( ( 0 != ftLastSeen.dwLowDateTime ) ||
|
|
( 0 != ftLastSeen.dwHighDateTime ) ) &&
|
|
( CompareFileTime( &_timeLastUpd, &ftLastSeen ) > 0 ) )
|
|
{
|
|
ftLastSeen = _timeLastUpd;
|
|
}
|
|
|
|
//
|
|
// On FAT volumes, ChangeTime is always 0. On NTFS, ChangeTime
|
|
// can be more recent than ModifyTime (alias LastWriteTime) if the
|
|
// change was to the ACLs of a file, in which case we need to
|
|
// honor the change.
|
|
//
|
|
|
|
FILETIME ftLastDelta;
|
|
if ( 0 == _pCurEntry->ChangeTime() )
|
|
ftLastDelta = _pCurEntry->ModifyTimeAsFILETIME();
|
|
else
|
|
ftLastDelta = _pCurEntry->ChangeTimeAsFILETIME();
|
|
|
|
result = CompareFileTime( &ftLastSeen, &ftLastDelta );
|
|
}
|
|
|
|
if (result < 0) // The file is newer than the catalog
|
|
{
|
|
ciDebugOut(( DEB_CAT, "Update %ws\n", lcaseFunnyPath.GetActualPath() ));
|
|
|
|
_cat.WriteFileAttributes( wid, _pCurEntry->Attributes() );
|
|
Add ( wid );
|
|
}
|
|
|
|
return TRUE;
|
|
} //ProcessFileInternal
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUpdate::IsEligibleForTraversal
|
|
//
|
|
// Synopsis: Checks to see if the current directory is eligible for
|
|
// traversal.
|
|
//
|
|
// Arguments: [lcaseFunnyDir] -
|
|
//
|
|
// History: 3-15-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CUpdate::IsEligibleForTraversal( const CLowerFunnyPath & lcaseFunnyDir ) const
|
|
{
|
|
return _cat.IsEligibleForFiltering( lcaseFunnyDir );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CUpdate::Add, public
|
|
//
|
|
// Synopsis: Add wid for update to doclist
|
|
//
|
|
// Arguments: [wid] -- Workid
|
|
//
|
|
// History: 04-Jan-96 KyleP Added header
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void CUpdate::Add( WORKID wid )
|
|
{
|
|
_cat.Touch(wid, eScansArray);
|
|
USN usn = 0;
|
|
|
|
_docList.Set ( _cDoc, wid, usn, CI_VOLID_USN_NOT_ENABLED );
|
|
_cDoc++;
|
|
|
|
if (_cDoc == CI_MAX_DOCS_IN_WORDLIST)
|
|
{
|
|
_docList.LokSetCount ( _cDoc );
|
|
|
|
_cat.AddDocuments( _docList );
|
|
|
|
_docList.LokClear();
|
|
_docList.SetPartId ( _PartId );
|
|
_cDoc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CRenameDir::CRenameDir
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
// Arguments: [strings] -- Strings class
|
|
// [lowerFunnyDirOldName] -- Old directory
|
|
// [lowerFunnyDirNewName] -- Renamed directory
|
|
// [fAbort] -- Set to TRUE for aborting
|
|
// [volumeId] -- Volume id
|
|
//
|
|
// History: 20-Mar-96 SitaramR Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CRenameDir::CRenameDir( CiCat & cicat,
|
|
const CLowerFunnyPath & lowerFunnyDirOldName,
|
|
const CLowerFunnyPath & lowerFunnyDirNewName,
|
|
BOOL & fAbort,
|
|
VOLUMEID volumeId )
|
|
: CTraverse( cicat, fAbort, TRUE ),
|
|
_cicat(cicat),
|
|
_volumeId(volumeId),
|
|
_lowerFunnyDirOldName( lowerFunnyDirOldName )
|
|
{
|
|
_lowerFunnyDirOldName.AppendBackSlash();
|
|
_uLenDirOldName = _lowerFunnyDirOldName.GetActualLength();
|
|
_uLenDirNewName = lowerFunnyDirNewName.GetActualLength();
|
|
|
|
|
|
//
|
|
// Recursive traversal of renamed dir (include the renamed dir also)
|
|
//
|
|
DoIt( lowerFunnyDirNewName );
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CRenameDir::ProcessFile
|
|
//
|
|
// Synopsis: Update indexes to reflect new file name
|
|
//
|
|
// Arguments: [lcaseFunnyFileNewName] - File name
|
|
//
|
|
// History: 20-Mar-96 SitaramR Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CRenameDir::ProcessFile( const CLowerFunnyPath & lcaseFunnyFileNewName )
|
|
{
|
|
unsigned uLenFileNewName = lcaseFunnyFileNewName.GetActualLength();
|
|
Win4Assert( uLenFileNewName >= _uLenDirNewName );
|
|
|
|
|
|
_lowerFunnyDirOldName.Truncate( _uLenDirOldName );
|
|
_lowerFunnyDirOldName.AppendBackSlash();
|
|
|
|
unsigned posNewFileNameStart = _uLenDirNewName;
|
|
|
|
if ( L'\\' == lcaseFunnyFileNewName.GetActualPath()[posNewFileNameStart] )
|
|
{
|
|
posNewFileNameStart++;
|
|
}
|
|
_lowerFunnyDirOldName.AppendPath( lcaseFunnyFileNewName.GetActualPath() + posNewFileNameStart,
|
|
uLenFileNewName - posNewFileNameStart );
|
|
|
|
_lowerFunnyDirOldName.RemoveBackSlash();
|
|
|
|
CLowerFunnyPath lcaseFunnyFileNewName2( lcaseFunnyFileNewName );
|
|
lcaseFunnyFileNewName2.RemoveBackSlash();
|
|
|
|
_cicat.RenameFile( _lowerFunnyDirOldName,
|
|
lcaseFunnyFileNewName2,
|
|
_pCurEntry->Attributes(),
|
|
_volumeId,
|
|
fileIdInvalid );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|