Hi,
How do i copy file from one location to other??
e.g. i want to copy file from c:\windows\system32\abc.exe to c:\windows\abc.exe.
I have file system driver.
Thanks in advance
Hi,
How do i copy file from one location to other??
e.g. i want to copy file from c:\windows\system32\abc.exe to c:\windows\abc.exe.
I have file system driver.
Thanks in advance
On Tue, Apr 6, 2010 at 10:56 AM, wrote:
> I have file system driver.
Are you sure?!?
> How do i copy file from one location to other??
> e.g. i want to copy file from c:\windows\system32\abc.exe to c:\windows\abc.exe.
ZwCreateFile(), ZwReadFile() and ZwWriteFile() are your friends.
â
Aram HÄvÄrneanu
Yes i have file system driver âŚ
Thank you for your help !!
Let me try thisâŚ
In order to fully duplicate the user mode CopyFile API you have a fair
amount of work to do. Donât forget about alternate data streams, security
descriptors, etc. Farming this out to user mode will be a better solution if
possible.
-scott
â
Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com
wrote in message news:xxxxx@ntfsdâŚ
> Yes i have file system driver âŚ
>
> Thank you for your help !!
>
> Let me try thisâŚ
>
>> Farming this out to user mode will be a better solution if possible.
This is not trivial either. For example, if you are responding to a callback in your driver for Foo.txt in location A and as a result you want to copy it to location B. If you block in the driver and wait for your service to copy the file and in your service you call functions like CopyFile or CreateDirectoryEx you will deadlock b/c the thread you are blocking in the driver will hold a resource and CopyFile and CreateDirectoryEx will ship some work off to a kernel mode worker thread who will also want that resource.
The only solution I have been able to come up with for this is to do a double file copy. Driver copies from location A to a temp file in location C, then service copies from temp file in location to C to location B. This is incredibly inefficient and a bad solution.
So, I have been on the path of converting to doing the copy in kernel mode as well, which opens up a whole different can of worms.
So, after providing that level of experience to this problem, anyone have any other advice to help the OP and me out with this?
>This is not trivial either. For example, if you are responding to a
callback in your driver for Foo.txt in location A and as a result >you want
to copy it to location B. If you block in the driver and wait for your
service to copy the file and in your service you call >functions like
CopyFile or CreateDirectoryEx you will deadlock b/c the thread you are
blocking in the driver
The OP just asked about copying a file, this sounds more like COW. Could
still be done with the help of user mode, though you just need to be sure to
not block the user thread doing the copy (same sort of issue the A/V folks
have, though they have it easier since theyâre in control of the scanning
code and thus can play more games). In that case it might not be the best
design decision though, it really depends. Also, the OP was talking about
doing this in a file system, which is going to be a different beast than in
a filter (Iâm actually still not sure what theyâre doing).
So, I have been on the path of converting to doing the copy in kernel mode
as well, which opens up a whole different can of >worms.
I wasnât meaning to indicate that doing the copy couldnât be done from
kernel mode, just offering a potentially easier solution if it fit the
design. Weâve successfully done a COW filter that does the copy from kernel
mode and SR on XP does its copy in kernel mode, so it is achievable.
-scott
â
Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com
wrote in message news:xxxxx@ntfsdâŚ
>>> Farming this out to user mode will be a better solution if possible.
>
> This is not trivial either. For example, if you are responding to a
> callback in your driver for Foo.txt in location A and as a result you want
> to copy it to location B. If you block in the driver and wait for your
> service to copy the file and in your service you call functions like
> CopyFile or CreateDirectoryEx you will deadlock b/c the thread you are
> blocking in the driver will hold a resource and CopyFile and
> CreateDirectoryEx will ship some work off to a kernel mode worker thread
> who will also want that resource.
>
> The only solution I have been able to come up with for this is to do a
> double file copy. Driver copies from location A to a temp file in
> location C, then service copies from temp file in location to C to
> location B. This is incredibly inefficient and a bad solution.
>
> So, I have been on the path of converting to doing the copy in kernel mode
> as well, which opens up a whole different can of worms.
>
> So, after providing that level of experience to this problem, anyone have
> any other advice to help the OP and me out with this?
>
>
>
>
Thanks Scott. I was just offering the OP some stuff to think about and also to learn a little something myself.
For a long time I thought the deadlocks were b/c I was running on a machine with A/V, but recently seen it repro without A/V in the picture. I guess it could work if the filter doesnât care about the results of the copy and thus does not wait for usermode to return (i.e. FltSendMessage). Otherise, it will block and deadlock.
> I wasnât meaning to indicate that doing the copy couldnât be done from
> kernel modeâŚjust offering a potentially easier solution
Indeed. Itâs been quite a challenge to get it to work correctly, but I feel if I can get it to work correctly (not close yet) it will be a better solution overall for me at least given my design and requirements (it is sort of a COW solution).
Hi,
this is the code i tried âŚ
few files get copied successfullyâŚ
Files with some sizes, i get DbgPrint(âfail 4 âŚâ); in the following code .i.e. ntstatus == STATUS_END_OF_FILE in the first loop itself ⌠and thus file didnt get copied
please help if i am doing something wrong hereâŚ
//code
DWORD dwSizeOfBuffer = 512;
ntstatus = ZwOpenFile(&OriFileHandle, GENERIC_READ, &objOriAttr, &ioOriStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE);
if(!NT_SUCCESS(ntstatus))
{
DbgPrint(âfail 1 âŚâ);
PsTerminateSystemThread(STATUS_SUCCESS);
return;
}
ntstatus = ZwCreateFile(&CopyFileHandle, GENERIC_WRITE, &objCopyAttr, &ioCopyStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_ALERT, NULL, 0 );
if(!NT_SUCCESS(ntstatus))
{
DbgPrint(âfail 2 âŚâ);
PsTerminateSystemThread(STATUS_SUCCESS);
ZwClose(OriFileHandle);
//close handle
return;
}
pBuffer = ExAllocatePoolWithTag(NonPagedPool, dwSizeOfBuffer, SDMANAGER_POOL_POOL_TAG);
do
{
DbgPrint(âcall 1 âŚâ);
ntstatus = ZwReadFile(OriFileHandle, NULL, NULL, NULL, &ioOriStatusBlock, pBuffer, dwSizeOfBuffer, &byteOffset, NULL);
if(ntstatus == STATUS_END_OF_FILE)
{
DbgPrint(âfail 4 âŚâ);
break;
}
if(!NT_SUCCESS(ntstatus))
{
DbgPrint(âfail 5 âŚâ);
break;
}
if(ioOriStatusBlock.Information > dwSizeOfBuffer+1)
{
DbgPrint(âfail 6 âŚâ);
break;
}
else if(ioOriStatusBlock.Information <=0)
{
DbgPrint(âfail 7 âŚâ);
break;
}
if(MmIsAddressValid(pBuffer) != TRUE)
{
DbgPrint(âfail 8 âŚâ);
break;
}
DbgPrint(âcall 2 âŚâ);
ntstatus = ZwWriteFile(CopyFileHandle, NULL, NULL, NULL, &ioCopyStatusBlock,
pBuffer, dwSizeOfBuffer, &byteOffsetWrite, NULL);
if(NT_ERROR(ntstatus))
{
DbgPrint(âerror in WriteFile Status : %Xâ,ntstatus);
break;
}
if(NT_ERROR(ioCopyStatusBlock.Status))
{
DbgPrint(âerror in WriteFile ioWrite Status : %Xâ,ioCopyStatusBlock.Status);
break;
}
DbgPrint(âcall 3 âŚâ);
byteOffset.QuadPart += ioOriStatusBlock.Information;
byteOffsetWrite.QuadPart += ioCopyStatusBlock.Information;
memset(pBuffer, 0, dwSizeOfBuffer);
}while(1);
ExFreePoolWithTag(pBuffer, SDMANAGER_POOL_POOL_TAG);
ZwClose(OriFileHandle);
ZwClose(CopyFileHandle);
I would assume that youâre getting the âSTATUS_END_OF_FILEâ error because youâre trying to read past the end of the file, due to always reading in a fixed size block. In this case, I believe that ioOriStatusBlock.Information will still contain the number of bytes read, which will be the remainder of the file.
The check âMmAddressIsValid()â wonât due what you appear to think that it will. You just need to check to see if pBuffer != 0, but you need to do it right after the call to ExAllocatePoolWithTag().
This - âif(ioOriStatusBlock.Information <=0)â will never happen, since the type of âIO_STATUS_BLOCK::Informationâ is unsigned (ULONG_PTR), so you donât need this check.
Nor will this happen âif(ioOriStatusBlock.Information > dwSizeOfBuffer+1)â
This - âif(NT_ERROR(ioCopyStatusBlock.Status))â wonât do what you appear to think it will. You would only check IO_STATUS_BLOCK::Status if ntstatus==STATUS_PENDING and then after the I/O completes; otherwise, you just go with the value of ntstatus.
Good luck,
mm
Whoops.
I missed the â=â in the â<=â in this:
Just the check for â<â is unnecessary.
mm
Thanks guys ⌠your suggestions worked âŚ
Here is the code that worked for me⌠i tried this in threadâŚ
just wanted to know one more thingâŚ
Is it necessary to do ZwQueryInformationFile of the original file and do ZwSetInformationFile for copied file???
{
HANDLE OriFileHandle = NULL;
HANDLE CopyFileHandle = NULL;
UNICODE_STRING usOriginalFile = {0}, usCopyFile = {0};
OBJECT_ATTRIBUTES objOriAttr, objCopyAttr;
IO_STATUS_BLOCK ioOriStatusBlock, ioCopyStatusBlock;
LARGE_INTEGER byteOffsetRead = {0}, byteOffsetWrite = {0};
NTSTATUS ntstatus;
PVOID pBuffer = NULL;
DWORD dwSizeOfBuffer = 2048;
RtlInitUnicodeString(&usOriginalFile, wsOriginalFilePath);
RtlInitUnicodeString(&usCopyFile, wsCopyFilePath);
InitializeObjectAttributes(&objOriAttr, &usOriginalFile, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
InitializeObjectAttributes(&objCopyAttr, &usCopyFile, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
ntstatus = ZwCreateFile(&OriFileHandle, GENERIC_READ, &objOriAttr, &ioOriStatusBlock, NULL,
FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if(!NT_SUCCESS(ntstatus))
{
return ntstatus;
}
ntstatus = ZwCreateFile(&CopyFileHandle, GENERIC_WRITE, &objCopyAttr, &ioCopyStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
if(!NT_SUCCESS(ntstatus))
{
ZwClose(OriFileHandle);
return ntstatus;
}
pBuffer = ExAllocatePoolWithTag(NonPagedPool, dwSizeOfBuffer, SDMANAGER_POOL_POOL_TAG);
if(!pBuffer)
{
ZwClose(OriFileHandle);
ZwClose(CopyFileHandle);
return STATUS_NO_MEMORY;
}
do
{
ntstatus = ZwReadFile(OriFileHandle, NULL, NULL, NULL, &ioOriStatusBlock, pBuffer,
dwSizeOfBuffer, &byteOffsetRead, NULL);
if(ntstatus == STATUS_END_OF_FILE)
{
if(ioOriStatusBlock.Information == 0)
{
break;
}
}
if(!NT_SUCCESS(ntstatus))
{
break;
}
ntstatus = ZwWriteFile(CopyFileHandle, NULL, NULL, NULL, &ioCopyStatusBlock,
pBuffer, ioOriStatusBlock.Information, &byteOffsetWrite, NULL);
if(NT_ERROR(ntstatus))
{
break;
}
if(NT_ERROR(ioCopyStatusBlock.Status))
{
break;
}
byteOffsetRead.QuadPart += ioOriStatusBlock.Information;
byteOffsetWrite.QuadPart += ioCopyStatusBlock.Information;
memset(pBuffer, 0, dwSizeOfBuffer);
}while(1);
ExFreePoolWithTag(pBuffer, SDMANAGER_POOL_POOL_TAG);
ZwClose(OriFileHandle);
ZwClose(CopyFileHandle);
return ntstatus;
}
Hi,
Scott:
you were talking about alternate data streams, security descriptors, etcâŚ
how do i set all such important information in my copied file, as there are many values in FILE_INFORMATION_CLASS. I am copying system files.
FileStreamInformation for the streams of the file and FileBasicInformation
for the attributes and timestamps of the file. ZwQuerySecurityObject for the
SD of the file. EAs might also be necessary to copy (IRP_MJ_QUERY_EA).
-scott
â
Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com
wrote in message news:xxxxx@ntfsdâŚ
> Hi,
>
> Scott:
> you were talking about alternate data streams, security descriptors,
> etcâŚ
> how do i set all such important information in my copied file, as there
> are many values in FILE_INFORMATION_CLASS. I am copying system files.
>
Thank you Scott.
seems a little more work to do for me. I will try this now.
Thank you again.
-yuvraj
You are going to have to check for these features in the file, so you are going to have to query the file to see if it has streams, and you are going to have to check to see if the file has an SD, and maybe even an EA. Now, one quick check may be to see what the source FS is, since not all FSâs support all these featuresâŚ
âMark Cariddi
OSR, Open Systems Resources, Inc.
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, April 08, 2010 8:15 AM
To: Windows File Systems Devs Interest List
Subject: RE:[ntfsd] Copy file from one location to other
Hi,
Scott:
you were talking about alternate data streams, security descriptors, etcâŚ
how do i set all such important information in my copied file, as there are many values in FILE_INFORMATION_CLASS. I am copying system files.
NTFSD is sponsored by OSR
For our schedule of debugging and file system seminars
(including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
On Thu, Apr 8, 2010 at 4:05 PM, Mark Cariddi wrote:
> You are going to have to check for these features in the file, so you are going to have to query the file to see if it has streams, and you are going to have to check to see if the file has an SD, and maybe even an EA. Now, one quick check may be to see what the source FS is, since not all FSâs support all these featuresâŚ
Unfortunately, no matter what you do, you will not be forward
compatible with possible file systems enhancements.
â
Aram HÄvÄrneanu
Hi guys,
For stream information i did the following and it worked for me
NTSTATUS SetFileSecurityDescriptor(HANDLE OriFileHandle, HANDLE CopyFileHandle)
{
NTSTATUS ntstatus;
PSECURITY_DESCRIPTOR pSecDesc = NULL;
ULONG ulDescriptorSize;
ntstatus = ZwQuerySecurityObject(OriFileHandle,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
pSecDesc, sizeof(SECURITY_DESCRIPTOR), &ulDescriptorSize);
if(ntstatus == STATUS_BUFFER_TOO_SMALL )
{
pSecDesc = ExAllocatePoolWithTag(NonPagedPool, ulDescriptorSize, SDMANAGER_POOL_POOL_TAG);
if(!pSecDesc)
{
return STATUS_NO_MEMORY;
}
memset(pSecDesc, 0, ulDescriptorSize);
ntstatus = ZwQuerySecurityObject(OriFileHandle,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
pSecDesc, ulDescriptorSize, &ulDescriptorSize);
}
if(NT_SUCCESS(ntstatus))
{
ntstatus = ZwSetSecurityObject(CopyFileHandle,
OWNER_SECURITY_INFORMATION,
pSecDesc);
ntstatus = ZwSetSecurityObject(CopyFileHandle,
DACL_SECURITY_INFORMATION,
pSecDesc);
ntstatus = ZwSetSecurityObject(CopyFileHandle,
GROUP_SECURITY_INFORMATION,
pSecDesc);
ntstatus = ZwSetSecurityObject(CopyFileHandle,
SACL_SECURITY_INFORMATION,
pSecDesc);
}
ExFreePoolWithTag(pSecDesc, SDMANAGER_POOL_POOL_TAG);
return ntstatus;
}
Sorry earlier was code for security descriptorâŚwhich is working fine âŚ
I am unable to set stream informationâŚPlease go through the following code and let me know if i am wrong somewhereâŚ
I never get dbgprint âset file stream successâŚâ,
it gives âque file stream âŚâ and âend file stream âŚâ
NTSTATUS SetFileStreamInformation(HANDLE OriFileHandle, HANDLE CopyFileHandle)
{
FILE_STREAM_INFORMATION oOriFileInfo = {0};
PFILE_STREAM_INFORMATION poCopyFileInfo = NULL;
IO_STATUS_BLOCK ioOriStatusBlock;
NTSTATUS ntstatus;
ntstatus = ZwQueryInformationFile(OriFileHandle, &ioOriStatusBlock, &oOriFileInfo,
sizeof(FILE_STREAM_INFORMATION), FileStreamInformation);
DbgPrint(âerror in read Status : %Xâ,ntstatus);
if(ntstatus == STATUS_BUFFER_OVERFLOW)
{
DbgPrint(âbuffferr file stream âŚâ);
poCopyFileInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_STREAM_INFORMATION)*2, SDMANAGER_POOL_POOL_TAG);
ntstatus = ZwQueryInformationFile(OriFileHandle, &ioOriStatusBlock, poCopyFileInfo,
sizeof(FILE_STREAM_INFORMATION)*2, FileStreamInformation);
}
else
{
poCopyFileInfo = &oOriFileInfo;
}
if(NT_SUCCESS(ntstatus))
{
DbgPrint(âque file stream âŚâ);
ntstatus = ZwSetInformationFile(CopyFileHandle, &ioOriStatusBlock, poCopyFileInfo,
sizeof(FILE_STREAM_INFORMATION)*2, FileStreamInformation);
DbgPrint(âset error in read Status : %Xâ,ntstatus);
if(NT_SUCCESS(ntstatus))
{
DbgPrint(âset file stream successâŚâ);
}
}
ExFreePoolWithTag(poCopyFileInfo, SDMANAGER_POOL_POOL_TAG);
DbgPrint(âend file stream âŚâ);
return ntstatus;
}
Lots of problems/questions here:
If you get âque file stream âŚâ and âend file stream âŚâ but not âset
file stream successâŚâ, then you should get âset error in read Statusâ â
what is it?
Your buffer allocation is goofy. A FILE_STREAM_INFORMATION only includes
one character for the stream name. If your first ZwQueryInformationFile
fails (which it should, with STATUS_BUFFER_OVERFLOW or
STATUS_BUFFER_TOO_SMALL), you allocate sizeof(FILE_STREAM_INFORMATION)*2
which might still be too small. Make that smarter.
If the first ZwQueryInformationFile should somehow succeed, you still use
sizeof(FILE_STREAM_INFORMATION)*2 for the buffer size in the
ZwSetInformationFile. Thatâs wrong.
More importantly, you canât use FileStreamInformation to create streams in a
file â it can only be used to query stream info.
Ken
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Saturday, April 10, 2010 4:37 AM
To: Windows File Systems Devs Interest List
Subject: RE:[ntfsd] Copy file from one location to other
Sorry earlier was code for security descriptorâŚwhich is working fine
âŚ
I am unable to set stream informationâŚPlease go through the following code
and let me know if i am wrong somewhereâŚ
I never get dbgprint âset file stream successâŚâ,
it gives âque file stream âŚâ and âend file stream âŚâ
NTSTATUS SetFileStreamInformation(HANDLE OriFileHandle, HANDLE
CopyFileHandle)
{
FILE_STREAM_INFORMATION oOriFileInfo = {0};
PFILE_STREAM_INFORMATION poCopyFileInfo = NULL;
IO_STATUS_BLOCK ioOriStatusBlock;
NTSTATUS ntstatus;
ntstatus = ZwQueryInformationFile(OriFileHandle, &ioOriStatusBlock,
&oOriFileInfo,
sizeof(FILE_STREAM_INFORMATION), FileStreamInformation);
DbgPrint(âerror in read Status : %Xâ,ntstatus);
if(ntstatus == STATUS_BUFFER_OVERFLOW)
{
DbgPrint(âbuffferr file stream âŚâ);
poCopyFileInfo = ExAllocatePoolWithTag(NonPagedPool,
sizeof(FILE_STREAM_INFORMATION)*2, SDMANAGER_POOL_POOL_TAG);
ntstatus = ZwQueryInformationFile(OriFileHandle,
&ioOriStatusBlock, poCopyFileInfo,
sizeof(FILE_STREAM_INFORMATION)*2, FileStreamInformation);
}
else
{
poCopyFileInfo = &oOriFileInfo;
}
if(NT_SUCCESS(ntstatus))
{
DbgPrint(âque file stream âŚâ);
ntstatus = ZwSetInformationFile(CopyFileHandle,
&ioOriStatusBlock, poCopyFileInfo,
sizeof(FILE_STREAM_INFORMATION)*2, FileStreamInformation);
DbgPrint(âset error in read Status : %Xâ,ntstatus);
if(NT_SUCCESS(ntstatus))
{
DbgPrint(âset file stream successâŚâ);
}
}
ExFreePoolWithTag(poCopyFileInfo, SDMANAGER_POOL_POOL_TAG);
DbgPrint(âend file stream âŚâ);
return ntstatus;
}
NTFSD is sponsored by OSR
For our schedule of debugging and file system seminars
(including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer
This is not my thing, but I donât think that what youâre trying to do - create stream information with ZwSetInformationFile() - will work, no matter what you do.
The way youâre guessing at buffer sizes is not a good approach. Youâre also not checking the return value after the second query attempt. It may be failing there.
Taking a step back, youâre not handling the buffer correctly, no matter what the required size, because the last member of FILE_STREAM_INFORMATION is a âvariableâ sized array, so you need to add the actual size of that array (the stream name) to the total buffer size.
Something like this:
void * buffer = ExAllocatePoolWithTag(âŚ)
FILE_STREAM_INFORMATION * pStreamInfo = (FILE_STREAM_INFORMATION *) buffer;
As far as the size of the buffer, most routines will return STATUS_BUFFER_OVERFLOW (or STATUS_BUFFER_TO_SMALL) and put the required size in some field; according to the docs (SEE them for FILE_STREAM_INFORMATION), this is not the case here, so you apparently have to keep guessing with a larger size.
This - poCopyFileInfo = &oOriFileInfo; - will also cause problems later, as youâre telling ZwSetInformationFile() that the buffer is sizeof(FILE_STREAM_INFORMATION) * 2, which is not the case if that (poCopyFileInfo = & oOriFileInfo) executes.
Good luck,
mm