445 lines
16 KiB
C
445 lines
16 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 2000-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
FileIo.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements various FileSystem routines used by
|
|||
|
the PGM Transport
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Mohammad Shabbir Alam (MAlam) 3-30-2000
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#endif
|
|||
|
//******************* Pageable Routine Declarations ****************
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
BuildPgmDataFileName(
|
|||
|
IN tSEND_SESSION *pSend
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine build the string for the file name used for buffering
|
|||
|
data packets.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN pSend -- the Send object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NONE -- since we don't expect any error
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNICODE_STRING ucPortNumber;
|
|||
|
WCHAR wcPortNumber[10];
|
|||
|
USHORT MaxFileLength;
|
|||
|
ULONG RandomNumber;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (pPgmRegistryConfig->Flags & PGM_REGISTRY_SENDER_FILE_SPECIFIED)
|
|||
|
{
|
|||
|
MaxFileLength = pPgmRegistryConfig->ucSenderFileLocation.Length / sizeof(WCHAR);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
MaxFileLength = sizeof (WS_DEFAULT_SENDER_FILE_LOCATION) / sizeof (WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The file name is composed of the following:
|
|||
|
// "\\T" + 2DigitRandom# + UptoMAX_USHORTPort# + ".PGM" + "\0"
|
|||
|
//
|
|||
|
MaxFileLength += 2 + 2 + 5 + 4 + 1;
|
|||
|
|
|||
|
if (!(pSend->pSender->DataFileName.Buffer = PgmAllocMem ((sizeof (WCHAR) * MaxFileLength), PGM_TAG('2'))))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "BuildPgmDataFileName",
|
|||
|
"STATUS_INSUFFICIENT_RESOURCES allocating <%d> bytes\n", MaxFileLength);
|
|||
|
|
|||
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
pSend->pSender->DataFileName.MaximumLength = sizeof (WCHAR) * MaxFileLength;
|
|||
|
pSend->pSender->DataFileName.Length = 0;
|
|||
|
|
|||
|
//
|
|||
|
// First, set the root directory
|
|||
|
//
|
|||
|
if (pPgmRegistryConfig->Flags & PGM_REGISTRY_SENDER_FILE_SPECIFIED)
|
|||
|
{
|
|||
|
RtlAppendUnicodeToString (&pSend->pSender->DataFileName, pPgmRegistryConfig->ucSenderFileLocation.Buffer);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
RtlAppendUnicodeToString (&pSend->pSender->DataFileName, WS_DEFAULT_SENDER_FILE_LOCATION);
|
|||
|
}
|
|||
|
|
|||
|
RtlAppendUnicodeToString (&pSend->pSender->DataFileName, L"\\T");
|
|||
|
|
|||
|
//
|
|||
|
// Now, Append a random 2 digit value
|
|||
|
//
|
|||
|
ucPortNumber.MaximumLength = sizeof (wcPortNumber);
|
|||
|
ucPortNumber.Buffer = wcPortNumber;
|
|||
|
RandomNumber = GetRandomInteger (0, 99);
|
|||
|
if (RandomNumber < 10)
|
|||
|
{
|
|||
|
RtlAppendUnicodeToString (&pSend->pSender->DataFileName, L"0");
|
|||
|
}
|
|||
|
RtlIntegerToUnicodeString (RandomNumber, 10, &ucPortNumber);
|
|||
|
RtlAppendUnicodeStringToString (&pSend->pSender->DataFileName, &ucPortNumber);
|
|||
|
|
|||
|
//
|
|||
|
// Append the Port#
|
|||
|
//
|
|||
|
RtlIntegerToUnicodeString ((ULONG) pSend->TSIPort, 10, &ucPortNumber);
|
|||
|
RtlAppendUnicodeStringToString (&pSend->pSender->DataFileName, &ucPortNumber);
|
|||
|
|
|||
|
//
|
|||
|
// Now, add the file name extension for id
|
|||
|
//
|
|||
|
RtlAppendUnicodeToString (&pSend->pSender->DataFileName, L".PGM");
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PgmCreateDataFileAndMapSection(
|
|||
|
IN tSEND_SESSION *pSend
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine creates the file and creates a section mapping for it.
|
|||
|
This file is used for buffering the data packets on behalf of the sender
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN pSend -- the Send object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Final status of the create operation
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
LARGE_INTEGER lgMaxDataFileSize;
|
|||
|
NTSTATUS Status;
|
|||
|
ULONGLONG Size, BlockSize, PacketsInWindow;
|
|||
|
|
|||
|
ULONG DesiredAccess;
|
|||
|
ULONG FileAttributes, AllocationAttributes;
|
|||
|
ULONG ShareAccess;
|
|||
|
ULONG CreateDisposition;
|
|||
|
ULONG CreateOptions;
|
|||
|
ULONG Protection;
|
|||
|
SIZE_T ViewSize;
|
|||
|
KAPC_STATE ApcState;
|
|||
|
BOOLEAN fAttached;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we are currently attached to the Application process
|
|||
|
//
|
|||
|
PgmAttachToProcessForVMAccess (pSend, &ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
|
|||
|
|
|||
|
//
|
|||
|
// First build the File name string
|
|||
|
//
|
|||
|
Status = BuildPgmDataFileName (pSend);
|
|||
|
if (!NT_SUCCESS (Status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
|
|||
|
"BuildPgmDataFileName returned <%x>\n", Status);
|
|||
|
|
|||
|
PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Compute the size of the Data file required to hold 2 * Window size
|
|||
|
// Also make it a multiple of the MTU and the FECGroupSize (if applicable)
|
|||
|
//
|
|||
|
PacketsInWindow = pSend->pAssociatedAddress->WindowSizeInBytes / pSend->pAssociatedAddress->OutIfMTU;
|
|||
|
PacketsInWindow += PacketsInWindow + pSend->FECGroupSize - 1;
|
|||
|
if (PacketsInWindow > SENDER_MAX_WINDOW_SIZE_PACKETS)
|
|||
|
{
|
|||
|
PacketsInWindow = SENDER_MAX_WINDOW_SIZE_PACKETS;
|
|||
|
if (pSend->pAssociatedAddress->WindowSizeInBytes > ((PacketsInWindow >> 1) *
|
|||
|
pSend->pAssociatedAddress->OutIfMTU))
|
|||
|
{
|
|||
|
pSend->pAssociatedAddress->WindowSizeInBytes = (PacketsInWindow >> 1) * pSend->pAssociatedAddress->OutIfMTU;
|
|||
|
pSend->pAssociatedAddress->WindowSizeInMSecs = (BITS_PER_BYTE *
|
|||
|
pSend->pAssociatedAddress->WindowSizeInBytes) /
|
|||
|
pSend->pAssociatedAddress->RateKbitsPerSec;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BlockSize = pSend->FECGroupSize * pSend->pSender->PacketBufferSize;
|
|||
|
Size = PacketsInWindow * pSend->pSender->PacketBufferSize;
|
|||
|
Size = (Size / BlockSize) * BlockSize;
|
|||
|
pSend->pSender->MaxDataFileSize = Size;
|
|||
|
pSend->pSender->MaxPacketsInBuffer = Size / pSend->pSender->PacketBufferSize;
|
|||
|
lgMaxDataFileSize.QuadPart = Size;
|
|||
|
|
|||
|
PgmZeroMemory (&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
|
|||
|
InitializeObjectAttributes (&ObjectAttributes,
|
|||
|
&pSend->pSender->DataFileName,
|
|||
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We need to open the data file. This file contains data
|
|||
|
// and will be mapped into memory. Read and Write access
|
|||
|
// are requested.
|
|||
|
//
|
|||
|
|
|||
|
DesiredAccess = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
|
|||
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE;
|
|||
|
// Using the FILE_ATTRIBUTE_TEMPORARY flag:
|
|||
|
// you let the system know that the file is likely to be short lived.
|
|||
|
// The temporary file is created as a normal file. The system needs to do
|
|||
|
// a minimal amount of lazy writes to the file system to keep the disk
|
|||
|
// structures (directories and so forth) consistent. This gives the
|
|||
|
// appearance that the file has been written to the disk. However, unless
|
|||
|
// the Memory Manager detects an inadequate supply of free pages and
|
|||
|
// starts writing modified pages to the disk, the Cache Manager's Lazy
|
|||
|
// Writer may never write the data pages of this file to the disk.
|
|||
|
// If the system has enough memory, the pages may remain in memory for
|
|||
|
// any arbitrary amount of time. Because temporary files are generally
|
|||
|
// short lived, there is a good chance the system will never write the pages to the disk.
|
|||
|
FileAttributes = FILE_ATTRIBUTE_TEMPORARY;
|
|||
|
|
|||
|
ShareAccess = 0; // Gives the caller exclusive access to the open file
|
|||
|
CreateDisposition = FILE_CREATE; // If the file already exists, fail the request and do not create or
|
|||
|
// open the given file. If it does not, create the given file.
|
|||
|
|
|||
|
// Delete the file when the last handle to it is is passed to ZwClose.
|
|||
|
CreateOptions = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE;
|
|||
|
|
|||
|
PgmZeroMemory (&IoStatusBlock, sizeof(IO_STATUS_BLOCK));
|
|||
|
Status = ZwCreateFile (&pSend->pSender->FileHandle,
|
|||
|
DesiredAccess,
|
|||
|
&ObjectAttributes,
|
|||
|
&IoStatusBlock,
|
|||
|
&lgMaxDataFileSize, // AllocationSize
|
|||
|
FileAttributes,
|
|||
|
ShareAccess,
|
|||
|
CreateDisposition,
|
|||
|
CreateOptions,
|
|||
|
NULL, // EaBuffer
|
|||
|
0); // EaLength
|
|||
|
|
|||
|
if (!NT_SUCCESS (Status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
|
|||
|
"ZwCreateFile for <%wZ> returned <%x>\n", &pSend->pSender->DataFileName, Status);
|
|||
|
|
|||
|
PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
|
|||
|
pSend->pSender->FileHandle = NULL;
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now we have a handle to our open test file. We now create a section
|
|||
|
// object with this handle.
|
|||
|
//
|
|||
|
DesiredAccess = STANDARD_RIGHTS_REQUIRED |
|
|||
|
SECTION_QUERY |
|
|||
|
SECTION_MAP_READ |
|
|||
|
SECTION_MAP_WRITE;
|
|||
|
Protection = PAGE_READWRITE;
|
|||
|
AllocationAttributes = SEC_COMMIT;
|
|||
|
|
|||
|
PgmZeroMemory (&ObjectAttributes, sizeof (OBJECT_ATTRIBUTES));
|
|||
|
InitializeObjectAttributes (&ObjectAttributes,
|
|||
|
NULL,
|
|||
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
Status = ZwCreateSection (&pSend->pSender->SectionHandle,
|
|||
|
DesiredAccess,
|
|||
|
&ObjectAttributes, // NULL ?
|
|||
|
&lgMaxDataFileSize,
|
|||
|
Protection,
|
|||
|
AllocationAttributes,
|
|||
|
pSend->pSender->FileHandle);
|
|||
|
|
|||
|
if (!NT_SUCCESS (Status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
|
|||
|
"ZwCreateSection for <%wZ> returned <%x>\n", &pSend->pSender->DataFileName, Status);
|
|||
|
|
|||
|
ZwClose (pSend->pSender->FileHandle);
|
|||
|
PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reference the section object, if a view is mapped to the section
|
|||
|
// object, the object is not dereferenced as the virtual address
|
|||
|
// descriptor contains a pointer to the section object.
|
|||
|
//
|
|||
|
|
|||
|
Status = ObReferenceObjectByHandle (pSend->pSender->SectionHandle,
|
|||
|
0,
|
|||
|
0,
|
|||
|
KernelMode,
|
|||
|
&pSend->pSender->pSectionObject,
|
|||
|
NULL );
|
|||
|
|
|||
|
if (!NT_SUCCESS (Status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
|
|||
|
"ObReferenceObjectByHandle for SectionHandle=<%x> returned <%x>\n",
|
|||
|
pSend->pSender->SectionHandle, Status);
|
|||
|
|
|||
|
ZwClose (pSend->pSender->SectionHandle);
|
|||
|
ZwClose (pSend->pSender->FileHandle);
|
|||
|
PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Our section object has been created and linked to the file
|
|||
|
// object that was previous opened. Now we map a view on
|
|||
|
// this section.
|
|||
|
//
|
|||
|
ViewSize = 0;
|
|||
|
Protection = PAGE_READWRITE;
|
|||
|
Status = ZwMapViewOfSection (pSend->pSender->SectionHandle,
|
|||
|
NtCurrentProcess(),
|
|||
|
&pSend->pSender->SendDataBufferMapping,
|
|||
|
0L, // ZeroBits
|
|||
|
0L, // CommitSize (initially committed region)
|
|||
|
NULL, // &SectionOffset
|
|||
|
&ViewSize,
|
|||
|
ViewUnmap, // InheritDisposition: for child processes
|
|||
|
0L, // AllocationType
|
|||
|
Protection);
|
|||
|
|
|||
|
if (!NT_SUCCESS (Status))
|
|||
|
{
|
|||
|
PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
|
|||
|
"ZwMapViewOfSection for <%wZ> returned <%x>\n", &pSend->pSender->DataFileName, Status);
|
|||
|
|
|||
|
ObDereferenceObject (pSend->pSender->pSectionObject);
|
|||
|
pSend->pSender->pSectionObject = NULL;
|
|||
|
|
|||
|
ZwClose (pSend->pSender->SectionHandle);
|
|||
|
pSend->pSender->SectionHandle = NULL;
|
|||
|
ZwClose (pSend->pSender->FileHandle);
|
|||
|
pSend->pSender->FileHandle = NULL;
|
|||
|
PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
|
|||
|
return (Status);
|
|||
|
}
|
|||
|
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
|
|||
|
"Mapped <%wZ> to address<%x>, Filelength=<%d>\n",
|
|||
|
&pSend->pSender->DataFileName, pSend->pSender->SendDataBufferMapping, Size);
|
|||
|
|
|||
|
pSend->pSender->BufferSizeAvailable = pSend->pSender->MaxDataFileSize;
|
|||
|
pSend->pSender->LeadingWindowOffset = pSend->pSender->TrailingWindowOffset = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Now, reference the process
|
|||
|
//
|
|||
|
ObReferenceObject (pSend->Process);
|
|||
|
PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PgmUnmapAndCloseDataFile(
|
|||
|
IN tSEND_SESSION *pSend
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine cleansup the file mapping and closes the file
|
|||
|
handles. The file should automatically get deleted on closing
|
|||
|
the handle since we used the FILE_DELETE_ON_CLOSE option while
|
|||
|
creating the file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN pSend -- the Send object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Final status of the operation (STATUS_SUCCESS)
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
KAPC_STATE ApcState;
|
|||
|
BOOLEAN fAttached;
|
|||
|
|
|||
|
PgmAttachToProcessForVMAccess (pSend, &ApcState, &fAttached, REF_PROCESS_ATTACH_CLOSE_DATA_FILE);
|
|||
|
Status = ZwUnmapViewOfSection (NtCurrentProcess(), (PVOID) pSend->pSender->SendDataBufferMapping);
|
|||
|
ASSERT (NT_SUCCESS (Status));
|
|||
|
|
|||
|
Status = ObDereferenceObject (pSend->pSender->pSectionObject);
|
|||
|
ASSERT (NT_SUCCESS (Status));
|
|||
|
pSend->pSender->pSectionObject = NULL;
|
|||
|
|
|||
|
Status = ZwClose (pSend->pSender->SectionHandle);
|
|||
|
ASSERT (NT_SUCCESS (Status));
|
|||
|
pSend->pSender->SectionHandle = NULL;
|
|||
|
|
|||
|
Status = ZwClose (pSend->pSender->FileHandle);
|
|||
|
ASSERT (NT_SUCCESS (Status));
|
|||
|
|
|||
|
PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CLOSE_DATA_FILE);
|
|||
|
ObDereferenceObject (pSend->Process); // Since we had referenced it when the file was created
|
|||
|
|
|||
|
pSend->pSender->SendDataBufferMapping = NULL;
|
|||
|
pSend->pSender->pSectionObject = NULL;
|
|||
|
pSend->pSender->SectionHandle = NULL;
|
|||
|
pSend->pSender->FileHandle = NULL;
|
|||
|
|
|||
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_SEND, "PgmUnmapAndCloseDataFile",
|
|||
|
"pSend = <%x>\n", pSend);
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|