Tracking file

Dear whom it may concern,

I’m a device driver engineer from Japan, Recently, i have been writing
a FS Filter Driver, and I got a big probelm. I would really like somebady
helping me to deal this probelm.
In this driver, I need tracking a file, I refer NT Insider in the OSR site,
(http://www.osronline.com/article.cfm?id=102) and try to use same method to do it.

However, the file tracking doesn’t seem to work correctly.
The poblem is that the context cann’t be removed correctly.

Since DataSectionObject is not NULL when closing a certain file, a request
is completed without deleting a context.
Next, CLOSE of a stream file object with the same FCB comes.
At this time, since DataSectionObject is not NULL, a context is not deleted, either.
CLOSE of a file with the same FCB is not notified to a driver after this.
Instead, the CREATE request whose FS returns the same FCB is notified.
But, the file name passed by this CREATE differs from upper CLOSE.

I am troubled very much by this problem.
Has somebaby bumped into the similar problem?

And, I am performing the tracking of a file,
in order to acquire a file name from the stream file object at the time of delay writing.
If I could find the way to acquire a file from a stream file object, This problem will be solved.
Does somebady know the method of acquiring a file name without the file tracking?

If you have any useful information, Please e-mail me, I really appreciate for you help.

Tadashi, Kimura

Here is code I am providing to track files objects via the simple method. I
use this code in a production driver. If you find any problems or
enhancements let me know. Also if it doesn’t come out right in the list, I
will find some website to host on. The functions I don’t provide source
code to should be obvious, but if not let me know I will explain what they
do. It should be trivial to convert it to C source code (its in CPP)

fo_ref.h ---------------------------------------------
/*

fo_ref.h - Copyright (c) 2004 Columbia Data Products, Inc. All
Rights Reserved.

Maintains reference counts on file objects
see http://www.osronline.com/article.cfm?id=102 for more info on how
this works

Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04

Version 1.1 7/14/2004

You may use freely in as long as you give credit in the source code.

Found bugs? send them to me (xxxxx@cdp.com)
*/

/**
* Querys, adds or removes a object on the list
*
* This function uses FsContexts to determine a specific
* file that is open instead of FileObjects which identify
* an instance. IOW You can have 5 opens of the same file
* and you will have 5 file objects and 1 FsContext.
*
* see http://www.osronline.com/article.cfm?id=102 for more info
* on how this works
*/

class Generic_FileObject_RefCount: public DeletableObject
{
protected:
RTL_GENERIC_TABLE Table;

#define FO_REF_ACTION_QUERY 0
#define FO_REF_ACTION_ADD 1
#define FO_REF_ACTION_REMOVE 2

typedef struct sFO_Ref {
ULONG RefCount;
PUNICODE_STRING Name;
PFILE_OBJECT FileObject;
PVOID FsContext;
PVOID Data;
} tFO_Ref;

static RTL_GENERIC_COMPARE_RESULTS CompareElement (
struct _RTL_GENERIC_TABLE *Table,
PVOID FirstStruct,
PVOID SecondStruct
)
{

if(((tFO_Ref*)FirstStruct)->FsContext==((tFO_Ref*)SecondStruct)->FsContext)
return GenericEqual;

if(((tFO_Ref*)FirstStruct)->FsContext<((tFO_Ref*)SecondStruct)->FsContext)
return GenericLessThan;

return GenericGreaterThan;
}

static PVOID AllocElement (
struct _RTL_GENERIC_TABLE *Table,
CLONG ByteSize
)
{
return MemAllocatePoolWithTag(PagedPool,ByteSize,PSM_FO_TAG);
}

static VOID FreeElement (
struct _RTL_GENERIC_TABLE *Table,
PVOID Buffer
)
{
MemFreePool(Buffer);
return;
}

bool DoWork( PFILE_OBJECT FileObject, DWORD Action, PVOID *Data,
PUNICODE_STRING *Uni );

private:
FAST_MUTEX Mutex;

virtual NTSTATUS Init()
{
PAGED_CODE();
ExInitializeFastMutex(&Mutex);
RtlInitializeGenericTable(
&Table,
(PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
(PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElement,
(PRTL_GENERIC_FREE_ROUTINE)FreeElement,
NULL
);
return STATUS_SUCCESS;
}

virtual VOID GetLock()
{
PAGED_CODE();
ExAcquireFastMutex( &Mutex );
}

virtual VOID ReleaseLock()
{
PAGED_CODE();
ExReleaseFastMutex(&Mutex);
}

virtual void Destroy()
{
// shouldnt get called
ASSERT(FALSE);
}

public:
Generic_FileObject_RefCount()
{
/*lint -e{534} ignore return value*/
Init();
}

virtual ~Generic_FileObject_RefCount()
{
Destroy();
}

/**
* Adds a file object to the list if it doesnt already
* exist, otherwise the reference count is incremented.
*
* This method must be called during the create completion
* handler or in the dispatch handler after the call has
* been sent down synchronously.
*
* @param FileObject FileObject to keep track of.
*
* @return true - File was already in list
* false - File was not in list
*/
bool Add( PFILE_OBJECT FileObject )
{
return DoWork(FileObject,FO_REF_ACTION_ADD,NULL,NULL);
}
bool Add( PFILE_OBJECT FileObject, PVOID Data )
{
return DoWork(FileObject,FO_REF_ACTION_ADD,&Data,NULL);
}

/**
* Returns if the file object is in the list
*
* @param FileObject FileObject to check for
*
* @return true - file is on list
* false - file is not on list
*/
bool Query( PFILE_OBJECT FileObject )
{
return DoWork(FileObject,FO_REF_ACTION_QUERY,NULL,NULL);
}
bool Query( PFILE_OBJECT FileObject, PVOID *Data )
{
return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,NULL);
}
bool Query( PFILE_OBJECT FileObject, PVOID *Data, PUNICODE_STRING *Uni )
{
return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,Uni);
}

/**
* Decrements a reference count on the file object.
* If the reference count is 0 the file object may be
* removed from the list.
*
* @param FileObject File object to remove
*
* @return true - file object was on list
* false - file object was not on list
*/
bool Remove( PFILE_OBJECT FileObject )
{
return DoWork(FileObject,FO_REF_ACTION_REMOVE,NULL,NULL);
}
bool Remove( PFILE_OBJECT FileObject, PVOID *Data )
{
return DoWork(FileObject,FO_REF_ACTION_REMOVE,Data,NULL);
}
};

class Generic_FileObject_RefCountNP: public Generic_FileObject_RefCount
{
private:
KSPIN_LOCK SpinLock;
KIRQL OldIrql;

static PVOID AllocElementNP (
struct _RTL_GENERIC_TABLE *Table,
CLONG ByteSize
)
{
return MemAllocatePoolWithTag(NonPagedPool,ByteSize,PSM_FO_TAG);
}

virtual NTSTATUS Init()
{
KeInitializeSpinLock(&SpinLock);
RtlInitializeGenericTable(
&Table,
(PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
(PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElementNP,
(PRTL_GENERIC_FREE_ROUTINE)FreeElement,
NULL
);
return STATUS_SUCCESS;
}

virtual VOID GetLock()
{
pmAcquireSpinLock ( &SpinLock, &OldIrql );
}

virtual VOID ReleaseLock()
{
pmReleaseSpinLock(&SpinLock,OldIrql);
}

};
fo_ref.cpp ---------------------------------------------
/*

fo_ref.cpp - Copyright (c) 2004 Columbia Data Products, Inc. All
Rights Reserved.

Maintains reference counts on file objects
see http://www.osronline.com/article.cfm?id=102 for more info on how
this works

Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04

Version 1.1 7/14/2004

You may use freely in as long as you give credit in the source code.

Found bugs? send them to me (xxxxx@cdp.com)
*/

#include “precomp.h”

#ifdef RUN_WPP
extern “C” {
#include “fo_ref.tmh”
}
#endif

// Note: If a file is cached we may not see the close for it until sometime
later
// this could be immediately or hours or days. It depends on how busy the
system
// is
bool Generic_FileObject_RefCount::DoWork( PFILE_OBJECT FileObject, DWORD
Action, PVOID *Data, PUNICODE_STRING *Uni )
{
if(FileObject->FsContext == NULL) {
return false;
}

GetLock();

tFO_Ref _x;
_x.FsContext = FileObject->FsContext;

tFO_Ref *Found = (tFO_Ref *)RtlLookupElementGenericTable(&Table,&_x);

if ( (Action == FO_REF_ACTION_QUERY) && (Found) ) {
if(Data) {
*Data = Found->Data;
}
if(Uni) {
*Uni = Found->Name;
}
} else
if ( (Action == FO_REF_ACTION_REMOVE) && (Found)) {
// For each IRP_MJ_CLOSE the filter driver decrements the reference
// count on the per-file context structure if the FO_STREAM_FILE bit
// is not set for the file object.
if((!(FileObject->Flags & FO_STREAM_FILE)) && (Found->RefCount)) {
Found->RefCount–;
}

// If the reference count for the per-file context structure reaches
// zero and both the ImageSectionObject and DataSectionObject of the
// SectionObjectPointers field from the FILE_OBJECT is zero, the
// filter driver may then delete the per-file context data.

if ((Found->RefCount==0) &&
((!FileObject->SectionObjectPointer) ||
((!FileObject->SectionObjectPointer->ImageSectionObject) &&
(!FileObject->SectionObjectPointer->DataSectionObject)))) {

if(Found->Name) {
MemFreePool(Found->Name);
Found->Name = NULL;
}

if(Data) {
*Data=Found->Data;
}
RtlDeleteElementGenericTable(&Table,Found);
} else {
// only say found if we actually delete the entry
Found = NULL;
}
}

tFO_Ref *GetFileNameEntry=NULL;

if(Action == FO_REF_ACTION_ADD) {
// For each IRP_MJ_CREATE, the filter driver increments the
reference
// count on the per-file context structure.

if(!Found) {
tFO_Ref x;
BOOLEAN Ret;

x.FsContext = FileObject->FsContext;
x.RefCount=1;

x.Name = NULL;
x.FileObject = FileObject;

if(Data) {
x.Data = *Data;
} else {
x.Data = NULL;
}

Found =
(tFO_Ref*)RtlInsertElementGenericTable(&Table,&x,sizeof(tFO_Ref),&Ret);

// so we will get the name after the lock is released
GetFileNameEntry = Found;

} else {
Found->RefCount++;
}
} // if add

ReleaseLock();

if(GetFileNameEntry) {
GetFileNameEntry->Name =
File_QueryFileName(GetFileNameEntry->FileObject);
if(Uni) {
*Uni = GetFileNameEntry->Name;
}
}

return Found ? true : false;
}

/*

How to declare

Generic_FileObject_RefCount *StreamFiles=NULL;
StreamFiles = new Generic_FileObject_RefCount();

How to add
Note: You must call the add routine in the Create Completion
routine
or after you have already sent the request down in the
dispatch
routine

StreamFiles->Add(IrpSp->FileObject,PrivateData);

How to Query

if(StreamFiles->Query(IrpSp->FileObject,(PVOID*)&PrivateData,&Uni)) {
Debug(DEBUG_DICT,( “File = %wZ\n”,Uni));
}

*/

Thanks,
Rob

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-181171-
xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
Sent: Wednesday, July 14, 2004 8:24 PM
To: Windows File Systems Devs Interest List
Subject: [ntfsd] Tracking file

Dear whom it may concern,

I’m a device driver engineer from Japan, Recently, i have been writing
a FS Filter Driver, and I got a big probelm. I would really like somebady
helping me to deal this probelm.
In this driver, I need tracking a file, I refer NT Insider in the OSR
site,
(http://www.osronline.com/article.cfm?id=102) and try to use same method
to do it.

However, the file tracking doesn’t seem to work correctly.
The poblem is that the context cann’t be removed correctly.

Since DataSectionObject is not NULL when closing a certain file, a request
is completed without deleting a context.
Next, CLOSE of a stream file object with the same FCB comes.
At this time, since DataSectionObject is not NULL, a context is not
deleted, either.
CLOSE of a file with the same FCB is not notified to a driver after this.
Instead, the CREATE request whose FS returns the same FCB is notified.
But, the file name passed by this CREATE differs from upper CLOSE.

I am troubled very much by this problem.
Has somebaby bumped into the similar problem?

And, I am performing the tracking of a file,
in order to acquire a file name from the stream file object at the time
of delay writing.
If I could find the way to acquire a file from a stream file object, This
problem will be solved.
Does somebady know the method of acquiring a file name without the file
tracking?

If you have any useful information, Please e-mail me, I really appreciate
for you help.

Tadashi, Kimura


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@cdp.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Rob,

Thank you for your reply.

I challenged file tracking again using the following code.
But problem was not solved.

Even if I use a new driver including following code, our driver can find context(FCB pointer).
That context matches current context in driver’s FCB table, but filename is wrong.

Therefore, I think that the cause of this problem is either of the following.

  1. IRP_MJ_CLOSE is not notified to a filter driver.
  2. VM reuses a stream file object for a another file.

Is my guess right?

Now, in my driver, in order to solve this problem, delay write is disabled.
I need only the tracking of READ/WRITE.
Therefore, I think that this problem is solved by CcFlushCache in CLEANUP.
Are there other problems which interfere the tracking of READ/WRITE?

When other problems are known, please let me know.

Tadashi, Kimura

----- Original Message -----
From: “Rob Green”
To: “Windows File Systems Devs Interest List”
Sent: Thursday, July 15, 2004 10:01 AM
Subject: RE: [ntfsd] Tracking file

Here is code I am providing to track files objects via the simple method. I
use this code in a production driver. If you find any problems or
enhancements let me know. Also if it doesn’t come out right in the list, I
will find some website to host on. The functions I don’t provide source
code to should be obvious, but if not let me know I will explain what they
do. It should be trivial to convert it to C source code (its in CPP)

fo_ref.h ---------------------------------------------
/

fo_ref.h - Copyright (c) 2004 Columbia Data Products, Inc. All
Rights Reserved.

Maintains reference counts on file objects
see http://www.osronline.com/article.cfm?id=102 for more info on how
this works

Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04

Version 1.1 7/14/2004

You may use freely in as long as you give credit in the source code.

Found bugs? send them to me (xxxxx@cdp.com)
/

/
* Querys, adds or removes a object on the list

* This function uses FsContexts to determine a specific
* file that is open instead of FileObjects which identify
* an instance. IOW You can have 5 opens of the same file
* and you will have 5 file objects and 1 FsContext.

* see http://www.osronline.com/article.cfm?id=102 for more info
* on how this works
/

class Generic_FileObject_RefCount: public DeletableObject
{
protected:
RTL_GENERIC_TABLE Table;

#define FO_REF_ACTION_QUERY 0
#define FO_REF_ACTION_ADD 1
#define FO_REF_ACTION_REMOVE 2

typedef struct sFO_Ref {
ULONG RefCount;
PUNICODE_STRING Name;
PFILE_OBJECT FileObject;
PVOID FsContext;
PVOID Data;
} tFO_Ref;

static RTL_GENERIC_COMPARE_RESULTS CompareElement (
struct _RTL_GENERIC_TABLE Table,
PVOID FirstStruct,
PVOID SecondStruct
)
{

if(((tFO_Ref
)FirstStruct)->FsContext==((tFO_Ref
)SecondStruct)->FsContext)
return GenericEqual;

if(((tFO_Ref
)FirstStruct)->FsContext<((tFO_Ref
)SecondStruct)->FsContext)
return GenericLessThan;

return GenericGreaterThan;
}

static PVOID AllocElement (
struct _RTL_GENERIC_TABLE *Table,
CLONG ByteSize
)
{
return MemAllocatePoolWithTag(PagedPool,ByteSize,PSM_FO_TAG);
}

static VOID FreeElement (
struct _RTL_GENERIC_TABLE *Table,
PVOID Buffer
)
{
MemFreePool(Buffer);
return;
}

bool DoWork( PFILE_OBJECT FileObject, DWORD Action, PVOID *Data,
PUNICODE_STRING *Uni );

private:
FAST_MUTEX Mutex;

virtual NTSTATUS Init()
{
PAGED_CODE();
ExInitializeFastMutex(&Mutex);
RtlInitializeGenericTable(
&Table,
(PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
(PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElement,
(PRTL_GENERIC_FREE_ROUTINE)FreeElement,
NULL
);
return STATUS_SUCCESS;
}

virtual VOID GetLock()
{
PAGED_CODE();
ExAcquireFastMutex( &Mutex );
}

virtual VOID ReleaseLock()
{
PAGED_CODE();
ExReleaseFastMutex(&Mutex);
}

virtual void Destroy()
{
// shouldnt get called
ASSERT(FALSE);
}

public:
Generic_FileObject_RefCount()
{
/lint -e{534} ignore return value/
Init();
}

virtual ~Generic_FileObject_RefCount()
{
Destroy();
}

/

* Adds a file object to the list if it doesnt already
* exist, otherwise the reference count is incremented.
*
* This method must be called during the create completion
* handler or in the dispatch handler after the call has
* been sent down synchronously.
*
* @param FileObject FileObject to keep track of.
*
* @return true - File was already in list
* false - File was not in list
*/
bool Add( PFILE_OBJECT FileObject )
{
return DoWork(FileObject,FO_REF_ACTION_ADD,NULL,NULL);
}
bool Add( PFILE_OBJECT FileObject, PVOID Data )
{
return DoWork(FileObject,FO_REF_ACTION_ADD,&Data,NULL);
}

/
* Returns if the file object is in the list
*
* @param FileObject FileObject to check for
*
* @return true - file is on list
* false - file is not on list
*/
bool Query( PFILE_OBJECT FileObject )
{
return DoWork(FileObject,FO_REF_ACTION_QUERY,NULL,NULL);
}
bool Query( PFILE_OBJECT FileObject, PVOID *Data )
{
return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,NULL);
}
bool Query( PFILE_OBJECT FileObject, PVOID *Data, PUNICODE_STRING *Uni )
{
return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,Uni);
}

/

* Decrements a reference count on the file object.
* If the reference count is 0 the file object may be
* removed from the list.
*
* @param FileObject File object to remove
*
* @return true - file object was on list
* false - file object was not on list
*/
bool Remove( PFILE_OBJECT FileObject )
{
return DoWork(FileObject,FO_REF_ACTION_REMOVE,NULL,NULL);
}
bool Remove( PFILE_OBJECT FileObject, PVOID Data )
{
return DoWork(FileObject,FO_REF_ACTION_REMOVE,Data,NULL);
}
};

class Generic_FileObject_RefCountNP: public Generic_FileObject_RefCount
{
private:
KSPIN_LOCK SpinLock;
KIRQL OldIrql;

static PVOID AllocElementNP (
struct _RTL_GENERIC_TABLE Table,
CLONG ByteSize
)
{
return MemAllocatePoolWithTag(NonPagedPool,ByteSize,PSM_FO_TAG);
}

virtual NTSTATUS Init()
{
KeInitializeSpinLock(&SpinLock);
RtlInitializeGenericTable(
&Table,
(PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
(PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElementNP,
(PRTL_GENERIC_FREE_ROUTINE)FreeElement,
NULL
);
return STATUS_SUCCESS;
}

virtual VOID GetLock()
{
pmAcquireSpinLock ( &SpinLock, &OldIrql );
}

virtual VOID ReleaseLock()
{
pmReleaseSpinLock(&SpinLock,OldIrql);
}

};
fo_ref.cpp ---------------------------------------------
/


fo_ref.cpp - Copyright (c) 2004 Columbia Data Products, Inc. All
Rights Reserved.

Maintains reference counts on file objects
see http://www.osronline.com/article.cfm?id=102 for more info on how
this works

Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04

Version 1.1 7/14/2004

You may use freely in as long as you give credit in the source code.

Found bugs? send them to me (xxxxx@cdp.com)
/

#include “precomp.h”

#ifdef RUN_WPP
extern “C” {
#include “fo_ref.tmh”
}
#endif

// Note: If a file is cached we may not see the close for it until sometime
later
// this could be immediately or hours or days. It depends on how busy the
system
// is
bool Generic_FileObject_RefCount::DoWork( PFILE_OBJECT FileObject, DWORD
Action, PVOID *Data, PUNICODE_STRING *Uni )
{
if(FileObject->FsContext == NULL) {
return false;
}

GetLock();

tFO_Ref _x;
_x.FsContext = FileObject->FsContext;

tFO_Ref *Found = (tFO_Ref *)RtlLookupElementGenericTable(&Table,&_x);

if ( (Action == FO_REF_ACTION_QUERY) && (Found) ) {
if(Data) {
*Data = Found->Data;
}
if(Uni) {
*Uni = Found->Name;
}
} else
if ( (Action == FO_REF_ACTION_REMOVE) && (Found)) {
// For each IRP_MJ_CLOSE the filter driver decrements the reference
// count on the per-file context structure if the FO_STREAM_FILE bit
// is not set for the file object.
if((!(FileObject->Flags & FO_STREAM_FILE)) && (Found->RefCount)) {
Found->RefCount–;
}

// If the reference count for the per-file context structure reaches
// zero and both the ImageSectionObject and DataSectionObject of the
// SectionObjectPointers field from the FILE_OBJECT is zero, the
// filter driver may then delete the per-file context data.

if ((Found->RefCount==0) &&
((!FileObject->SectionObjectPointer) ||
((!FileObject->SectionObjectPointer->ImageSectionObject) &&
(!FileObject->SectionObjectPointer->DataSectionObject)))) {

if(Found->Name) {
MemFreePool(Found->Name);
Found->Name = NULL;
}

if(Data) {
*Data=Found->Data;
}
RtlDeleteElementGenericTable(&Table,Found);
} else {
// only say found if we actually delete the entry
Found = NULL;
}
}

tFO_Ref GetFileNameEntry=NULL;

if(Action == FO_REF_ACTION_ADD) {
// For each IRP_MJ_CREATE, the filter driver increments the
reference
// count on the per-file context structure.

if(!Found) {
tFO_Ref x;
BOOLEAN Ret;

x.FsContext = FileObject->FsContext;
x.RefCount=1;

x.Name = NULL;
x.FileObject = FileObject;

if(Data) {
x.Data = Data;
} else {
x.Data = NULL;
}

Found =
(tFO_Ref
)RtlInsertElementGenericTable(&Table,&x,sizeof(tFO_Ref),&Ret);

// so we will get the name after the lock is released
GetFileNameEntry = Found;

} else {
Found->RefCount++;
}
} // if add

ReleaseLock();

if(GetFileNameEntry) {
GetFileNameEntry->Name =
File_QueryFileName(GetFileNameEntry->FileObject);
if(Uni) {
Uni = GetFileNameEntry->Name;
}
}

return Found ? true : false;
}

/


How to declare

Generic_FileObject_RefCount StreamFiles=NULL;
StreamFiles = new Generic_FileObject_RefCount();

How to add
Note: You must call the add routine in the Create Completion
routine
or after you have already sent the request down in the
dispatch
routine

StreamFiles->Add(IrpSp->FileObject,PrivateData);

How to Query

if(StreamFiles->Query(IrpSp->FileObject,(PVOID
)&PrivateData,&Uni)) {
Debug(DEBUG_DICT,( “File = %wZ\n”,Uni));
}

/

Thanks,
Rob

> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:bounce-181171-
> xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> Sent: Wednesday, July 14, 2004 8:24 PM
> To: Windows File Systems Devs Interest List
> Subject: [ntfsd] Tracking file
>
> Dear whom it may concern,
>
> I’m a device driver engineer from Japan, Recently, i have been writing
> a FS Filter Driver, and I got a big probelm. I would really like somebady
> helping me to deal this probelm.
> In this driver, I need tracking a file, I refer NT Insider in the OSR
> site,
> (http://www.osronline.com/article.cfm?id=102) and try to use same method
> to do it.
>
> However, the file tracking doesn’t seem to work correctly.
> The poblem is that the context cann’t be removed correctly.
>
> Since DataSectionObject is not NULL when closing a certain file, a request
> is completed without deleting a context.
> Next, CLOSE of a stream file object with the same FCB comes.
> At this time, since DataSectionObject is not NULL, a context is not
> deleted, either.
> CLOSE of a file with the same FCB is not notified to a driver after this.
> Instead, the CREATE request whose FS returns the same FCB is notified.
> But, the file name passed by this CREATE differs from upper CLOSE.
>
> I am troubled very much by this problem.
> Has somebaby bumped into the similar problem?
>
>
> And, I am performing the tracking of a file,
> in order to acquire a file name from the stream file object at the time
> of delay writing.
> If I could find the way to acquire a file from a stream file object, This
> problem will be solved.
> Does somebady know the method of acquiring a file name without the file
> tracking?
>
> If you have any useful information, Please e-mail me, I really appreciate
> for you help.
>
> Tadashi, Kimura
>
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@cdp.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
To unsubscribe send a blank email to xxxxx@lists.osr.com

When you indicate that the file name is ‘wrong’, how are you getting the
name for the current fileobject to check against your table?

Pete

Peter Scott
xxxxx@KernelDrivers.com
www.KernelDrivers.com

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-182242-
xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
Sent: Friday, July 23, 2004 6:47 AM
To: Windows File Systems Devs Interest List
Subject: Re: [ntfsd] Tracking file

Rob,

Thank you for your reply.

I challenged file tracking again using the following code.
But problem was not solved.

Even if I use a new driver including following code, our driver can find
context(FCB pointer).
That context matches current context in driver’s FCB table, but filename
is wrong.

Therefore, I think that the cause of this problem is either of the
following.

  1. IRP_MJ_CLOSE is not notified to a filter driver.
  2. VM reuses a stream file object for a another file.

Is my guess right?

Now, in my driver, in order to solve this problem, delay write is
disabled.
I need only the tracking of READ/WRITE.
Therefore, I think that this problem is solved by CcFlushCache in CLEANUP.
Are there other problems which interfere the tracking of READ/WRITE?

When other problems are known, please let me know.

Tadashi, Kimura

----- Original Message -----
From: “Rob Green”
> To: “Windows File Systems Devs Interest List”
> Sent: Thursday, July 15, 2004 10:01 AM
> Subject: RE: [ntfsd] Tracking file
>
>
> Here is code I am providing to track files objects via the simple method.
> I
> use this code in a production driver. If you find any problems or
> enhancements let me know. Also if it doesn’t come out right in the list,
> I
> will find some website to host on. The functions I don’t provide source
> code to should be obvious, but if not let me know I will explain what they
> do. It should be trivial to convert it to C source code (its in CPP)
>
> fo_ref.h ---------------------------------------------
> /*
>
> fo_ref.h - Copyright (c) 2004 Columbia Data Products, Inc. All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
>
> /
> * Querys, adds or removes a object on the list
>
> * This function uses FsContexts to determine a specific
> * file that is open instead of FileObjects which identify
> * an instance. IOW You can have 5 opens of the same file
> * and you will have 5 file objects and 1 FsContext.
>
> * see http://www.osronline.com/article.cfm?id=102 for more info
> * on how this works
> /
>
> class Generic_FileObject_RefCount: public DeletableObject
> {
> protected:
> RTL_GENERIC_TABLE Table;
>
> #define FO_REF_ACTION_QUERY 0
> #define FO_REF_ACTION_ADD 1
> #define FO_REF_ACTION_REMOVE 2
>
> typedef struct sFO_Ref {
> ULONG RefCount;
> PUNICODE_STRING Name;
> PFILE_OBJECT FileObject;
> PVOID FsContext;
> PVOID Data;
> } tFO_Ref;
>
> static RTL_GENERIC_COMPARE_RESULTS CompareElement (
> struct _RTL_GENERIC_TABLE Table,
> PVOID FirstStruct,
> PVOID SecondStruct
> )
> {
>
> if(((tFO_Ref
)FirstStruct)->FsContext==((tFO_Ref
)SecondStruct)-
> >FsContext)
> return GenericEqual;
>
>
> if(((tFO_Ref
)FirstStruct)->FsContext<((tFO_Ref
)SecondStruct)->FsContext)
> return GenericLessThan;
>
> return GenericGreaterThan;
> }
>
> static PVOID AllocElement (
> struct _RTL_GENERIC_TABLE *Table,
> CLONG ByteSize
> )
> {
> return MemAllocatePoolWithTag(PagedPool,ByteSize,PSM_FO_TAG);
> }
>
> static VOID FreeElement (
> struct _RTL_GENERIC_TABLE *Table,
> PVOID Buffer
> )
> {
> MemFreePool(Buffer);
> return;
> }
>
> bool DoWork( PFILE_OBJECT FileObject, DWORD Action, PVOID *Data,
> PUNICODE_STRING *Uni );
>
> private:
> FAST_MUTEX Mutex;
>
> virtual NTSTATUS Init()
> {
> PAGED_CODE();
> ExInitializeFastMutex(&Mutex);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElement,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> PAGED_CODE();
> ExAcquireFastMutex( &Mutex );
> }
>
> virtual VOID ReleaseLock()
> {
> PAGED_CODE();
> ExReleaseFastMutex(&Mutex);
> }
>
> virtual void Destroy()
> {
> // shouldnt get called
> ASSERT(FALSE);
> }
>
> public:
> Generic_FileObject_RefCount()
> {
> /lint -e{534} ignore return value/
> Init();
> }
>
> virtual ~Generic_FileObject_RefCount()
> {
> Destroy();
> }
>
> /

> * Adds a file object to the list if it doesnt already
> * exist, otherwise the reference count is incremented.
> *
> * This method must be called during the create completion
> * handler or in the dispatch handler after the call has
> * been sent down synchronously.
> *
> * @param FileObject FileObject to keep track of.
> *
> * @return true - File was already in list
> * false - File was not in list
> */
> bool Add( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,NULL,NULL);
> }
> bool Add( PFILE_OBJECT FileObject, PVOID Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,&Data,NULL);
> }
>
> /
> * Returns if the file object is in the list
> *
> * @param FileObject FileObject to check for
> *
> * @return true - file is on list
> * false - file is not on list
> */
> bool Query( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,NULL,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data, PUNICODE_STRING *Uni
> )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,Uni);
> }
>
> /

> * Decrements a reference count on the file object.
> * If the reference count is 0 the file object may be
> * removed from the list.
> *
> * @param FileObject File object to remove
> *
> * @return true - file object was on list
> * false - file object was not on list
> */
> bool Remove( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,NULL,NULL);
> }
> bool Remove( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,Data,NULL);
> }
> };
>
> class Generic_FileObject_RefCountNP: public Generic_FileObject_RefCount
> {
> private:
> KSPIN_LOCK SpinLock;
> KIRQL OldIrql;
>
> static PVOID AllocElementNP (
> struct _RTL_GENERIC_TABLE Table,
> CLONG ByteSize
> )
> {
> return MemAllocatePoolWithTag(NonPagedPool,ByteSize,PSM_FO_TAG);
> }
>
> virtual NTSTATUS Init()
> {
> KeInitializeSpinLock(&SpinLock);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElementNP,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> pmAcquireSpinLock ( &SpinLock, &OldIrql );
> }
>
> virtual VOID ReleaseLock()
> {
> pmReleaseSpinLock(&SpinLock,OldIrql);
> }
>
> };
> fo_ref.cpp ---------------------------------------------
> /

>
> fo_ref.cpp - Copyright (c) 2004 Columbia Data Products, Inc. All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
> #include “precomp.h”
>
> #ifdef RUN_WPP
> extern “C” {
> #include “fo_ref.tmh”
> }
> #endif
>
>
> // Note: If a file is cached we may not see the close for it until
> sometime
> later
> // this could be immediately or hours or days. It depends on how busy the
> system
> // is
> bool Generic_FileObject_RefCount::DoWork( PFILE_OBJECT FileObject, DWORD
> Action, PVOID *Data, PUNICODE_STRING *Uni )
> {
> if(FileObject->FsContext == NULL) {
> return false;
> }
>
> GetLock();
>
> tFO_Ref _x;
> _x.FsContext = FileObject->FsContext;
>
> tFO_Ref *Found = (tFO_Ref *)RtlLookupElementGenericTable(&Table,&_x);
>
> if ( (Action == FO_REF_ACTION_QUERY) && (Found) ) {
> if(Data) {
> *Data = Found->Data;
> }
> if(Uni) {
> *Uni = Found->Name;
> }
> } else
> if ( (Action == FO_REF_ACTION_REMOVE) && (Found)) {
> // For each IRP_MJ_CLOSE the filter driver decrements the
> reference
> // count on the per-file context structure if the FO_STREAM_FILE
> bit
> // is not set for the file object.
> if((!(FileObject->Flags & FO_STREAM_FILE)) && (Found->RefCount)) {
> Found->RefCount–;
> }
>
> // If the reference count for the per-file context structure
> reaches
> // zero and both the ImageSectionObject and DataSectionObject of
> the
> // SectionObjectPointers field from the FILE_OBJECT is zero, the
> // filter driver may then delete the per-file context data.
>
> if ((Found->RefCount==0) &&
> ((!FileObject->SectionObjectPointer) ||
> ((!FileObject->SectionObjectPointer->ImageSectionObject) &&
> (!FileObject->SectionObjectPointer->DataSectionObject)))) {
>
> if(Found->Name) {
> MemFreePool(Found->Name);
> Found->Name = NULL;
> }
>
> if(Data) {
> *Data=Found->Data;
> }
> RtlDeleteElementGenericTable(&Table,Found);
> } else {
> // only say found if we actually delete the entry
> Found = NULL;
> }
> }
>
> tFO_Ref *GetFileNameEntry=NULL;
>
> if(Action == FO_REF_ACTION_ADD) {
> // For each IRP_MJ_CREATE, the filter driver increments the
> reference
> // count on the per-file context structure.
>
> if(!Found) {
> tFO_Ref x;
> BOOLEAN Ret;
>
> x.FsContext = FileObject->FsContext;
> x.RefCount=1;
>
> x.Name = NULL;
> x.FileObject = FileObject;
>
> if(Data) {
> x.Data = Data;
> } else {
> x.Data = NULL;
> }
>
> Found =
> (tFO_Ref
)RtlInsertElementGenericTable(&Table,&x,sizeof(tFO_Ref),&Ret);
>
> // so we will get the name after the lock is released
> GetFileNameEntry = Found;
>
> } else {
> Found->RefCount++;
> }
> } // if add
>
> ReleaseLock();
>
> if(GetFileNameEntry) {
> GetFileNameEntry->Name =
> File_QueryFileName(GetFileNameEntry->FileObject);
> if(Uni) {
> Uni = GetFileNameEntry->Name;
> }
> }
>
>
> return Found ? true : false;
> }
>
>
>
>
>
> /

>
> How to declare
>
> Generic_FileObject_RefCount StreamFiles=NULL;
> StreamFiles = new Generic_FileObject_RefCount();
>
>
> How to add
> Note: You must call the add routine in the Create Completion
> routine
> or after you have already sent the request down in the
> dispatch
> routine
>
> StreamFiles->Add(IrpSp->FileObject,PrivateData);
>
> How to Query
>
> if(StreamFiles->Query(IrpSp->FileObject,(PVOID
)&PrivateData,&Uni)) {
> Debug(DEBUG_DICT,( “File = %wZ\n”,Uni));
> }
>
>
>
>
>
> */
>
> Thanks,
> Rob
>
>
> > -----Original Message-----
> > From: xxxxx@lists.osr.com [mailto:bounce-181171-
> > xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> > Sent: Wednesday, July 14, 2004 8:24 PM
> > To: Windows File Systems Devs Interest List
> > Subject: [ntfsd] Tracking file
> >
> > Dear whom it may concern,
> >
> > I’m a device driver engineer from Japan, Recently, i have been writing
> > a FS Filter Driver, and I got a big probelm. I would really like
> somebady
> > helping me to deal this probelm.
> > In this driver, I need tracking a file, I refer NT Insider in the OSR
> > site,
> > (http://www.osronline.com/article.cfm?id=102) and try to use same
> method
> > to do it.
> >
> > However, the file tracking doesn’t seem to work correctly.
> > The poblem is that the context cann’t be removed correctly.
> >
> > Since DataSectionObject is not NULL when closing a certain file, a
> request
> > is completed without deleting a context.
> > Next, CLOSE of a stream file object with the same FCB comes.
> > At this time, since DataSectionObject is not NULL, a context is not
> > deleted, either.
> > CLOSE of a file with the same FCB is not notified to a driver after
> this.
> > Instead, the CREATE request whose FS returns the same FCB is notified.
> > But, the file name passed by this CREATE differs from upper CLOSE.
> >
> > I am troubled very much by this problem.
> > Has somebaby bumped into the similar problem?
> >
> >
> > And, I am performing the tracking of a file,
> > in order to acquire a file name from the stream file object at the time
> > of delay writing.
> > If I could find the way to acquire a file from a stream file object,
> This
> > problem will be solved.
> > Does somebady know the method of acquiring a file name without the file
> > tracking?
> >
> > If you have any useful information, Please e-mail me, I really
> appreciate
> > for you help.
> >
> > Tadashi, Kimura
> >
> >
> > —
> > Questions? First check the IFS FAQ at
> > https://www.osronline.com/article.cfm?id=17
> >
> > You are currently subscribed to ntfsd as: xxxxx@cdp.com
> > To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@kerneldrivers.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com

I agree with Peter. How are you getting the file name? you should not be
accessing the FileObject->FileName field. If you use the Query below, it
will return you the name of the file. I have attached the filename function
incase yours is wrong. This routine can only be called when not in the
current file system path as some locks are already held and a deadlock will
occur.

PUNICODE_STRING File_QueryFileName(
PFILE_OBJECT fileObject
)
{
PFILE_NAME_INFORMATION Name;
PUNICODE_STRING UniName=NULL;
ULONG AllocSize;
NTSTATUS Status;

if(!fileObject) {
return NULL;
}

__try {

AllocSize = 1024*sizeof(WCHAR)+sizeof(ULONG);
Name =
(PFILE_NAME_INFORMATION)MemAllocatePoolWithTag(PagedPool,AllocSize,FILENAMET
AG);

if(Name) {
Status = IoQueryFileInformation( fileObject,
FileNameInformation,
AllocSize,
Name,
&AllocSize);

if(NT_SUCCESS(Status)) {
if(Name->FileNameLength<=AllocSize) {
UniName = GetUniString(Name->FileNameLength);
if(UniName) {
__try {

RtlCopyMemory(UniName->Buffer,Name->FileName,Name->FileNameLength);
}
__except(ExceptionFilter(GetExceptionInformation())) {
Debug(DEBUG_FILE,(“GetFileName: Exception
%08x\n”,GetExceptionCode()));
FREE_POINTER(UniName);
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Out of memory for
uniname\n”));
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Filename length is to
large\n”));
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Error %08x querying file
information\n”,Status));
}
FREE_POINTER(Name);
} else {
Debug(DEBUG_FILE,(“GetFileName: Error out of memory\n”));
}

} __except (ExceptionFilter(GetExceptionInformation())) {
Debug(DEBUG_FILE,(“GetFileName: Exception
%08x\n”,GetExceptionCode()));
}
return UniName;
}

STATIC PUNICODE_STRING GetUniString( ULONG Size )
{
PUNICODE_STRING String;

PAGED_CODE();
String =
(PUNICODE_STRING)MemAllocatePoolWithTag(NonPagedPool,sizeof(UNICODE_STRING)+
Size+sizeof(WCHAR),FILENAMETAG);
if(String) {
RtlZeroMemory(String, sizeof(UNICODE_STRING)+Size+sizeof(WCHAR));

String->Length = (unsigned short)Size;
String->MaximumLength = (unsigned short)(Size+sizeof(WCHAR));
String->Buffer = (WCHAR*)(String+1);
}
return String;
}

Thanks,
Rob

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-182242-
xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
Sent: Friday, July 23, 2004 9:47 AM
To: Windows File Systems Devs Interest List
Subject: Re: [ntfsd] Tracking file

Rob,

Thank you for your reply.

I challenged file tracking again using the following code.
But problem was not solved.

Even if I use a new driver including following code, our driver can find
context(FCB pointer).
That context matches current context in driver’s FCB table, but filename
is wrong.

Therefore, I think that the cause of this problem is either of the
following.

  1. IRP_MJ_CLOSE is not notified to a filter driver.
  2. VM reuses a stream file object for a another file.

Is my guess right?

Now, in my driver, in order to solve this problem, delay write is
disabled.
I need only the tracking of READ/WRITE.
Therefore, I think that this problem is solved by CcFlushCache in CLEANUP.
Are there other problems which interfere the tracking of READ/WRITE?

When other problems are known, please let me know.

Tadashi, Kimura

----- Original Message -----
From: “Rob Green”
> To: “Windows File Systems Devs Interest List”
> Sent: Thursday, July 15, 2004 10:01 AM
> Subject: RE: [ntfsd] Tracking file
>
>
> Here is code I am providing to track files objects via the simple method.
> I
> use this code in a production driver. If you find any problems or
> enhancements let me know. Also if it doesn’t come out right in the list,
> I
> will find some website to host on. The functions I don’t provide source
> code to should be obvious, but if not let me know I will explain what they
> do. It should be trivial to convert it to C source code (its in CPP)
>
> fo_ref.h ---------------------------------------------
> /*
>
> fo_ref.h - Copyright (c) 2004 Columbia Data Products, Inc. All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
>
> /
> * Querys, adds or removes a object on the list
>
> * This function uses FsContexts to determine a specific
> * file that is open instead of FileObjects which identify
> * an instance. IOW You can have 5 opens of the same file
> * and you will have 5 file objects and 1 FsContext.
>
> * see http://www.osronline.com/article.cfm?id=102 for more info
> * on how this works
> /
>
> class Generic_FileObject_RefCount: public DeletableObject
> {
> protected:
> RTL_GENERIC_TABLE Table;
>
> #define FO_REF_ACTION_QUERY 0
> #define FO_REF_ACTION_ADD 1
> #define FO_REF_ACTION_REMOVE 2
>
> typedef struct sFO_Ref {
> ULONG RefCount;
> PUNICODE_STRING Name;
> PFILE_OBJECT FileObject;
> PVOID FsContext;
> PVOID Data;
> } tFO_Ref;
>
> static RTL_GENERIC_COMPARE_RESULTS CompareElement (
> struct _RTL_GENERIC_TABLE Table,
> PVOID FirstStruct,
> PVOID SecondStruct
> )
> {
>
> if(((tFO_Ref
)FirstStruct)->FsContext==((tFO_Ref
)SecondStruct)-
> >FsContext)
> return GenericEqual;
>
>
> if(((tFO_Ref
)FirstStruct)->FsContext<((tFO_Ref
)SecondStruct)->FsContext)
> return GenericLessThan;
>
> return GenericGreaterThan;
> }
>
> static PVOID AllocElement (
> struct _RTL_GENERIC_TABLE *Table,
> CLONG ByteSize
> )
> {
> return MemAllocatePoolWithTag(PagedPool,ByteSize,PSM_FO_TAG);
> }
>
> static VOID FreeElement (
> struct _RTL_GENERIC_TABLE *Table,
> PVOID Buffer
> )
> {
> MemFreePool(Buffer);
> return;
> }
>
> bool DoWork( PFILE_OBJECT FileObject, DWORD Action, PVOID *Data,
> PUNICODE_STRING *Uni );
>
> private:
> FAST_MUTEX Mutex;
>
> virtual NTSTATUS Init()
> {
> PAGED_CODE();
> ExInitializeFastMutex(&Mutex);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElement,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> PAGED_CODE();
> ExAcquireFastMutex( &Mutex );
> }
>
> virtual VOID ReleaseLock()
> {
> PAGED_CODE();
> ExReleaseFastMutex(&Mutex);
> }
>
> virtual void Destroy()
> {
> // shouldnt get called
> ASSERT(FALSE);
> }
>
> public:
> Generic_FileObject_RefCount()
> {
> /lint -e{534} ignore return value/
> Init();
> }
>
> virtual ~Generic_FileObject_RefCount()
> {
> Destroy();
> }
>
> /

> * Adds a file object to the list if it doesnt already
> * exist, otherwise the reference count is incremented.
> *
> * This method must be called during the create completion
> * handler or in the dispatch handler after the call has
> * been sent down synchronously.
> *
> * @param FileObject FileObject to keep track of.
> *
> * @return true - File was already in list
> * false - File was not in list
> */
> bool Add( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,NULL,NULL);
> }
> bool Add( PFILE_OBJECT FileObject, PVOID Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,&Data,NULL);
> }
>
> /
> * Returns if the file object is in the list
> *
> * @param FileObject FileObject to check for
> *
> * @return true - file is on list
> * false - file is not on list
> */
> bool Query( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,NULL,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data, PUNICODE_STRING *Uni
> )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,Uni);
> }
>
> /

> * Decrements a reference count on the file object.
> * If the reference count is 0 the file object may be
> * removed from the list.
> *
> * @param FileObject File object to remove
> *
> * @return true - file object was on list
> * false - file object was not on list
> */
> bool Remove( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,NULL,NULL);
> }
> bool Remove( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,Data,NULL);
> }
> };
>
> class Generic_FileObject_RefCountNP: public Generic_FileObject_RefCount
> {
> private:
> KSPIN_LOCK SpinLock;
> KIRQL OldIrql;
>
> static PVOID AllocElementNP (
> struct _RTL_GENERIC_TABLE Table,
> CLONG ByteSize
> )
> {
> return MemAllocatePoolWithTag(NonPagedPool,ByteSize,PSM_FO_TAG);
> }
>
> virtual NTSTATUS Init()
> {
> KeInitializeSpinLock(&SpinLock);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElementNP,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> pmAcquireSpinLock ( &SpinLock, &OldIrql );
> }
>
> virtual VOID ReleaseLock()
> {
> pmReleaseSpinLock(&SpinLock,OldIrql);
> }
>
> };
> fo_ref.cpp ---------------------------------------------
> /

>
> fo_ref.cpp - Copyright (c) 2004 Columbia Data Products, Inc. All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
> #include “precomp.h”
>
> #ifdef RUN_WPP
> extern “C” {
> #include “fo_ref.tmh”
> }
> #endif
>
>
> // Note: If a file is cached we may not see the close for it until
> sometime
> later
> // this could be immediately or hours or days. It depends on how busy the
> system
> // is
> bool Generic_FileObject_RefCount::DoWork( PFILE_OBJECT FileObject, DWORD
> Action, PVOID *Data, PUNICODE_STRING *Uni )
> {
> if(FileObject->FsContext == NULL) {
> return false;
> }
>
> GetLock();
>
> tFO_Ref _x;
> _x.FsContext = FileObject->FsContext;
>
> tFO_Ref *Found = (tFO_Ref *)RtlLookupElementGenericTable(&Table,&_x);
>
> if ( (Action == FO_REF_ACTION_QUERY) && (Found) ) {
> if(Data) {
> *Data = Found->Data;
> }
> if(Uni) {
> *Uni = Found->Name;
> }
> } else
> if ( (Action == FO_REF_ACTION_REMOVE) && (Found)) {
> // For each IRP_MJ_CLOSE the filter driver decrements the
> reference
> // count on the per-file context structure if the FO_STREAM_FILE
> bit
> // is not set for the file object.
> if((!(FileObject->Flags & FO_STREAM_FILE)) && (Found->RefCount)) {
> Found->RefCount–;
> }
>
> // If the reference count for the per-file context structure
> reaches
> // zero and both the ImageSectionObject and DataSectionObject of
> the
> // SectionObjectPointers field from the FILE_OBJECT is zero, the
> // filter driver may then delete the per-file context data.
>
> if ((Found->RefCount==0) &&
> ((!FileObject->SectionObjectPointer) ||
> ((!FileObject->SectionObjectPointer->ImageSectionObject) &&
> (!FileObject->SectionObjectPointer->DataSectionObject)))) {
>
> if(Found->Name) {
> MemFreePool(Found->Name);
> Found->Name = NULL;
> }
>
> if(Data) {
> *Data=Found->Data;
> }
> RtlDeleteElementGenericTable(&Table,Found);
> } else {
> // only say found if we actually delete the entry
> Found = NULL;
> }
> }
>
> tFO_Ref *GetFileNameEntry=NULL;
>
> if(Action == FO_REF_ACTION_ADD) {
> // For each IRP_MJ_CREATE, the filter driver increments the
> reference
> // count on the per-file context structure.
>
> if(!Found) {
> tFO_Ref x;
> BOOLEAN Ret;
>
> x.FsContext = FileObject->FsContext;
> x.RefCount=1;
>
> x.Name = NULL;
> x.FileObject = FileObject;
>
> if(Data) {
> x.Data = Data;
> } else {
> x.Data = NULL;
> }
>
> Found =
> (tFO_Ref
)RtlInsertElementGenericTable(&Table,&x,sizeof(tFO_Ref),&Ret);
>
> // so we will get the name after the lock is released
> GetFileNameEntry = Found;
>
> } else {
> Found->RefCount++;
> }
> } // if add
>
> ReleaseLock();
>
> if(GetFileNameEntry) {
> GetFileNameEntry->Name =
> File_QueryFileName(GetFileNameEntry->FileObject);
> if(Uni) {
> Uni = GetFileNameEntry->Name;
> }
> }
>
>
> return Found ? true : false;
> }
>
>
>
>
>
> /

>
> How to declare
>
> Generic_FileObject_RefCount StreamFiles=NULL;
> StreamFiles = new Generic_FileObject_RefCount();
>
>
> How to add
> Note: You must call the add routine in the Create Completion
> routine
> or after you have already sent the request down in the
> dispatch
> routine
>
> StreamFiles->Add(IrpSp->FileObject,PrivateData);
>
> How to Query
>
> if(StreamFiles->Query(IrpSp->FileObject,(PVOID
)&PrivateData,&Uni)) {
> Debug(DEBUG_DICT,( “File = %wZ\n”,Uni));
> }
>
>
>
>
>
> */
>
> Thanks,
> Rob
>
>
> > -----Original Message-----
> > From: xxxxx@lists.osr.com [mailto:bounce-181171-
> > xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> > Sent: Wednesday, July 14, 2004 8:24 PM
> > To: Windows File Systems Devs Interest List
> > Subject: [ntfsd] Tracking file
> >
> > Dear whom it may concern,
> >
> > I’m a device driver engineer from Japan, Recently, i have been writing
> > a FS Filter Driver, and I got a big probelm. I would really like
> somebady
> > helping me to deal this probelm.
> > In this driver, I need tracking a file, I refer NT Insider in the OSR
> > site,
> > (http://www.osronline.com/article.cfm?id=102) and try to use same
> method
> > to do it.
> >
> > However, the file tracking doesn’t seem to work correctly.
> > The poblem is that the context cann’t be removed correctly.
> >
> > Since DataSectionObject is not NULL when closing a certain file, a
> request
> > is completed without deleting a context.
> > Next, CLOSE of a stream file object with the same FCB comes.
> > At this time, since DataSectionObject is not NULL, a context is not
> > deleted, either.
> > CLOSE of a file with the same FCB is not notified to a driver after
> this.
> > Instead, the CREATE request whose FS returns the same FCB is notified.
> > But, the file name passed by this CREATE differs from upper CLOSE.
> >
> > I am troubled very much by this problem.
> > Has somebaby bumped into the similar problem?
> >
> >
> > And, I am performing the tracking of a file,
> > in order to acquire a file name from the stream file object at the time
> > of delay writing.
> > If I could find the way to acquire a file from a stream file object,
> This
> > problem will be solved.
> > Does somebady know the method of acquiring a file name without the file
> > tracking?
> >
> > If you have any useful information, Please e-mail me, I really
> appreciate
> > for you help.
> >
> > Tadashi, Kimura
> >
> >
> > —
> > Questions? First check the IFS FAQ at
> > https://www.osronline.com/article.cfm?id=17
> >
> > You are currently subscribed to ntfsd as: xxxxx@cdp.com
> > To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@cdp.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com

Hello, Rob and Peter:

Thank you for your reply.

I got the file name by using ObQueryNameString.

The file name got by using ObQueryNameString is saved in a context.
Then, this file name is compared with the file name got newly at the CREATE request.
When these two file names differ, I judge that a file name is wrong.

Take your advice, I exchanged ObQueryNameString to File_QueryFileName and tried it again.
But, I find “the wrong file name” at a CREATE request.

When “the wrong file name” is found, the two difference file name can be find as follows.

[Context] E:\SYSTEM VOLUMEINFORMATION_RESTORE{9BD92293-76B7-482B-9C4B-3FD6B666017D}_FILELST.CFG
[FileObject] E:\WINDOWS\System32\odbcint.dll

Does NTFS treat the file in “System Volume Information” by using the special method?
Could you tell me if you have a difference ideas?

Thank you for helping.

Tadashi Kimura,

----- Original Message -----
From: “Rob Green”
To: “Windows File Systems Devs Interest List”
Sent: Saturday, July 24, 2004 12:13 AM
Subject: RE: [ntfsd] Tracking file

I agree with Peter. How are you getting the file name? you should not be
accessing the FileObject->FileName field. If you use the Query below, it
will return you the name of the file. I have attached the filename function
incase yours is wrong. This routine can only be called when not in the
current file system path as some locks are already held and a deadlock will
occur.

PUNICODE_STRING File_QueryFileName(
PFILE_OBJECT fileObject
)
{
PFILE_NAME_INFORMATION Name;
PUNICODE_STRING UniName=NULL;
ULONG AllocSize;
NTSTATUS Status;

if(!fileObject) {
return NULL;
}

__try {

AllocSize = 1024sizeof(WCHAR)+sizeof(ULONG);
Name =
(PFILE_NAME_INFORMATION)MemAllocatePoolWithTag(PagedPool,AllocSize,FILENAMET
AG);

if(Name) {
Status = IoQueryFileInformation( fileObject,
FileNameInformation,
AllocSize,
Name,
&AllocSize);

if(NT_SUCCESS(Status)) {
if(Name->FileNameLength<=AllocSize) {
UniName = GetUniString(Name->FileNameLength);
if(UniName) {
__try {

RtlCopyMemory(UniName->Buffer,Name->FileName,Name->FileNameLength);
}
__except(ExceptionFilter(GetExceptionInformation())) {
Debug(DEBUG_FILE,(“GetFileName: Exception
%08x\n”,GetExceptionCode()));
FREE_POINTER(UniName);
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Out of memory for
uniname\n”));
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Filename length is to
large\n”));
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Error %08x querying file
information\n”,Status));
}
FREE_POINTER(Name);
} else {
Debug(DEBUG_FILE,(“GetFileName: Error out of memory\n”));
}

}__except (ExceptionFilter(GetExceptionInformation())) {
Debug(DEBUG_FILE,(“GetFileName: Exception
%08x\n”,GetExceptionCode()));
}
return UniName;
}

STATIC PUNICODE_STRING GetUniString( ULONG Size )
{
PUNICODE_STRING String;

PAGED_CODE();
String =
(PUNICODE_STRING)MemAllocatePoolWithTag(NonPagedPool,sizeof(UNICODE_STRING)+
Size+sizeof(WCHAR),FILENAMETAG);
if(String) {
RtlZeroMemory(String, sizeof(UNICODE_STRING)+Size+sizeof(WCHAR));

String->Length = (unsigned short)Size;
String->MaximumLength = (unsigned short)(Size+sizeof(WCHAR));
String->Buffer = (WCHAR
)(String+1);
}
return String;
}

Thanks,
Rob

> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:bounce-182242-
> xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> Sent: Friday, July 23, 2004 9:47 AM
> To: Windows File Systems Devs Interest List
> Subject: Re: [ntfsd] Tracking file
>
> Rob,
>
> Thank you for your reply.
>
> I challenged file tracking again using the following code.
> But problem was not solved.
>
> Even if I use a new driver including following code, our driver can find
> context(FCB pointer).
> That context matches current context in driver’s FCB table, but filename
> is wrong.
>
> Therefore, I think that the cause of this problem is either of the
> following.
> 1. IRP_MJ_CLOSE is not notified to a filter driver.
> 2. VM reuses a stream file object for a another file.
>
> Is my guess right?
>
>
> Now, in my driver, in order to solve this problem, delay write is
> disabled.
> I need only the tracking of READ/WRITE.
> Therefore, I think that this problem is solved by CcFlushCache in CLEANUP.
> Are there other problems which interfere the tracking of READ/WRITE?
>
> When other problems are known, please let me know.
>
>
> Tadashi, Kimura
>
>
> ----- Original Message -----
> From: “Rob Green”
> To: “Windows File Systems Devs Interest List”
> Sent: Thursday, July 15, 2004 10:01 AM
> Subject: RE: [ntfsd] Tracking file
>
>
> Here is code I am providing to track files objects via the simple method.
> I
> use this code in a production driver. If you find any problems or
> enhancements let me know. Also if it doesn’t come out right in the list,
> I
> will find some website to host on. The functions I don’t provide source
> code to should be obvious, but if not let me know I will explain what they
> do. It should be trivial to convert it to C source code (its in CPP)
>
> fo_ref.h ---------------------------------------------
> /*
>
> fo_ref.h - Copyright (c) 2004 Columbia Data Products, Inc. All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
>
> /
> * Querys, adds or removes a object on the list
>
> * This function uses FsContexts to determine a specific
> * file that is open instead of FileObjects which identify
> * an instance. IOW You can have 5 opens of the same file
> * and you will have 5 file objects and 1 FsContext.
>
> * see http://www.osronline.com/article.cfm?id=102 for more info
> * on how this works
> /
>
> class Generic_FileObject_RefCount: public DeletableObject
> {
> protected:
> RTL_GENERIC_TABLE Table;
>
> #define FO_REF_ACTION_QUERY 0
> #define FO_REF_ACTION_ADD 1
> #define FO_REF_ACTION_REMOVE 2
>
> typedef struct sFO_Ref {
> ULONG RefCount;
> PUNICODE_STRING Name;
> PFILE_OBJECT FileObject;
> PVOID FsContext;
> PVOID Data;
> } tFO_Ref;
>
> static RTL_GENERIC_COMPARE_RESULTS CompareElement (
> struct _RTL_GENERIC_TABLE Table,
> PVOID FirstStruct,
> PVOID SecondStruct
> )
> {
>
> if(((tFO_Ref
)FirstStruct)->FsContext==((tFO_Ref
)SecondStruct)-
> >FsContext)
> return GenericEqual;
>
>
> if(((tFO_Ref
)FirstStruct)->FsContext<((tFO_Ref
)SecondStruct)->FsContext)
> return GenericLessThan;
>
> return GenericGreaterThan;
> }
>
> static PVOID AllocElement (
> struct _RTL_GENERIC_TABLE *Table,
> CLONG ByteSize
> )
> {
> return MemAllocatePoolWithTag(PagedPool,ByteSize,PSM_FO_TAG);
> }
>
> static VOID FreeElement (
> struct _RTL_GENERIC_TABLE *Table,
> PVOID Buffer
> )
> {
> MemFreePool(Buffer);
> return;
> }
>
> bool DoWork( PFILE_OBJECT FileObject, DWORD Action, PVOID *Data,
> PUNICODE_STRING *Uni );
>
> private:
> FAST_MUTEX Mutex;
>
> virtual NTSTATUS Init()
> {
> PAGED_CODE();
> ExInitializeFastMutex(&Mutex);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElement,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> PAGED_CODE();
> ExAcquireFastMutex( &Mutex );
> }
>
> virtual VOID ReleaseLock()
> {
> PAGED_CODE();
> ExReleaseFastMutex(&Mutex);
> }
>
> virtual void Destroy()
> {
> // shouldnt get called
> ASSERT(FALSE);
> }
>
> public:
> Generic_FileObject_RefCount()
> {
> /lint -e{534} ignore return value/
> Init();
> }
>
> virtual ~Generic_FileObject_RefCount()
> {
> Destroy();
> }
>
> /

> * Adds a file object to the list if it doesnt already
> * exist, otherwise the reference count is incremented.
> *
> * This method must be called during the create completion
> * handler or in the dispatch handler after the call has
> * been sent down synchronously.
> *
> * @param FileObject FileObject to keep track of.
> *
> * @return true - File was already in list
> * false - File was not in list
> */
> bool Add( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,NULL,NULL);
> }
> bool Add( PFILE_OBJECT FileObject, PVOID Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,&Data,NULL);
> }
>
> /
> * Returns if the file object is in the list
> *
> * @param FileObject FileObject to check for
> *
> * @return true - file is on list
> * false - file is not on list
> */
> bool Query( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,NULL,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data, PUNICODE_STRING *Uni
> )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,Uni);
> }
>
> /

> * Decrements a reference count on the file object.
> * If the reference count is 0 the file object may be
> * removed from the list.
> *
> * @param FileObject File object to remove
> *
> * @return true - file object was on list
> * false - file object was not on list
> */
> bool Remove( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,NULL,NULL);
> }
> bool Remove( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,Data,NULL);
> }
> };
>
> class Generic_FileObject_RefCountNP: public Generic_FileObject_RefCount
> {
> private:
> KSPIN_LOCK SpinLock;
> KIRQL OldIrql;
>
> static PVOID AllocElementNP (
> struct _RTL_GENERIC_TABLE Table,
> CLONG ByteSize
> )
> {
> return MemAllocatePoolWithTag(NonPagedPool,ByteSize,PSM_FO_TAG);
> }
>
> virtual NTSTATUS Init()
> {
> KeInitializeSpinLock(&SpinLock);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElementNP,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> pmAcquireSpinLock ( &SpinLock, &OldIrql );
> }
>
> virtual VOID ReleaseLock()
> {
> pmReleaseSpinLock(&SpinLock,OldIrql);
> }
>
> };
> fo_ref.cpp ---------------------------------------------
> /

>
> fo_ref.cpp - Copyright (c) 2004 Columbia Data Products, Inc. All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
> #include “precomp.h”
>
> #ifdef RUN_WPP
> extern “C” {
> #include “fo_ref.tmh”
> }
> #endif
>
>
> // Note: If a file is cached we may not see the close for it until
> sometime
> later
> // this could be immediately or hours or days. It depends on how busy the
> system
> // is
> bool Generic_FileObject_RefCount::DoWork( PFILE_OBJECT FileObject, DWORD
> Action, PVOID *Data, PUNICODE_STRING *Uni )
> {
> if(FileObject->FsContext == NULL) {
> return false;
> }
>
> GetLock();
>
> tFO_Ref _x;
> _x.FsContext = FileObject->FsContext;
>
> tFO_Ref *Found = (tFO_Ref *)RtlLookupElementGenericTable(&Table,&_x);
>
> if ( (Action == FO_REF_ACTION_QUERY) && (Found) ) {
> if(Data) {
> *Data = Found->Data;
> }
> if(Uni) {
> *Uni = Found->Name;
> }
> } else
> if ( (Action == FO_REF_ACTION_REMOVE) && (Found)) {
> // For each IRP_MJ_CLOSE the filter driver decrements the
> reference
> // count on the per-file context structure if the FO_STREAM_FILE
> bit
> // is not set for the file object.
> if((!(FileObject->Flags & FO_STREAM_FILE)) && (Found->RefCount)) {
> Found->RefCount–;
> }
>
> // If the reference count for the per-file context structure
> reaches
> // zero and both the ImageSectionObject and DataSectionObject of
> the
> // SectionObjectPointers field from the FILE_OBJECT is zero, the
> // filter driver may then delete the per-file context data.
>
> if ((Found->RefCount==0) &&
> ((!FileObject->SectionObjectPointer) ||
> ((!FileObject->SectionObjectPointer->ImageSectionObject) &&
> (!FileObject->SectionObjectPointer->DataSectionObject)))) {
>
> if(Found->Name) {
> MemFreePool(Found->Name);
> Found->Name = NULL;
> }
>
> if(Data) {
> *Data=Found->Data;
> }
> RtlDeleteElementGenericTable(&Table,Found);
> } else {
> // only say found if we actually delete the entry
> Found = NULL;
> }
> }
>
> tFO_Ref *GetFileNameEntry=NULL;
>
> if(Action == FO_REF_ACTION_ADD) {
> // For each IRP_MJ_CREATE, the filter driver increments the
> reference
> // count on the per-file context structure.
>
> if(!Found) {
> tFO_Ref x;
> BOOLEAN Ret;
>
> x.FsContext = FileObject->FsContext;
> x.RefCount=1;
>
> x.Name = NULL;
> x.FileObject = FileObject;
>
> if(Data) {
> x.Data = Data;
> } else {
> x.Data = NULL;
> }
>
> Found =
> (tFO_Ref
)RtlInsertElementGenericTable(&Table,&x,sizeof(tFO_Ref),&Ret);
>
> // so we will get the name after the lock is released
> GetFileNameEntry = Found;
>
> } else {
> Found->RefCount++;
> }
> } // if add
>
> ReleaseLock();
>
> if(GetFileNameEntry) {
> GetFileNameEntry->Name =
> File_QueryFileName(GetFileNameEntry->FileObject);
> if(Uni) {
> Uni = GetFileNameEntry->Name;
> }
> }
>
>
> return Found ? true : false;
> }
>
>
>
>
>
> /

>
> How to declare
>
> Generic_FileObject_RefCount StreamFiles=NULL;
> StreamFiles = new Generic_FileObject_RefCount();
>
>
> How to add
> Note: You must call the add routine in the Create Completion
> routine
> or after you have already sent the request down in the
> dispatch
> routine
>
> StreamFiles->Add(IrpSp->FileObject,PrivateData);
>
> How to Query
>
> if(StreamFiles->Query(IrpSp->FileObject,(PVOID
)&PrivateData,&Uni)) {
> Debug(DEBUG_DICT,( “File = %wZ\n”,Uni));
> }
>
>
>
>
>
> */
>
> Thanks,
> Rob
>
>
> > -----Original Message-----
> > From: xxxxx@lists.osr.com [mailto:bounce-181171-
> > xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> > Sent: Wednesday, July 14, 2004 8:24 PM
> > To: Windows File Systems Devs Interest List
> > Subject: [ntfsd] Tracking file
> >
> > Dear whom it may concern,
> >
> > I’m a device driver engineer from Japan, Recently, i have been writing
> > a FS Filter Driver, and I got a big probelm. I would really like
> somebady
> > helping me to deal this probelm.
> > In this driver, I need tracking a file, I refer NT Insider in the OSR
> > site,
> > (http://www.osronline.com/article.cfm?id=102) and try to use same
> method
> > to do it.
> >
> > However, the file tracking doesn’t seem to work correctly.
> > The poblem is that the context cann’t be removed correctly.
> >
> > Since DataSectionObject is not NULL when closing a certain file, a
> request
> > is completed without deleting a context.
> > Next, CLOSE of a stream file object with the same FCB comes.
> > At this time, since DataSectionObject is not NULL, a context is not
> > deleted, either.
> > CLOSE of a file with the same FCB is not notified to a driver after
> this.
> > Instead, the CREATE request whose FS returns the same FCB is notified.
> > But, the file name passed by this CREATE differs from upper CLOSE.
> >
> > I am troubled very much by this problem.
> > Has somebaby bumped into the similar problem?
> >
> >
> > And, I am performing the tracking of a file,
> > in order to acquire a file name from the stream file object at the time
> > of delay writing.
> > If I could find the way to acquire a file from a stream file object,
> This
> > problem will be solved.
> > Does somebady know the method of acquiring a file name without the file
> > tracking?
> >
> > If you have any useful information, Please e-mail me, I really
> appreciate
> > for you help.
> >
> > Tadashi, Kimura
> >
> >
> > —
> > Questions? First check the IFS FAQ at
> > https://www.osronline.com/article.cfm?id=17
> >
> > You are currently subscribed to ntfsd as: xxxxx@cdp.com
> > To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@cdp.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
To unsubscribe send a blank email to xxxxx@lists.osr.com

Where and how are you getting the file names for both of them? You CAN NOT
access FileObject->FileName outside of IRP_MJ_CREATE as the buffer may have
been FREED by NTFS, or worse reallocated for another file object.

Thanks,
Rob

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-183410-
xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
Sent: Wednesday, August 04, 2004 5:12 AM
To: Windows File Systems Devs Interest List
Subject: Re: [ntfsd] Tracking file

Hello, Rob and Peter:

Thank you for your reply.

I got the file name by using ObQueryNameString.

The file name got by using ObQueryNameString is saved in a context.
Then, this file name is compared with the file name got newly at the
CREATE request.
When these two file names differ, I judge that a file name is wrong.

Take your advice, I exchanged ObQueryNameString to File_QueryFileName and
tried it again.
But, I find “the wrong file name” at a CREATE request.

When “the wrong file name” is found, the two difference file name can be
find as follows.

[Context] E:\SYSTEM VOLUMEINFORMATION_RESTORE{9BD92293-76B7-482B-9C4B-
3FD6B666017D}_FILELST.CFG
[FileObject] E:\WINDOWS\System32\odbcint.dll

Does NTFS treat the file in “System Volume Information” by using the
special method?
Could you tell me if you have a difference ideas?

Thank you for helping.

Tadashi Kimura,

----- Original Message -----
From: “Rob Green”
> To: “Windows File Systems Devs Interest List”
> Sent: Saturday, July 24, 2004 12:13 AM
> Subject: RE: [ntfsd] Tracking file
>
>
> I agree with Peter. How are you getting the file name? you should not be
> accessing the FileObject->FileName field. If you use the Query below, it
> will return you the name of the file. I have attached the filename
> function
> incase yours is wrong. This routine can only be called when not in the
> current file system path as some locks are already held and a deadlock
> will
> occur.
>
> PUNICODE_STRING File_QueryFileName(
> PFILE_OBJECT fileObject
> )
> {
> PFILE_NAME_INFORMATION Name;
> PUNICODE_STRING UniName=NULL;
> ULONG AllocSize;
> NTSTATUS Status;
>
> if(!fileObject) {
> return NULL;
> }
>
> __try {
>
> AllocSize = 1024sizeof(WCHAR)+sizeof(ULONG);
> Name =
> (PFILE_NAME_INFORMATION)MemAllocatePoolWithTag(PagedPool,AllocSize,FILENAM
> ET
> AG);
>
> if(Name) {
> Status = IoQueryFileInformation( fileObject,
> FileNameInformation,
> AllocSize,
> Name,
> &AllocSize);
>
> if(NT_SUCCESS(Status)) {
> if(Name->FileNameLength<=AllocSize) {
> UniName = GetUniString(Name->FileNameLength);
> if(UniName) {
>__try {
>
> RtlCopyMemory(UniName->Buffer,Name->FileName,Name->FileNameLength);
> }
> __except(ExceptionFilter(GetExceptionInformation())) {
> Debug(DEBUG_FILE,(“GetFileName: Exception
> %08x\n”,GetExceptionCode()));
> FREE_POINTER(UniName);
> }
> } else {
> Debug(DEBUG_FILE,(“GetFileName: Out of memory for
> uniname\n”));
> }
> } else {
> Debug(DEBUG_FILE,(“GetFileName: Filename length is to
> large\n”));
> }
> } else {
> Debug(DEBUG_FILE,(“GetFileName: Error %08x querying file
> information\n”,Status));
> }
> FREE_POINTER(Name);
> } else {
> Debug(DEBUG_FILE,(“GetFileName: Error out of memory\n”));
> }
>
> }__except (ExceptionFilter(GetExceptionInformation())) {
> Debug(DEBUG_FILE,(“GetFileName: Exception
> %08x\n”,GetExceptionCode()));
> }
> return UniName;
> }
>
> STATIC PUNICODE_STRING GetUniString( ULONG Size )
> {
> PUNICODE_STRING String;
>
> PAGED_CODE();
> String =
> (PUNICODE_STRING)MemAllocatePoolWithTag(NonPagedPool,sizeof(UNICODE_STRING
> )+
> Size+sizeof(WCHAR),FILENAMETAG);
> if(String) {
> RtlZeroMemory(String, sizeof(UNICODE_STRING)+Size+sizeof(WCHAR));
>
> String->Length = (unsigned short)Size;
> String->MaximumLength = (unsigned short)(Size+sizeof(WCHAR));
> String->Buffer = (WCHAR
)(String+1);
> }
> return String;
> }
>
> Thanks,
> Rob
>
>
> > -----Original Message-----
> > From: xxxxx@lists.osr.com [mailto:bounce-182242-
> > xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> > Sent: Friday, July 23, 2004 9:47 AM
> > To: Windows File Systems Devs Interest List
> > Subject: Re: [ntfsd] Tracking file
> >
> > Rob,
> >
> > Thank you for your reply.
> >
> > I challenged file tracking again using the following code.
> > But problem was not solved.
> >
> > Even if I use a new driver including following code, our driver can find
> > context(FCB pointer).
> > That context matches current context in driver’s FCB table, but filename
> > is wrong.
> >
> > Therefore, I think that the cause of this problem is either of the
> > following.
> > 1. IRP_MJ_CLOSE is not notified to a filter driver.
> > 2. VM reuses a stream file object for a another file.
> >
> > Is my guess right?
> >
> >
> > Now, in my driver, in order to solve this problem, delay write is
> > disabled.
> > I need only the tracking of READ/WRITE.
> > Therefore, I think that this problem is solved by CcFlushCache in
> CLEANUP.
> > Are there other problems which interfere the tracking of READ/WRITE?
> >
> > When other problems are known, please let me know.
> >
> >
> > Tadashi, Kimura
> >
> >
> > ----- Original Message -----
> > From: “Rob Green”
> > To: “Windows File Systems Devs Interest List”
> > Sent: Thursday, July 15, 2004 10:01 AM
> > Subject: RE: [ntfsd] Tracking file
> >
> >
> > Here is code I am providing to track files objects via the simple
> method.
> > I
> > use this code in a production driver. If you find any problems or
> > enhancements let me know. Also if it doesn’t come out right in the
> list,
> > I
> > will find some website to host on. The functions I don’t provide source
> > code to should be obvious, but if not let me know I will explain what
> they
> > do. It should be trivial to convert it to C source code (its in CPP)
> >
> > fo_ref.h ---------------------------------------------
> > /*
> >
> > fo_ref.h - Copyright (c) 2004 Columbia Data Products, Inc. All
> > Rights Reserved.
> >
> > Maintains reference counts on file objects
> > see http://www.osronline.com/article.cfm?id=102 for more info on how
> > this works
> >
> > Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
> >
> > Version 1.1 7/14/2004
> >
> > You may use freely in as long as you give credit in the source code.
> >
> > Found bugs? send them to me (xxxxx@cdp.com)
> > */
> >
> >
> > /
> > * Querys, adds or removes a object on the list
> >
> > * This function uses FsContexts to determine a specific
> > * file that is open instead of FileObjects which identify
> > * an instance. IOW You can have 5 opens of the same file
> > * and you will have 5 file objects and 1 FsContext.
> >
> > * see http://www.osronline.com/article.cfm?id=102 for more info
> > * on how this works
> > /
> >
> > class Generic_FileObject_RefCount: public DeletableObject
> > {
> > protected:
> > RTL_GENERIC_TABLE Table;
> >
> > #define FO_REF_ACTION_QUERY 0
> > #define FO_REF_ACTION_ADD 1
> > #define FO_REF_ACTION_REMOVE 2
> >
> > typedef struct sFO_Ref {
> > ULONG RefCount;
> > PUNICODE_STRING Name;
> > PFILE_OBJECT FileObject;
> > PVOID FsContext;
> > PVOID Data;
> > } tFO_Ref;
> >
> > static RTL_GENERIC_COMPARE_RESULTS CompareElement (
> > struct _RTL_GENERIC_TABLE Table,
> > PVOID FirstStruct,
> > PVOID SecondStruct
> > )
> > {
> >
> > if(((tFO_Ref
)FirstStruct)->FsContext==((tFO_Ref
)SecondStruct)-
> > >FsContext)
> > return GenericEqual;
> >
> >
> > if(((tFO_Ref
)FirstStruct)->FsContext<((tFO_Ref
)SecondStruct)-
> >FsContext)
> > return GenericLessThan;
> >
> > return GenericGreaterThan;
> > }
> >
> > static PVOID AllocElement (
> > struct _RTL_GENERIC_TABLE *Table,
> > CLONG ByteSize
> > )
> > {
> > return MemAllocatePoolWithTag(PagedPool,ByteSize,PSM_FO_TAG);
> > }
> >
> > static VOID FreeElement (
> > struct _RTL_GENERIC_TABLE *Table,
> > PVOID Buffer
> > )
> > {
> > MemFreePool(Buffer);
> > return;
> > }
> >
> > bool DoWork( PFILE_OBJECT FileObject, DWORD Action, PVOID *Data,
> > PUNICODE_STRING *Uni );
> >
> > private:
> > FAST_MUTEX Mutex;
> >
> > virtual NTSTATUS Init()
> > {
> > PAGED_CODE();
> > ExInitializeFastMutex(&Mutex);
> > RtlInitializeGenericTable(
> > &Table,
> > (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> > (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElement,
> > (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> > NULL
> > );
> > return STATUS_SUCCESS;
> > }
> >
> > virtual VOID GetLock()
> > {
> > PAGED_CODE();
> > ExAcquireFastMutex( &Mutex );
> > }
> >
> > virtual VOID ReleaseLock()
> > {
> > PAGED_CODE();
> > ExReleaseFastMutex(&Mutex);
> > }
> >
> > virtual void Destroy()
> > {
> > // shouldnt get called
> > ASSERT(FALSE);
> > }
> >
> > public:
> > Generic_FileObject_RefCount()
> > {
> > /lint -e{534} ignore return value/
> > Init();
> > }
> >
> > virtual ~Generic_FileObject_RefCount()
> > {
> > Destroy();
> > }
> >
> > /

> > * Adds a file object to the list if it doesnt already
> > * exist, otherwise the reference count is incremented.
> > *
> > * This method must be called during the create completion
> > * handler or in the dispatch handler after the call has
> > * been sent down synchronously.
> > *
> > * @param FileObject FileObject to keep track of.
> > *
> > * @return true - File was already in list
> > * false - File was not in list
> > */
> > bool Add( PFILE_OBJECT FileObject )
> > {
> > return DoWork(FileObject,FO_REF_ACTION_ADD,NULL,NULL);
> > }
> > bool Add( PFILE_OBJECT FileObject, PVOID Data )
> > {
> > return DoWork(FileObject,FO_REF_ACTION_ADD,&Data,NULL);
> > }
> >
> > /
> > * Returns if the file object is in the list
> > *
> > * @param FileObject FileObject to check for
> > *
> > * @return true - file is on list
> > * false - file is not on list
> > */
> > bool Query( PFILE_OBJECT FileObject )
> > {
> > return DoWork(FileObject,FO_REF_ACTION_QUERY,NULL,NULL);
> > }
> > bool Query( PFILE_OBJECT FileObject, PVOID *Data )
> > {
> > return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,NULL);
> > }
> > bool Query( PFILE_OBJECT FileObject, PVOID *Data, PUNICODE_STRING
> *Uni
> > )
> > {
> > return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,Uni);
> > }
> >
> > /

> > * Decrements a reference count on the file object.
> > * If the reference count is 0 the file object may be
> > * removed from the list.
> > *
> > * @param FileObject File object to remove
> > *
> > * @return true - file object was on list
> > * false - file object was not on list
> > */
> > bool Remove( PFILE_OBJECT FileObject )
> > {
> > return DoWork(FileObject,FO_REF_ACTION_REMOVE,NULL,NULL);
> > }
> > bool Remove( PFILE_OBJECT FileObject, PVOID *Data )
> > {
> > return DoWork(FileObject,FO_REF_ACTION_REMOVE,Data,NULL);
> > }
> > };
> >
> > class Generic_FileObject_RefCountNP: public Generic_FileObject_RefCount
> > {
> > private:
> > KSPIN_LOCK SpinLock;
> > KIRQL OldIrql;
> >
> > static PVOID AllocElementNP (
> > struct _RTL_GENERIC_TABLE Table,
> > CLONG ByteSize
> > )
> > {
> > return MemAllocatePoolWithTag(NonPagedPool,ByteSize,PSM_FO_TAG);
> > }
> >
> > virtual NTSTATUS Init()
> > {
> > KeInitializeSpinLock(&SpinLock);
> > RtlInitializeGenericTable(
> > &Table,
> > (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> > (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElementNP,
> > (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> > NULL
> > );
> > return STATUS_SUCCESS;
> > }
> >
> > virtual VOID GetLock()
> > {
> > pmAcquireSpinLock ( &SpinLock, &OldIrql );
> > }
> >
> > virtual VOID ReleaseLock()
> > {
> > pmReleaseSpinLock(&SpinLock,OldIrql);
> > }
> >
> > };
> > fo_ref.cpp ---------------------------------------------
> > /

> >
> > fo_ref.cpp - Copyright (c) 2004 Columbia Data Products, Inc. All
> > Rights Reserved.
> >
> > Maintains reference counts on file objects
> > see http://www.osronline.com/article.cfm?id=102 for more info on how
> > this works
> >
> > Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
> >
> > Version 1.1 7/14/2004
> >
> > You may use freely in as long as you give credit in the source code.
> >
> > Found bugs? send them to me (xxxxx@cdp.com)
> > */
> >
> > #include “precomp.h”
> >
> > #ifdef RUN_WPP
> > extern “C” {
> > #include “fo_ref.tmh”
> > }
> > #endif
> >
> >
> > // Note: If a file is cached we may not see the close for it until
> > sometime
> > later
> > // this could be immediately or hours or days. It depends on how busy
> the
> > system
> > // is
> > bool Generic_FileObject_RefCount::DoWork( PFILE_OBJECT FileObject, DWORD
> > Action, PVOID *Data, PUNICODE_STRING *Uni )
> > {
> > if(FileObject->FsContext == NULL) {
> > return false;
> > }
> >
> > GetLock();
> >
> > tFO_Ref _x;
> > _x.FsContext = FileObject->FsContext;
> >
> > tFO_Ref *Found = (tFO_Ref
> *)RtlLookupElementGenericTable(&Table,&_x);
> >
> > if ( (Action == FO_REF_ACTION_QUERY) && (Found) ) {
> > if(Data) {
> > *Data = Found->Data;
> > }
> > if(Uni) {
> > *Uni = Found->Name;
> > }
> > } else
> > if ( (Action == FO_REF_ACTION_REMOVE) && (Found)) {
> > // For each IRP_MJ_CLOSE the filter driver decrements the
> > reference
> > // count on the per-file context structure if the FO_STREAM_FILE
> > bit
> > // is not set for the file object.
> > if((!(FileObject->Flags & FO_STREAM_FILE)) && (Found->RefCount))
> {
> > Found->RefCount–;
> > }
> >
> > // If the reference count for the per-file context structure
> > reaches
> > // zero and both the ImageSectionObject and DataSectionObject of
> > the
> > // SectionObjectPointers field from the FILE_OBJECT is zero, the
> > // filter driver may then delete the per-file context data.
> >
> > if ((Found->RefCount==0) &&
> > ((!FileObject->SectionObjectPointer) ||
> > ((!FileObject->SectionObjectPointer->ImageSectionObject) &&
> > (!FileObject->SectionObjectPointer->DataSectionObject)))) {
> >
> > if(Found->Name) {
> > MemFreePool(Found->Name);
> > Found->Name = NULL;
> > }
> >
> > if(Data) {
> > *Data=Found->Data;
> > }
> > RtlDeleteElementGenericTable(&Table,Found);
> > } else {
> > // only say found if we actually delete the entry
> > Found = NULL;
> > }
> > }
> >
> > tFO_Ref *GetFileNameEntry=NULL;
> >
> > if(Action == FO_REF_ACTION_ADD) {
> > // For each IRP_MJ_CREATE, the filter driver increments the
> > reference
> > // count on the per-file context structure.
> >
> > if(!Found) {
> > tFO_Ref x;
> > BOOLEAN Ret;
> >
> > x.FsContext = FileObject->FsContext;
> > x.RefCount=1;
> >
> > x.Name = NULL;
> > x.FileObject = FileObject;
> >
> > if(Data) {
> > x.Data = Data;
> > } else {
> > x.Data = NULL;
> > }
> >
> > Found =
> > (tFO_Ref
)RtlInsertElementGenericTable(&Table,&x,sizeof(tFO_Ref),&Ret);
> >
> > // so we will get the name after the lock is released
> > GetFileNameEntry = Found;
> >
> > } else {
> > Found->RefCount++;
> > }
> > } // if add
> >
> > ReleaseLock();
> >
> > if(GetFileNameEntry) {
> > GetFileNameEntry->Name =
> > File_QueryFileName(GetFileNameEntry->FileObject);
> > if(Uni) {
> > Uni = GetFileNameEntry->Name;
> > }
> > }
> >
> >
> > return Found ? true : false;
> > }
> >
> >
> >
> >
> >
> > /

> >
> > How to declare
> >
> > Generic_FileObject_RefCount StreamFiles=NULL;
> > StreamFiles = new Generic_FileObject_RefCount();
> >
> >
> > How to add
> > Note: You must call the add routine in the Create Completion
> > routine
> > or after you have already sent the request down in the
> > dispatch
> > routine
> >
> > StreamFiles->Add(IrpSp->FileObject,PrivateData);
> >
> > How to Query
> >
> > if(StreamFiles->Query(IrpSp->FileObject,(PVOID
)&PrivateData,&Uni)) {
> > Debug(DEBUG_DICT,( “File = %wZ\n”,Uni));
> > }
> >
> >
> >
> >
> >
> > */
> >
> > Thanks,
> > Rob
> >
> >
> > > -----Original Message-----
> > > From: xxxxx@lists.osr.com [mailto:bounce-181171-
> > > xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> > > Sent: Wednesday, July 14, 2004 8:24 PM
> > > To: Windows File Systems Devs Interest List
> > > Subject: [ntfsd] Tracking file
> > >
> > > Dear whom it may concern,
> > >
> > > I’m a device driver engineer from Japan, Recently, i have been
> writing
> > > a FS Filter Driver, and I got a big probelm. I would really like
> > somebady
> > > helping me to deal this probelm.
> > > In this driver, I need tracking a file, I refer NT Insider in the
> OSR
> > > site,
> > > (http://www.osronline.com/article.cfm?id=102) and try to use same
> > method
> > > to do it.
> > >
> > > However, the file tracking doesn’t seem to work correctly.
> > > The poblem is that the context cann’t be removed correctly.
> > >
> > > Since DataSectionObject is not NULL when closing a certain file, a
> > request
> > > is completed without deleting a context.
> > > Next, CLOSE of a stream file object with the same FCB comes.
> > > At this time, since DataSectionObject is not NULL, a context is not
> > > deleted, either.
> > > CLOSE of a file with the same FCB is not notified to a driver after
> > this.
> > > Instead, the CREATE request whose FS returns the same FCB is notified.
> > > But, the file name passed by this CREATE differs from upper CLOSE.
> > >
> > > I am troubled very much by this problem.
> > > Has somebaby bumped into the similar problem?
> > >
> > >
> > > And, I am performing the tracking of a file,
> > > in order to acquire a file name from the stream file object at the
> time
> > > of delay writing.
> > > If I could find the way to acquire a file from a stream file object,
> > This
> > > problem will be solved.
> > > Does somebady know the method of acquiring a file name without the
> file
> > > tracking?
> > >
> > > If you have any useful information, Please e-mail me, I really
> > appreciate
> > > for you help.
> > >
> > > Tadashi, Kimura
> > >
> > >
> > > —
> > > Questions? First check the IFS FAQ at
> > > https://www.osronline.com/article.cfm?id=17
> > >
> > > You are currently subscribed to ntfsd as: xxxxx@cdp.com
> > > To unsubscribe send a blank email to xxxxx@lists.osr.com
> >
> >
> > —
> > Questions? First check the IFS FAQ at
> > https://www.osronline.com/article.cfm?id=17
> >
> > You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
> > To unsubscribe send a blank email to xxxxx@lists.osr.com
> >
> > —
> > Questions? First check the IFS FAQ at
> > https://www.osronline.com/article.cfm?id=17
> >
> > You are currently subscribed to ntfsd as: xxxxx@cdp.com
> > To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@cdp.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com

Just so this is clear for everyone.

There are no special back-doors into the file systems that are used
internally. There are no secret directories that are handled specially.
We want filters to see all of the operations to all of the files so they
can appropriately do their job.

For the problem below you are most likely doing something wrong in your
filter.

Neal Christiansen
Microsoft File System Filter Group Lead
This posting is provided “AS IS” with no warranties, and confers no
rights

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
Sent: Wednesday, August 04, 2004 2:12 AM
To: Windows File Systems Devs Interest List
Subject: Re: [ntfsd] Tracking file

Hello, Rob and Peter:

Thank you for your reply.

I got the file name by using ObQueryNameString.

The file name got by using ObQueryNameString is saved in a context.
Then, this file name is compared with the file name got newly at the
CREATE request.
When these two file names differ, I judge that a file name is wrong.

Take your advice, I exchanged ObQueryNameString to File_QueryFileName
and tried it again.
But, I find “the wrong file name” at a CREATE request.

When “the wrong file name” is found, the two difference file name can be
find as follows.

[Context] E:\SYSTEM
VOLUMEINFORMATION_RESTORE{9BD92293-76B7-482B-9C4B-3FD6B666017D}_FILELS
T.CFG
[FileObject] E:\WINDOWS\System32\odbcint.dll

Does NTFS treat the file in “System Volume Information” by using the
special method?
Could you tell me if you have a difference ideas?

Thank you for helping.

Tadashi Kimura,

----- Original Message -----
From: “Rob Green”
To: “Windows File Systems Devs Interest List”
Sent: Saturday, July 24, 2004 12:13 AM
Subject: RE: [ntfsd] Tracking file

I agree with Peter. How are you getting the file name? you should not
be
accessing the FileObject->FileName field. If you use the Query below,
it
will return you the name of the file. I have attached the filename
function
incase yours is wrong. This routine can only be called when not in the
current file system path as some locks are already held and a deadlock
will
occur.

PUNICODE_STRING File_QueryFileName(
PFILE_OBJECT fileObject
)
{
PFILE_NAME_INFORMATION Name;
PUNICODE_STRING UniName=NULL;
ULONG AllocSize;
NTSTATUS Status;

if(!fileObject) {
return NULL;
}

__try {

AllocSize = 1024sizeof(WCHAR)+sizeof(ULONG);
Name =
(PFILE_NAME_INFORMATION)MemAllocatePoolWithTag(PagedPool,AllocSize,FILEN
AMET
AG);

if(Name) {
Status = IoQueryFileInformation( fileObject,
FileNameInformation,
AllocSize,
Name,
&AllocSize);

if(NT_SUCCESS(Status)) {
if(Name->FileNameLength<=AllocSize) {
UniName = GetUniString(Name->FileNameLength);
if(UniName) {
__try {

RtlCopyMemory(UniName->Buffer,Name->FileName,Name->FileNameLength);
}
__except(ExceptionFilter(GetExceptionInformation())) {
Debug(DEBUG_FILE,(“GetFileName: Exception
%08x\n”,GetExceptionCode()));
FREE_POINTER(UniName);
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Out of memory
for
uniname\n”));
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Filename length is
to
large\n”));
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Error %08x querying file
information\n”,Status));
}
FREE_POINTER(Name);
} else {
Debug(DEBUG_FILE,(“GetFileName: Error out of memory\n”));
}

}__except (ExceptionFilter(GetExceptionInformation())) {
Debug(DEBUG_FILE,(“GetFileName: Exception
%08x\n”,GetExceptionCode()));
}
return UniName;
}

STATIC PUNICODE_STRING GetUniString( ULONG Size )
{
PUNICODE_STRING String;

PAGED_CODE();
String =
(PUNICODE_STRING)MemAllocatePoolWithTag(NonPagedPool,sizeof(UNICODE_STRI
NG)+
Size+sizeof(WCHAR),FILENAMETAG);
if(String) {
RtlZeroMemory(String,
sizeof(UNICODE_STRING)+Size+sizeof(WCHAR));

String->Length = (unsigned short)Size;
String->MaximumLength = (unsigned short)(Size+sizeof(WCHAR));
String->Buffer = (WCHAR
)(String+1);
}
return String;
}

Thanks,
Rob

> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:bounce-182242-
> xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> Sent: Friday, July 23, 2004 9:47 AM
> To: Windows File Systems Devs Interest List
> Subject: Re: [ntfsd] Tracking file
>
> Rob,
>
> Thank you for your reply.
>
> I challenged file tracking again using the following code.
> But problem was not solved.
>
> Even if I use a new driver including following code, our driver can
find
> context(FCB pointer).
> That context matches current context in driver’s FCB table, but
filename
> is wrong.
>
> Therefore, I think that the cause of this problem is either of the
> following.
> 1. IRP_MJ_CLOSE is not notified to a filter driver.
> 2. VM reuses a stream file object for a another file.
>
> Is my guess right?
>
>
> Now, in my driver, in order to solve this problem, delay write is
> disabled.
> I need only the tracking of READ/WRITE.
> Therefore, I think that this problem is solved by CcFlushCache in
CLEANUP.
> Are there other problems which interfere the tracking of READ/WRITE?
>
> When other problems are known, please let me know.
>
>
> Tadashi, Kimura
>
>
> ----- Original Message -----
> From: “Rob Green”
> To: “Windows File Systems Devs Interest List”
> Sent: Thursday, July 15, 2004 10:01 AM
> Subject: RE: [ntfsd] Tracking file
>
>
> Here is code I am providing to track files objects via the simple
method.
> I
> use this code in a production driver. If you find any problems or
> enhancements let me know. Also if it doesn’t come out right in the
list,
> I
> will find some website to host on. The functions I don’t provide
source
> code to should be obvious, but if not let me know I will explain what
they
> do. It should be trivial to convert it to C source code (its in CPP)
>
> fo_ref.h ---------------------------------------------
> /*
>
> fo_ref.h - Copyright (c) 2004 Columbia Data Products, Inc. All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on
how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source
code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
>
> /
> * Querys, adds or removes a object on the list
>
> * This function uses FsContexts to determine a specific
> * file that is open instead of FileObjects which identify
> * an instance. IOW You can have 5 opens of the same file
> * and you will have 5 file objects and 1 FsContext.
>
> * see http://www.osronline.com/article.cfm?id=102 for more info
> * on how this works
> /
>
> class Generic_FileObject_RefCount: public DeletableObject
> {
> protected:
> RTL_GENERIC_TABLE Table;
>
> #define FO_REF_ACTION_QUERY 0
> #define FO_REF_ACTION_ADD 1
> #define FO_REF_ACTION_REMOVE 2
>
> typedef struct sFO_Ref {
> ULONG RefCount;
> PUNICODE_STRING Name;
> PFILE_OBJECT FileObject;
> PVOID FsContext;
> PVOID Data;
> } tFO_Ref;
>
> static RTL_GENERIC_COMPARE_RESULTS CompareElement (
> struct _RTL_GENERIC_TABLE Table,
> PVOID FirstStruct,
> PVOID SecondStruct
> )
> {
>
> if(((tFO_Ref
)FirstStruct)->FsContext==((tFO_Ref
)SecondStruct)-
> >FsContext)
> return GenericEqual;
>
>
>
if(((tFO_Ref
)FirstStruct)->FsContext<((tFO_Ref
)SecondStruct)->FsContex
t)
> return GenericLessThan;
>
> return GenericGreaterThan;
> }
>
> static PVOID AllocElement (
> struct _RTL_GENERIC_TABLE *Table,
> CLONG ByteSize
> )
> {
> return MemAllocatePoolWithTag(PagedPool,ByteSize,PSM_FO_TAG);
> }
>
> static VOID FreeElement (
> struct _RTL_GENERIC_TABLE *Table,
> PVOID Buffer
> )
> {
> MemFreePool(Buffer);
> return;
> }
>
> bool DoWork( PFILE_OBJECT FileObject, DWORD Action, PVOID *Data,
> PUNICODE_STRING *Uni );
>
> private:
> FAST_MUTEX Mutex;
>
> virtual NTSTATUS Init()
> {
> PAGED_CODE();
> ExInitializeFastMutex(&Mutex);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElement,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> PAGED_CODE();
> ExAcquireFastMutex( &Mutex );
> }
>
> virtual VOID ReleaseLock()
> {
> PAGED_CODE();
> ExReleaseFastMutex(&Mutex);
> }
>
> virtual void Destroy()
> {
> // shouldnt get called
> ASSERT(FALSE);
> }
>
> public:
> Generic_FileObject_RefCount()
> {
> /lint -e{534} ignore return value/
> Init();
> }
>
> virtual ~Generic_FileObject_RefCount()
> {
> Destroy();
> }
>
> /

> * Adds a file object to the list if it doesnt already
> * exist, otherwise the reference count is incremented.
> *
> * This method must be called during the create completion
> * handler or in the dispatch handler after the call has
> * been sent down synchronously.
> *
> * @param FileObject FileObject to keep track of.
> *
> * @return true - File was already in list
> * false - File was not in list
> */
> bool Add( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,NULL,NULL);
> }
> bool Add( PFILE_OBJECT FileObject, PVOID Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,&Data,NULL);
> }
>
> /
> * Returns if the file object is in the list
> *
> * @param FileObject FileObject to check for
> *
> * @return true - file is on list
> * false - file is not on list
> */
> bool Query( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,NULL,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data, PUNICODE_STRING
*Uni
> )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,Uni);
> }
>
> /

> * Decrements a reference count on the file object.
> * If the reference count is 0 the file object may be
> * removed from the list.
> *
> * @param FileObject File object to remove
> *
> * @return true - file object was on list
> * false - file object was not on list
> */
> bool Remove( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,NULL,NULL);
> }
> bool Remove( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,Data,NULL);
> }
> };
>
> class Generic_FileObject_RefCountNP: public
Generic_FileObject_RefCount
> {
> private:
> KSPIN_LOCK SpinLock;
> KIRQL OldIrql;
>
> static PVOID AllocElementNP (
> struct _RTL_GENERIC_TABLE Table,
> CLONG ByteSize
> )
> {
> return
MemAllocatePoolWithTag(NonPagedPool,ByteSize,PSM_FO_TAG);
> }
>
> virtual NTSTATUS Init()
> {
> KeInitializeSpinLock(&SpinLock);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElementNP,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> pmAcquireSpinLock ( &SpinLock, &OldIrql );
> }
>
> virtual VOID ReleaseLock()
> {
> pmReleaseSpinLock(&SpinLock,OldIrql);
> }
>
> };
> fo_ref.cpp ---------------------------------------------
> /

>
> fo_ref.cpp - Copyright (c) 2004 Columbia Data Products, Inc.
All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on
how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source
code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
> #include “precomp.h”
>
> #ifdef RUN_WPP
> extern “C” {
> #include “fo_ref.tmh”
> }
> #endif
>
>
> // Note: If a file is cached we may not see the close for it until
> sometime
> later
> // this could be immediately or hours or days. It depends on how busy
the
> system
> // is
> bool Generic_FileObject_RefCount::DoWork( PFILE_OBJECT FileObject,
DWORD
> Action, PVOID *Data, PUNICODE_STRING *Uni )
> {
> if(FileObject->FsContext == NULL) {
> return false;
> }
>
> GetLock();
>
> tFO_Ref _x;
> _x.FsContext = FileObject->FsContext;
>
> tFO_Ref Found = (tFO_Ref
)RtlLookupElementGenericTable(&Table,&_x);
>
> if ( (Action == FO_REF_ACTION_QUERY) && (Found) ) {
> if(Data) {
> *Data = Found->Data;
> }
> if(Uni) {
> *Uni = Found->Name;
> }
> } else
> if ( (Action == FO_REF_ACTION_REMOVE) && (Found)) {
> // For each IRP_MJ_CLOSE the filter driver decrements the
> reference
> // count on the per-file context structure if the
FO_STREAM_FILE
> bit
> // is not set for the file object.
> if((!(FileObject->Flags & FO_STREAM_FILE)) &&
(Found->RefCount)) {
> Found->RefCount–;
> }
>
> // If the reference count for the per-file context structure
> reaches
> // zero and both the ImageSectionObject and DataSectionObject
of
> the
> // SectionObjectPointers field from the FILE_OBJECT is zero,
the
> // filter driver may then delete the per-file context data.
>
> if ((Found->RefCount==0) &&
> ((!FileObject->SectionObjectPointer) ||
> ((!FileObject->SectionObjectPointer->ImageSectionObject)
&&
> (!FileObject->SectionObjectPointer->DataSectionObject))))
{
>
> if(Found->Name) {
> MemFreePool(Found->Name);
> Found->Name = NULL;
> }
>
> if(Data) {
> *Data=Found->Data;
> }
> RtlDeleteElementGenericTable(&Table,Found);
> } else {
> // only say found if we actually delete the entry
> Found = NULL;
> }
> }
>
> tFO_Ref *GetFileNameEntry=NULL;
>
> if(Action == FO_REF_ACTION_ADD) {
> // For each IRP_MJ_CREATE, the filter driver increments the
> reference
> // count on the per-file context structure.
>
> if(!Found) {
> tFO_Ref x;
> BOOLEAN Ret;
>
> x.FsContext = FileObject->FsContext;
> x.RefCount=1;
>
> x.Name = NULL;
> x.FileObject = FileObject;
>
> if(Data) {
> x.Data = Data;
> } else {
> x.Data = NULL;
> }
>
> Found =
>
(tFO_Ref
)RtlInsertElementGenericTable(&Table,&x,sizeof(tFO_Ref),&Ret);
>
> // so we will get the name after the lock is released
> GetFileNameEntry = Found;
>
> } else {
> Found->RefCount++;
> }
> } // if add
>
> ReleaseLock();
>
> if(GetFileNameEntry) {
> GetFileNameEntry->Name =
> File_QueryFileName(GetFileNameEntry->FileObject);
> if(Uni) {
> Uni = GetFileNameEntry->Name;
> }
> }
>
>
> return Found ? true : false;
> }
>
>
>
>
>
> /

>
> How to declare
>
> Generic_FileObject_RefCount StreamFiles=NULL;
> StreamFiles = new Generic_FileObject_RefCount();
>
>
> How to add
> Note: You must call the add routine in the Create
Completion
> routine
> or after you have already sent the request down in
the
> dispatch
> routine
>
> StreamFiles->Add(IrpSp->FileObject,PrivateData);
>
> How to Query
>
> if(StreamFiles->Query(IrpSp->FileObject,(PVOID
)&PrivateData,&Uni)) {
> Debug(DEBUG_DICT,( “File = %wZ\n”,Uni));
> }
>
>
>
>
>
> */
>
> Thanks,
> Rob
>
>
> > -----Original Message-----
> > From: xxxxx@lists.osr.com [mailto:bounce-181171-
> > xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> > Sent: Wednesday, July 14, 2004 8:24 PM
> > To: Windows File Systems Devs Interest List
> > Subject: [ntfsd] Tracking file
> >
> > Dear whom it may concern,
> >
> > I’m a device driver engineer from Japan, Recently, i have been
writing
> > a FS Filter Driver, and I got a big probelm. I would really like
> somebady
> > helping me to deal this probelm.
> > In this driver, I need tracking a file, I refer NT Insider in the
OSR
> > site,
> > (http://www.osronline.com/article.cfm?id=102) and try to use same
> method
> > to do it.
> >
> > However, the file tracking doesn’t seem to work correctly.
> > The poblem is that the context cann’t be removed correctly.
> >
> > Since DataSectionObject is not NULL when closing a certain file, a
> request
> > is completed without deleting a context.
> > Next, CLOSE of a stream file object with the same FCB comes.
> > At this time, since DataSectionObject is not NULL, a context is not
> > deleted, either.
> > CLOSE of a file with the same FCB is not notified to a driver after
> this.
> > Instead, the CREATE request whose FS returns the same FCB is
notified.
> > But, the file name passed by this CREATE differs from upper CLOSE.
> >
> > I am troubled very much by this problem.
> > Has somebaby bumped into the similar problem?
> >
> >
> > And, I am performing the tracking of a file,
> > in order to acquire a file name from the stream file object at the
time
> > of delay writing.
> > If I could find the way to acquire a file from a stream file object,
> This
> > problem will be solved.
> > Does somebady know the method of acquiring a file name without the
file
> > tracking?
> >
> > If you have any useful information, Please e-mail me, I really
> appreciate
> > for you help.
> >
> > Tadashi, Kimura
> >
> >
> > —
> > Questions? First check the IFS FAQ at
> > https://www.osronline.com/article.cfm?id=17
> >
> > You are currently subscribed to ntfsd as: xxxxx@cdp.com
> > To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@cdp.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@windows.microsoft.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Neal is right - I’ve said this myself numerous times.

I want to make sure people are aware (and this is a general comment, not
specifically directed to the original case) that there ARE cases where
other OS components will store away information and if they do this
before your filter is installed, they won’t necessarily find your
filter. For example, SRV maintains a private table of fast I/O
functions (on a per-file basis no less) that it uses directly. So, if
your filter attaches after a file is already open in SRV, the SRV fast
I/O calls will bypass your filter, while the IRP calls will not. We’ve
seen this sort of thing in various OS components over the years and I’ve
always considered them to be bugs in the implementation (basically, my
attitude is “if you are going to take on the role of the I/O Manager you
are responsible for doing it the SAME WAY the I/O Manager does it”).

The ONLY time that the file system(s) are bypassed for disk access are
(at present) hibernation and crash dump writing. All other access is
always done through the file system, via the exposed API - there are no
backdoors.

We’re very fortunate now because Neal & Co. are vigilant against future
stupidities where other developers try to “optimize” the behavior here.

Regards,

Tony

Tony Mason
Consulting Partner
OSR Open Systems Resources Inc.
http://www.osr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Neal Christiansen
Sent: Friday, August 06, 2004 11:05 AM
To: ntfsd redirect
Subject: RE: [ntfsd] Tracking file

Just so this is clear for everyone.

There are no special back-doors into the file systems that are used
internally. There are no secret directories that are handled specially.
We want filters to see all of the operations to all of the files so they
can appropriately do their job.

For the problem below you are most likely doing something wrong in your
filter.

Neal Christiansen
Microsoft File System Filter Group Lead
This posting is provided “AS IS” with no warranties, and confers no
rights

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
Sent: Wednesday, August 04, 2004 2:12 AM
To: Windows File Systems Devs Interest List
Subject: Re: [ntfsd] Tracking file

Hello, Rob and Peter:

Thank you for your reply.

I got the file name by using ObQueryNameString.

The file name got by using ObQueryNameString is saved in a context.
Then, this file name is compared with the file name got newly at the
CREATE request.
When these two file names differ, I judge that a file name is wrong.

Take your advice, I exchanged ObQueryNameString to File_QueryFileName
and tried it again.
But, I find “the wrong file name” at a CREATE request.

When “the wrong file name” is found, the two difference file name can be
find as follows.

[Context] E:\SYSTEM
VOLUMEINFORMATION_RESTORE{9BD92293-76B7-482B-9C4B-3FD6B666017D}_FILELS
T.CFG
[FileObject] E:\WINDOWS\System32\odbcint.dll

Does NTFS treat the file in “System Volume Information” by using the
special method?
Could you tell me if you have a difference ideas?

Thank you for helping.

Tadashi Kimura,

----- Original Message -----
From: “Rob Green”
To: “Windows File Systems Devs Interest List”
Sent: Saturday, July 24, 2004 12:13 AM
Subject: RE: [ntfsd] Tracking file

I agree with Peter. How are you getting the file name? you should not
be
accessing the FileObject->FileName field. If you use the Query below,
it
will return you the name of the file. I have attached the filename
function
incase yours is wrong. This routine can only be called when not in the
current file system path as some locks are already held and a deadlock
will
occur.

PUNICODE_STRING File_QueryFileName(
PFILE_OBJECT fileObject
)
{
PFILE_NAME_INFORMATION Name;
PUNICODE_STRING UniName=NULL;
ULONG AllocSize;
NTSTATUS Status;

if(!fileObject) {
return NULL;
}

__try {

AllocSize = 1024sizeof(WCHAR)+sizeof(ULONG);
Name =
(PFILE_NAME_INFORMATION)MemAllocatePoolWithTag(PagedPool,AllocSize,FILEN
AMET
AG);

if(Name) {
Status = IoQueryFileInformation( fileObject,
FileNameInformation,
AllocSize,
Name,
&AllocSize);

if(NT_SUCCESS(Status)) {
if(Name->FileNameLength<=AllocSize) {
UniName = GetUniString(Name->FileNameLength);
if(UniName) {
__try {

RtlCopyMemory(UniName->Buffer,Name->FileName,Name->FileNameLength);
}
__except(ExceptionFilter(GetExceptionInformation())) {
Debug(DEBUG_FILE,(“GetFileName: Exception
%08x\n”,GetExceptionCode()));
FREE_POINTER(UniName);
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Out of memory
for
uniname\n”));
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Filename length is
to
large\n”));
}
} else {
Debug(DEBUG_FILE,(“GetFileName: Error %08x querying file
information\n”,Status));
}
FREE_POINTER(Name);
} else {
Debug(DEBUG_FILE,(“GetFileName: Error out of memory\n”));
}

}__except (ExceptionFilter(GetExceptionInformation())) {
Debug(DEBUG_FILE,(“GetFileName: Exception
%08x\n”,GetExceptionCode()));
}
return UniName;
}

STATIC PUNICODE_STRING GetUniString( ULONG Size )
{
PUNICODE_STRING String;

PAGED_CODE();
String =
(PUNICODE_STRING)MemAllocatePoolWithTag(NonPagedPool,sizeof(UNICODE_STRI
NG)+
Size+sizeof(WCHAR),FILENAMETAG);
if(String) {
RtlZeroMemory(String,
sizeof(UNICODE_STRING)+Size+sizeof(WCHAR));

String->Length = (unsigned short)Size;
String->MaximumLength = (unsigned short)(Size+sizeof(WCHAR));
String->Buffer = (WCHAR
)(String+1);
}
return String;
}

Thanks,
Rob

> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:bounce-182242-
> xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> Sent: Friday, July 23, 2004 9:47 AM
> To: Windows File Systems Devs Interest List
> Subject: Re: [ntfsd] Tracking file
>
> Rob,
>
> Thank you for your reply.
>
> I challenged file tracking again using the following code.
> But problem was not solved.
>
> Even if I use a new driver including following code, our driver can
find
> context(FCB pointer).
> That context matches current context in driver’s FCB table, but
filename
> is wrong.
>
> Therefore, I think that the cause of this problem is either of the
> following.
> 1. IRP_MJ_CLOSE is not notified to a filter driver.
> 2. VM reuses a stream file object for a another file.
>
> Is my guess right?
>
>
> Now, in my driver, in order to solve this problem, delay write is
> disabled.
> I need only the tracking of READ/WRITE.
> Therefore, I think that this problem is solved by CcFlushCache in
CLEANUP.
> Are there other problems which interfere the tracking of READ/WRITE?
>
> When other problems are known, please let me know.
>
>
> Tadashi, Kimura
>
>
> ----- Original Message -----
> From: “Rob Green”
> To: “Windows File Systems Devs Interest List”
> Sent: Thursday, July 15, 2004 10:01 AM
> Subject: RE: [ntfsd] Tracking file
>
>
> Here is code I am providing to track files objects via the simple
method.
> I
> use this code in a production driver. If you find any problems or
> enhancements let me know. Also if it doesn’t come out right in the
list,
> I
> will find some website to host on. The functions I don’t provide
source
> code to should be obvious, but if not let me know I will explain what
they
> do. It should be trivial to convert it to C source code (its in CPP)
>
> fo_ref.h ---------------------------------------------
> /*
>
> fo_ref.h - Copyright (c) 2004 Columbia Data Products, Inc. All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on
how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source
code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
>
> /
> * Querys, adds or removes a object on the list
>
> * This function uses FsContexts to determine a specific
> * file that is open instead of FileObjects which identify
> * an instance. IOW You can have 5 opens of the same file
> * and you will have 5 file objects and 1 FsContext.
>
> * see http://www.osronline.com/article.cfm?id=102 for more info
> * on how this works
> /
>
> class Generic_FileObject_RefCount: public DeletableObject
> {
> protected:
> RTL_GENERIC_TABLE Table;
>
> #define FO_REF_ACTION_QUERY 0
> #define FO_REF_ACTION_ADD 1
> #define FO_REF_ACTION_REMOVE 2
>
> typedef struct sFO_Ref {
> ULONG RefCount;
> PUNICODE_STRING Name;
> PFILE_OBJECT FileObject;
> PVOID FsContext;
> PVOID Data;
> } tFO_Ref;
>
> static RTL_GENERIC_COMPARE_RESULTS CompareElement (
> struct _RTL_GENERIC_TABLE Table,
> PVOID FirstStruct,
> PVOID SecondStruct
> )
> {
>
> if(((tFO_Ref
)FirstStruct)->FsContext==((tFO_Ref
)SecondStruct)-
> >FsContext)
> return GenericEqual;
>
>
>
if(((tFO_Ref
)FirstStruct)->FsContext<((tFO_Ref
)SecondStruct)->FsContex
t)
> return GenericLessThan;
>
> return GenericGreaterThan;
> }
>
> static PVOID AllocElement (
> struct _RTL_GENERIC_TABLE *Table,
> CLONG ByteSize
> )
> {
> return MemAllocatePoolWithTag(PagedPool,ByteSize,PSM_FO_TAG);
> }
>
> static VOID FreeElement (
> struct _RTL_GENERIC_TABLE *Table,
> PVOID Buffer
> )
> {
> MemFreePool(Buffer);
> return;
> }
>
> bool DoWork( PFILE_OBJECT FileObject, DWORD Action, PVOID *Data,
> PUNICODE_STRING *Uni );
>
> private:
> FAST_MUTEX Mutex;
>
> virtual NTSTATUS Init()
> {
> PAGED_CODE();
> ExInitializeFastMutex(&Mutex);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElement,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> PAGED_CODE();
> ExAcquireFastMutex( &Mutex );
> }
>
> virtual VOID ReleaseLock()
> {
> PAGED_CODE();
> ExReleaseFastMutex(&Mutex);
> }
>
> virtual void Destroy()
> {
> // shouldnt get called
> ASSERT(FALSE);
> }
>
> public:
> Generic_FileObject_RefCount()
> {
> /lint -e{534} ignore return value/
> Init();
> }
>
> virtual ~Generic_FileObject_RefCount()
> {
> Destroy();
> }
>
> /

> * Adds a file object to the list if it doesnt already
> * exist, otherwise the reference count is incremented.
> *
> * This method must be called during the create completion
> * handler or in the dispatch handler after the call has
> * been sent down synchronously.
> *
> * @param FileObject FileObject to keep track of.
> *
> * @return true - File was already in list
> * false - File was not in list
> */
> bool Add( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,NULL,NULL);
> }
> bool Add( PFILE_OBJECT FileObject, PVOID Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_ADD,&Data,NULL);
> }
>
> /
> * Returns if the file object is in the list
> *
> * @param FileObject FileObject to check for
> *
> * @return true - file is on list
> * false - file is not on list
> */
> bool Query( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,NULL,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,NULL);
> }
> bool Query( PFILE_OBJECT FileObject, PVOID *Data, PUNICODE_STRING
*Uni
> )
> {
> return DoWork(FileObject,FO_REF_ACTION_QUERY,Data,Uni);
> }
>
> /

> * Decrements a reference count on the file object.
> * If the reference count is 0 the file object may be
> * removed from the list.
> *
> * @param FileObject File object to remove
> *
> * @return true - file object was on list
> * false - file object was not on list
> */
> bool Remove( PFILE_OBJECT FileObject )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,NULL,NULL);
> }
> bool Remove( PFILE_OBJECT FileObject, PVOID *Data )
> {
> return DoWork(FileObject,FO_REF_ACTION_REMOVE,Data,NULL);
> }
> };
>
> class Generic_FileObject_RefCountNP: public
Generic_FileObject_RefCount
> {
> private:
> KSPIN_LOCK SpinLock;
> KIRQL OldIrql;
>
> static PVOID AllocElementNP (
> struct _RTL_GENERIC_TABLE Table,
> CLONG ByteSize
> )
> {
> return
MemAllocatePoolWithTag(NonPagedPool,ByteSize,PSM_FO_TAG);
> }
>
> virtual NTSTATUS Init()
> {
> KeInitializeSpinLock(&SpinLock);
> RtlInitializeGenericTable(
> &Table,
> (PRTL_GENERIC_COMPARE_ROUTINE)CompareElement,
> (PRTL_GENERIC_ALLOCATE_ROUTINE)AllocElementNP,
> (PRTL_GENERIC_FREE_ROUTINE)FreeElement,
> NULL
> );
> return STATUS_SUCCESS;
> }
>
> virtual VOID GetLock()
> {
> pmAcquireSpinLock ( &SpinLock, &OldIrql );
> }
>
> virtual VOID ReleaseLock()
> {
> pmReleaseSpinLock(&SpinLock,OldIrql);
> }
>
> };
> fo_ref.cpp ---------------------------------------------
> /

>
> fo_ref.cpp - Copyright (c) 2004 Columbia Data Products, Inc.
All
> Rights Reserved.
>
> Maintains reference counts on file objects
> see http://www.osronline.com/article.cfm?id=102 for more info on
how
> this works
>
> Written by Rob Green/CDP (xxxxx@cdp.com) 3/22/04
>
> Version 1.1 7/14/2004
>
> You may use freely in as long as you give credit in the source
code.
>
> Found bugs? send them to me (xxxxx@cdp.com)
> */
>
> #include “precomp.h”
>
> #ifdef RUN_WPP
> extern “C” {
> #include “fo_ref.tmh”
> }
> #endif
>
>
> // Note: If a file is cached we may not see the close for it until
> sometime
> later
> // this could be immediately or hours or days. It depends on how busy
the
> system
> // is
> bool Generic_FileObject_RefCount::DoWork( PFILE_OBJECT FileObject,
DWORD
> Action, PVOID *Data, PUNICODE_STRING *Uni )
> {
> if(FileObject->FsContext == NULL) {
> return false;
> }
>
> GetLock();
>
> tFO_Ref _x;
> _x.FsContext = FileObject->FsContext;
>
> tFO_Ref Found = (tFO_Ref
)RtlLookupElementGenericTable(&Table,&_x);
>
> if ( (Action == FO_REF_ACTION_QUERY) && (Found) ) {
> if(Data) {
> *Data = Found->Data;
> }
> if(Uni) {
> *Uni = Found->Name;
> }
> } else
> if ( (Action == FO_REF_ACTION_REMOVE) && (Found)) {
> // For each IRP_MJ_CLOSE the filter driver decrements the
> reference
> // count on the per-file context structure if the
FO_STREAM_FILE
> bit
> // is not set for the file object.
> if((!(FileObject->Flags & FO_STREAM_FILE)) &&
(Found->RefCount)) {
> Found->RefCount–;
> }
>
> // If the reference count for the per-file context structure
> reaches
> // zero and both the ImageSectionObject and DataSectionObject
of
> the
> // SectionObjectPointers field from the FILE_OBJECT is zero,
the
> // filter driver may then delete the per-file context data.
>
> if ((Found->RefCount==0) &&
> ((!FileObject->SectionObjectPointer) ||
> ((!FileObject->SectionObjectPointer->ImageSectionObject)
&&
> (!FileObject->SectionObjectPointer->DataSectionObject))))
{
>
> if(Found->Name) {
> MemFreePool(Found->Name);
> Found->Name = NULL;
> }
>
> if(Data) {
> *Data=Found->Data;
> }
> RtlDeleteElementGenericTable(&Table,Found);
> } else {
> // only say found if we actually delete the entry
> Found = NULL;
> }
> }
>
> tFO_Ref *GetFileNameEntry=NULL;
>
> if(Action == FO_REF_ACTION_ADD) {
> // For each IRP_MJ_CREATE, the filter driver increments the
> reference
> // count on the per-file context structure.
>
> if(!Found) {
> tFO_Ref x;
> BOOLEAN Ret;
>
> x.FsContext = FileObject->FsContext;
> x.RefCount=1;
>
> x.Name = NULL;
> x.FileObject = FileObject;
>
> if(Data) {
> x.Data = Data;
> } else {
> x.Data = NULL;
> }
>
> Found =
>
(tFO_Ref
)RtlInsertElementGenericTable(&Table,&x,sizeof(tFO_Ref),&Ret);
>
> // so we will get the name after the lock is released
> GetFileNameEntry = Found;
>
> } else {
> Found->RefCount++;
> }
> } // if add
>
> ReleaseLock();
>
> if(GetFileNameEntry) {
> GetFileNameEntry->Name =
> File_QueryFileName(GetFileNameEntry->FileObject);
> if(Uni) {
> Uni = GetFileNameEntry->Name;
> }
> }
>
>
> return Found ? true : false;
> }
>
>
>
>
>
> /

>
> How to declare
>
> Generic_FileObject_RefCount StreamFiles=NULL;
> StreamFiles = new Generic_FileObject_RefCount();
>
>
> How to add
> Note: You must call the add routine in the Create
Completion
> routine
> or after you have already sent the request down in
the
> dispatch
> routine
>
> StreamFiles->Add(IrpSp->FileObject,PrivateData);
>
> How to Query
>
> if(StreamFiles->Query(IrpSp->FileObject,(PVOID
)&PrivateData,&Uni)) {
> Debug(DEBUG_DICT,( “File = %wZ\n”,Uni));
> }
>
>
>
>
>
> */
>
> Thanks,
> Rob
>
>
> > -----Original Message-----
> > From: xxxxx@lists.osr.com [mailto:bounce-181171-
> > xxxxx@lists.osr.com] On Behalf Of Tadashi Kimura
> > Sent: Wednesday, July 14, 2004 8:24 PM
> > To: Windows File Systems Devs Interest List
> > Subject: [ntfsd] Tracking file
> >
> > Dear whom it may concern,
> >
> > I’m a device driver engineer from Japan, Recently, i have been
writing
> > a FS Filter Driver, and I got a big probelm. I would really like
> somebady
> > helping me to deal this probelm.
> > In this driver, I need tracking a file, I refer NT Insider in the
OSR
> > site,
> > (http://www.osronline.com/article.cfm?id=102) and try to use same
> method
> > to do it.
> >
> > However, the file tracking doesn’t seem to work correctly.
> > The poblem is that the context cann’t be removed correctly.
> >
> > Since DataSectionObject is not NULL when closing a certain file, a
> request
> > is completed without deleting a context.
> > Next, CLOSE of a stream file object with the same FCB comes.
> > At this time, since DataSectionObject is not NULL, a context is not
> > deleted, either.
> > CLOSE of a file with the same FCB is not notified to a driver after
> this.
> > Instead, the CREATE request whose FS returns the same FCB is
notified.
> > But, the file name passed by this CREATE differs from upper CLOSE.
> >
> > I am troubled very much by this problem.
> > Has somebaby bumped into the similar problem?
> >
> >
> > And, I am performing the tracking of a file,
> > in order to acquire a file name from the stream file object at the
time
> > of delay writing.
> > If I could find the way to acquire a file from a stream file object,
> This
> > problem will be solved.
> > Does somebady know the method of acquiring a file name without the
file
> > tracking?
> >
> > If you have any useful information, Please e-mail me, I really
> appreciate
> > for you help.
> >
> > Tadashi, Kimura
> >
> >
> > —
> > Questions? First check the IFS FAQ at
> > https://www.osronline.com/article.cfm?id=17
> >
> > You are currently subscribed to ntfsd as: xxxxx@cdp.com
> > To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>
> —
> Questions? First check the IFS FAQ at
> https://www.osronline.com/article.cfm?id=17
>
> You are currently subscribed to ntfsd as: xxxxx@cdp.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@sciencepark.co.jp
To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@windows.microsoft.com
To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com