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