Copy file from one location to other

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?

1 Like

>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);

  1. 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.

  2. 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().

  3. 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.

  4. Nor will this happen ‘if(ioOriStatusBlock.Information > dwSizeOfBuffer+1)’

  5. 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:

  1. 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.

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

  1. 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.

  2. 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.

  3. 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;

  1. 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.

  2. 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