windows-nt/Source/XPSP1/NT/base/fs/utils/openfiles/handle.cpp
2020-09-26 16:20:57 +08:00

1479 lines
46 KiB
C++

/******************************************************************************
Copyright (C) Microsoft Corporation
Module Name:
Handle.CPP
Abstract:
This module deals with Query functionality of OpenFiles.exe
NT command line utility. This module will specifically query open files
for local system.
Author:
Akhil Gokhale (akhil.gokhale@wipro.com) 25-APRIL-2000
Revision History:
Akhil Gokhale (akhil.gokhale@wipro.com) 25-APRIL-2000 : Created It.
*****************************************************************************/
#include "pch.h"
#include "OpenFiles.h"
#define MAX_POSSIBLE_DRIVES 26 // maximum possible drives are A,B....Y,Z
#define RTL_NEW( p ) RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *p ) )
#define RTL_FREE(p) \
if(p!=NULL)\
{\
RtlFreeHeap( RtlProcessHeap(), 0, p);\
p = NULL;\
}\
1
#define MAX_TYPE_NAMES 128
struct DriveTypeInfo
{
TCHAR szDrive[4];
UINT uiDriveType;
BOOL bDrivePresent;
};
BOOLEAN fAnonymousToo;
HANDLE ProcessId;
WCHAR TypeName[ MAX_TYPE_NAMES ];
WCHAR SearchName[ 512 ];
CHAR OutputFileName[ MAX_PATH ];
HANDLE OutputFile;
HKEY hKey;
CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
HANDLE hStdHandle;
typedef struct _PROCESS_INFO
{
LIST_ENTRY Entry;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_THREAD_INFORMATION ThreadInfo[ 1 ];
} PROCESS_INFO, *PPROCESS_INFO;
LIST_ENTRY ProcessListHead;
PSYSTEM_OBJECTTYPE_INFORMATION ObjectInformation;
PSYSTEM_HANDLE_INFORMATION_EX HandleInformation;
PSYSTEM_PROCESS_INFORMATION ProcessInformation;
typedef struct _TYPE_COUNT
{
UNICODE_STRING TypeName ;
ULONG HandleCount ;
} TYPE_COUNT, * PTYPE_COUNT ;
TYPE_COUNT TypeCounts[ MAX_TYPE_NAMES + 1 ] ;
UNICODE_STRING UnknownTypeIndex;
// Local function decleration
PRTL_DEBUG_INFORMATION RtlQuerySystemDebugInformation(void);
BOOLEAN LoadSystemModules(PRTL_DEBUG_INFORMATION Buffer);
BOOLEAN LoadSystemObjects(PRTL_DEBUG_INFORMATION Buffer);
BOOLEAN LoadSystemHandles(PRTL_DEBUG_INFORMATION Buffer);
BOOLEAN LoadSystemProcesses(PRTL_DEBUG_INFORMATION Buffer);
PSYSTEM_PROCESS_INFORMATION FindProcessInfoForCid(IN HANDLE UniqueProcessId);
VOID DumpHandles( DWORD dwFormat,BOOL bShowNoHeader,BOOL bVerbose);
BOOL GetCompleteFileName(LPCTSTR pszSourceFile,LPTSTR pszFinalPath,struct DriveTypeInfo *pdrvInfo,DWORD dwTotalDrives,LPCTSTR pszCurrentDirectory,LPCTSTR pszSystemDirectory,PBOOL pAppendToCache) ;
void FormatFileName(LPTSTR pFileName,DWORD dwFormat,LONG dwColWidth);
void PrintProgressMsg(HANDLE hOutput,LPCWSTR pwszMsg,const CONSOLE_SCREEN_BUFFER_INFO& csbi);
/*****************************************************************************
Routine Description:
This function will change an ansi string to UNICODE string
Arguments:
[in] Source : Source string
[out] Destination : Destination string
[in] NumberOfChars : No of character in source string
Return Value:
BOOL TRUE : Successfully conversion
FALSE: Unsuccessful
******************************************************************************/
BOOLEAN
AnsiToUnicode(
LPCSTR Source,
PWSTR Destination,
ULONG NumberOfChars
)
{
if (NumberOfChars == 0)
{
NumberOfChars = strlen( Source );
}
if (MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
Source,
NumberOfChars,
Destination,
NumberOfChars
) != (LONG)NumberOfChars)
{
SetLastError( ERROR_NO_UNICODE_TRANSLATION );
return FALSE;
}
else
{
Destination[ NumberOfChars ] = UNICODE_NULL;
return TRUE;
}
}
/*****************************************************************************
Routine Description:
Functin gets system registry key.
Arguments:
none
Return Value:
DWORD : Registry key value
******************************************************************************/
DWORD
GetSystemRegistryFlags( VOID )
{
DWORD cbKey;
DWORD GFlags;
DWORD type;
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
_T("SYSTEM\\CurrentControlSet\\Control\\Session Manager"),
0,
KEY_READ | KEY_WRITE,
&hKey
) != ERROR_SUCCESS)
{
return 0;
}
cbKey = sizeof( GFlags );
if (RegQueryValueEx( hKey,
_T("GlobalFlag"),
0,
&type,
(LPBYTE)&GFlags,
&cbKey
) != ERROR_SUCCESS ||type != REG_DWORD)
{
RegCloseKey( hKey );
return 0;
}
return GFlags;
}
/*****************************************************************************
Routine Description:
Sets system registry Global Flag with given value.
Arguments:
[in] GFlags : Key value
Return Value:
BOOLEAN TRUE: success
FALSE: FAIL
******************************************************************************/
BOOLEAN
SetSystemRegistryFlags(
DWORD GFlags
)
{
if (RegSetValueEx( hKey,
_T("GlobalFlag"),
0,
REG_DWORD,
(LPBYTE)&GFlags,
sizeof( GFlags )
) != ERROR_SUCCESS)
{
RegCloseKey( hKey );
return FALSE;
}
return TRUE;
}
/*****************************************************************************
Routine Description:
This function will show all locally opened open files.
Arguments:
[in] dwFormat : Format value for output e.g LIST, CSV or TABLE
[in] bShowNoHeader : Whether to show header or not.
[in] bVerbose : Verbose ouput or not.
[in] bDisableObjectTypeList : To disable object type list;
Return Value:
BOOL
******************************************************************************/
BOOL DoLocalOpenFiles(DWORD dwFormat,BOOL bShowNoHeader,BOOL bVerbose,LPCTSTR pszLocalValue)
{
char *s;
NTSTATUS Status;
PRTL_DEBUG_INFORMATION p;
DWORD dwRegistryFlags = 0;
dwRegistryFlags = GetSystemRegistryFlags();
if(lstrcmpi(pszLocalValue,GetResString(IDS_LOCAL_OFF)) == 0) // disabling the object typelist
{
dwRegistryFlags &= ~FLG_MAINTAIN_OBJECT_TYPELIST;
if (!(NtCurrentPeb()->NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST))
{
ShowMessage(stderr,GetResString(IDS_LOCAL_FLG_ALREADY_RESET));
}
else
{
SetSystemRegistryFlags(dwRegistryFlags);
ShowMessage(stderr,GetResString(IDS_LOCAL_FLG_RESET));
}
RegCloseKey( hKey );
return TRUE;
}
else if(lstrcmpi(pszLocalValue,GetResString(IDS_LOCAL_ON)) == 0)
{
if (!(NtCurrentPeb()->NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST))
{
// SUNIL: Enabling the OS to maintain the objects list flag
// The user help text calls this global flag 'maintain objects list'
// and enables it with "/local" switch.
SetSystemRegistryFlags( dwRegistryFlags | FLG_MAINTAIN_OBJECT_TYPELIST );
ShowMessage(stderr,GetResString(IDS_LOCAL_FLG_SET));
}
else
{
ShowMessage(stderr,GetResString(IDS_LOCAL_FLG_ALREADY_SET));
}
RegCloseKey( hKey );
return TRUE;
}
else if(lstrcmpi(pszLocalValue,L"SHOW_STATUS") == 0)
{
dwRegistryFlags &= ~FLG_MAINTAIN_OBJECT_TYPELIST;
if (!(NtCurrentPeb()->NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST))
{
ShowMessage(stderr,GetResString(IDS_LOCAL_FLG_ALREADY_RESET));
}
else
{
ShowMessage(stderr,GetResString(IDS_LOCAL_FLG_ALREADY_SET));
}
RegCloseKey( hKey );
return TRUE;
}
else // just check for FLG_MAINTAIN_OBJECT_TYPELIST
{
if (!(NtCurrentPeb()->NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST))
{
RegCloseKey( hKey );
ShowMessage(stderr,GetResString(IDS_LOCAL_NEEDS_TO_SET));
return TRUE;
}
}
// Not required Reg. key so close it
RegCloseKey( hKey );
hStdHandle = GetStdHandle(STD_ERROR_HANDLE);
if(hStdHandle!=NULL)
{
GetConsoleScreenBufferInfo(hStdHandle,&screenBufferInfo);
}
PrintProgressMsg(hStdHandle,GetResString(IDS_WAIT),screenBufferInfo);
OutputFileName[0]='\0';
OutputFile = INVALID_HANDLE_VALUE;
ProcessId = NULL;
fAnonymousToo = FALSE;
AnsiToUnicode(
"File",
TypeName,
4
);
p = RtlQuerySystemDebugInformation();
if (p == NULL)
{
return FALSE;
}
Status = STATUS_SUCCESS;
if (NT_SUCCESS( Status ))
{
DumpHandles(dwFormat,bShowNoHeader,bVerbose);
}
if (OutputFile != INVALID_HANDLE_VALUE)
{
CloseHandle( OutputFile );
}
RtlDestroyQueryDebugBuffer( p );
return TRUE;
}
/*****************************************************************************
Routine Description:
Query system for System object, System handles and system process
Arguments:
none
result.
Return Value:
PRTL_DEBUG_INFORMATION
******************************************************************************/
PRTL_DEBUG_INFORMATION
RtlQuerySystemDebugInformation( void)
{
PRTL_DEBUG_INFORMATION Buffer;
Buffer = (PRTL_DEBUG_INFORMATION)RTL_NEW( Buffer );
if (Buffer == NULL)
{
RTL_FREE(Buffer);
return NULL;
}
if (!LoadSystemObjects( Buffer ))
{
RTL_FREE(Buffer);
return NULL;
}
if (!LoadSystemHandles( Buffer ))
{
RTL_FREE(Buffer);
return NULL;
}
if (!LoadSystemProcesses( Buffer ))
{
RTL_FREE(Buffer);
return NULL;
}
return Buffer;
}
/*****************************************************************************
Routine Description:
This routine will reserves or commits a region of pages in the virtual .
address space of given size.
Arguments:
[in] Lenght : Size of memory required
result.
Return Value:
PVOID
******************************************************************************/
PVOID
BufferAlloc(
IN OUT SIZE_T *Length
)
{
PVOID Buffer;
MEMORY_BASIC_INFORMATION MemoryInformation;
Buffer = VirtualAlloc( NULL,
*Length,
MEM_COMMIT,
PAGE_READWRITE
);
if(Buffer == NULL)
{
return NULL;
}
if (Buffer != NULL && VirtualQuery( Buffer, &MemoryInformation, sizeof( MemoryInformation ) ) )
{
*Length = MemoryInformation.RegionSize;
}
return Buffer;
}
/*****************************************************************************
Routine Description:
This routine will free buffer.
Arguments:
[in] Buffer : Buffer which is to be freed.
Return Value:
none
******************************************************************************/
VOID
BufferFree(
IN PVOID Buffer
)
{
VirtualFree (Buffer,0, MEM_DECOMMIT) ;
return;
}
/*****************************************************************************
Routine Description:
Loads the system objects
Arguments:
[out] Buffer: returns system objects
Return Value:
******************************************************************************/
BOOLEAN
LoadSystemObjects(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
SYSTEM_OBJECTTYPE_INFORMATION ObjectInfoBuffer;
SIZE_T RequiredLength, NewLength=0;
ULONG i;
PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo;
DWORD length;
ObjectInformation = &ObjectInfoBuffer;
RequiredLength = sizeof( *ObjectInformation );
while (TRUE)
{
Status = NtQuerySystemInformation( SystemObjectInformation,
ObjectInformation,
(ULONG)RequiredLength,
(ULONG *)&NewLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH && NewLength > RequiredLength)
{
if (ObjectInformation != &ObjectInfoBuffer)
{
BufferFree (ObjectInformation);
}
RequiredLength = NewLength + 4096;
ObjectInformation = (PSYSTEM_OBJECTTYPE_INFORMATION)BufferAlloc (&RequiredLength);
if (ObjectInformation == NULL)
{
return FALSE;
}
}
else if (!NT_SUCCESS( Status ))
{
if (ObjectInformation != &ObjectInfoBuffer)
{
BufferFree (ObjectInformation);
}
return FALSE;
}
else
{
break;
}
}
TypeInfo = ObjectInformation;
while (TRUE)
{
if (TypeInfo->TypeIndex < MAX_TYPE_NAMES)
{
TypeCounts[ TypeInfo->TypeIndex ].TypeName = TypeInfo->TypeName;
}
if (TypeInfo->NextEntryOffset == 0) {
break;
}
TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
((PCHAR)ObjectInformation + TypeInfo->NextEntryOffset);
}
RtlInitUnicodeString( &UnknownTypeIndex, L"UnknownTypeIdx" );
for (i=0; i<=MAX_TYPE_NAMES; i++)
{
if (TypeCounts[ i ].TypeName.Length == 0 )
{
TypeCounts[ i ].TypeName = UnknownTypeIndex;
}
}
return TRUE;
}
/*****************************************************************************
Routine Description:
Loads the system handles
Arguments:
[out] Buffer: returns system handles
Return Value:
BOOLEAN
******************************************************************************/
BOOLEAN
LoadSystemHandles(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
SYSTEM_HANDLE_INFORMATION_EX HandleInfoBuffer;
SIZE_T RequiredLength, NewLength=0;
PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo;
PSYSTEM_OBJECT_INFORMATION ObjectInfo;
HandleInformation = &HandleInfoBuffer;
RequiredLength = sizeof( *HandleInformation );
while (TRUE)
{
Status = NtQuerySystemInformation( SystemExtendedHandleInformation,
HandleInformation,
(ULONG)RequiredLength,
(ULONG *)&NewLength
);
if (Status == STATUS_INFO_LENGTH_MISMATCH && NewLength > RequiredLength)
{
if (HandleInformation != &HandleInfoBuffer)
{
BufferFree (HandleInformation);
}
RequiredLength = NewLength + 4096; // slop, since we may trigger more handle creations.
HandleInformation = (PSYSTEM_HANDLE_INFORMATION_EX)BufferAlloc( &RequiredLength );
if (HandleInformation == NULL)
{
return FALSE;
}
}
else if (!NT_SUCCESS( Status ))
{
if (HandleInformation != &HandleInfoBuffer)
{
BufferFree (HandleInformation);
}
return FALSE;
}
else
{
break;
}
}
TypeInfo = ObjectInformation;
while (TRUE)
{
ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
((PCHAR)TypeInfo->TypeName.Buffer + TypeInfo->TypeName.MaximumLength);
while (TRUE)
{
if (ObjectInfo->HandleCount != 0)
{
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleEntry;
ULONG HandleNumber;
HandleEntry = &HandleInformation->Handles[ 0 ];
HandleNumber = 0;
while (HandleNumber++ < HandleInformation->NumberOfHandles)
{
if (!(HandleEntry->HandleAttributes & 0x80) &&
HandleEntry->Object == ObjectInfo->Object)
{
HandleEntry->Object = ObjectInfo;
HandleEntry->HandleAttributes |= 0x80;
}
HandleEntry++;
}
}
if (ObjectInfo->NextEntryOffset == 0)
{
break;
}
ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)
((PCHAR)ObjectInformation + ObjectInfo->NextEntryOffset);
}
if (TypeInfo->NextEntryOffset == 0)
{
break;
}
TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)
((PCHAR)ObjectInformation + TypeInfo->NextEntryOffset);
}
return TRUE;
}
/*****************************************************************************
Routine Description:
Loads the system process .
Arguments:
[out] Buffer: returns sysem process
Return Value:
BOOLEAN
******************************************************************************/
BOOLEAN
LoadSystemProcesses(
PRTL_DEBUG_INFORMATION Buffer
)
{
NTSTATUS Status;
SIZE_T RequiredLength;
ULONG i, TotalOffset;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_THREAD_INFORMATION ThreadInfo;
PPROCESS_INFO ProcessEntry;
CHAR NameBuffer[ MAX_PATH ];
ANSI_STRING AnsiString;
//
// Always initialize the list head, so that a failed
// NtQuerySystemInformation call won't cause an AV later on.
//
InitializeListHead( &ProcessListHead );
RequiredLength = 64 * 1024;
ProcessInformation = (PSYSTEM_PROCESS_INFORMATION)BufferAlloc( &RequiredLength );
if (ProcessInformation == NULL)
{
return FALSE;
}
while (TRUE)
{
Status = NtQuerySystemInformation( SystemProcessInformation,
ProcessInformation,
(ULONG)RequiredLength,
NULL
);
if (Status == STATUS_INFO_LENGTH_MISMATCH)
{
if (!VirtualFree( ProcessInformation,
RequiredLength,
MEM_DECOMMIT
))
{
return FALSE;
}
if (RequiredLength * 2 < RequiredLength)
{
// Very rare loop case, but I want to handle it anyways
return FALSE;
}
RequiredLength = RequiredLength * 2;
ProcessInformation = (PSYSTEM_PROCESS_INFORMATION)BufferAlloc( &RequiredLength );
if (ProcessInformation == NULL)
{
return FALSE;
}
}
else if (!NT_SUCCESS( Status ))
{
return FALSE;
}
else
{
break;
}
}
ProcessInfo = ProcessInformation;
TotalOffset = 0;
while (TRUE)
{
if (ProcessInfo->ImageName.Buffer == NULL)
{
sprintf( NameBuffer, "System Process (%p)", ProcessInfo->UniqueProcessId );
}
else
{
sprintf( NameBuffer, "%wZ",
&ProcessInfo->ImageName);
}
RtlInitAnsiString( &AnsiString, NameBuffer );
RtlAnsiStringToUnicodeString( &ProcessInfo->ImageName, &AnsiString, TRUE );
ProcessEntry =(PPROCESS_INFO) RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( *ProcessEntry ) +
(sizeof( ThreadInfo ) * ProcessInfo->NumberOfThreads));
if (ProcessEntry == NULL)
{
return FALSE;
}
InitializeListHead( &ProcessEntry->Entry );
ProcessEntry->ProcessInfo = ProcessInfo;
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
for (i = 0; i < ProcessInfo->NumberOfThreads; i++)
{
ProcessEntry->ThreadInfo[ i ] = ThreadInfo++;
}
InsertTailList( &ProcessListHead, &ProcessEntry->Entry );
if (ProcessInfo->NextEntryOffset == 0)
{
break;
}
TotalOffset += ProcessInfo->NextEntryOffset;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
((PCHAR)ProcessInformation + TotalOffset);
}
return TRUE;
}
/*****************************************************************************
Routine Description:
This routine will get Process information.
Arguments:
[in] UniqueProcessId = Process ID.
Return Value:
PSYSTEM_PROCESS_INFORMATION, Structure which hold information about process
******************************************************************************/
PSYSTEM_PROCESS_INFORMATION
FindProcessInfoForCid(
IN HANDLE UniqueProcessId
)
{
PLIST_ENTRY Next, Head;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PPROCESS_INFO ProcessEntry;
CHAR NameBuffer[ 64 ];
ANSI_STRING AnsiString;
Head = &ProcessListHead;
Next = Head->Flink;
while (Next != Head)
{
ProcessEntry = CONTAINING_RECORD( Next,
PROCESS_INFO,
Entry
);
ProcessInfo = ProcessEntry->ProcessInfo;
if (ProcessInfo->UniqueProcessId == UniqueProcessId)
{
return ProcessInfo;
}
Next = Next->Flink;
}
ProcessEntry =(PPROCESS_INFO) RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( *ProcessEntry ) +
sizeof( *ProcessInfo )
);
if (ProcessEntry == NULL)
{
return NULL;
}
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessEntry+1);
ProcessEntry->ProcessInfo = ProcessInfo;
sprintf( NameBuffer, "Unknown Process");
RtlInitAnsiString( &AnsiString, NameBuffer );
RtlAnsiStringToUnicodeString( (PUNICODE_STRING)&ProcessInfo->ImageName, &AnsiString, TRUE );
ProcessInfo->UniqueProcessId = UniqueProcessId;
InitializeListHead( &ProcessEntry->Entry );
InsertTailList( &ProcessListHead, &ProcessEntry->Entry );
return ProcessInfo;
}
/*****************************************************************************
Routine Description:
This function will show result.
Arguments:
[in] dwFormat : Format value for output e.g LIST, CSV or TABLE
[in] bShowNoHeader : Whether to show header or not.
[in] bVerbose : Verbose ouput or not.
Return Value:
void
******************************************************************************/
VOID
DumpHandles( DWORD dwFormat,BOOL bShowNoHeader,BOOL bVerbose)
{
HANDLE PreviousUniqueProcessId;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleEntry;
ULONG HandleNumber;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_OBJECT_INFORMATION ObjectInfo;
PUNICODE_STRING ObjectTypeName;
WCHAR ObjectName[ MAX_RES_STRING ];
PVOID Object;
CHAR OutputLine[ MAX_RES_STRING];
CHString szFileType;
PWSTR s;
ULONG n;
DWORD dwRow = 0; // no of rows
DWORD dwAvailableLogivalDrives = 0; // Stores avalable logical drives info.
TCHAR szWorkingDirectory[MAX_PATH+1] = NULL_STRING; // stores working directory.
TCHAR szSystemDirectory[MAX_PATH+1] = NULL_STRING; // Stores the System (Active OS) directory
struct DriveTypeInfo drvInfo[MAX_POSSIBLE_DRIVES];
DWORD dwNoOfAvailableDrives = 0; // Stores no. of available drives
TCHAR cDriveLater = 65; // "A" is First available driveDrive
DWORD dwDriveMaskPattern = 1; // "A" is First available driveDrive
// so mask pattern is
// 0xFFF1
// variable used for _splitpath function...
TCHAR szDrive[_MAX_DRIVE] = NULL_STRING;
TCHAR szDir[_MAX_DIR]= NULL_STRING;
TCHAR szFname[_MAX_FNAME]= NULL_STRING;
TCHAR szExt[_MAX_EXT]= NULL_STRING;
TCHAR szTemp[MAX_RES_STRING*2]=NULL_STRING;
TCHAR szCompleteFileName[MAX_PATH] = NULL_STRING;
DWORD dwHandle = 0;
BOOL bAtLeastOne = FALSE;
DWORD dwIndx = 0; // variable used for indexing
TCHAR szFileSystemNameBuffer[MAX_PATH+1] = NULL_STRING;
TCHAR szVolName[MAX_PATH+1] = NULL_STRING;
DWORD dwVolumeSerialNumber = 0;
DWORD dwSerialNumber = 0;
DWORD dwFileSystemFlags = 0;
DWORD dwMaximumCompenentLength = 0;
BOOL bReturn = FALSE;
DWORD dwNoOfElements = 0;
DWORD dwIteration = 0;
BY_HANDLE_FILE_INFORMATION byHandleFileInfo;
DWORD dwFileAttributes;
BOOL bAppendToCache = FALSE;
//Some column required to hide in non verbose mode query
DWORD dwMask = bVerbose?SR_TYPE_STRING:SR_HIDECOLUMN|SR_TYPE_STRING;
TCOLUMNS pMainCols[]=
{
{NULL_STRING,COL_L_ID,SR_TYPE_STRING,NULL_STRING,NULL,NULL},
{NULL_STRING,COL_L_TYPE,SR_HIDECOLUMN,NULL_STRING,NULL,NULL},
{NULL_STRING,COL_L_ACCESSED_BY,dwMask,NULL_STRING,NULL,NULL},
{NULL_STRING,COL_L_PROCESS_NAME,SR_TYPE_STRING,NULL_STRING,NULL,NULL},
{NULL_STRING,COL_L_OPEN_FILENAME,SR_TYPE_STRING|(SR_NO_TRUNCATION&~(SR_WORDWRAP)),NULL_STRING,NULL,NULL}
};
LPTSTR pszAccessedby = new TCHAR[MAX_RES_STRING*2];
if(pszAccessedby==NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
ShowLastError(stderr);
return;
}
TARRAY pColData = CreateDynamicArray();//array to stores
//result
if((pColData == NULL))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
ShowLastError(stderr);
SAFEDELETE(pszAccessedby);
return;
}
TARRAY pCacheData = CreateDynamicArray();//array to stores
if(pCacheData == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
ShowLastError(stderr);
SAFERELDYNARRAY(pColData);
SAFERELDYNARRAY(pCacheData);
SAFEDELETE(pszAccessedby);
return;
}
lstrcpy(pMainCols[LOF_ID].szColumn,GetResString(IDS_STRING_ID));
lstrcpy(pMainCols[LOF_TYPE].szColumn,GetResString(IDS_FILE_TYPE));
lstrcpy(pMainCols[LOF_ACCESSED_BY].szColumn,GetResString(IDS_STRING_ACCESSED_BY) );
lstrcpy(pMainCols[LOF_PROCESS_NAME].szColumn,GetResString(IDS_STRING_PROCESS_NAME));
lstrcpy(pMainCols[LOF_OPEN_FILENAME].szColumn,GetResString(IDS_STRING_OPEN_FILE) );
dwAvailableLogivalDrives = GetLogicalDrives(); // Get logical drives.
// Store current working direcory.
_wgetcwd(szWorkingDirectory,MAX_PATH);
// Get System Active (OS) directory
if(GetSystemDirectory(szSystemDirectory,MAX_PATH)==NULL)
{
DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
ShowLastError(stderr); // Shows the error string set by API function.
SAFERELDYNARRAY(pColData);
SAFERELDYNARRAY(pCacheData);
SAFEDELETE(pszAccessedby);
return ;
}
// Check each drive and set its info.
for(dwIndx=0;dwIndx<MAX_POSSIBLE_DRIVES;dwIndx++,cDriveLater++)
{
// dwAvailableLogivalDrives contains drive information in bit wise
// 0000 0000 0000 0000 0000 01101 means A C and D drives are
// logical drives.
if(dwAvailableLogivalDrives & dwDriveMaskPattern)
{
// means we catch a drive latter.
// copy drive latter (line c:\ or a: for example).
wsprintf(drvInfo[dwNoOfAvailableDrives].szDrive,_T("%c:"),cDriveLater);
// Check type of the drive .
drvInfo[dwNoOfAvailableDrives].uiDriveType = GetDriveType(drvInfo[dwNoOfAvailableDrives].szDrive);
// Check if drive is ready or not.
wsprintf(szTemp,_T("%s\\"),drvInfo[dwNoOfAvailableDrives].szDrive);
bReturn = GetVolumeInformation((LPCWSTR)szTemp,
szVolName,
MAX_PATH,
&dwVolumeSerialNumber,
&dwMaximumCompenentLength,
&dwFileSystemFlags,
szFileSystemNameBuffer,
MAX_PATH);
drvInfo[dwNoOfAvailableDrives].bDrivePresent = bReturn;
dwNoOfAvailableDrives++;
}
dwDriveMaskPattern = dwDriveMaskPattern << 1; // Left shift 1
}
HandleEntry = &HandleInformation->Handles[ 0 ];
HandleNumber = 0;
PreviousUniqueProcessId = INVALID_HANDLE_VALUE;
for (HandleNumber = 0;HandleNumber < HandleInformation->NumberOfHandles;HandleNumber++, HandleEntry++)
{
if (PreviousUniqueProcessId != (HANDLE)HandleEntry->UniqueProcessId)
{
PreviousUniqueProcessId = (HANDLE)HandleEntry->UniqueProcessId;
ProcessInfo = FindProcessInfoForCid( PreviousUniqueProcessId );
}
ObjectName[ 0 ] = UNICODE_NULL;
if (HandleEntry->HandleAttributes & 0x80)
{
ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)HandleEntry->Object;
Object = ObjectInfo->Object;
if (ObjectInfo->NameInfo.Name.Length != 0 &&
*(ObjectInfo->NameInfo.Name.Buffer) == UNICODE_NULL)
{
ObjectInfo->NameInfo.Name.Length = 0;
}
n = ObjectInfo->NameInfo.Name.Length / sizeof( WCHAR );
if(ObjectInfo->NameInfo.Name.Buffer != NULL)
{
wcsncpy( ObjectName,
ObjectInfo->NameInfo.Name.Buffer,
n
);
ObjectName[ n ] = UNICODE_NULL;
}
else
{
ObjectName[ 0 ] = UNICODE_NULL;
}
}
else
{
ObjectInfo = NULL;
Object = HandleEntry->Object;
}
if (ProcessId != 0 && ProcessInfo->UniqueProcessId != ProcessId)
{
continue;
}
ObjectTypeName = &TypeCounts[ HandleEntry->ObjectTypeIndex < MAX_TYPE_NAMES ?
HandleEntry->ObjectTypeIndex : MAX_TYPE_NAMES ].TypeName ;
TypeCounts[ HandleEntry->ObjectTypeIndex < MAX_TYPE_NAMES ?
HandleEntry->ObjectTypeIndex : MAX_TYPE_NAMES ].HandleCount++ ;
if (TypeName[0])
{
if (_wcsicmp( TypeName, ObjectTypeName->Buffer ))
{
continue;
}
}
if (!*ObjectName)
{
if (!fAnonymousToo)
{
continue;
}
}
else if (SearchName[0])
{
if (!wcsstr( ObjectName, SearchName ))
{
s = ObjectName;
n = wcslen( SearchName );
while (*s)
{
if (!_wcsnicmp( s, SearchName, n ))
{
break;
}
s += 1;
}
if (!*s)
{
continue;
}
}
}
dwHandle = PtrToUlong( ProcessInfo->UniqueProcessId ); //HandleEntry->HandleValue;
// SUNIL: Blocking the display of files that were opened by system accounts ( NT AUTHORITY )
// if( bVerbose == TRUE )
// {
if ( GetProcessOwner( pszAccessedby, dwHandle ) == FALSE )
continue;// As user is "SYSTEM" related....
// }
// Get File name ..
wsprintf(szTemp,_T("%ws"),*ObjectName ? ObjectName : L"");
// Search this file in cache, if it is there skip this file
// for further processing. As this is already processed and
// was found invalid.
if(IsValidArray(pCacheData) == TRUE)
{
if ( DynArrayFindString( pCacheData, szTemp, TRUE, 0 ) != -1 )
continue;
}
lstrcpy( szCompleteFileName, _T( "" ) );
if(GetCompleteFileName(szTemp,szCompleteFileName,&drvInfo[0],dwNoOfAvailableDrives,szWorkingDirectory,szSystemDirectory,&bAppendToCache) == FALSE)
{
if(bAppendToCache == TRUE) // szTemp contains a directory which is not physicaly exist
// so add this to cache to skip it in future for checking
// of its existance
{
if(IsValidArray(pCacheData) == TRUE)
{
// dwNoOfElements = DynArrayGetCount( pCacheData );
DynArrayAppendString(pCacheData, (LPCWSTR)szTemp,0);
}
}
continue;
}
// Now fill the result to dynamic array "pColData"
DynArrayAppendRow( pColData, 0 );
// File id
wsprintf(szTemp,_T("%ld"),HandleEntry->HandleValue);
DynArrayAppendString2(pColData ,dwRow,szTemp,0);
// Type
DynArrayAppendString2(pColData ,dwRow,(LPCWSTR)szFileType,0);
// Accessed by
DynArrayAppendString2(pColData,dwRow,pszAccessedby,0);
// Process Name
sprintf(OutputLine,"%wZ",&ProcessInfo->ImageName);
GetCompatibleStringFromMultiByte(OutputLine,szTemp,MAX_RES_STRING);
DynArrayAppendString2(pColData ,dwRow,szTemp,0);
if(bVerbose == FALSE) // Formate file name only in non verbose mode.
{
FormatFileName(szCompleteFileName,dwFormat,COL_L_OPEN_FILENAME);
}
// Open File name
DynArrayAppendString2(pColData ,dwRow,szCompleteFileName,0);
dwRow++;
bAtLeastOne = TRUE;
}
// Display output result.
//Output should start after one blank line
PrintProgressMsg(hStdHandle,NULL_STRING,screenBufferInfo);
if(bShowNoHeader==TRUE)
{
dwFormat |=SR_NOHEADER;
}
if(bVerbose == TRUE)
{
pMainCols[LOF_OPEN_FILENAME].dwWidth = 80;
}
if(bAtLeastOne==FALSE)// if not a single open file found, show info
// as - INFO: No open file found.
{
ShowMessage(stdout,GetResString(IDS_NO_OPENFILES));
}
else
{
ShowMessage(stdout,GetResString(IDS_LOCAL_OPEN_FILES));
ShowMessage(stdout,GetResString(IDS_LOCAL_OPEN_FILES_SP1));
ShowResults(NO_OF_COL_LOCAL_OPENFILE,pMainCols,dwFormat,pColData);
}
SAFERELDYNARRAY(pColData);
SAFERELDYNARRAY(pCacheData);
SAFEDELETE(pszAccessedby);
return;
}
/*****************************************************************************
Routine Description:
Prints the message on console.
Arguments:
[in] hOutput = Handle value for console.
[in] pwszMsg = Message to be printed.
[in] csbi = Coordinates of console from where message will print.
Return Value:
none
******************************************************************************/
void PrintProgressMsg(HANDLE hOutput,LPCWSTR pwszMsg,const CONSOLE_SCREEN_BUFFER_INFO& csbi)
{
COORD coord;
DWORD dwSize = 0;
WCHAR wszSpaces[80] = L"";
if(hOutput == NULL)
return;
coord.X = 0;
coord.Y = csbi.dwCursorPosition.Y;
ZeroMemory(wszSpaces,80);
SetConsoleCursorPosition(hOutput,coord);
WriteConsoleW(hOutput,Replicate(wszSpaces,L"",79),79,&dwSize,NULL);
SetConsoleCursorPosition(hOutput,coord);
if(pwszMsg!=NULL)
WriteConsoleW(hOutput,pwszMsg,lstrlen(pwszMsg),&dwSize,NULL);
return;
}
/*****************************************************************************
Routine Description:
This function will accept a path (with out drive letter), and returns
the path with drive letter.
Arguments:
[in] pszSourceFile = Source path
[out] pszFinalPath = Final path
[in] DriveTypeInfo = Logical drive information structure pointer
[in] pszCurrentDirectory = Current woking directory path
[in] pszSystemDirectory = Current Active (OS) System directory
[out] pAppendToCache = whether to pszSourceFile to cache
Return Value:
BOOL: TRUE: if fuction successfuly returns pszFinalPath
FALSE: otherwise
******************************************************************************/
BOOL GetCompleteFileName(LPCTSTR pszSourceFile,LPTSTR pszFinalPath,struct DriveTypeInfo *pdrvInfo,DWORD dwTotalDrives,LPCTSTR pszCurrentDirectory,LPCTSTR pszSystemDirectory,PBOOL pAppendToCache)
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ALGORITHM USED
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Following is the procedure for getting full path name ..
// 1. First check if the first character in pszSourceFile is '\' .
// 2. If first character of pszSourceFile is '\' then check for the second character...
// 3. If second character is ';' then than take 3 rd character as drive letter and
// find rest of string for 3rd "\" (Or 4th from first). String after 3rd character
// will be final path. for example let the source string is
// \;Z:00000000000774c8\sanny\c$\nt\base\fs\utils\OpenFiles\Changed\obj\i386
// then final path is z:\nt\base\fs\utils\OpenFiles\Changed\obj\i386
// 4. If second character is not ';' then try to find pszSourceFile for its existance
// by first prefixing the available drive letter one by one. The first occurence
// of file existance will be the final valid path. Appending of file letter has
// a rule. First append FIXED DRIVES then try to append MOVABLE DRIVES.
//
// Here there is a known limitation. Let there exists two files with same name like...
// c:\document\abc.doc and d:\documet\abc.doc and actual file opened is d:\documet\abc.doc
// then this will show final path as c:\documet\abc.doc as it starts with A:....Z:(also preference
// will be given to FIXED TYPE DRIVE).
// 5. If first character is not '\' then prefix Current working directory path to file name.
// and check it for its existance. IF this not exits then search this path by prefixing
// logical drive letter to it.
///////////////////////////////////////////////////////////////////////////////////////////////////////
CHString szTemp(pszSourceFile); // Temp string
DWORD dwTemp = 0;// Temp variable
LONG lTemp = 0;
LONG lCount = 0;
TCHAR szTempStr[MAX_PATH+1] = NULL_STRING;
HANDLE hHandle = NULL;
DWORD dwFoundCount = 0;
WIN32_FIND_DATA win32FindData; // data buffer for FindFirstFile function.
DriveTypeInfo *pHeadPosition = pdrvInfo; // Hold the head position.
*pAppendToCache = FALSE; // Make it false by default.
// check if first character is '\'
TCHAR szSystemDrive[5] = NULL_STRING;
lstrcpyn(szSystemDrive,pszSystemDirectory,3); // First two character will be system drive (a:).
if(pszSourceFile[0] == _T('\\'))
{
// Check if second character if it is ';'
if(pszSourceFile[1] == ';')
{
pszFinalPath[0] = pszSourceFile[2]; // make 3rd character as drive letter
pszFinalPath[1] = ':'; // make 2nd character ':'
pszFinalPath[2] = '\0'; // make 3nd character NULL
dwFoundCount = 0;
for (lTemp = 0;lTemp <5;lTemp++) // search for 3rd '\'
{
lCount = szTemp.Find(_T("\\"));
if(lCount!=-1)
{
dwFoundCount++;
if(dwFoundCount == 4 )// this should always (if any)after 4rd character from start
{
lstrcat(pszFinalPath,(LPCWSTR)szTemp.Mid(lCount));
return TRUE;
}
szTemp = szTemp.Mid(lCount+1);
continue;
}
*pAppendToCache = TRUE;
return FALSE;
}
}
else
{
// check first of all for system drive
szTemp = szSystemDrive;
szTemp+=pszSourceFile;
// now check for its existance....
hHandle = FindFirstFile((LPCWSTR)szTemp,&win32FindData);
if(hHandle != INVALID_HANDLE_VALUE)
{
FindClose(hHandle); // closed opened find handle
lstrcpy(pszFinalPath,(LPCWSTR)szTemp);
return TRUE;
}
// check file for each FIXED drive
for (dwTemp=0;dwTemp<dwTotalDrives;dwTemp++,pdrvInfo++)
{
if(lstrcmpi(szSystemDrive,pdrvInfo->szDrive) == 0)
continue; // as system drive is already checked
if(pdrvInfo->uiDriveType == DRIVE_FIXED)
{
szTemp = pdrvInfo->szDrive;
szTemp+=pszSourceFile;
// now check for its existance....
hHandle = FindFirstFile((LPCWSTR)szTemp,&win32FindData);
if(hHandle == INVALID_HANDLE_VALUE)
{
continue;
}
else
{
FindClose(hHandle); // closed opened find handle
lstrcpy(pszFinalPath,(LPCWSTR)szTemp);
return TRUE;
}
} // end if
} // End for loop
pdrvInfo = pHeadPosition ; // retore original position.
// check file for other drive which is present...
for (dwTemp=0;dwTemp<dwTotalDrives;dwTemp++,pdrvInfo++)
{
// Check for NON_FIXED drive only if it is physicaly present
if((pdrvInfo->uiDriveType != DRIVE_FIXED) && (pdrvInfo->bDrivePresent == TRUE))
{
szTemp = pdrvInfo->szDrive;
szTemp+=pszSourceFile;
// now check for its existance....
hHandle = FindFirstFile((LPCWSTR)szTemp,&win32FindData);
if(hHandle == INVALID_HANDLE_VALUE)
{
continue;
}
else
{
FindClose(hHandle); // closed opened find handle
lstrcpy(pszFinalPath,(LPCWSTR)szTemp);
return TRUE;
}
} // end if
} // End for loop
// Now try if file is opend on remote system without
// having drive map. in this we are assuming that file name
// is containing atleast 3 '\' characters.
szTemp = pszSourceFile;
pszFinalPath[0] = '\\'; // make 3rd character '\'
pszFinalPath[1] = '\0'; // make 2nd character '\o'
dwFoundCount = 0;
for (lTemp = 0;lTemp <4;lTemp++) // search for 3rd '\'
{
lCount = szTemp.Find(_T("\\"));
if(lCount!=-1)
{
szTemp = szTemp.Mid(lCount+1);
dwFoundCount++;
}
else
{
break;
}
if (dwFoundCount == 3)
{
lstrcat(pszFinalPath,pszSourceFile);
// Now try to check its physical existance
hHandle = FindFirstFile(pszFinalPath,&win32FindData);
if(hHandle == INVALID_HANDLE_VALUE)
{
// Now try to append \* to it...(this will check if
// if pszFinalPath is a directory or not)
lstrcpy(szTempStr,pszFinalPath);
lstrcat(szTempStr,L"\\*");
hHandle = FindFirstFile(szTempStr,&win32FindData);
if(hHandle == INVALID_HANDLE_VALUE)
{
// now its sure this is not a valid directory or file
// so append it to chache
*pAppendToCache = TRUE;
return FALSE;
}
FindClose(hHandle);
return TRUE;
}
FindClose(hHandle);
return TRUE;
}
} // End for
}// End else
} // end if
else // means string not started with '\'
{
lstrcpy(pszFinalPath,pszCurrentDirectory);
lstrcat(pszFinalPath,L"\\");
lstrcat(pszFinalPath,pszSourceFile);
hHandle = FindFirstFile((LPCWSTR)szTemp,&win32FindData);
if(hHandle != INVALID_HANDLE_VALUE)
{
FindClose(hHandle); // closed opened find handle
return TRUE;
}
// check first of all for system drive
szTemp = szSystemDrive;
szTemp+=pszSourceFile;
// now check for its existance....
hHandle = FindFirstFile((LPCWSTR)szTemp,&win32FindData);
if(hHandle != INVALID_HANDLE_VALUE)
{
FindClose(hHandle); // closed opened find handle
lstrcpy(pszFinalPath,(LPCWSTR)szTemp);
return TRUE;
}
// restores the head position for the pointer.
pdrvInfo = pHeadPosition ;
// check file for each FIXED drive
for (dwTemp=0;dwTemp<dwTotalDrives;dwTemp++,pdrvInfo++)
{
if(lstrcmpi(szSystemDrive,pdrvInfo->szDrive) == 0)
continue; // as system drive is already checked
if(pdrvInfo->uiDriveType == DRIVE_FIXED)
{
szTemp = pdrvInfo->szDrive;
szTemp += L"\\"; // append \
szTemp+=pszSourceFile;
// now check for its existance....
hHandle = FindFirstFile((LPCWSTR)szTemp,&win32FindData);
if(hHandle == INVALID_HANDLE_VALUE)
{
continue;
}
else
{
FindClose(hHandle); // closed opened find handle
lstrcpy(pszFinalPath,(LPCWSTR)szTemp);
return TRUE;
}
} // end if
} // End for loop
pdrvInfo = pHeadPosition ; // retore original position.
// check file for other drive (Like Floppy or CD-ROM etc. ) which is present...
for (dwTemp=0;dwTemp<dwTotalDrives;dwTemp++,pdrvInfo++)
{
if((pdrvInfo->uiDriveType != DRIVE_FIXED) && (pdrvInfo->bDrivePresent == TRUE))
{
szTemp = pdrvInfo->szDrive;
szTemp += L"\\"; // append '\'
szTemp+=pszSourceFile;
// now check for its existance....
hHandle = FindFirstFile((LPCWSTR)szTemp,&win32FindData);
if(hHandle == INVALID_HANDLE_VALUE)
{
continue;
}
else
{
FindClose(hHandle); // closed opened find handle
lstrcpy(pszFinalPath,(LPCWSTR)szTemp);
return TRUE;
}
} // end if
} // End for loop
}
*pAppendToCache = TRUE;
return FALSE;
}
/*****************************************************************************
Routine Description:
This routine will format the pFileName according to column width
Arguments:
[in/out] pFileName : path to be formatted
[in] dwFormat : Format given
[in] dwColWidth : Column width
Return Value:
none
******************************************************************************/
void FormatFileName(LPTSTR pFileName,DWORD dwFormat,LONG dwColWidth)
{
CHString szCHString(pFileName);
if((szCHString.GetLength()>(dwColWidth))&&
(dwFormat == SR_FORMAT_TABLE))
{
// If file path is too big to fit in column width
// then it is cut like..
// c:\..\rest_of_the_path.
CHString szTemp = szCHString.Right(dwColWidth-6);;
DWORD dwTemp = szTemp.GetLength();
szTemp = szTemp.Mid(szTemp.Find(SINGLE_SLASH),
dwTemp);
szCHString.Format(L"%s%s%s",szCHString.Mid(0,3),
DOT_DOT,
szTemp);
}
lstrcpy(pFileName,(LPCWSTR)szCHString);
return;
}