Hi folks,
I’ve read quite a number of OSR threads regarding inter-volume I/O
redirections using STATUS_REPARSE particularly in PreCreate. Recapping the
method, see the code snippet below (Redirect function invoked by PreCreate).
It is known to be the only reliable and inter-operable method by far AFAIK.
Summarizing the known issue regarding this method, there is no way to tell
whether the received file object in PreCreate represents a reparsed file
path we requested or a brand-new file path when the I/O is retried by I/O
Manager from scratch creating a new IRP, a new FileObject, and a new buffer.
In other words, PreCreate doesn’t have the knowledge to differentiate the
re-entered IRP and the IRP being passed the first time to our minifilter.
Inter-volume I/O redirection is required by several critical applications
including Microsoft System Resotre(sr.sys), file virtualization programs,
and so forth. The only way I can think of to overcome this problem is
append a special string to the initially passed filename and initiate
STATUS_REPARSE method. In PreCreate, it checks this special string at the
end of the filename and decides whether it is a reparsed file path or a
brand-new file path.
Does any one see a problem with this approach or an inter-operability issue
across filter stack?
Your responses are greatly appreciated.
Regards,
FLT_PREOP_CALLBACK_STATUS Redirect(
PFLT_CALLBACK_DATA Data,
PCFLT_RELATED_OBJECTS FltObjects,
PUNICODE_STRING TargetName
)
{
UNICODE_STRING& filename = FltObjects->FileObject->FileName;
if(TargetName->MaximumLength < filename.MaximumLength)
{
// Create a new buffer and free existing one.
// Note that allocated buffer will be freed automatically by the system.
PWSTR pBuffer = (PWSTR) new (NonPagedPool)
char[TargetName->MaximumLength];
if(pBuffer == NULL)
return FLT_PREOP_SUCCESS_NO_CALLBACK;
if(filename.Buffer)
ExFreePool(filename.Buffer);
RtlCopyMemory(pBuffer, TargetName->Buffer, TargetName->Length);
filename.Length = TargetName->Length;
filename.MaximumLength = TargetName->MaximumLength;
filename.Buffer = pBuffer;
}
else
{
// Reuse the existing buffer
RtlCopyMemory(filename.Buffer, TargetName->Buffer, TargetName->Length);
filename.Length = TargetName->Length;
}
Data->IoStatus.Status = STATUS_REPARSE;
Data->IoStatus.Information = IO_REPARSE;
FltSetCallbackDataDirty( Data );
return FLT_PREOP_COMPLETE;
}