I decided to write a filter fsd that would tempararily show just a “window”
of some file.
The idea: you (1) have c:\folder\file.big of 700Mb; (2) send some IOCTL to
my filter and now c:\folder\file.big looks like a 10Mb file, actually, you
see only what’s there from 300Mb up to 310Mb; (3) when done, you send
another IOCTL to my filter and the file returns to its “real” state.
I thought it is simple: I will start from FileSpy and substitute some
offsets
on the way down (that’s what “–>” means) and, probably, on bubbling up, in
a completion routine.
Here I attach to C: and try to make a window into some long file c: \
_msvcmon_stuff \ try.me; the window is 1234 bytes long and starts at file’s
oiffset 1,000,000:
UNICODE_STRING myFileName;
RtlInitUnicodeString(&myFileName, L"_msvcmon_stuff\try.me");
if(!RtlCompareUnicodeString(&myFileName, &stack->FileObject->FileName,
FALSE)) {
CHAR irpMajorString[OPERATION_NAME_BUFFER_SIZE];
CHAR irpMinorString[OPERATION_NAME_BUFFER_SIZE];
GetIrpName(stack->MajorFunction, stack->MinorFunction,
stack->Parameters.FileSystemControl.FsControlCode, irpMajorString,
irpMinorString);
DbgPrint(“–> try.me: %s/%s\n”, irpMajorString, irpMinorString);
switch(stack->MajorFunction) {
case IRP_MJ_READ:
DbgPrint(“–> READ offset=%I64u length=%u\n”,
stack->Parameters.Read.ByteOffset.QuadPart, stack->Parameters.Read.Length);
stack->Parameters.Read.ByteOffset.QuadPart += 1000000;
DbgPrint(“–> READ modified offset=%I64u\n”,
stack->Parameters.Read.ByteOffset.QuadPart);
break;
case IRP_MJ_WRITE:
DbgPrint(“–> WRITE offset=%I64u length=%u\n”,
stack->Parameters.Read.ByteOffset.QuadPart, stack->Parameters.Read.Length);
stack->Parameters.Read.ByteOffset.QuadPart += 1000000;
DbgPrint(“–> WRITE modified offset=%I64u\n”,
stack->Parameters.Read.ByteOffset.QuadPart);
break;
case IRP_MJ_QUERY_INFORMATION: // I never saw this one (the file system
takes the info from cache…)
case IRP_MJ_SET_INFORMATION:
OnQueryOrSet(Irp, “–>”);
if(FileEndOfFileInformation ==
stack->Parameters.QueryFile.FileInformationClass) {
FILE_END_OF_FILE_INFORMATION* pEofInfo;
pEofInfo =
(FILE_END_OF_FILE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
pEofInfo->EndOfFile.QuadPart = 1234;
}
OnQueryOrSet(Irp, “–>”); // just a helper, changes nothing
break;
default:
break;
}
}
Strange things:
(1) I never ever get IRP_MJ_QUERY_INFORMATION, even when I call GetFileSize
from a user-mode testing utility.
My guess is that this info is kept in some kind of a cache that sits above
the driver.
(2) Ok, I cheated on the user-mode side of things: I read and write back
first 512 bytes of a file without changes just to provoke a write and hence
an IRP_MJ_SET_INFORMATION after that; an offset thing started working - I do
see bytes 1000000, 1000001 etc. as bytes 0, 1 etc.
But file’s length does not change…
Log snippet:
opening file…
–> try.me: IRP_MJ_CREATE/
<– try.me: IRP_MJ_CREATE/
…opening file done
reading file…
–> try.me: IRP_MJ_READ/IRP_MN_NORMAL
–> READ offset=0 length=512
–> READ modified offset=1000000
<– try.me: IRP_MJ_READ/IRP_MN_NORMAL
<– READ offset=1000000 length=512
…reading file done
moving file pointer…
…moving file pointer done
writing file… - this is a
forced write that changes nothing but provokes IRP_MJ_SET_INFORMATION
…writing file done
calling GetFileSize…
GetFileSize done, fileSize=13002432 - as it was before (???)
–> try.me: IRP_MJ_CLEANUP/
<– try.me: IRP_MJ_CLEANUP/
–> try.me: IRP_MJ_WRITE/IRP_MN_NORMAL
–> WRITE offset=0 length=4096
–> WRITE modified offset=1000000
<– try.me: IRP_MJ_WRITE/IRP_MN_NORMAL
<– WRITE offset=1000000 length=4096
–> try.me: IRP_MJ_SET_INFORMATION/
–> SET FileEndOfFileInformation
–> EndOfFile=13002432
–> SET FileEndOfFileInformation
–> EndOfFile=1234 - logged later, but
actually happened immediately after write
<– try.me: IRP_MJ_SET_INFORMATION/
<– SET FileEndOfFileInformation
<– EndOfFile=1234
<– try.me: IRP_MJ_CREATE/
–> try.me: IRP_MJ_READ/IRP_MN_NORMAL
–> READ offset=0 length=512
–> READ modified offset=1000000
–> try.me: IRP_MJ_CLOSE/
<– try.me: IRP_MJ_READ/IRP_MN_NORMAL
<– READ offset=1000000 length=512
–> try.me: IRP_MJ_CLEANUP/
<– try.me: IRP_MJ_CLEANUP/
What is it that I’m missing?
Regards,
Aleksandr Shvedov