转自:http://bbs3.driverdevelop.com/read.php?tid-110833.html
编译环境:ifs2003
目标系统:windowsXP + sp2
基本是按照楚狂人的教程来的,长短名转换确实挺麻烦,已通过测试。
在驱网看了很多好文章,心底有很多谢意,也许这个东西能对别人有用。
FYI:
//get the name with FILE_OBJECT's FileName and RelatedObject fields
void SfGetFileNameFromFileObject(
IN PSFILTER_DEVICE_EXTENSION devExt,
IN PFILE_OBJECT FileObject,
OUT ULONG* FileNameLength,
OUT PWCHAR buffer
)
{
POBJECT_NAME_INFORMATION nameInfo = NULL;
ULONG returnLength;
ULONG index;
NTSTATUS status;
ULONG i;
BOOLEAN firstPassed;
HANDLE hDir = NULL;
PWCHAR s2li = NULL;
PWCHAR start;
PWCHAR wc;
WCHAR longName[MAXPATHLEN];
ULONG longNameIndex;
UNICODE_STRING usDirName;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK statusBlock;
ULONG dirInfoLength;
PVOID dirInfo;
PFILE_BOTH_DIR_INFORMATION dirEntryInfo; //for winXP;
PWCHAR wci;
PWCHAR wcj;
ULONG j;
BOOLEAN differ;
HANDLE hEvent;
//1) add the drive letter which I get it in SfFsControlMountVolume()
buffer[0] = devExt->DriveLetter;
buffer[1] = L':';
index = 2;
returnLength = 0;
if(FileObject->RelatedFileObject != NULL)
{
nameInfo = ExAllocatePoolWithTag(
PagedPool,
sizeof(OBJECT_NAME_INFORMATION) + MAXPATHLEN * sizeof(WCHAR),
CJTAG);
status = ObQueryNameString(
FileObject->RelatedFileObject,
nameInfo,
sizeof(OBJECT_NAME_INFORMATION) + MAXPATHLEN * sizeof(WCHAR),
&returnLength);
if(!NT_SUCCESS(status))
{
ExFreePool(nameInfo);
return;
}
//2)add the directory's path if the file is queried by relative
//the path gotten with ObQueryNameString is like:
//"\Device\HarddiskVolume1\WINDOWS"
KdPrint(("_CJDN: %wZ\n", nameInfo->Name));
firstPassed = FALSE;
for(i=1; i<nameInfo->Name.Length; i++)
{
if(nameInfo->Name.Buffer == L'\\')
{
if(firstPassed)
break;
else
firstPassed = TRUE;
}
}
RtlCopyMemory(buffer + index,
nameInfo->Name.Buffer + i,
nameInfo->Name.Length - i * sizeof(WCHAR));
index += nameInfo->Name.Length / sizeof(WCHAR) - i;
}
if(FileObject->FileName.Length == 0)
{
if(nameInfo)
ExFreePool(nameInfo);
return;
}
RtlCopyMemory(&buffer[index], FileObject->FileName.Buffer, FileObject->FileName.Length);
index += FileObject->FileName.Length / sizeof(WCHAR);
buffer[index] = L'\0';
//substitute short names if exist with their relative long names.
//buffer now is like L"C:\\PROGRA~1" but the ZwCreateFile() need
//file name like L"\\Device\\HarddiskVolume1\PROGRA~1".
RtlCopyMemory(longName, devExt->DeviceName.Buffer, devExt->DeviceName.Length);
longNameIndex = devExt->DeviceName.Length / sizeof(WCHAR);
start = buffer + 2;
while((s2li = wcschr(start, L'~')) != NULL)
{
for(wc=s2li; (*wc)!=L'\\'; wc--) //the previous L'\\'
;
RtlCopyMemory(&longName[longNameIndex],
start,
(wc + 1 - start) * sizeof(WCHAR));
longNameIndex += wc + 1 - start;
for(wc=s2li; (*wc)!=L'\\' && (*wc)!=L'\0'; wc++) //the next L'\\' or end
;
if(*wc == L'\0')
break;
longName[longNameIndex] = L'\0';//compose a temporary directory file path
RtlInitUnicodeString(&usDirName, longName);
InitializeObjectAttributes(&objectAttributes,
&usDirName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = ZwCreateFile(&hDir,
FILE_READ_DATA | SYNCHRONIZE,
&objectAttributes,
&statusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if(!NT_SUCCESS(status))
{
if(nameInfo)
ExFreePool(nameInfo);
KdPrint(("_cj ZwCreateFile() @ SfGetFileNameFromFileObject() failed, status: 0x%x\n", status));
return;
}
dirInfoLength = 4048;//one page size
dirInfo = ExAllocatePoolWithTag(NonPagedPool, dirInfoLength, CJTAG);
ZwCreateEvent(&hEvent, GENERIC_ALL, NULL, NotificationEvent, FALSE);
status = ZwQueryDirectoryFile(hDir,
hEvent,
NULL,
NULL,
&statusBlock,
dirInfo,
dirInfoLength,
FileBothDirectoryInformation,
FALSE,
NULL,
TRUE);
if(STATUS_PENDING == status)
{
ZwWaitForSingleObject(hEvent, TRUE, NULL);
}
else if(!NT_SUCCESS(status))
{
ExFreePool(dirInfo);
ZwClose(hDir);
if(nameInfo)
ExFreePool(nameInfo);
KdPrint(("_CJ ZwWaitForSingleObject() @ SfGetFileNameFromFileObject() failed, status: 0x%x\n", status));
return;
}
dirEntryInfo = (PFILE_BOTH_DIR_INFORMATION)dirInfo;
while(1)//compare the directory's entries one by one to find the one I want
{
//judge whether this entry is which I need.
//start --- wc is like: L"PROGRA~1\\", while start is L'P', and wc is L'\\'
if(dirEntryInfo->ShortNameLength / 2 == (wc - start -1))
{
differ = FALSE;
wci = start + 1;
wcj = dirEntryInfo->ShortName;
for(; wci < wc; wci++, wcj++)
{
if(*wci != *wcj)
{
differ = TRUE;
break;
}
}
if(differ == FALSE) //no difference found, so I get the appropriate one
{
for(j=0; j<dirEntryInfo->FileNameLength/2; j++)
{
longName[longNameIndex] = dirEntryInfo->FileName[j];
longNameIndex++;
}
break;// break while(1)
}
}
if(dirEntryInfo->NextEntryOffset == 0)
{//can't find one, so this is a long name, such as "abc~def.txt"
for(wci = start; wci < wc; wci++)
{
longName[longNameIndex] = *wci;
longNameIndex++;
}
break;
}
else
dirEntryInfo = (PFILE_BOTH_DIR_INFORMATION)((char*)dirEntryInfo + dirEntryInfo->NextEntryOffset);
}
ExFreePool(dirInfo);
ZwClose(hDir);
start = wc;
}
//the remainder doesn't have L'~', so I just make a copy.
RtlCopyMemory(&longName[longNameIndex],
start,
(buffer + index - start) * sizeof(WCHAR));
longNameIndex += buffer + index - start;
//finally, I copy the result to my output buffer
RtlCopyMemory(buffer + 2,
longName + devExt->DeviceName.Length / sizeof(WCHAR),
longNameIndex * sizeof(WCHAR) - devExt->DeviceName.Length);
*FileNameLength = 2 * sizeof(WCHAR) + (longNameIndex * sizeof(WCHAR) - devExt->DeviceName.Length);
if(nameInfo)
ExFreePool(nameInfo);
}