File System Filter Driver - different buffer sizes?  
Author Message
FrancoisHoude





PostPosted: Fri Aug 26 18:55:50 CDT 2005 Top

Drivers >> File System Filter Driver - different buffer sizes?

Hi All,

I am writing a file system filter driver to encrypt/decrypt files
on-the-fly. I use a crypto algorithm that changes the size of the
original file after encryption/decryption - how can I handle this
situation? For example, here is the Filemon code (the completion
routine) that works when orgBuffer and newBuffer have the same sizes.
What would happen if the buffer sizes should differ? How to change this
code to make it work? Thanks in advance for all advices and
cooperation!

PMDL orgMdl,newMdl;
PVOID orgBuffer, newBuffer;
orgMdl = Context;

//Getting the original buffer data
orgBuffer = MmGetSystemAddressForMdl(orgMdl);
//Allocating a new buffer
newBuffer = ExAllocatePool(NonPagedPoolCacheAligned, count);
//Decrypting data using and placing it into the newBuffer
Decode( &ctx, orgBuffer, newBuffer, count);
//Replacing the content of the original encrypted buffer with the
plain text
RtlMoveMemory(orgBuffer, newBuffer, count);
ExFreePool(newBuffer);
//Make sure the buffer pointer is correct
Irp->MdlAddress = orgMdl;
if( Irp->PendingReturned )
IoMarkIrpPending( Irp );
return STATUS_SUCCESS;

Windows OS41  
 
 
Don





PostPosted: Fri Aug 26 18:55:50 CDT 2005 Top

Drivers >> File System Filter Driver - different buffer sizes? Well since you are using FileMon, you have obviously paid SysInternals for
use of the source. I would recomend you ask them.

If you haven't paid SysInternals, you might fork over the $119 for the IFS
kit (or if you can wait till after Longhorn to ship, get the WDK beta for
free), and use the minifilter model, and something solid and reliable for
modifying files as a base.


--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply





> Hi All,
>
> I am writing a file system filter driver to encrypt/decrypt files
> on-the-fly. I use a crypto algorithm that changes the size of the
> original file after encryption/decryption - how can I handle this
> situation? For example, here is the Filemon code (the completion
> routine) that works when orgBuffer and newBuffer have the same sizes.
> What would happen if the buffer sizes should differ? How to change this
> code to make it work? Thanks in advance for all advices and
> cooperation!
>
> PMDL orgMdl,newMdl;
> PVOID orgBuffer, newBuffer;
> orgMdl = Context;
>
> //Getting the original buffer data
> orgBuffer = MmGetSystemAddressForMdl(orgMdl);
> //Allocating a new buffer
> newBuffer = ExAllocatePool(NonPagedPoolCacheAligned, count);
> //Decrypting data using and placing it into the newBuffer
> Decode( &ctx, orgBuffer, newBuffer, count);
> //Replacing the content of the original encrypted buffer with the
> plain text
> RtlMoveMemory(orgBuffer, newBuffer, count);
> ExFreePool(newBuffer);
> //Make sure the buffer pointer is correct
> Irp->MdlAddress = orgMdl;
> if( Irp->PendingReturned )
> IoMarkIrpPending( Irp );
> return STATUS_SUCCESS;
>


 
 
codexpert





PostPosted: Fri Aug 26 19:16:44 CDT 2005 Top

Drivers >> File System Filter Driver - different buffer sizes? Thanks Don! Its ok with the Sysinternals at this stage of the
development!

I forgot to post what I have in the IRP_MJ_READ routine:

case IRP_MJ_READ:
prefRes = RtlPrefixUnicodeString(&usrvc, &asrvc, TRUE);
if(prefRes && flag){
count = currentIrpStack->Parameters.Read.Length;
orgMdl = Irp->MdlAddress; // To be passed in the completion routine
*nextIrpStack = *currentIrpStack;
//Settting a completion routine
IoSetCompletionRoutine(Irp, FilterHookReadDone, orgMdl,
TRUE,TRUE,TRUE);
hookCompletion = LogRecord( TRUE, &seqNum,
&dateTime, NULL,

"%s\tIRP_MJ_READDD%c\t%s\tOffset: %d Length: %d",
name,
(Irp->Flags & IRP_PAGING_IO)
||
(Irp->Flags &
IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',
fullPathName,

currentIrpStack->Parameters.Read.ByteOffset.LowPart,

currentIrpStack->Parameters.Read.Length );

//Call the next driver down the driver statck
return IoCallDriver( hookExt->FileSystem, Irp );
}

Where is teh trick? Should I have allocated a new Mdl with the
appropriate buffer size and put it in place of the orgMdl in the
completion routine?

Thanks once again for your cooperation!

 
 
codexpert





PostPosted: Fri Aug 26 20:01:06 CDT 2005 Top

Drivers >> File System Filter Driver - different buffer sizes? Thanks Don! It's ok for now with Sysinternals for this stage of the
filter development.

I forgot to include the code in my IRP_MJ_READ routine:

case IRP_MJ_READ:
prefRes =3D RtlPrefixUnicodeString(&usrvc, &asrvc, TRUE);
if(prefRes && flag){
count =3D currentIrpStack->Parameters.Read.Length;
orgMdl =3D Irp->MdlAddress; // To be passed in the completion
routine
*nextIrpStack =3D *currentIrpStack;
//Settting a completion routine
IoSetCompletionRoutine(Irp, FilterHookReadDone, orgMdl,
TRUE,TRUE,TRUE);
...
//Call the next driver down the driver statck
return IoCallDriver( hookExt->FileSystem, Irp );

Where is the tick? Should I allocate a new MDL with different buffer
size and pass it to the completion routine?

Thanks again!

Don Burn =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0:
> Well since you are using FileMon, you have obviously paid SysInternals for
> use of the source. I would recomend you ask them.
>
> If you haven't paid SysInternals, you might fork over the $119 for the IFS
> kit (or if you can wait till after Longhorn to ship, get the WDK beta for
> free), and use the minifilter model, and something solid and reliable for
> modifying files as a base.
>
>
> --
> Don Burn (MVP, Windows DDK)
> Windows 2k/XP/2k3 Filesystem and Driver Consulting
> Remove StopSpam from the email to reply
>
>
>


> > Hi All,
> >
> > I am writing a file system filter driver to encrypt/decrypt files
> > on-the-fly. I use a crypto algorithm that changes the size of the
> > original file after encryption/decryption - how can I handle this
> > situation? For example, here is the Filemon code (the completion
> > routine) that works when orgBuffer and newBuffer have the same sizes.
> > What would happen if the buffer sizes should differ? How to change this
> > code to make it work? Thanks in advance for all advices and
> > cooperation!
> >
> > PMDL orgMdl,newMdl;
> > PVOID orgBuffer, newBuffer;
> > orgMdl =3D Context;
> >
> > //Getting the original buffer data
> > orgBuffer =3D MmGetSystemAddressForMdl(orgMdl);
> > //Allocating a new buffer
> > newBuffer =3D ExAllocatePool(NonPagedPoolCacheAligned, count);
> > //Decrypting data using and placing it into the newBuffer
> > Decode( &ctx, orgBuffer, newBuffer, count);
> > //Replacing the content of the original encrypted buffer with the
> > plain text
> > RtlMoveMemory(orgBuffer, newBuffer, count);
> > ExFreePool(newBuffer);
> > //Make sure the buffer pointer is correct
> > Irp->MdlAddress =3D orgMdl;
> > if( Irp->PendingReturned )
> > IoMarkIrpPending( Irp );
> > return STATUS_SUCCESS;
> >

 
 
David





PostPosted: Fri Aug 26 23:16:31 CDT 2005 Top

Drivers >> File System Filter Driver - different buffer sizes? You just said it is ok for now with Sysinternals, so they provide consulting
and assistance to those who are using their code with permission. You will
not get help from this group in any substantial way with filemon since the
last version that had source available was not designed for production use.
It uses many special tricks that induce instability in production systems,
but are useful for testing.

Why not use the examples provided with the IFS Kit? They are stable and a
good basis to begin writing a production driver. They are passive filters
and don't show how to do what you want, but neither does filemon.



Thanks Don! It's ok for now with Sysinternals for this stage of the
filter development.

I forgot to include the code in my IRP_MJ_READ routine:

case IRP_MJ_READ:
prefRes = RtlPrefixUnicodeString(&usrvc, &asrvc, TRUE);
if(prefRes && flag){
count = currentIrpStack->Parameters.Read.Length;
orgMdl = Irp->MdlAddress; // To be passed in the completion
routine
*nextIrpStack = *currentIrpStack;
//Settting a completion routine
IoSetCompletionRoutine(Irp, FilterHookReadDone, orgMdl,
TRUE,TRUE,TRUE);
...
//Call the next driver down the driver statck
return IoCallDriver( hookExt->FileSystem, Irp );

Where is the tick? Should I allocate a new MDL with different buffer
size and pass it to the completion routine?

Thanks again!

Don Burn ??????:
> Well since you are using FileMon, you have obviously paid SysInternals for
> use of the source. I would recomend you ask them.
>
> If you haven't paid SysInternals, you might fork over the $119 for the IFS
> kit (or if you can wait till after Longhorn to ship, get the WDK beta for
> free), and use the minifilter model, and something solid and reliable for
> modifying files as a base.
>
>
> --
> Don Burn (MVP, Windows DDK)
> Windows 2k/XP/2k3 Filesystem and Driver Consulting
> Remove StopSpam from the email to reply
>
>
>


> > Hi All,
> >
> > I am writing a file system filter driver to encrypt/decrypt files
> > on-the-fly. I use a crypto algorithm that changes the size of the
> > original file after encryption/decryption - how can I handle this
> > situation? For example, here is the Filemon code (the completion
> > routine) that works when orgBuffer and newBuffer have the same sizes.
> > What would happen if the buffer sizes should differ? How to change this
> > code to make it work? Thanks in advance for all advices and
> > cooperation!
> >
> > PMDL orgMdl,newMdl;
> > PVOID orgBuffer, newBuffer;
> > orgMdl = Context;
> >
> > //Getting the original buffer data
> > orgBuffer = MmGetSystemAddressForMdl(orgMdl);
> > //Allocating a new buffer
> > newBuffer = ExAllocatePool(NonPagedPoolCacheAligned, count);
> > //Decrypting data using and placing it into the newBuffer
> > Decode( &ctx, orgBuffer, newBuffer, count);
> > //Replacing the content of the original encrypted buffer with the
> > plain text
> > RtlMoveMemory(orgBuffer, newBuffer, count);
> > ExFreePool(newBuffer);
> > //Make sure the buffer pointer is correct
> > Irp->MdlAddress = orgMdl;
> > if( Irp->PendingReturned )
> > IoMarkIrpPending( Irp );
> > return STATUS_SUCCESS;
> >


 
 
Don





PostPosted: Sat Aug 27 06:02:49 CDT 2005 Top

Drivers >> File System Filter Driver - different buffer sizes? As David said, Filemon is a poor basis for any production filesystem kit,
particularily a active filter. First get the IFS kit and consider using the
mini filter model (they even have a sample of swapping buffers). Second,
ask your questions on NTFSD at http://www.osronline.com since that is the
list that file system people hang out at. Third, think about your
approach, you have a lot more problems than just swapping the buffers, you
are changing the file's size and offsets, how is your filter going to handle
this?



--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply





> You just said it is ok for now with Sysinternals, so they provide
> consulting and assistance to those who are using their code with
> permission. You will not get help from this group in any substantial way
> with filemon since the last version that had source available was not
> designed for production use. It uses many special tricks that induce
> instability in production systems, but are useful for testing.
>
> Why not use the examples provided with the IFS Kit? They are stable and a
> good basis to begin writing a production driver. They are passive filters
> and don't show how to do what you want, but neither does filemon.
>


> Thanks Don! It's ok for now with Sysinternals for this stage of the
> filter development.
>
> I forgot to include the code in my IRP_MJ_READ routine:
>
> case IRP_MJ_READ:
> prefRes = RtlPrefixUnicodeString(&usrvc, &asrvc, TRUE);
> if(prefRes && flag){
> count = currentIrpStack->Parameters.Read.Length;
> orgMdl = Irp->MdlAddress; // To be passed in the completion
> routine
> *nextIrpStack = *currentIrpStack;
> //Settting a completion routine
> IoSetCompletionRoutine(Irp, FilterHookReadDone, orgMdl,
> TRUE,TRUE,TRUE);
> ...
> //Call the next driver down the driver statck
> return IoCallDriver( hookExt->FileSystem, Irp );
>
> Where is the tick? Should I allocate a new MDL with different buffer
> size and pass it to the completion routine?
>
> Thanks again!
>
> Don Burn ??????:
>> Well since you are using FileMon, you have obviously paid SysInternals
>> for
>> use of the source. I would recomend you ask them.
>>
>> If you haven't paid SysInternals, you might fork over the $119 for the
>> IFS
>> kit (or if you can wait till after Longhorn to ship, get the WDK beta for
>> free), and use the minifilter model, and something solid and reliable for
>> modifying files as a base.
>>
>>
>> --
>> Don Burn (MVP, Windows DDK)
>> Windows 2k/XP/2k3 Filesystem and Driver Consulting
>> Remove StopSpam from the email to reply
>>
>>
>>


>> > Hi All,
>> >
>> > I am writing a file system filter driver to encrypt/decrypt files
>> > on-the-fly. I use a crypto algorithm that changes the size of the
>> > original file after encryption/decryption - how can I handle this
>> > situation? For example, here is the Filemon code (the completion
>> > routine) that works when orgBuffer and newBuffer have the same sizes.
>> > What would happen if the buffer sizes should differ? How to change this
>> > code to make it work? Thanks in advance for all advices and
>> > cooperation!
>> >
>> > PMDL orgMdl,newMdl;
>> > PVOID orgBuffer, newBuffer;
>> > orgMdl = Context;
>> >
>> > //Getting the original buffer data
>> > orgBuffer = MmGetSystemAddressForMdl(orgMdl);
>> > //Allocating a new buffer
>> > newBuffer = ExAllocatePool(NonPagedPoolCacheAligned, count);
>> > //Decrypting data using and placing it into the newBuffer
>> > Decode( &ctx, orgBuffer, newBuffer, count);
>> > //Replacing the content of the original encrypted buffer with the
>> > plain text
>> > RtlMoveMemory(orgBuffer, newBuffer, count);
>> > ExFreePool(newBuffer);
>> > //Make sure the buffer pointer is correct
>> > Irp->MdlAddress = orgMdl;
>> > if( Irp->PendingReturned )
>> > IoMarkIrpPending( Irp );
>> > return STATUS_SUCCESS;
>> >
>
>


 
 
codexpert





PostPosted: Sat Aug 27 09:12:09 CDT 2005 Top

Drivers >> File System Filter Driver - different buffer sizes? Thanks Don!

Unfortunately, I work for a company with a legal team which is
particularly petrified, and because of that, I wasn't allowed to sign
the license agreement for the IFS kit. This is extremely unfortunate
because I'm stuck with very few resources. I've been looking at the
filemon code, and read through the NT FS internals book, so that's
about all I have to go on so far.

Don Burn =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0:
> As David said, Filemon is a poor basis for any production filesystem kit,
> particularily a active filter. First get the IFS kit and consider using =
the
> mini filter model (they even have a sample of swapping buffers). Second,
> ask your questions on NTFSD at http://www.osronline.com since that is the
> list that file system people hang out at. Third, think about your
> approach, you have a lot more problems than just swapping the buffers, you
> are changing the file's size and offsets, how is your filter going to han=
dle
> this?
>
>
>
> --
> Don Burn (MVP, Windows DDK)
> Windows 2k/XP/2k3 Filesystem and Driver Consulting
> Remove StopSpam from the email to reply
>
>
>


> > You just said it is ok for now with Sysinternals, so they provide
> > consulting and assistance to those who are using their code with
> > permission. You will not get help from this group in any substantial w=
ay
> > with filemon since the last version that had source available was not
> > designed for production use. It uses many special tricks that induce
> > instability in production systems, but are useful for testing.
> >
> > Why not use the examples provided with the IFS Kit? They are stable an=
d a
> > good basis to begin writing a production driver. They are passive filt=
ers
> > and don't show how to do what you want, but neither does filemon.
> >


> > Thanks Don! It's ok for now with Sysinternals for this stage of the
> > filter development.
> >
> > I forgot to include the code in my IRP_MJ_READ routine:
> >
> > case IRP_MJ_READ:
> > prefRes =3D RtlPrefixUnicodeString(&usrvc, &asrvc, TRUE);
> > if(prefRes && flag){
> > count =3D currentIrpStack->Parameters.Read.Length;
> > orgMdl =3D Irp->MdlAddress; // To be passed in the completion
> > routine
> > *nextIrpStack =3D *currentIrpStack;
> > //Settting a completion routine
> > IoSetCompletionRoutine(Irp, FilterHookReadDone, orgMdl,
> > TRUE,TRUE,TRUE);
> > ...
> > //Call the next driver down the driver statck
> > return IoCallDriver( hookExt->FileSystem, Irp );
> >
> > Where is the tick? Should I allocate a new MDL with different buffer
> > size and pass it to the completion routine?
> >
> > Thanks again!
> >
> > Don Burn ??????:
> >> Well since you are using FileMon, you have obviously paid SysInternals
> >> for
> >> use of the source. I would recomend you ask them.
> >>
> >> If you haven't paid SysInternals, you might fork over the $119 for the
> >> IFS
> >> kit (or if you can wait till after Longhorn to ship, get the WDK beta =
for
> >> free), and use the minifilter model, and something solid and reliable =
for
> >> modifying files as a base.
> >>
> >>
> >> --
> >> Don Burn (MVP, Windows DDK)
> >> Windows 2k/XP/2k3 Filesystem and Driver Consulting
> >> Remove StopSpam from the email to reply
> >>
> >>
> >>


> >> > Hi All,
> >> >
> >> > I am writing a file system filter driver to encrypt/decrypt files
> >> > on-the-fly. I use a crypto algorithm that changes the size of the
> >> > original file after encryption/decryption - how can I handle this
> >> > situation? For example, here is the Filemon code (the completion
> >> > routine) that works when orgBuffer and newBuffer have the same size=
s=2E
> >> > What would happen if the buffer sizes should differ? How to change t=
his
> >> > code to make it work? Thanks in advance for all advices and
> >> > cooperation!
> >> >
> >> > PMDL orgMdl,newMdl;
> >> > PVOID orgBuffer, newBuffer;
> >> > orgMdl =3D Context;
> >> >
> >> > //Getting the original buffer data
> >> > orgBuffer =3D MmGetSystemAddressForMdl(orgMdl);
> >> > //Allocating a new buffer
> >> > newBuffer =3D ExAllocatePool(NonPagedPoolCacheAligned, count);
> >> > //Decrypting data using and placing it into the newBuffer
> >> > Decode( &ctx, orgBuffer, newBuffer, count);
> >> > //Replacing the content of the original encrypted buffer with t=
he
> >> > plain text
> >> > RtlMoveMemory(orgBuffer, newBuffer, count);
> >> > ExFreePool(newBuffer);
> >> > //Make sure the buffer pointer is correct
> >> > Irp->MdlAddress =3D orgMdl;
> >> > if( Irp->PendingReturned )
> >> > IoMarkIrpPending( Irp );
> >> > return STATUS_SUCCESS;
> >> >
> >
> >

 
 
Don





PostPosted: Sat Aug 27 11:08:26 CDT 2005 Top

Drivers >> File System Filter Driver - different buffer sizes? Since you need the DDK for Filemon, see if the will accept the WDK's legal
agreement. The WDK is a beta but includes the IFS kit. Bottom line is you
are going to need the IFS kit for interfaces etc. Please note that the GNU
ntifs.h is stolen code, so you are placing your company at risk if you use
it.


--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply





Thanks Don!

Unfortunately, I work for a company with a legal team which is
particularly petrified, and because of that, I wasn't allowed to sign
the license agreement for the IFS kit. This is extremely unfortunate
because I'm stuck with very few resources. I've been looking at the
filemon code, and read through the NT FS internals book, so that's
about all I have to go on so far.

Don Burn ??????:
> As David said, Filemon is a poor basis for any production filesystem kit,
> particularily a active filter. First get the IFS kit and consider using
> the
> mini filter model (they even have a sample of swapping buffers). Second,
> ask your questions on NTFSD at http://www.osronline.com since that is the
> list that file system people hang out at. Third, think about your
> approach, you have a lot more problems than just swapping the buffers, you
> are changing the file's size and offsets, how is your filter going to
> handle
> this?
>
>
>
> --
> Don Burn (MVP, Windows DDK)
> Windows 2k/XP/2k3 Filesystem and Driver Consulting
> Remove StopSpam from the email to reply
>
>
>


> > You just said it is ok for now with Sysinternals, so they provide
> > consulting and assistance to those who are using their code with
> > permission. You will not get help from this group in any substantial
> > way
> > with filemon since the last version that had source available was not
> > designed for production use. It uses many special tricks that induce
> > instability in production systems, but are useful for testing.
> >
> > Why not use the examples provided with the IFS Kit? They are stable and
> > a
> > good basis to begin writing a production driver. They are passive
> > filters
> > and don't show how to do what you want, but neither does filemon.
> >


> > Thanks Don! It's ok for now with Sysinternals for this stage of the
> > filter development.
> >
> > I forgot to include the code in my IRP_MJ_READ routine:
> >
> > case IRP_MJ_READ:
> > prefRes = RtlPrefixUnicodeString(&usrvc, &asrvc, TRUE);
> > if(prefRes && flag){
> > count = currentIrpStack->Parameters.Read.Length;
> > orgMdl = Irp->MdlAddress; // To be passed in the completion
> > routine
> > *nextIrpStack = *currentIrpStack;
> > //Settting a completion routine
> > IoSetCompletionRoutine(Irp, FilterHookReadDone, orgMdl,
> > TRUE,TRUE,TRUE);
> > ...
> > //Call the next driver down the driver statck
> > return IoCallDriver( hookExt->FileSystem, Irp );
> >
> > Where is the tick? Should I allocate a new MDL with different buffer
> > size and pass it to the completion routine?
> >
> > Thanks again!
> >
> > Don Burn ??????:
> >> Well since you are using FileMon, you have obviously paid SysInternals
> >> for
> >> use of the source. I would recomend you ask them.
> >>
> >> If you haven't paid SysInternals, you might fork over the $119 for the
> >> IFS
> >> kit (or if you can wait till after Longhorn to ship, get the WDK beta
> >> for
> >> free), and use the minifilter model, and something solid and reliable
> >> for
> >> modifying files as a base.
> >>
> >>
> >> --
> >> Don Burn (MVP, Windows DDK)
> >> Windows 2k/XP/2k3 Filesystem and Driver Consulting
> >> Remove StopSpam from the email to reply
> >>
> >>
> >>


> >> > Hi All,
> >> >
> >> > I am writing a file system filter driver to encrypt/decrypt files
> >> > on-the-fly. I use a crypto algorithm that changes the size of the
> >> > original file after encryption/decryption - how can I handle this
> >> > situation? For example, here is the Filemon code (the completion
> >> > routine) that works when orgBuffer and newBuffer have the same
> >> > sizes.
> >> > What would happen if the buffer sizes should differ? How to change
> >> > this
> >> > code to make it work? Thanks in advance for all advices and
> >> > cooperation!
> >> >
> >> > PMDL orgMdl,newMdl;
> >> > PVOID orgBuffer, newBuffer;
> >> > orgMdl = Context;
> >> >
> >> > //Getting the original buffer data
> >> > orgBuffer = MmGetSystemAddressForMdl(orgMdl);
> >> > //Allocating a new buffer
> >> > newBuffer = ExAllocatePool(NonPagedPoolCacheAligned, count);
> >> > //Decrypting data using and placing it into the newBuffer
> >> > Decode( &ctx, orgBuffer, newBuffer, count);
> >> > //Replacing the content of the original encrypted buffer with
> >> > the
> >> > plain text
> >> > RtlMoveMemory(orgBuffer, newBuffer, count);
> >> > ExFreePool(newBuffer);
> >> > //Make sure the buffer pointer is correct
> >> > Irp->MdlAddress = orgMdl;
> >> > if( Irp->PendingReturned )
> >> > IoMarkIrpPending( Irp );
> >> > return STATUS_SUCCESS;
> >> >
> >
> >