/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    copy.c

Abstract:

    This module contains the routine to copy a file.

Author:

    Dan Hinsley (DanHi) 24-Feb-1991

Revision History:

    02-Feb-1994     Danl
        Fixed memory leak where ioBuffer wasn't getting free'd when doing
        an error exit from ElfpCopyFile.

--*/

//
// INCLUDES
//

#include <eventp.h>


NTSTATUS
ElfpCopyFile (
    IN HANDLE SourceHandle,
    IN PUNICODE_STRING TargetFileName
    )

/*++

Routine Description:

    This routine copies or appends from the source file to the target file.
    If the target file already exists, the copy fails.

Arguments:

    SourceHandle - An open handle to the source file.

    TargetFileName - The name of the file to copy to.


Return Value:

    NTSTATUS - STATUS_SUCCESS or error.

--*/

{

    NTSTATUS Status;

    IO_STATUS_BLOCK IoStatusBlock;
    FILE_STANDARD_INFORMATION sourceStandardInfo;

    OBJECT_ATTRIBUTES ObjectAttributes;
    HANDLE TargetHandle;

    PCHAR ioBuffer;
    ULONG ioBufferSize;
    ULONG bytesRead;

    //
    // Get the size of the file so we can set the attributes of the target
    // file.
    //

    Status = NtQueryInformationFile(
                 SourceHandle,
                 &IoStatusBlock,
                 &sourceStandardInfo,
                 sizeof(sourceStandardInfo),
                 FileStandardInformation
                 );

    if ( !NT_SUCCESS(Status) ) {

        return(Status);
    }

    //
    // Open the target file, fail if the file already exists.
    //

    InitializeObjectAttributes(
                    &ObjectAttributes,
                    TargetFileName,
                    OBJ_CASE_INSENSITIVE,
                    NULL,
                    NULL
                    );

    Status = NtCreateFile(&TargetHandle,
                        GENERIC_WRITE | SYNCHRONIZE,
                        &ObjectAttributes,
                        &IoStatusBlock,
                        &(sourceStandardInfo.EndOfFile),
                        FILE_ATTRIBUTE_NORMAL,
                        0,                       // Share access
                        FILE_CREATE,
                        FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY,
                        NULL,                    // EA buffer
                        0                        // EA length
                        );

    if (!NT_SUCCESS(Status)) {
        return(Status);
    }

    //
    // Allocate a buffer to use for the data copy.
    //

    ioBufferSize = 4096;

    ioBuffer = ElfpAllocateBuffer ( ioBufferSize);

    if ( ioBuffer == NULL ) {

        return (STATUS_NO_MEMORY);
    }

    //
    // Copy data--read from source, write to target.  Do this until
    // all the data is written or an error occurs.
    //

    while ( TRUE ) {

        Status = NtReadFile(
                         SourceHandle,
                         NULL,                // Event
                         NULL,                // ApcRoutine
                         NULL,                // ApcContext
                         &IoStatusBlock,
                         ioBuffer,
                         ioBufferSize,
                         NULL,                // ByteOffset
                         NULL                 // Key
                         );

        if ( !NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE ) {

            ElfDbgPrint(("[ELF] Copy failed reading source file - %X\n",
                Status));
            ElfpFreeBuffer(ioBuffer);
            return (Status);

        }

        if ( IoStatusBlock.Information == 0 ||
             Status == STATUS_END_OF_FILE ) {
            break;
        }

        bytesRead = IoStatusBlock.Information;

        Status = NtWriteFile(
                          TargetHandle,
                          NULL,               // Event
                          NULL,               // ApcRoutine
                          NULL,               // ApcContext
                          &IoStatusBlock,
                          ioBuffer,
                          bytesRead,
                          NULL,               // ByteOffset
                          NULL                // Key
                          );

        if ( !NT_SUCCESS(Status) ) {
            ElfDbgPrint(("[ELF] Copy failed writing target file - %X\n",
                Status));
            ElfpFreeBuffer(ioBuffer);
            return (Status);
        }
    }

    ElfpFreeBuffer ( ioBuffer );

    Status = NtClose(TargetHandle);

    ASSERT(NT_SUCCESS(Status));

    return STATUS_SUCCESS;

} // ElfpCopyFile

