sunway_yin
驱动牛犊
驱动牛犊
  • 注册日期2006-06-09
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分312分
  • 威望42点
  • 贡献值0点
  • 好评度31点
  • 原创分0分
  • 专家分0分
阅读:1726回复:2

再提2000系统下irp_mj_read中获取盘符looluo 大虾请进

楼主#
更多 发布于:2007-07-25 16:30
looluo大侠以前曾提过如何在irp_mj_read里面获取盘符内容如下:
   我恢复一下上面两位
我测试的机器是Windows XP sp2

1.IoVolumeDeviceToDosName(RtlVolumeDeviceToDosName)在IRP_MJ_CREATE中使用是没有问题的,下面是我写在SfDisplayCreateFileName中代码,没有问题
UNICODE_STRING dosname;
IoVolumeDeviceToDosName(irpSp->FileObject->DeviceObject, &dosname);

SF_LOG_PRINT( SFDEBUG_DISPLAY_CREATE_NAMES,
(\"SFilter!SfDisplayCreateVolumeName: Opened %wZ\\n\",
&dosname) );

ExFreePool(dosname.Buffer);

2.IoVolumeDeviceToDosName(RtlVolumeDeviceToDosName)在IRP_MJ_READ中的确有问题,我看了源码后发现问题出在IoVolumeDeviceToDosName构造IRP去查询DeviceName,如果把这部分去掉就没有问题,下面是我修改的RtlVolumeDeviceToDosName,参数部分有改变,第一个参数是传进去的设备名称,这个名称怎么取下面讲
NTSTATUS
QuerySymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,
OUT PUNICODE_STRING LinkTarget
)

/*++

Routine Description:

This routine returns the target of the symbolic link name.

Arguments:

SymbolicLinkName - Supplies the symbolic link name.

LinkTarget - Returns the link target.

Return Value:

NTSTATUS

--*/

{
OBJECT_ATTRIBUTES oa;
NTSTATUS status;
HANDLE h;

InitializeObjectAttributes(&oa, SymbolicLinkName, OBJ_CASE_INSENSITIVE,
0, 0);

status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &oa);
if (!NT_SUCCESS(status)) {
return status;
}

LinkTarget->MaximumLength = 200*sizeof(WCHAR);
LinkTarget->Length = 0;
LinkTarget->Buffer = ExAllocatePool(PagedPool, LinkTarget->MaximumLength);
if (!LinkTarget->Buffer) {
ZwClose(h);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(LinkTarget->Buffer, LinkTarget->MaximumLength);

status = ZwQuerySymbolicLinkObject(h, LinkTarget, NULL);
ZwClose(h);

if (!NT_SUCCESS(status)) {
ExFreePool(LinkTarget->Buffer);
}

return status;
}

NTSTATUS
SFRtlVolumeDeviceToDosName(
IN PUNICODE_STRING DeviceName,
OUT PUNICODE_STRING DosName
)

/*++

Routine Description:

This routine returns a valid DOS path for the given device object.
This caller of this routine must call ExFreePool on DosName->Buffer
when it is no longer needed.

Arguments:

VolumeDeviceObject - Supplies the volume device object.

DosName - Returns the DOS name for the volume

Return Value:

NTSTATUS

--*/

{
NTSTATUS status;
UNICODE_STRING driveLetterName;
WCHAR c;
UNICODE_STRING linkTarget;

RtlInitUnicodeString(&driveLetterName, L\"\\\\??\\\\C:\");

for (c = \'A\'; c <= \'Z\'; c++) {
driveLetterName.Buffer[4] = c;

status = QuerySymbolicLink(&driveLetterName, &linkTarget);
if (!NT_SUCCESS(status)) {
continue;
}

if (RtlEqualUnicodeString(&linkTarget, DeviceName, TRUE)) {
ExFreePool(linkTarget.Buffer);
break;
}

ExFreePool(linkTarget.Buffer);
}

if (c <= \'Z\') {
DosName->Buffer = ExAllocatePool(PagedPool, 3*sizeof(WCHAR));
if (!DosName->Buffer) {
return STATUS_INSUFFICIENT_RESOURCES;
}
DosName->MaximumLength = 6;
DosName->Length = 4;
DosName->Buffer[0] = c;
DosName->Buffer[1] = \':\';
DosName->Buffer[2] = 0;
return STATUS_SUCCESS;
}

/*for (c = \'A\'; c <= \'Z\'; c++) {
driveLetterName.Buffer[4] = c;
InitializeListHead(&devicesInPath);
status = FindPathForDevice(&driveLetterName, &deviceName,
&devicesInPath, DosName);

if (NT_SUCCESS(status)) {
DosName->Length -= 4*sizeof(WCHAR);
RtlMoveMemory(DosName->Buffer, &DosName->Buffer[4],
DosName->Length);
DosName->Buffer[DosName->Length/sizeof(WCHAR)] = 0;
return status;
}
}*/

return status;
}

最后注掉的部分是为了简化处理,这部分处理在24个盘符中找不到的情况,我没有仔细研究。

3.怎么在IRP_MJ_READ中取盘符。其实这个盘符对应的设备名一直在DeviceExtension中,可以在Create的时候就将盘符取出,保存在DeviceExtension中,Filemon就是这么做的,但是他取盘符不是用的RtlVolumeDeviceToDosName,但是原理是一样的,在Read中取盘符可以使用上面的函数。

4.为什么不能在IRP_MJ_READ中用sfgetfilename。sfgetfilename在内部使用的是ObQueryNameString,但是在IRP_MJ_READ中使用这个函数有IRP重入的问题,所以不能使用这个函数。在这里取文件名可以是使用Filespy中的方法,也可以使用Filemon的,两者是差不多,但是我在试Filemon老是有点问题,索性就没去研究。下面是我从filespy中抽取的方法,注意这里是Filespy中取文件名case 5CASE 5: We are retrieving the file name sometime after the CREATE operation.

VOID
SFGetFullPath(
PFILE_OBJECT fileObject,
PSFILTER_DEVICE_EXTENSION devExt,
PUNICODE_STRING FileName
)
{
PFILE_NAME_INFORMATION fileNameInfo;
ULONG returnLength;
UCHAR buffer[sizeof(FILE_NAME_INFORMATION) + MAXPATHLEN];

fileNameInfo = (PFILE_NAME_INFORMATION)buffer;

if( fileNameInfo) {
SpyQueryFileSystemForFileName( fileObject,
devExt->AttachedToDeviceObject,
sizeof( buffer ),
fileNameInfo,
&returnLength );
RtlCopyMemory(FileName->Buffer,
fileNameInfo->FileName,
fileNameInfo->FileNameLength ); );
}

}

这里取到的文件名加上前面取的盘符就可以得到完整的文件路径名。



但是有两个问题我想问问looluo大侠
1 : SFRtlVolumeDeviceToDosName函数的第一个参数是怎样的?怎样获取?
2:  能否给出一段实际运用的例呢?就象第一个例子样。
                                           谢谢:)
sunway_yin
驱动牛犊
驱动牛犊
  • 注册日期2006-06-09
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分312分
  • 威望42点
  • 贡献值0点
  • 好评度31点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-07-26 11:13
ding!!!
sunway_yin
驱动牛犊
驱动牛犊
  • 注册日期2006-06-09
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分312分
  • 威望42点
  • 贡献值0点
  • 好评度31点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-07-26 15:16
Re:再提2000系统下irp_mj_read中获取盘符
各位大侠都帮下忙哈
游客

返回顶部