📄 namelookup.c
字号:
/*++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
namelookup.c
Abstract:
Header file which contains the definitions that may be
shared with the file spy kernel debugger extensions
Environment:
Kernel mode
--*/
//
// Fixes Win2K compatibility regarding lookaside lists.
//
#ifndef _WIN2K_COMPAT_SLIST_USAGE
#define _WIN2K_COMPAT_SLIST_USAGE
#endif
#include <stdio.h>
#include "ntifs.h"
#include "ntdddisk.h"
#include "namelookup.h"
#define NL_POOL_TAG 'tPlN'
#if WINVER == 0x0500
#define RtlInitEmptyUnicodeString(_ucStr,_buf,_bufSize) \
((_ucStr)->Buffer = (_buf), \
(_ucStr)->Length = 0, \
(_ucStr)->MaximumLength = (USHORT)(_bufSize))
#define ExFreePoolWithTag( a, b ) ExFreePool( (a) )
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#endif
//
// The context used to send the task of getting the DOS device name off to
// a worker thread.
//
typedef struct _NL_DOS_NAME_COMPLETION_CONTEXT {
WORK_QUEUE_ITEM WorkItem;
//
// The DeviceObject whose name is being retrieved. We need this in addition
// to the other fields so we can make sure it doesn't disappear while
// we're retrieving the name.
//
PDEVICE_OBJECT DeviceObject;
//
// The name library device extension header of the device object to get
// the DOS name of.
//
PNL_DEVICE_EXTENSION_HEADER NLExtHeader;
} NL_DOS_NAME_COMPLETION_CONTEXT, *PNL_DOS_NAME_COMPLETION_CONTEXT;
//
// Function prototypes
//
NTSTATUS
NLPQueryFileSystemForFileName (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT NextDeviceObject,
OUT PNAME_CONTROL FileName
);
NTSTATUS
NLPQueryCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT SynchronizingEvent
);
VOID
NLPGetDosDeviceNameWorker (
IN PNL_DOS_NAME_COMPLETION_CONTEXT Context
);
#pragma alloc_text(PAGE, NLPQueryFileSystemForFileName)
#pragma alloc_text(PAGE, NLInitNameControl)
#pragma alloc_text(PAGE, NLCleanupNameControl)
#pragma alloc_text(PAGE, NLGetAndAllocateObjectName)
#pragma alloc_text(PAGE, NLGetObjectName)
#pragma alloc_text(PAGE, NLGetDosDeviceName)
#pragma alloc_text(PAGE, NLPGetDosDeviceNameWorker)
#pragma alloc_text(PAGE, NLAllocateAndCopyUnicodeString)
#pragma alloc_text(PAGE, NLAllocateNameControl)
#pragma alloc_text(PAGE, NLInitNameControl)
#pragma alloc_text(PAGE, NLCleanupNameControl)
#pragma alloc_text(PAGE, NLReallocNameControl)
#pragma alloc_text(PAGE, NLCheckAndGrowNameControl)
/////////////////////////////////////////////////////////////////////////////
//
// Name lookup functions.
//
/////////////////////////////////////////////////////////////////////////////
NTSTATUS
NLGetFullPathName (
IN PFILE_OBJECT FileObject,
IN OUT PNAME_CONTROL FileNameControl,
IN PNL_DEVICE_EXTENSION_HEADER NLExtHeader,
IN NAME_LOOKUP_FLAGS LookupFlags,
IN PPAGED_LOOKASIDE_LIST LookasideList,
OUT PBOOLEAN CacheName
)
/*++
Routine Description:
This routine retrieves the full pathname of the FileObject. Note that
the buffers containing pathname components may be stored in paged pool,
therefore if we are at DISPATCH_LEVEL we cannot look up the name.
The file is looked up one of the following ways based on the LookupFlags:
1. FlagOn( FileObject->Flags, FO_VOLUME_OPEN ) or
(FileObject->FileName.Length == 0). This is a volume open, so just use
DeviceName from the NLExtHeader for the FileName, if it exists.
2. NAMELOOKUPFL_IN_CREATE and NAMELOOKUPFL_OPEN_BY_ID are set.
This is an open by file id, so format the file id into the FileName
string if there is enough room.
3. NAMELOOKUPFL_IN_CREATE set and FileObject->RelatedFileObject != NULL.
This is a relative open, therefore the fullpath file name must
be built up from the name of the FileObject->RelatedFileObject
and FileObject->FileName.
4. NAMELOOKUPFL_IN_CREATE and FileObject->RelatedFileObject == NULL.
This is an absolute open, therefore the fullpath file name is
found in FileObject->FileName.
5. No LookupFlags set.
This is a lookup sometime after CREATE. FileObject->FileName is
no longer guaranteed to be valid, so we call
NLPQueryFileSystemForFileName which rolls a IRP_MJ_QUERY_INFORMATION to
get the file name.
Arguments:
FileObject - Pointer to the FileObject to the get name of.
FileNameControl - A caller-allocated name control that will be filled with
the filename. The string will be NULL terminated.
NLExtHeader - The portion of a device extension needed to build the file
name.
LookupFlags - Flags that determine how the name is generated.
CacheName - TRUE if the returned name should be saved in the cache, FALSE
if the returned name should NOT be saved in the cache.
Return Value:
STATUS_INSUFFICIENT_RESOURCES if there was not enough memory to retrieve
the full name. If this is the case, FileNameControl->Name.Length will
be set to 0. Do not expect any specific value for CacheName.
STATUS_BUFFER_OVERFLOW if the status buffer to hold the file ID or object ID
was not large enough. If this is the case, FileNameControl->Name.Length
will be set to 0. Do not expect any specific value for CacheName.
STATUS_SUCCESS if
1) The full name was retrieved successfully, OR
2) At DPC level, full name could not be retrieved, OR
3) The name was only to be looked up in the cache, OR
4) Nested operation, full name could not be retrieved, OR
--*/
{
NTSTATUS status = STATUS_SUCCESS;
NTSTATUS returnValue = STATUS_SUCCESS;
ULONG i;
BOOLEAN cacheName = TRUE;
LONG count;
//
// Copy over the name the user gave for this device. These names
// should be meaningful to the user. Note that we do not do this for
// NETWORK file system because internally they already show the
// connection name. If this is a direct device open of the network
// file system device, we will copy over the device name to be
// returned to the user.
//
if (FILE_DEVICE_NETWORK_FILE_SYSTEM != NLExtHeader->ThisDeviceObject->DeviceType &&
FlagOn( LookupFlags, NLFL_USE_DOS_DEVICE_NAME ) &&
NLExtHeader->DosName.Length != 0) {
status = NLCheckAndGrowNameControl( FileNameControl,
NLExtHeader->DosName.Length );
if (!NT_SUCCESS( status )) {
goto NoResources;
}
RtlCopyUnicodeString( &FileNameControl->Name, &NLExtHeader->DosName );
} else if (FlagOn( FileObject->Flags, FO_DIRECT_DEVICE_OPEN )) {
status = NLCheckAndGrowNameControl( FileNameControl,
NLExtHeader->DeviceName.Length );
if (!NT_SUCCESS( status )) {
goto NoResources;
}
RtlCopyUnicodeString( &FileNameControl->Name,
&NLExtHeader->DeviceName );
//
// We are now done since there will be no more to the name in this
// case, so return TRUE.
//
*CacheName = TRUE;
return STATUS_SUCCESS;
} else {
status = NLCheckAndGrowNameControl( FileNameControl,
NLExtHeader->DeviceName.Length );
if (!NT_SUCCESS( status )) {
goto NoResources;
}
RtlCopyUnicodeString( &FileNameControl->Name,
&NLExtHeader->DeviceName );
}
//
// See if we can request the name
//
if (FlagOn( LookupFlags, NLFL_ONLY_CHECK_CACHE )) {
# define NotInCacheMsg L"[-=Not In Cache=-]"
status = NLCheckAndGrowNameControl( FileNameControl,
FileNameControl->Name.Length +
sizeof( NotInCacheMsg ) );
if (!NT_SUCCESS( status )) {
goto NoResources;
}
RtlAppendUnicodeToString( &FileNameControl->Name,
NotInCacheMsg );
*CacheName = TRUE;
return STATUS_UNSUCCESSFUL;
}
//
// Can not get the name at DPC level
//
if (KeGetCurrentIrql() > APC_LEVEL) {
# define AtDPCMsg L"[-=At DPC Level=-]"
status = NLCheckAndGrowNameControl( FileNameControl,
FileNameControl->Name.Length +
sizeof( AtDPCMsg ) );
if (!NT_SUCCESS( status )) {
goto NoResources;
}
RtlAppendUnicodeToString( &FileNameControl->Name,
AtDPCMsg );
*CacheName = FALSE;
return STATUS_UNSUCCESSFUL;
}
//
// If there is a ToplevelIrp then this is a nested operation and
// there might be other locks held. Can not get name without the
// potential of deadlocking.
//
if (IoGetTopLevelIrp() != NULL) {
# define NestedMsg L"[-=Nested Operation=-]"
status = NLCheckAndGrowNameControl( FileNameControl,
FileNameControl->Name.Length +
sizeof( NestedMsg ) );
if (!NT_SUCCESS( status )) {
goto NoResources;
}
RtlAppendUnicodeToString( &FileNameControl->Name,
NestedMsg );
*CacheName = FALSE;
return STATUS_UNSUCCESSFUL;
}
//
// CASE 1: This FileObject refers to a Volume open. Either the
// flag is set or no filename is specified.
//
if (FlagOn( FileObject->Flags, FO_VOLUME_OPEN ) ||
(FlagOn( LookupFlags, NLFL_IN_CREATE ) &&
(FileObject->FileName.Length == 0) &&
(FileObject->RelatedFileObject == NULL))) {
//
// We've already copied the VolumeName so just return.
//
}
//
// CASE 2: We are opening the file by ID.
//
else if (FlagOn( LookupFlags, NLFL_IN_CREATE ) &&
FlagOn( LookupFlags, NLFL_OPEN_BY_ID )) {
# define OBJECT_ID_KEY_LENGTH 16
# define ID_BUFFER_SIZE 40
//
// Static buffer big enough for a file Id or object Id.
//
WCHAR idName[ID_BUFFER_SIZE];
if (FileObject->FileName.Length == sizeof(LONGLONG)) {
//
// Opening by FILE ID, generate a name.
//
// To get the actual file name, you could use the file id to open
// the file and then get the file name.
//
count = _snwprintf( idName,
ID_BUFFER_SIZE,
L"<%016I64x>",
*((PLONGLONG)FileObject->FileName.Buffer) );
//
// If the buffer wasn't big enough for the entire string, fail.
//
if (count < 0) {
FileNameControl->Name.Length = 0;
return STATUS_BUFFER_OVERFLOW;
}
} else if ((FileObject->FileName.Length == OBJECT_ID_KEY_LENGTH) ||
(FileObject->FileName.Length == OBJECT_ID_KEY_LENGTH +
sizeof(WCHAR)))
{
PUCHAR idBuffer;
//
// Opening by Object ID, generate a name
//
// To get the actual file name, you could use the file id to open
// the file and then get the file name.
//
idBuffer = (PUCHAR)&FileObject->FileName.Buffer[0];
if (FileObject->FileName.Length != OBJECT_ID_KEY_LENGTH) {
//
// Skip win32 backslash at start of buffer
//
idBuffer = (PUCHAR)&FileObject->FileName.Buffer[1];
}
count = _snwprintf( idName,
ID_BUFFER_SIZE,
L"<%08x-%04hx-%04hx-%04hx-%04hx%08x>",
*(PULONG)&idBuffer[0],
*(PUSHORT)&idBuffer[0+4],
*(PUSHORT)&idBuffer[0+4+2],
*(PUSHORT)&idBuffer[0+4+2+2],
*(PUSHORT)&idBuffer[0+4+2+2+2],
*(PULONG)&idBuffer[0+4+2+2+2+2] );
//
// If the buffer wasn't big enough for the entire string, fail.
//
if (count < 0) {
FileNameControl->Name.Length = 0;
return STATUS_BUFFER_OVERFLOW;
}
} else {
//
// Unknown ID format.
//
count = _snwprintf( idName,
ID_BUFFER_SIZE,
L"[-=Unknown ID (Len=%u)=-]\n",
FileObject->FileName.Length );
}
//
// Append the idName to FileNameControl.
//
status = NLCheckAndGrowNameControl( FileNameControl,
FileNameControl->Name.Length +
ID_BUFFER_SIZE );
if (!NT_SUCCESS( status )) {
goto NoResources;
}
RtlAppendUnicodeToString( &FileNameControl->Name,
idName );
//
// Don't cache the ID name
//
cacheName = FALSE;
//
// Continue on to the end of the routine and return STATUS_UNSUCCESSFUL
// since we are not able to return a "usable" file name (caller cannot
// use the file name we return in other calls because it is not
// "valid").
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -