summaryrefslogtreecommitdiffstats
path: root/private/ntos/npfs
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/npfs
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/npfs')
-rw-r--r--private/ntos/npfs/aliassup.c576
-rw-r--r--private/ntos/npfs/cleanup.c229
-rw-r--r--private/ntos/npfs/close.c236
-rw-r--r--private/ntos/npfs/create.c794
-rw-r--r--private/ntos/npfs/createnp.c895
-rw-r--r--private/ntos/npfs/datasup.c1077
-rw-r--r--private/ntos/npfs/deviosup.c141
-rw-r--r--private/ntos/npfs/dir.c882
-rw-r--r--private/ntos/npfs/dumpsup.c491
-rw-r--r--private/ntos/npfs/eventsup.c391
-rw-r--r--private/ntos/npfs/fileinfo.c1412
-rw-r--r--private/ntos/npfs/filobsup.c272
-rw-r--r--private/ntos/npfs/flushbuf.c239
-rw-r--r--private/ntos/npfs/fsctrl.c3296
-rw-r--r--private/ntos/npfs/makefile6
-rw-r--r--private/ntos/npfs/nodetype.h143
-rw-r--r--private/ntos/npfs/npdata.c117
-rw-r--r--private/ntos/npfs/npdata.h182
-rw-r--r--private/ntos/npfs/npfs.prf1
-rw-r--r--private/ntos/npfs/npfs.rc12
-rw-r--r--private/ntos/npfs/npinit.c178
-rw-r--r--private/ntos/npfs/npprocs.h791
-rw-r--r--private/ntos/npfs/npstruc.h810
-rw-r--r--private/ntos/npfs/prefxsup.c255
-rw-r--r--private/ntos/npfs/read.c529
-rw-r--r--private/ntos/npfs/readsup.c293
-rw-r--r--private/ntos/npfs/resrcsup.c234
-rw-r--r--private/ntos/npfs/secursup.c387
-rw-r--r--private/ntos/npfs/seinfo.c416
-rw-r--r--private/ntos/npfs/sources65
-rw-r--r--private/ntos/npfs/statesup.c1179
-rw-r--r--private/ntos/npfs/strucsup.c1022
-rw-r--r--private/ntos/npfs/volinfo.c360
-rw-r--r--private/ntos/npfs/waitsup.c626
-rw-r--r--private/ntos/npfs/write.c608
-rw-r--r--private/ntos/npfs/writesup.c329
36 files changed, 19474 insertions, 0 deletions
diff --git a/private/ntos/npfs/aliassup.c b/private/ntos/npfs/aliassup.c
new file mode 100644
index 000000000..ca8b20d63
--- /dev/null
+++ b/private/ntos/npfs/aliassup.c
@@ -0,0 +1,576 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ AliasSup.c
+
+Abstract:
+
+ This module implements alias support for the Named Pipe file system.
+
+Author:
+
+ Chuck Lenzmeier [chuckl] 16-Nov-1993
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// Registry path (relative to Services key) to alias list
+//
+
+#define ALIAS_PATH L"Npfs\\Aliases"
+
+//
+// The Alias record defines an aliased pipe name -- what the original
+// name is, and what it should be translated to. Alias records are
+// linked together in singly linked lists.
+//
+
+typedef struct _ALIAS {
+ SINGLE_LIST_ENTRY ListEntry;
+ PUNICODE_STRING TranslationString;
+ UNICODE_STRING AliasString;
+} ALIAS, *PALIAS;
+
+//
+// ALIAS_CONTEXT is used during initialization to pass context to the
+// ReadAlias routine, which is called by RtlQueryRegistryValues.
+//
+
+typedef struct _ALIAS_CONTEXT {
+ BOOLEAN Phase1;
+ ULONG RequiredSize;
+ ULONG AliasCount;
+ ULONG TranslationCount;
+ PALIAS NextAlias;
+ PUNICODE_STRING NextTranslation;
+ PWCH NextStringData;
+} ALIAS_CONTEXT, *PALIAS_CONTEXT;
+
+//
+// Forward declarations.
+//
+
+NTSTATUS
+ReadAlias (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NpInitializeAliases)
+#pragma alloc_text(INIT,ReadAlias)
+#pragma alloc_text(PAGE, NpTranslateAlias)
+#endif
+
+
+NTSTATUS
+NpInitializeAliases (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the alias package. It reads the registry,
+ builds the alias list, and sorts it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NTSTATUS - Returns an error if the contents of the registry contents
+ are invalid or if an allocation fails.
+
+--*/
+
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ ALIAS_CONTEXT Context;
+ NTSTATUS Status;
+ PALIAS Alias;
+ ULONG i;
+ ULONG Length;
+ PSINGLE_LIST_ENTRY PreviousEntry;
+ PSINGLE_LIST_ENTRY Entry;
+ PALIAS TestAlias;
+
+ //
+ // Phase 1: Calculate number of aliases and size of alias buffer.
+ //
+
+ QueryTable[0].QueryRoutine = ReadAlias;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[0].Name = NULL;
+ QueryTable[0].EntryContext = NULL;
+ QueryTable[0].DefaultType = REG_NONE;
+ QueryTable[0].DefaultData = NULL;
+ QueryTable[0].DefaultLength = 0;
+
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+
+ Context.Phase1 = TRUE;
+ Context.RequiredSize = 0;
+ Context.AliasCount = 0;
+ Context.TranslationCount = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
+ ALIAS_PATH,
+ QueryTable,
+ &Context,
+ NULL
+ );
+
+ //
+ // If an error occurred, return that error, unless the alias
+ // key wasn't present, which is not an error. Also, if the key
+ // was there, but was empty, this is not an error.
+ //
+
+ if (!NT_SUCCESS(Status)) {
+ if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
+ Status = STATUS_SUCCESS;
+ }
+ return Status;
+ }
+
+ if (Context.RequiredSize == 0) {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Allocate a buffer to hold the alias information.
+ //
+
+ NpAliases = ExAllocatePoolWithTag( NonPagedPool,
+ Context.RequiredSize,
+ 'sfpN'
+ );
+ if (NpAliases == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Phase 2: Read alias information into the alias buffer.
+ //
+
+ Context.Phase1 = FALSE;
+ Context.NextTranslation = (PUNICODE_STRING)NpAliases;
+ Alias = Context.NextAlias =
+ (PALIAS)(Context.NextTranslation + Context.TranslationCount);
+ Context.NextStringData = (PWCH)(Context.NextAlias + Context.AliasCount);
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
+ ALIAS_PATH,
+ QueryTable,
+ &Context,
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+ ExFreePool( NpAliases );
+ NpAliases = NULL;
+ return Status;
+ }
+
+ //
+ // Phase 3: Link aliases into alias lists.
+ //
+
+ for ( i = 0;
+ i < Context.AliasCount;
+ i++, Alias++ ) {
+
+ //
+ // Point to the appropriate list head.
+ //
+
+ Length = Alias->AliasString.Length;
+ if ( (Length >= MIN_LENGTH_ALIAS_ARRAY) &&
+ (Length <= MAX_LENGTH_ALIAS_ARRAY) ) {
+ PreviousEntry = &NpAliasListByLength[(Length - MIN_LENGTH_ALIAS_ARRAY) / sizeof(WCHAR)];
+ } else {
+ PreviousEntry = &NpAliasList;
+ }
+
+ //
+ // Walk the list to determine the proper place for this alias.
+ //
+
+ for ( Entry = PreviousEntry->Next;
+ Entry != NULL;
+ PreviousEntry = Entry, Entry = Entry->Next ) {
+
+ TestAlias = CONTAINING_RECORD( Entry, ALIAS, ListEntry );
+
+ //
+ // If the test alias is longer than the new alias, we want to
+ // insert the new alias in front of the test alias. If the
+ // test alias is shorter, we need to continue walking the list.
+ //
+
+ if ( TestAlias->AliasString.Length > Length ) break;
+ if ( TestAlias->AliasString.Length < Length ) continue;
+
+ //
+ // The aliases are the same length. Compare them. If the new
+ // alias is lexically before the test alias, we want to insert
+ // it in front of the test alias. If it's after, we need to
+ // keep walking.
+ //
+ // Alias and TestAlias should never have the same string, but
+ // if they do, we'll insert the second occurrence of the string
+ // immediately after the first one, and all will be well.
+ //
+
+ if ( _wcsicmp( Alias->AliasString.Buffer,
+ TestAlias->AliasString.Buffer ) < 0 ) {
+ break;
+ }
+
+ }
+
+ //
+ // We have found the place where this alias belongs. PreviousEntry
+ // points to the alias that the new alias should follow.
+ // (PreviousEntry may point to the list head.)
+ //
+
+ Alias->ListEntry.Next = PreviousEntry->Next;
+ PreviousEntry->Next = &Alias->ListEntry;
+
+ }
+
+#if 0
+ for ( Length = MIN_LENGTH_ALIAS_ARRAY;
+ Length <= MAX_LENGTH_ALIAS_ARRAY + 2;
+ Length += 2 ) {
+ if ( (Length >= MIN_LENGTH_ALIAS_ARRAY) &&
+ (Length <= MAX_LENGTH_ALIAS_ARRAY) ) {
+ PreviousEntry = &NpAliasListByLength[(Length - MIN_LENGTH_ALIAS_ARRAY) / sizeof(WCHAR)];
+ DbgPrint( "Length %d list:\n", Length );
+ } else {
+ PreviousEntry = &NpAliasList;
+ DbgPrint( "Odd length list:\n" );
+ }
+ for ( Entry = PreviousEntry->Next;
+ Entry != NULL;
+ Entry = Entry->Next ) {
+ Alias = CONTAINING_RECORD( Entry, ALIAS, ListEntry );
+ DbgPrint( " %wZ -> %wZ\n", &Alias->AliasString, Alias->TranslationString );
+ }
+ }
+#endif
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+ReadAlias (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+ PALIAS_CONTEXT Ctx = Context;
+ USHORT Length;
+ PWCH p;
+ PUNICODE_STRING TranslationString;
+ PALIAS Alias;
+
+ //
+ // The value must be a REG_MULTI_SZ value.
+ //
+
+ if (ValueType != REG_MULTI_SZ) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // In phase 1, we calculate the required size of the alias buffer.
+ // In phase 2, we build the alias descriptors.
+ //
+
+ if ( Ctx->Phase1 ) {
+
+ //
+ // The value name is the translation. The value data is one or
+ // more strings that are aliases for the translation.
+ //
+ // The "1+" and "sizeof(WCHAR)+" are for the '\' that will be
+ // placed in front of the translation string and the alias string.
+ //
+
+ Ctx->TranslationCount++;
+ Length = (USHORT)((1 + wcslen(ValueName) + 1) * sizeof(WCHAR));
+ Ctx->RequiredSize += Length + sizeof(UNICODE_STRING);
+
+ p = ValueData;
+ while ( *p != 0 ) {
+ Ctx->AliasCount++;
+ Length = (USHORT)((wcslen(p) + 1) * sizeof(WCHAR));
+ Ctx->RequiredSize += sizeof(WCHAR) + Length + sizeof(ALIAS);
+ p = (PWCH)((PCHAR)p + Length);
+ }
+
+ } else {
+
+ //
+ // Build a string descriptor for the translation string.
+ //
+
+ TranslationString = Ctx->NextTranslation++;
+ Length = (USHORT)((1 + wcslen(ValueName) + 1) * sizeof(WCHAR));
+ TranslationString->Length = Length - sizeof(WCHAR);
+ TranslationString->MaximumLength = Length;
+ TranslationString->Buffer = Ctx->NextStringData;
+ Ctx->NextStringData = (PWCH)((PCHAR)Ctx->NextStringData + Length);
+
+ //
+ // Copy the string data. Place a '\' at the beginning.
+ //
+
+ TranslationString->Buffer[0] = L'\\';
+ RtlCopyMemory( &TranslationString->Buffer[1],
+ ValueName,
+ Length - sizeof(WCHAR) );
+
+ //
+ // Build aliases descriptors.
+ //
+
+ p = ValueData;
+
+ while ( *p != 0 ) {
+
+ Alias = Ctx->NextAlias++;
+
+ //
+ // Point the alias descriptor to the translation string.
+ //
+
+ Alias->TranslationString = TranslationString;
+
+ //
+ // Build the alias string descriptor.
+ //
+
+ Length = (USHORT)((1 + wcslen(p) + 1) * sizeof(WCHAR));
+ Alias->AliasString.Length = Length - sizeof(WCHAR);
+ Alias->AliasString.MaximumLength = Length;
+ Alias->AliasString.Buffer = Ctx->NextStringData;
+ Ctx->NextStringData = (PWCH)((PCHAR)Ctx->NextStringData + Length);
+
+ //
+ // Copy the string data. Place a '\' at the beginning.
+ //
+
+ Alias->AliasString.Buffer[0] = L'\\';
+ RtlCopyMemory( &Alias->AliasString.Buffer[1],
+ p,
+ Length - sizeof(WCHAR) );
+
+ //
+ // Upcase the string.
+ //
+
+ RtlUpcaseUnicodeString( &Alias->AliasString,
+ &Alias->AliasString,
+ FALSE );
+
+ p = (PWCH)((PCHAR)p + Length - sizeof(WCHAR));
+
+ }
+
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+NpTranslateAlias (
+ IN OUT PUNICODE_STRING String
+ )
+
+/*++
+
+Routine Description:
+
+ This routine translates a pipe name string based on information
+ obtained from the registry at boot time. This translation is used
+ to allow RPC services that had different names in NT 1.0 to have
+ common names in 1.0a and beyond.
+
+Arguments:
+
+ String - Supplies the input string to search for; returns the output
+ string, if the name was translated. If so, the string points to
+ a buffer allocated from paged pool. The caller should NOT free
+ this buffer.
+
+Return Value:
+
+ NTSTATUS - Returns STATUS_SUCCESS unless an allocation failure occurs.
+ The status does NOT indicate whether the name was translated.
+
+--*/
+
+{
+ NTSTATUS Status;
+ UNICODE_STRING UpcaseString;
+ ULONG Length;
+ PSINGLE_LIST_ENTRY Entry;
+ PALIAS Alias;
+ PWCH sp, ap;
+ WCHAR a, s;
+ BOOLEAN NoSlash;
+
+ WCHAR UpcaseBuffer[MAX_LENGTH_ALIAS_ARRAY];
+ BOOLEAN FreeUpcaseBuffer;
+
+ PAGED_CODE();
+
+ //
+ // Before upcasing the string (a relatively expensive operation),
+ // make sure that the string length matches at least one alias.
+ //
+
+ Length = String->Length;
+ if ( Length == 0 ) {
+ return STATUS_SUCCESS;
+ }
+
+ if ( *String->Buffer != L'\\' ) {
+ Length += sizeof(WCHAR);
+ NoSlash = TRUE;
+ } else {
+ NoSlash = FALSE;
+ }
+
+ if ( (Length >= MIN_LENGTH_ALIAS_ARRAY) &&
+ (Length <= MAX_LENGTH_ALIAS_ARRAY) ) {
+ Entry = NpAliasListByLength[(Length - MIN_LENGTH_ALIAS_ARRAY) / sizeof(WCHAR)].Next;
+ Alias = CONTAINING_RECORD( Entry, ALIAS, ListEntry );
+ } else {
+ Entry = NpAliasList.Next;
+ while ( Entry != NULL ) {
+ Alias = CONTAINING_RECORD( Entry, ALIAS, ListEntry );
+ if ( Alias->AliasString.Length == Length ) {
+ break;
+ }
+ if ( Alias->AliasString.Length > Length ) {
+ return STATUS_SUCCESS;
+ }
+ Entry = Entry->Next;
+ }
+ }
+
+ if ( Entry == NULL ) {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // The string's length matches at least one alias. Upcase the string.
+ //
+
+ if ( Length <= MAX_LENGTH_ALIAS_ARRAY ) {
+ UpcaseString.MaximumLength = MAX_LENGTH_ALIAS_ARRAY;
+ UpcaseString.Buffer = UpcaseBuffer;
+ Status = RtlUpcaseUnicodeString( &UpcaseString, String, FALSE );
+ ASSERT( NT_SUCCESS(Status) );
+ FreeUpcaseBuffer = FALSE;
+ } else {
+ Status = RtlUpcaseUnicodeString( &UpcaseString, String, TRUE );
+ if ( !NT_SUCCESS(Status) ) {
+ return Status;
+ }
+ FreeUpcaseBuffer = TRUE;
+ }
+
+ ASSERT( UpcaseString.Length == (Length - (NoSlash ? sizeof(WCHAR) : 0)) );
+
+ //
+ // At this point, Entry points to an alias list entry whose length
+ // matches that of the input string. This list entry may be the
+ // first element of a length-specific list (in which all entries
+ // have the same length), or it may be an element of a length-ordered
+ // list (in which case we'll need to check each next entry to see if
+ // it's the same length. In both cases, strings of the same length
+ // are in lexical order.
+ //
+ // Try to match the upcased string up to an alias.
+ //
+
+ do {
+
+ sp = UpcaseString.Buffer;
+ ap = Alias->AliasString.Buffer;
+ if ( NoSlash ) {
+ ap++;
+ }
+
+ while ( TRUE ) {
+ a = *ap;
+ if ( a == 0 ) {
+ *String = *Alias->TranslationString;
+ if ( NoSlash ) {
+ String->Length -= sizeof(WCHAR);
+ String->Buffer++;
+ }
+ goto exit;
+ }
+ s = *sp;
+ if ( s < a ) goto exit;
+ if ( s > a ) break;
+ sp++;
+ ap++;
+ }
+
+ //
+ // The input string doesn't match the current alias. Move to
+ // the next one.
+ //
+
+ Entry = Entry->Next;
+ if ( Entry == NULL ) {
+ goto exit;
+ }
+
+ Alias = CONTAINING_RECORD( Entry, ALIAS, ListEntry );
+
+ } while ( Alias->AliasString.Length == Length );
+
+exit:
+
+ if (FreeUpcaseBuffer) {
+ ASSERT( UpcaseString.Buffer != UpcaseBuffer );
+ ExFreePool( UpcaseString.Buffer );
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
diff --git a/private/ntos/npfs/cleanup.c b/private/ntos/npfs/cleanup.c
new file mode 100644
index 000000000..f666b335a
--- /dev/null
+++ b/private/ntos/npfs/cleanup.c
@@ -0,0 +1,229 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Cleanup.c
+
+Abstract:
+
+ This module implements the File Cleanup routine for NPFS called by the
+ dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_CLEANUP)
+
+//
+// local procedure prototypes
+//
+
+NTSTATUS
+NpCommonCleanup (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonCleanup)
+#pragma alloc_text(PAGE, NpFsdCleanup)
+#endif
+
+
+NTSTATUS
+NpFsdCleanup (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtCleanupFile API calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdCleanup\n", 0);
+
+ //
+ // Call the common Cleanup routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ try {
+
+ Status = NpCommonCleanup( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdCleanup -> %08lx\n", Status );
+
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonCleanup (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for cleanup
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PIO_STACK_LOCATION IrpSp;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonCleanup...\n", 0);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+
+ //
+ // Now acquire exclusive access to the Vcb
+ //
+
+ NpAcquireExclusiveVcb();
+
+ try {
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is null then the pipe has been disconnected.
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ try_return( Status = STATUS_PIPE_DISCONNECTED );
+ }
+
+ //
+ // Now case on the type of file object we're closing
+ //
+
+ switch (NodeTypeCode) {
+
+ case NPFS_NTC_VCB:
+ case NPFS_NTC_ROOT_DCB:
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ case NPFS_NTC_CCB:
+
+ //
+ // If this is the server end of a pipe, decrement the count
+ // of the number of instances the server end has open.
+ // When this count is 0, attempts to connect to the pipe
+ // return OBJECT_NAME_NOT_FOUND instead of
+ // PIPE_NOT_AVAILABLE.
+ //
+
+ if ( NamedPipeEnd == FILE_PIPE_SERVER_END ) {
+ ASSERT( Ccb->Fcb->ServerOpenCount != 0 );
+ Ccb->Fcb->ServerOpenCount -= 1;
+ }
+
+ //
+ // The set closing state routines does everything to transition
+ // the named pipe to a closing state.
+ //
+
+ Status = NpSetClosingPipeState( Ccb, Irp, NamedPipeEnd );
+
+ break;
+ }
+
+ try_exit: NOTHING;
+ } finally {
+
+ NpReleaseVcb( );
+ }
+
+ DebugTrace(-1, Dbg, "NpCommonCleanup -> %08lx\n", Status);
+ return Status;
+}
+
diff --git a/private/ntos/npfs/close.c b/private/ntos/npfs/close.c
new file mode 100644
index 000000000..8b169d3b5
--- /dev/null
+++ b/private/ntos/npfs/close.c
@@ -0,0 +1,236 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Close.c
+
+Abstract:
+
+ This module implements the File Close routine for NPFS called by the
+ dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_CLOSE)
+
+//
+// local procedure prototypes
+//
+
+NTSTATUS
+NpCommonClose (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonClose)
+#pragma alloc_text(PAGE, NpFsdClose)
+#endif
+
+
+NTSTATUS
+NpFsdClose (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtCloseFile API calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdClose\n", 0);
+
+ //
+ // Call the common Close routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ try {
+
+ Status = NpCommonClose( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdClose -> %08lx\n", Status );
+
+ return Status;
+}
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonClose (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for creating/opening a file.
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PIO_STACK_LOCATION IrpSp;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PFCB Fcb;
+ PCCB Ccb;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonClose...\n", 0);
+ DebugTrace( 0, Dbg, " Irp = %08lx\n", Irp);
+
+ //
+ // Now acquire exclusive access to the vcb
+ //
+
+ NpAcquireExclusiveVcb();
+
+ try {
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is null then the pipe has been disconnected.
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ &Fcb,
+ &Ccb,
+ NULL )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ try_return( Status = STATUS_PIPE_DISCONNECTED );
+ }
+
+ //
+ // Now case on the type of file object we're closing
+ //
+
+ switch (NodeTypeCode) {
+
+ case NPFS_NTC_VCB:
+
+ //
+ // Decrement the Open count and clear our fields in the file object
+ //
+
+ NpVcb->OpenCount -= 1;
+ NpSetFileObject( IrpSp->FileObject, NULL, NULL, FILE_PIPE_SERVER_END );
+
+ break;
+
+ case NPFS_NTC_ROOT_DCB:
+
+ //
+ // Decrement the Open count and clear our fields in the file object
+ //
+
+ Fcb->OpenCount -= 1;
+ NpSetFileObject( IrpSp->FileObject, NULL, NULL, FILE_PIPE_SERVER_END );
+
+ //
+ // Remove the root dcb ccb.
+ //
+
+ NpDeleteCcb( Ccb );
+
+ break;
+
+ case NPFS_NTC_CCB:
+
+ break;
+ }
+
+ //
+ // Complete the close irp
+ //
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+
+ Status = STATUS_SUCCESS;
+
+ try_exit: NOTHING;
+ } finally {
+
+ NpReleaseVcb( );
+ }
+
+ DebugTrace(-1, Dbg, "NpCommonClose -> %08lx\n", Status);
+ return Status;
+}
+
diff --git a/private/ntos/npfs/create.c b/private/ntos/npfs/create.c
new file mode 100644
index 000000000..ea1146051
--- /dev/null
+++ b/private/ntos/npfs/create.c
@@ -0,0 +1,794 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Create.c
+
+Abstract:
+
+ This module implements the File Create routine for NPFS called by the
+ dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_CREATE)
+
+//
+// local procedure prototypes
+//
+
+NTSTATUS
+NpCommonCreate (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+IO_STATUS_BLOCK
+NpCreateClientEnd(
+ IN PFCB Fcb,
+ IN PFILE_OBJECT FileObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess,
+ IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
+ IN PACCESS_STATE AccessState,
+ IN KPROCESSOR_MODE RequestorMode,
+ IN PETHREAD UserThread
+ );
+
+IO_STATUS_BLOCK
+NpOpenNamedPipeFileSystem (
+ IN PFILE_OBJECT FileObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess
+ );
+
+IO_STATUS_BLOCK
+NpOpenNamedPipeRootDirectory (
+ IN PROOT_DCB RootDcb,
+ IN PFILE_OBJECT FileObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonCreate)
+#pragma alloc_text(PAGE, NpFsdCreate)
+#pragma alloc_text(PAGE, NpOpenNamedPipeFileSystem)
+#pragma alloc_text(PAGE, NpOpenNamedPipeRootDirectory)
+#endif
+
+
+NTSTATUS
+NpFsdCreate (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtCreateFile and NtOpenFile
+ API calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdCreate\n", 0);
+
+ //
+ // Call the common create routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ try {
+
+ Status = NpCommonCreate( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdCreate -> %08lx\n", Status );
+
+ return Status;
+}
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonCreate (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for creating/opening a file.
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ PFILE_OBJECT FileObject;
+ PFILE_OBJECT RelatedFileObject;
+ UNICODE_STRING FileName;
+ ACCESS_MASK DesiredAccess;
+ USHORT ShareAccess;
+
+ BOOLEAN CaseInsensitive = TRUE; //**** Make all searches case insensitive
+
+ PFCB Fcb;
+
+ UNICODE_STRING RemainingPart;
+
+ PAGED_CODE();
+
+ //
+ // Reference our input parameters to make things easier
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+ FileObject = IrpSp->FileObject;
+ RelatedFileObject = IrpSp->FileObject->RelatedFileObject;
+ FileName = *(PUNICODE_STRING)&IrpSp->FileObject->FileName;
+ DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
+ ShareAccess = IrpSp->Parameters.Create.ShareAccess;
+
+ DebugTrace(+1, Dbg, "NpCommonCreate\n", 0 );
+ DebugTrace( 0, Dbg, "NpfsDeviceObject = %08xl\n", NpfsDeviceObject );
+ DebugTrace( 0, Dbg, "Irp = %08xl\n", Irp );
+ DebugTrace( 0, Dbg, "FileObject = %08xl\n", FileObject );
+ DebugTrace( 0, Dbg, "RelatedFileObject = %08xl\n", RelatedFileObject );
+ DebugTrace( 0, Dbg, "FileName = %Z\n", &FileName );
+ DebugTrace( 0, Dbg, "DesiredAccess = %08xl\n", DesiredAccess );
+ DebugTrace( 0, Dbg, "ShareAccess = %08xl\n", ShareAccess );
+
+ //
+ // Acquire exclusive access to the Vcb
+ //
+
+ NpAcquireExclusiveVcb();
+
+ try {
+
+ //
+ // Check if we are trying to open the named pipe file system
+ // (i.e., the Vcb).
+ //
+
+ if ((FileName.Length == 0) &&
+ ((RelatedFileObject == NULL) || (NodeType(RelatedFileObject->FsContext) == NPFS_NTC_VCB))) {
+
+ DebugTrace(0, Dbg, "Open name pipe file system\n", 0);
+
+ Irp->IoStatus = NpOpenNamedPipeFileSystem( FileObject,
+ DesiredAccess,
+ ShareAccess );
+
+ Status = Irp->IoStatus.Status;
+ NpCompleteRequest( Irp, Status );
+ try_return( NOTHING );
+ }
+
+ //
+ // Check if we are trying to open the root directory
+ //
+
+ if (((FileName.Length == 2) && (FileName.Buffer[0] == L'\\') && (RelatedFileObject == NULL))
+
+ ||
+
+ ((FileName.Length == 0) && (NodeType(RelatedFileObject->FsContext) == NPFS_NTC_ROOT_DCB))) {
+
+ DebugTrace(0, Dbg, "Open root directory system\n", 0);
+
+ Irp->IoStatus = NpOpenNamedPipeRootDirectory( NpVcb->RootDcb,
+ FileObject,
+ DesiredAccess,
+ ShareAccess );
+
+ Status = Irp->IoStatus.Status;
+ NpCompleteRequest( Irp, Status );
+ try_return( NOTHING );
+ }
+
+ //
+ // If the name is an alias, translate it.
+ //
+
+ Status = NpTranslateAlias( &FileName );
+ if ( !NT_SUCCESS(Status) ) {
+ NpCompleteRequest( Irp, Status );
+ try_return( NOTHING );
+ }
+
+ //
+ // If there is a related file object then this is a relative open
+ // and it better be the root dcb. Both the then and the else clause
+ // return an Fcb.
+ //
+
+ if (RelatedFileObject != NULL) {
+
+ PDCB Dcb;
+
+ Dcb = RelatedFileObject->FsContext;
+
+ if (NodeType(Dcb) != NPFS_NTC_ROOT_DCB) {
+
+ DebugTrace(0, Dbg, "Bad file name\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_OBJECT_NAME_INVALID );
+ try_return( Status = STATUS_OBJECT_NAME_INVALID );
+ }
+
+ Fcb = NpFindRelativePrefix( Dcb, &FileName, CaseInsensitive, &RemainingPart );
+
+ } else {
+
+ //
+ // The only nonrelative name we allow are of the form "\pipe-name"
+ //
+
+ if ((FileName.Length <= 2) || (FileName.Buffer[0] != L'\\')) {
+
+ DebugTrace(0, Dbg, "Bad file name\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_OBJECT_NAME_INVALID );
+ try_return( Status = STATUS_OBJECT_NAME_INVALID );
+ }
+
+ Fcb = NpFindPrefix( &FileName, CaseInsensitive, &RemainingPart );
+ }
+
+ //
+ // If the remaining name is not empty then we have an error, either
+ // we have an illegal name or a non-existent name.
+ //
+
+ if (RemainingPart.Length != 0) {
+
+ if (Fcb->NodeTypeCode == NPFS_NTC_FCB) {
+
+ //
+ // We were given a name such as "\pipe-name\another-name"
+ //
+
+ DebugTrace(0, Dbg, "Illegal object name\n", 0);
+
+ Status = STATUS_OBJECT_NAME_INVALID;
+
+ } else {
+
+ //
+ // We were given a non-existent name
+ //
+
+ DebugTrace(0, Dbg, "non-existent name\n", 0);
+
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ } else {
+
+ //
+ // The remaining name is empty so we better have an Fcb otherwise
+ // we have an invalid object name.
+ //
+
+ if (Fcb->NodeTypeCode == NPFS_NTC_FCB) {
+
+ DebugTrace(0, Dbg, "Create client end named pipe, Fcb = %08lx\n", Fcb );
+
+ //
+ // If the server has no handles open, then pretend that
+ // the pipe name doesn't exist.
+ //
+
+ if ( Fcb->ServerOpenCount == 0 ) {
+
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+
+ } else {
+
+ Irp->IoStatus = NpCreateClientEnd( Fcb,
+ FileObject,
+ DesiredAccess,
+ ShareAccess,
+ IrpSp->Parameters.Create.SecurityContext->SecurityQos,
+ IrpSp->Parameters.Create.SecurityContext->AccessState,
+ (KPROCESSOR_MODE)(FlagOn(IrpSp->Flags, SL_FORCE_ACCESS_CHECK) ?
+ UserMode : Irp->RequestorMode),
+ Irp->Tail.Overlay.Thread );
+ Status = Irp->IoStatus.Status;
+ }
+
+ } else {
+
+ DebugTrace(0, Dbg, "Illegal object name\n", 0);
+
+ Status = STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ //
+ // Complete the IRP and return to our caller
+ //
+
+ NpCompleteRequest( Irp, Status );
+
+ try_exit: NOTHING;
+ } finally {
+
+ NpReleaseVcb( );
+
+ DebugTrace(-1, Dbg, "NpCommonCreate -> %08lx\n", Status);
+ }
+
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+IO_STATUS_BLOCK
+NpCreateClientEnd (
+ IN PFCB Fcb,
+ IN PFILE_OBJECT FileObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess,
+ IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
+ IN PACCESS_STATE AccessState,
+ IN KPROCESSOR_MODE RequestorMode,
+ IN PETHREAD UserThread
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the operation for opening the client end of a named
+ pipe. This routine does not complete the IRP, it performs the function
+ and then returns a status
+
+Arguments:
+
+ Fcb - Supplies the Fcb for the named pipe being accessed
+
+ FileObject - Supplies the file object associated with the client end
+
+ DesiredAccess - Supplies the callers desired access
+
+ ShareAccess - Supplies the callers share access
+
+ SecurityQos - Supplies the security qos parameter from the create irp
+
+ AccessState - Supplies the access state parameter from the create irp
+
+ RequestorMode - Supplies the mode of the originating irp
+
+ UserTherad - Supplies the client end user thread
+
+Return Value:
+
+ IO_STATUS_BLOCK - Returns the appropriate status for the operation
+
+--*/
+
+{
+ IO_STATUS_BLOCK Iosb;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ BOOLEAN AccessGranted;
+ ACCESS_MASK GrantedAccess;
+ UNICODE_STRING Name;
+
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ PLIST_ENTRY Links;
+ PPRIVILEGE_SET Privileges = NULL;
+
+ DebugTrace(+1, Dbg, "NpCreateClientEnd\n", 0 );
+
+ NamedPipeConfiguration = Fcb->Specific.Fcb.NamedPipeConfiguration;
+
+ try {
+
+ //
+ // First do an access check for the user against the Fcb
+ //
+
+ SeLockSubjectContext( &AccessState->SubjectSecurityContext );
+
+ AccessGranted = SeAccessCheck( Fcb->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ TRUE, // Tokens are locked
+ DesiredAccess,
+ 0,
+ &Privileges,
+ IoGetFileObjectGenericMapping(),
+ RequestorMode,
+ &GrantedAccess,
+ &Iosb.Status
+ );
+
+ if (Privileges != NULL) {
+
+ (VOID) SeAppendPrivileges(
+ AccessState,
+ Privileges
+ );
+
+ SeFreePrivileges( Privileges );
+ }
+
+ if (AccessGranted) {
+ AccessState->PreviouslyGrantedAccess |= GrantedAccess;
+ AccessState->RemainingDesiredAccess &= ~GrantedAccess;
+ }
+
+ RtlInitUnicodeString( &Name, L"NamedPipe" );
+
+ SeOpenObjectAuditAlarm( &Name,
+ NULL,
+ &FileObject->FileName,
+ Fcb->SecurityDescriptor,
+ AccessState,
+ FALSE,
+ AccessGranted,
+ RequestorMode,
+ &AccessState->GenerateOnClose );
+
+ SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
+
+ if (!AccessGranted) {
+
+ DebugTrace(0, Dbg, "Access Denied\n", 0 );
+
+ try_return( Iosb.Status );
+ }
+
+ //
+ // Check if the user wants to write to an outbound pipe or read from
+ // and inbound pipe. And if so then tell the user the error
+ //
+
+ if ((FlagOn(DesiredAccess, FILE_READ_DATA) && (NamedPipeConfiguration == FILE_PIPE_INBOUND)) ||
+ (FlagOn(DesiredAccess, FILE_WRITE_DATA) && (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))) {
+
+ Iosb.Status = STATUS_ACCESS_DENIED;
+
+ try_return( Iosb.Status );
+ }
+
+ //
+ // First try and find a ccb that is in the listening state. If we
+ // exit the loop with Ccb not equal to null then we've found one.
+ //
+
+ Ccb = NULL;
+ for (Links = Fcb->Specific.Fcb.CcbQueue.Flink;
+ Links != &Fcb->Specific.Fcb.CcbQueue;
+ Links = Links->Flink) {
+
+ Ccb = CONTAINING_RECORD( Links, CCB, CcbLinks );
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) {
+
+ DebugTrace(0, Dbg, "Located listening ccb = %08lx\n", Ccb);
+
+ break;
+ }
+
+ Ccb = NULL;
+ }
+
+ //
+ // Check that we found one
+ //
+
+ if (Ccb == NULL) {
+
+ try_return( Iosb.Status = STATUS_PIPE_NOT_AVAILABLE );
+ }
+
+ //
+ // Now make sure our share access is okay. If the user is asking
+ // for read data then given him shared read, if he's asking for
+ // write data then given him shared write.
+ //
+
+ if (NamedPipeConfiguration == FILE_PIPE_OUTBOUND) {
+
+ ShareAccess = FILE_SHARE_READ;
+
+ } else if (NamedPipeConfiguration == FILE_PIPE_INBOUND) {
+
+ ShareAccess = FILE_SHARE_WRITE;
+
+ } else {
+
+ ShareAccess = (FILE_SHARE_READ | FILE_SHARE_WRITE);
+ }
+
+ if (FlagOn(DesiredAccess, FILE_READ_DATA )) { ShareAccess |= FILE_SHARE_READ; }
+ if (FlagOn(DesiredAccess, FILE_WRITE_DATA)) { ShareAccess |= FILE_SHARE_WRITE; }
+
+ //if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( DesiredAccess,
+ // ShareAccess,
+ // FileObject,
+ // &Ccb->ShareAccess,
+ // TRUE ))) {
+ //
+ // DebugTrace(0, Dbg, "Sharing violation\n", 0);
+ //
+ // try_return( NOTHING );
+ //}
+
+ //
+ // Set up the security part of the ccb
+ //
+
+ if (!NT_SUCCESS(Iosb.Status = NpInitializeSecurity( Ccb,
+ SecurityQos,
+ UserThread ))) {
+
+ DebugTrace(0, Dbg, "Security QOS error\n", 0);
+
+ try_return( NOTHING );
+ }
+
+ //
+ // Set the pipe into the connect state, the read mode to byte stream,
+ // and the completion mode to queued operation. This also
+ // sets the client file object's back pointer to the ccb
+ //
+
+ if (!NT_SUCCESS(Iosb.Status = NpSetConnectedPipeState( Ccb,
+ FileObject ))) {
+
+ try_return( NOTHING );
+ }
+
+ //
+ // Now check to see if there are any waiting listening IRPs
+ // that need to be completed now
+ //
+
+ while (!IsListEmpty( &NonpagedCcb->ListeningQueue )) {
+ PIRP Irp;
+
+ Links = RemoveHeadList( &NonpagedCcb->ListeningQueue );
+
+ Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ IoSetCancelRoutine( Irp, NULL );
+ Irp->IoStatus.Information = 0;
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ NpCompleteRequest( Irp, STATUS_PIPE_CONNECTED );
+ }
+
+ //
+ // Set up the client session and process IDs. NULL for the
+ // client session indicates a local session.
+ //
+
+ Ccb->ClientSession = NULL;
+// Ccb->ClientProcess = THREAD_TO_PROCESS( UserThread );
+ Ccb->ClientProcess = IoThreadToProcess( UserThread );
+
+ //
+ // And set our return status
+ //
+
+ Iosb.Status = STATUS_SUCCESS;
+ Iosb.Information = FILE_OPENED;
+
+ try_exit: NOTHING;
+ } finally {
+
+ DebugTrace(-1, Dbg, "NpCreateClientEnd -> %08lx\n", Iosb.Status);
+ }
+
+ return Iosb;
+}
+
+
+//
+// Internal support routine
+//
+
+IO_STATUS_BLOCK
+NpOpenNamedPipeFileSystem (
+ IN PFILE_OBJECT FileObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess
+ )
+
+{
+ IO_STATUS_BLOCK Iosb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpOpenNamedPipeFileSystem, Vcb = %08lx\n", NpVcb);
+
+ try {
+
+ //
+ // Set the new share access
+ //
+
+ if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( DesiredAccess,
+ ShareAccess,
+ FileObject,
+ &NpVcb->ShareAccess,
+ TRUE ))) {
+
+ DebugTrace(0, Dbg, "bad share access\n", 0);
+
+ try_return( NOTHING );
+ }
+
+ //
+ // Have the file object point back to the Vcb, and increment the
+ // open count. The pipe end on the call to set file object really
+ // doesn't matter.
+ //
+
+ NpSetFileObject( FileObject, NpVcb, NULL, FILE_PIPE_CLIENT_END );
+
+ NpVcb->OpenCount += 1;
+
+ //
+ // Set our return status
+ //
+
+ Iosb.Status = STATUS_SUCCESS;
+ Iosb.Information = FILE_OPENED;
+
+ try_exit: NOTHING;
+ } finally {
+
+ DebugTrace(-1, Dbg, "NpOpenNamedPipeFileSystem -> Iosb.Status = %08lx\n", Iosb.Status);
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return Iosb;
+}
+
+
+//
+// Internal support routine
+//
+
+IO_STATUS_BLOCK
+NpOpenNamedPipeRootDirectory(
+ IN PROOT_DCB RootDcb,
+ IN PFILE_OBJECT FileObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN USHORT ShareAccess
+ )
+
+{
+ IO_STATUS_BLOCK Iosb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpOpenNamedPipeRootDirectory, RootDcb = %08lx\n", RootDcb);
+
+ try {
+
+ //
+ // Set the new share access
+ //
+
+ if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( DesiredAccess,
+ ShareAccess,
+ FileObject,
+ &RootDcb->Specific.Dcb.ShareAccess,
+ TRUE ))) {
+
+ DebugTrace(0, Dbg, "bad share access\n", 0);
+
+ try_return( NOTHING );
+ }
+
+ //
+ // Have the file object point back to the Dcb, and reference the root
+ // dcb, ccb, and increment our open count. The pipe end on the
+ // call to set file object really doesn't matter.
+ //
+
+ NpSetFileObject( FileObject,
+ RootDcb,
+ NpCreateRootDcbCcb(),
+ FILE_PIPE_CLIENT_END );
+
+ RootDcb->OpenCount += 1;
+
+ //
+ // Set our return status
+ //
+
+ Iosb.Status = STATUS_SUCCESS;
+ Iosb.Information = FILE_OPENED;
+
+ try_exit: NOTHING;
+ } finally {
+
+ DebugTrace(-1, Dbg, "NpOpenNamedPipeRootDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return Iosb;
+}
diff --git a/private/ntos/npfs/createnp.c b/private/ntos/npfs/createnp.c
new file mode 100644
index 000000000..20332a1b7
--- /dev/null
+++ b/private/ntos/npfs/createnp.c
@@ -0,0 +1,895 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ CreateNp.c
+
+Abstract:
+
+ This module implements the File Create Named Pipe routine for NPFS called
+ by the dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 04-Sep-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_CREATE_NAMED_PIPE)
+
+//
+// local procedure prototypes
+//
+
+NTSTATUS
+NpCommonCreateNamedPipe (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+IO_STATUS_BLOCK
+NpCreateNewNamedPipe (
+ IN PROOT_DCB RootDcb,
+ IN PFILE_OBJECT FileObject,
+ IN UNICODE_STRING FileName,
+ IN ACCESS_MASK DesiredAccess,
+ IN PACCESS_STATE AccessState,
+ IN ULONG CreateDisposition,
+ IN USHORT ShareAccess,
+ IN NAMED_PIPE_TYPE NamedPipeType,
+ IN READ_MODE ServerReadMode,
+ IN COMPLETION_MODE ServerCompletionMode,
+ IN ULONG MaximumInstances,
+ IN ULONG InboundQuota,
+ IN ULONG OutboundQuota,
+ IN LARGE_INTEGER DefaultTimeout,
+ IN BOOLEAN TimeoutSpecified,
+ IN PEPROCESS CreatorProcess
+ );
+
+IO_STATUS_BLOCK
+NpCreateExistingNamedPipe (
+ IN PFCB Fcb,
+ IN PFILE_OBJECT FileObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN PACCESS_STATE AccessState,
+ IN KPROCESSOR_MODE RequestorMode,
+ IN ULONG CreateDisposition,
+ IN USHORT ShareAccess,
+ IN READ_MODE ServerReadMode,
+ IN COMPLETION_MODE ServerCompletionMode,
+ IN ULONG InboundQuota,
+ IN ULONG OutboundQuota,
+ IN PEPROCESS CreatorProcess
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonCreateNamedPipe)
+#pragma alloc_text(PAGE, NpCreateExistingNamedPipe)
+#pragma alloc_text(PAGE, NpCreateNewNamedPipe)
+#pragma alloc_text(PAGE, NpFsdCreateNamedPipe)
+#endif
+
+
+NTSTATUS
+NpFsdCreateNamedPipe (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtCreateNamedPipeFile
+ API call.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdCreateNamedPipe\n", 0);
+
+ //
+ // Call the common create routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ try {
+
+ Status = NpCommonCreateNamedPipe( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdCreateNamedPipe -> %08lx\n", Status );
+
+ return Status;
+}
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonCreateNamedPipe (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for creating/opening a file.
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ PFILE_OBJECT FileObject;
+ PFILE_OBJECT RelatedFileObject;
+ UNICODE_STRING FileName;
+ ACCESS_MASK DesiredAccess;
+ ULONG Options;
+ USHORT ShareAccess;
+ PNAMED_PIPE_CREATE_PARAMETERS Parameters;
+ NAMED_PIPE_TYPE NamedPipeType;
+ READ_MODE ServerReadMode;
+ COMPLETION_MODE ServerCompletionMode;
+ ULONG MaximumInstances;
+ ULONG InboundQuota;
+ ULONG OutboundQuota;
+ LARGE_INTEGER DefaultTimeout;
+ BOOLEAN TimeoutSpecified;
+ PEPROCESS CreatorProcess;
+
+ BOOLEAN CaseInsensitive = TRUE; //**** Make all searches case insensitive
+
+ PFCB Fcb;
+
+ ULONG CreateDisposition;
+
+ UNICODE_STRING RemainingPart;
+
+ PAGED_CODE();
+
+ //
+ // Reference our input parameters to make things easier
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+ FileObject = IrpSp->FileObject;
+ RelatedFileObject = IrpSp->FileObject->RelatedFileObject;
+ FileName = *(PUNICODE_STRING)&IrpSp->FileObject->FileName;
+ DesiredAccess = IrpSp->Parameters.CreatePipe.SecurityContext->DesiredAccess;
+ Options = IrpSp->Parameters.CreatePipe.Options;
+ ShareAccess = IrpSp->Parameters.CreatePipe.ShareAccess;
+ Parameters = IrpSp->Parameters.CreatePipe.Parameters;
+ NamedPipeType = Parameters->NamedPipeType;
+ ServerReadMode = Parameters->ReadMode;
+ ServerCompletionMode = Parameters->CompletionMode;
+ MaximumInstances = Parameters->MaximumInstances;
+ InboundQuota = Parameters->InboundQuota;
+ OutboundQuota = Parameters->OutboundQuota;
+ DefaultTimeout = Parameters->DefaultTimeout;
+ TimeoutSpecified = Parameters->TimeoutSpecified;
+ CreatorProcess = IoGetRequestorProcess( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonCreateNamedPipe\n", 0 );
+ DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject );
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
+ DebugTrace( 0, Dbg, "FileObject = %08lx\n", FileObject );
+ DebugTrace( 0, Dbg, "RelatedFileObject = %08lx\n", RelatedFileObject );
+ DebugTrace( 0, Dbg, "FileName = %Z\n", &FileName );
+ DebugTrace( 0, Dbg, "DesiredAccess = %08lx\n", DesiredAccess );
+ DebugTrace( 0, Dbg, "Options = %08lx\n", Options );
+ DebugTrace( 0, Dbg, "ShareAccess = %08lx\n", ShareAccess );
+ DebugTrace( 0, Dbg, "Parameters = %08lx\n", Parameters );
+ DebugTrace( 0, Dbg, "NamedPipeType = %08lx\n", NamedPipeType );
+ DebugTrace( 0, Dbg, "ServerReadMode = %08lx\n", ServerReadMode );
+ DebugTrace( 0, Dbg, "ServerCompletionMode = %08lx\n", ServerCompletionMode );
+ DebugTrace( 0, Dbg, "MaximumInstances = %08lx\n", MaximumInstances );
+ DebugTrace( 0, Dbg, "InboundQuota = %08lx\n", InboundQuota );
+ DebugTrace( 0, Dbg, "OutboundQuota = %08lx\n", OutboundQuota );
+ DebugTrace( 0, Dbg, "DefaultTimeout = %08lx\n", DefaultTimeout );
+ DebugTrace( 0, Dbg, "TimeoutSpecified = %08lx\n", TimeoutSpecified );
+ DebugTrace( 0, Dbg, "CreatorProcess = %08lx\n", CreatorProcess );
+
+ //
+ // Extract the create disposition
+ //
+
+ CreateDisposition = (Options >> 24) & 0x000000ff;
+
+ //
+ // Acquire exclusive access to the Vcb.
+ //
+
+ NpAcquireExclusiveVcb();
+
+ try {
+
+ //
+ // If there is a related file object then this is a relative open
+ // and it better be the root dcb. Both the then and the else clause
+ // return an Fcb.
+ //
+
+ if (RelatedFileObject != NULL) {
+
+ PDCB Dcb;
+
+ Dcb = RelatedFileObject->FsContext;
+
+ if (NodeType(Dcb) != NPFS_NTC_ROOT_DCB) {
+
+ DebugTrace(0, Dbg, "Bad file name\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_OBJECT_NAME_INVALID );
+ try_return( Status = STATUS_OBJECT_NAME_INVALID );
+ }
+
+ Fcb = NpFindRelativePrefix( Dcb, &FileName, CaseInsensitive, &RemainingPart );
+
+ } else {
+
+ //
+ // The only nonrelative name we allow are of the form "\pipe-name"
+ //
+
+ if ((FileName.Length <= 2) || (FileName.Buffer[0] != L'\\')) {
+
+ DebugTrace(0, Dbg, "Bad file name\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_OBJECT_NAME_INVALID );
+ try_return( Status = STATUS_OBJECT_NAME_INVALID );
+ }
+
+ Fcb = NpFindPrefix( &FileName, CaseInsensitive, &RemainingPart );
+ }
+
+ //
+ // If the remaining name is empty then we better have an fcb
+ // otherwise we were given a illegal object name.
+ //
+
+ if (RemainingPart.Length == 0) {
+
+ if (Fcb->NodeTypeCode == NPFS_NTC_FCB) {
+
+ DebugTrace(0, Dbg, "Create existing named pipe, Fcb = %08lx\n", Fcb );
+
+ Irp->IoStatus = NpCreateExistingNamedPipe( Fcb,
+ FileObject,
+ DesiredAccess,
+ IrpSp->Parameters.CreatePipe.SecurityContext->AccessState,
+ (KPROCESSOR_MODE)(FlagOn(IrpSp->Flags, SL_FORCE_ACCESS_CHECK) ?
+ UserMode : Irp->RequestorMode),
+ CreateDisposition,
+ ShareAccess,
+ ServerReadMode,
+ ServerCompletionMode,
+ InboundQuota,
+ OutboundQuota,
+ CreatorProcess );
+ Status = Irp->IoStatus.Status;
+
+ } else {
+
+ DebugTrace(0, Dbg, "Illegal object name\n", 0);
+
+ Status = STATUS_OBJECT_NAME_INVALID;
+ }
+
+ } else {
+
+ //
+ // The remaining name is not empty so we better have the root Dcb
+ //
+
+ if (Fcb->NodeTypeCode == NPFS_NTC_ROOT_DCB) {
+
+ DebugTrace(0, Dbg, "Create new named pipe, Fcb = %08lx\n", Fcb );
+
+ Irp->IoStatus = NpCreateNewNamedPipe( Fcb,
+ FileObject,
+ FileName,
+ DesiredAccess,
+ IrpSp->Parameters.CreatePipe.SecurityContext->AccessState,
+ CreateDisposition,
+ ShareAccess,
+ NamedPipeType,
+ ServerReadMode,
+ ServerCompletionMode,
+ MaximumInstances,
+ InboundQuota,
+ OutboundQuota,
+ DefaultTimeout,
+ TimeoutSpecified,
+ CreatorProcess );
+ Status = Irp->IoStatus.Status;
+
+ } else {
+
+ DebugTrace(0, Dbg, "Illegal object name\n", 0);
+
+ Status = STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ //
+ // Complete the IRP and return to our caller
+ //
+
+ NpCompleteRequest( Irp, Status );
+
+ try_exit: NOTHING;
+ } finally {
+
+ NpReleaseVcb( );
+
+ DebugTrace(-1, Dbg, "NpCommonCreateNamedPipe -> %08lx\n", Status);
+ }
+
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+IO_STATUS_BLOCK
+NpCreateNewNamedPipe (
+ IN PROOT_DCB RootDcb,
+ IN PFILE_OBJECT FileObject,
+ IN UNICODE_STRING FileName,
+ IN ACCESS_MASK DesiredAccess,
+ IN PACCESS_STATE AccessState,
+ IN ULONG CreateDisposition,
+ IN USHORT ShareAccess,
+ IN ULONG NamedPipeType,
+ IN ULONG ServerReadMode,
+ IN ULONG ServerCompletionMode,
+ IN ULONG MaximumInstances,
+ IN ULONG InboundQuota,
+ IN ULONG OutboundQuota,
+ IN LARGE_INTEGER DefaultTimeout,
+ IN BOOLEAN TimeoutSpecified,
+ IN PEPROCESS CreatorProcess
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the operation for creating a new named pipe
+ Fcb and its first instance. This routine does not complete any
+ IRP, it preforms its function and then returns an iosb.
+
+Arguments:
+
+ RootDcb - Supplies the root dcb where this is going to be added
+
+ FileObject - Supplies the file object associated with the first
+ instance of the named pipe
+
+ FileName - Supplies the name of the named pipe (not qualified i.e.,
+ simply "pipe-name" and not "\pipe-name"
+
+ DesiredAccess - Supplies the callers desired access
+
+ AccessState - Supplies the access state from the irp
+
+ CreateDisposition - Supplies the callers create disposition flags
+
+ ShareAccess - Supplies the caller specified share access
+
+ NamedPipeType - Supplies the named type type
+
+ ServerReadMode - Supplies the named pipe read mode
+
+ ServerCompletionMode - Supplies the named pipe completion mode
+
+ MaximumInstances - Supplies the maximum instances for the named pipe
+
+ InboundQuota - Supplies the inbound quota amount
+
+ OutboundQuota - Supplies the outbound quota amount
+
+ DefaultTimeout - Supplies the default time out value
+
+ TimeoutSpecified - Indicates if the time out value was supplied by the
+ caller.
+
+ CreatorProcess - Supplies the process creating the named pipe
+
+Return Value:
+
+ IO_STATUS_BLOCK - Returns the appropriate status for the operation
+
+--*/
+
+{
+ // FIX, FIX - TEMPORARY ONLY.
+ UCHAR SDBody[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR TmpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&SDBody[0]);
+ // FIX, FIX - TEMPORARY ONLY.
+
+ IO_STATUS_BLOCK Iosb;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ PFCB Fcb;
+ PCCB Ccb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCreateNewNamedPipe\n", 0 );
+
+ Fcb = NULL;
+ Ccb = NULL;
+
+ try {
+
+ //
+ // Check the parameters that must be supplied for a new named pipe
+ // (i.e., the create disposition, timeout, and max instances better
+ // be greater than zero)
+ //
+
+ if (!TimeoutSpecified || MaximumInstances <= 0) {
+
+ try_return( Iosb.Status = STATUS_INVALID_PARAMETER );
+ }
+
+ //
+ // The default timeout needs to be less than zero otherwise it
+ // is an absolute time out which doesn't make sense.
+ //
+
+ {
+ PLARGE_INTEGER Int = (PLARGE_INTEGER)&DefaultTimeout;
+
+ if (Int->QuadPart >= 0) {
+
+ try_return( Iosb.Status = STATUS_INVALID_PARAMETER );
+ }
+ }
+
+ if (CreateDisposition == FILE_OPEN) {
+
+ try_return( Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND );
+ }
+
+ //
+ // Determine the pipe configuration
+ //
+
+ if (ShareAccess == (FILE_SHARE_READ | FILE_SHARE_WRITE)) {
+
+ NamedPipeConfiguration = FILE_PIPE_FULL_DUPLEX;
+
+ } else if (ShareAccess == FILE_SHARE_READ) {
+
+ NamedPipeConfiguration = FILE_PIPE_OUTBOUND;
+
+ } else if (ShareAccess == FILE_SHARE_WRITE) {
+
+ NamedPipeConfiguration = FILE_PIPE_INBOUND;
+
+ } else {
+
+ try_return( Iosb.Status = STATUS_INVALID_PARAMETER );
+ }
+
+ //
+ // Check that if named pipe type is byte stream then the read mode is
+ // not message mode
+ //
+
+ if ((NamedPipeType == FILE_PIPE_BYTE_STREAM_TYPE) &&
+ (ServerReadMode == FILE_PIPE_MESSAGE_MODE)) {
+
+ try_return( Iosb.Status = STATUS_INVALID_PARAMETER );
+ }
+
+ //
+ // Create a new fcb and ccb for the named pipe
+ //
+
+ Fcb = NpCreateFcb( RootDcb,
+ &FileName,
+ MaximumInstances,
+ DefaultTimeout,
+ NamedPipeConfiguration,
+ NamedPipeType );
+
+ Ccb = NpCreateCcb( Fcb,
+ FileObject,
+ FILE_PIPE_LISTENING_STATE,
+ ServerReadMode,
+ ServerCompletionMode,
+ CreatorProcess,
+ InboundQuota,
+ OutboundQuota );
+
+ //
+ // Set the security descriptor in the Fcb
+ //
+
+ SeLockSubjectContext( &AccessState->SubjectSecurityContext );
+
+ Iosb.Status = SeAssignSecurity( NULL,
+ AccessState->SecurityDescriptor,
+ &Fcb->SecurityDescriptor,
+ FALSE,
+ &AccessState->SubjectSecurityContext,
+ IoGetFileObjectGenericMapping(),
+ PagedPool );
+
+ SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
+
+ if (!NT_SUCCESS(Iosb.Status)) {
+
+ DebugTrace(0, Dbg, "Error calling SeAssignSecurity\n", 0 );
+
+ try_return( Iosb.Status );
+ }
+
+ //
+ // Set the new share access
+ //
+
+ //IoSetShareAccess( DesiredAccess,
+ // ShareAccess,
+ // FileObject,
+ // &Ccb->ShareAccess );
+
+ //
+ // Set the file object back pointers and our pointer to the
+ // server file object.
+ //
+
+ NpSetFileObject( FileObject, Ccb, Ccb->NonpagedCcb, FILE_PIPE_SERVER_END );
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = FileObject;
+
+ //
+ // Check to see if we need to notify outstanding Irps for any
+ // changes (i.e., we just added a named pipe).
+ //
+
+ NpCheckForNotify( RootDcb, TRUE );
+
+ //
+ // Set our return status
+ //
+
+ Iosb.Status = STATUS_SUCCESS;
+ Iosb.Information = FILE_CREATED;
+
+ try_exit: NOTHING;
+ } finally {
+
+ if (AbnormalTermination()) {
+
+ if (Ccb != NULL) { NpDeleteCcb( Ccb ); }
+ if (Fcb != NULL) { Fcb->OpenCount = 0; NpDeleteFcb( Fcb ); }
+
+ } else {
+
+ //
+ // Now if we ever terminate the preceding try-statement with
+ // a status that is not successful and the ccb or fcb pointer
+ // is non-null then we need to deallocate the structures
+ //
+
+ if (!NT_SUCCESS(Iosb.Status) && Ccb != NULL) { NpDeleteCcb( Ccb ); }
+ if (!NT_SUCCESS(Iosb.Status) && Fcb != NULL) { Fcb->OpenCount = 0; NpDeleteFcb( Fcb ); }
+ }
+
+ DebugTrace(-1, Dbg, "NpCreateNewNamedPipe -> %08lx\n", Iosb.Status);
+ }
+
+ return Iosb;
+}
+
+
+//
+// Internal support routine
+//
+
+IO_STATUS_BLOCK
+NpCreateExistingNamedPipe (
+ IN PFCB Fcb,
+ IN PFILE_OBJECT FileObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN PACCESS_STATE AccessState,
+ IN KPROCESSOR_MODE RequestorMode,
+ IN ULONG CreateDisposition,
+ IN USHORT ShareAccess,
+ IN ULONG ServerReadMode,
+ IN ULONG ServerCompletionMode,
+ IN ULONG InboundQuota,
+ IN ULONG OutboundQuota,
+ IN PEPROCESS CreatorProcess
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the operation for creating a new instance of
+ an existing named pipe. This routine does not complete any
+ IRP, it preforms its function and then returns an iosb.
+
+Arguments:
+
+ Fcb - Supplies the Fcb for the named pipe being created
+
+ FileObject - Supplies the file object associated with this
+ instance of the named pipe
+
+ DesiredAccess - Supplies the callers desired access
+
+ CreateDisposition - Supplies the callers create disposition flags
+
+ ShareAccess - Supplies the caller specified share access
+
+ ServerReadMode - Supplies the named pipe read mode
+
+ ServerCompletionMode - Supplies the named pipe completion mode
+
+ InboundQuota - Supplies the inbound quota amount
+
+ OutboundQuota - Supplies the outbound quota amount
+
+ CreatorProcess - Supplies the process creating the named pipe
+
+Return Value:
+
+ IO_STATUS_BLOCK - Returns the appropriate status for the operation
+
+--*/
+
+{
+ IO_STATUS_BLOCK Iosb;
+
+ BOOLEAN AccessGranted;
+ ACCESS_MASK GrantedAccess;
+ UNICODE_STRING Name;
+
+ PCCB Ccb;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ USHORT OriginalShareAccess;
+
+ PPRIVILEGE_SET Privileges = NULL;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCreateExistingNamedPipe\n", 0 );
+
+ Ccb = NULL;
+
+ try {
+
+ //
+ // First do an access check for the user against the Fcb
+ //
+
+ SeLockSubjectContext( &AccessState->SubjectSecurityContext );
+
+ AccessGranted = SeAccessCheck( Fcb->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ TRUE, // Tokens are locked
+ DesiredAccess,
+ 0,
+ &Privileges,
+ IoGetFileObjectGenericMapping(),
+ RequestorMode,
+ &GrantedAccess,
+ &Iosb.Status );
+
+ if (Privileges != NULL) {
+
+ (VOID) SeAppendPrivileges(
+ AccessState,
+ Privileges
+ );
+
+ SeFreePrivileges( Privileges );
+ }
+
+ if (AccessGranted) {
+ AccessState->PreviouslyGrantedAccess |= GrantedAccess;
+ AccessState->RemainingDesiredAccess &= ~GrantedAccess;
+ }
+
+
+ RtlInitUnicodeString( &Name, L"NamedPipe" );
+
+ SeOpenObjectAuditAlarm( &Name,
+ NULL,
+ &FileObject->FileName,
+ Fcb->SecurityDescriptor,
+ AccessState,
+ FALSE,
+ AccessGranted,
+ RequestorMode,
+ &AccessState->GenerateOnClose );
+
+ SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
+
+ if (!AccessGranted) {
+
+ DebugTrace(0, Dbg, "Access Denied\n", 0 );
+
+ try_return( Iosb.Status );
+ }
+
+ //
+ // Check that we're still under the maximum instances count
+ //
+
+ if (Fcb->OpenCount >= Fcb->Specific.Fcb.MaximumInstances) {
+
+ try_return( Iosb.Status = STATUS_INSTANCE_NOT_AVAILABLE );
+ }
+
+ if (CreateDisposition == FILE_CREATE) {
+
+ try_return( Iosb.Status = STATUS_ACCESS_DENIED );
+ }
+
+ //
+ // From the pipe configuration determine the share access specified
+ // on the first instance of this pipe. All subsequent instances must
+ // specify the same share access.
+ //
+
+ NamedPipeConfiguration = Fcb->Specific.Fcb.NamedPipeConfiguration;
+
+ if (NamedPipeConfiguration == FILE_PIPE_OUTBOUND) {
+
+ OriginalShareAccess = FILE_SHARE_READ;
+
+ } else if (NamedPipeConfiguration == FILE_PIPE_INBOUND) {
+
+ OriginalShareAccess = FILE_SHARE_WRITE;
+
+ } else {
+
+ OriginalShareAccess = (FILE_SHARE_READ | FILE_SHARE_WRITE);
+ }
+
+ if (OriginalShareAccess != ShareAccess) {
+
+ try_return( Iosb.Status = STATUS_ACCESS_DENIED );
+ }
+
+ //
+ // Create a new ccb for the named pipe
+ //
+
+ Ccb = NpCreateCcb( Fcb,
+ FileObject,
+ FILE_PIPE_LISTENING_STATE,
+ ServerReadMode,
+ ServerCompletionMode,
+ CreatorProcess,
+ InboundQuota,
+ OutboundQuota );
+
+ //
+ // Wake up anyone waiting for an instance to go into the listening state
+ //
+
+ NpCancelWaiter( &NpVcb->WaitQueue, &Fcb->FullFileName );
+
+ //
+ // Set the new share access
+ //
+
+ //IoSetShareAccess( DesiredAccess,
+ // ShareAccess,
+ // FileObject,
+ // &Ccb->ShareAccess );
+
+ //
+ // Set the file object back pointers and our pointer to the
+ // server file object.
+ //
+
+ NpSetFileObject( FileObject, Ccb, Ccb->NonpagedCcb, FILE_PIPE_SERVER_END );
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = FileObject;
+
+ //
+ // Check to see if we need to notify outstanding Irps for
+ // changes (i.e., we just added a new instance of a named pipe).
+ //
+
+ NpCheckForNotify( Fcb->ParentDcb, FALSE );
+
+ //
+ // Set our return status
+ //
+
+ Iosb.Status = STATUS_SUCCESS;
+ Iosb.Information = FILE_CREATED;
+
+ try_exit: NOTHING;
+ } finally {
+
+ if (AbnormalTermination()) {
+
+ if (Ccb != NULL) { NpDeleteCcb( Ccb ); }
+
+ } else {
+
+ //
+ // Now if we ever terminate the preceding try-statement with
+ // a status that is not successful and the ccb pointer
+ // is non-null then we need to deallocate the structure
+ //
+
+ if (!NT_SUCCESS(Iosb.Status) && Ccb != NULL) { NpDeleteCcb( Ccb ); }
+ }
+
+ DebugTrace(-1, Dbg, "NpCreateExistingNamedPipe -> %08lx\n", Iosb.Status);
+ }
+
+ return Iosb;
+}
+
diff --git a/private/ntos/npfs/datasup.c b/private/ntos/npfs/datasup.c
new file mode 100644
index 000000000..1adbace32
--- /dev/null
+++ b/private/ntos/npfs/datasup.c
@@ -0,0 +1,1077 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ DataSup.c
+
+Abstract:
+
+ This module implements the Named Pipe data queue support routines.
+
+Author:
+
+ Gary Kimura [GaryKi] 30-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_DATASUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpGetNextRealDataQueueEntry)
+#pragma alloc_text(PAGE, NpInitializeDataQueue)
+#pragma alloc_text(PAGE, NpUninitializeDataQueue)
+#endif
+
+//
+// The following macro is used to dump a data queue
+//
+
+#define DumpDataQueue(S,P) { \
+ ULONG NpDumpDataQueue(IN PDATA_QUEUE Ptr); \
+ DebugTrace(0,Dbg,S,0); \
+ DebugTrace(0,Dbg,"", NpDumpDataQueue(P)); \
+}
+
+//
+// This is a debugging aid
+//
+
+_inline BOOLEAN
+NpfsVerifyDataQueue( IN ULONG Line, IN PDATA_QUEUE DataQueue ) {
+ PDATA_ENTRY Entry;
+ ULONG BytesInQueue = 0;
+ ULONG EntriesInQueue = 0;
+ for (Entry = DataQueue->FrontOfQueue; Entry != NULL; Entry = Entry->Next) {
+ BytesInQueue += Entry->DataSize;
+ EntriesInQueue += 1;
+ if (Entry->Next == NULL) {
+ if (Entry != DataQueue->EndOfQueue) {
+ DbgPrint("%d DataQueue does not end corretly %08lx\n", Line, DataQueue );
+ DbgBreakPoint();
+ }
+ }
+ }
+ if ((DataQueue->EntriesInQueue != EntriesInQueue) ||
+ (DataQueue->BytesInQueue != BytesInQueue)) {
+ DbgPrint("%d DataQueue is illformed %08lx %x %x\n", Line, DataQueue, BytesInQueue, EntriesInQueue);
+ DbgBreakPoint();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+VOID
+NpCancelDataQueueIrp (
+ IN PDEVICE_OBJECT DevictObject,
+ IN PIRP Irp
+ );
+
+
+VOID
+NpInitializeDataQueue (
+ IN PDATA_QUEUE DataQueue,
+ IN PEPROCESS Process,
+ IN ULONG Quota
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a new data queue. The indicated quota is taken
+ from the process and not returned until the data queue is uninitialized.
+
+Arguments:
+
+ DataQueue - Supplies the data queue being initialized
+
+ Process - Supplies a pointer to the process creating the named pipe
+
+ Quota - Supplies the quota to assign to the data queue
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpInitializeDataQueue, DataQueue = %08lx\n", DataQueue);
+
+ //
+ // First thing we do is get the process's quota, if we can't get it
+ // then this call will raise status
+ //
+
+ ObReferenceObject( Process );
+ PsChargePoolQuota( Process, NonPagedPool, Quota );
+
+ //
+ // Now we can initialize the data queue structure
+ //
+
+ DataQueue->QueueState = Empty;
+ DataQueue->BytesInQueue = 0;
+ DataQueue->EntriesInQueue = 0;
+ DataQueue->Quota = Quota;
+ DataQueue->QuotaUsed = 0;
+ DataQueue->FrontOfQueue = NULL;
+ DataQueue->EndOfQueue = NULL;
+ DataQueue->NextByteOffset = 0;
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpInitializeDataQueue -> VOID\n", 0);
+
+ return;
+}
+
+
+VOID
+NpUninitializeDataQueue (
+ IN PDATA_QUEUE DataQueue,
+ IN PEPROCESS Process
+ )
+
+/*++
+
+Routine Description:
+
+ This routine uninitializes a data queue. The previously debited quota
+ is returned to the process.
+
+Arguments:
+
+ DataQueue - Supplies the data queue being uninitialized
+
+ Process - Supplies a pointer to the process who created the named pipe
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpUninitializeDataQueue, DataQueue = %08lx\n", DataQueue);
+
+ //
+ // Assert that the queue is empty
+ //
+
+ ASSERT( DataQueue->QueueState == Empty );
+
+ //
+ // Return all of our quota back to the process
+ //
+
+ PsReturnPoolQuota( Process, NonPagedPool, DataQueue->Quota );
+ ObDereferenceObject( Process );
+
+ //
+ // Then for safety sake we'll zero out the data queue structure
+ //
+
+ RtlZeroMemory( DataQueue, sizeof(DATA_QUEUE ) );
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpUnininializeDataQueue -> VOID\n", 0);
+
+ return;
+}
+
+
+PDATA_ENTRY
+NpAddDataQueueEntry (
+ IN PDATA_QUEUE DataQueue,
+ IN QUEUE_STATE Who,
+ IN DATA_ENTRY_TYPE Type,
+ IN ULONG DataSize,
+ IN PIRP Irp OPTIONAL,
+ IN PVOID DataPointer OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a new data entry to the end of the data queue.
+ If necessary it will allocate a data entry buffer, or use space in
+ the IRP, and possibly complete the indicated IRP.
+
+ The different actions we are perform are based on the type and who
+ parameters and quota requirements.
+
+ Type == Internal (i.e, Unbuffered)
+
+ +------+ - Allocate Data Entry from Irp
+ |Irp | +----------+
+ | |<---|Unbuffered| - Reference Irp
+ +------+ |InIrp |
+ | +----------+ - Use system buffer from Irp
+ v |
+ +------+ |
+ |System|<-----+
+ |Buffer|
+ +------+
+
+ Type == Buffered && Who == ReadEntries
+
+ +----------+ - Allocate Data Entry from Irp
+ |Irp | +-----------+
+ |BufferedIo|<----|Buffered | - Allocate New System buffer
+ |DeallBu...| |EitherQuota|
+ +----------+ +-----------+ - Reference and modify Irp to
+ | | | do Buffered I/O, Deallocate
+ v | v buffer, and have io completion
+ +------+ +------>+------+ copy the buffer (Input operation)
+ |User | |System|
+ |Buffer| |Buffer|
+ +------+ +------+
+
+ Type == Buffered && Who == WriteEntries && PipeQuota Available
+
+ +----------+ - Allocate Data Entry from Quota
+ |Irp | +-----------+
+ | | |Buffered | - Allocate New System buffer
+ | | |PipeQuota |
+ +----------+ +-----------+ - Copy data from User buffer to
+ | | system buffer
+ v v
+ +------+ +------+ - Complete Irp
+ |User |..copy..>|System|
+ |Buffer| |Buffer|
+ +------+ +------+
+
+ Type == Buffered && Who == WriteEntries && PipeQuota Not Available
+
+ +----------+ - Allocate Data Entry from Irp
+ |Irp | +-----------+
+ |BufferedIo|<----|Buffered | - Allocate New System buffer
+ |DeallBuff | |UserQuota |
+ +----------+ +-----------+ - Reference and modify Irp to use
+ | | | the new system buffer, do Buffered
+ v | v I/O, and Deallocate buffer
+ +------+ +------>+------+
+ |User | |System| - Copy data from User buffer to
+ |Buffer|..copy..>|Buffer| system buffer
+ +------+ +------+
+
+ Type == Flush or Close
+
+ +----------+ - Allocate Data Entry from Irp
+ |Irp | +-----------+
+ | |<----|Buffered | - Reference the Irp
+ | | |UserQuota |
+ +----------+ +-----------+
+
+Arguments:
+
+ DataQueue - Supplies the Data queue being modified
+
+ Who - Indicates if this is the reader or writer that is adding to the pipe
+
+ Type - Indicates the type of entry to add to the data queue
+
+ DataSize - Indicates the size of the data buffer needed to represent
+ this entry
+
+ Irp - Supplies a pointer to the Irp responsible for this entry
+ The irp is only optional for buffered write with available pipe quota
+
+ DataPointer - If the Irp is not supplied then this field points to the
+ user's write buffer.
+
+Return Value:
+
+ PDATA_ENTRY - Returns a pointer to the newly added data entry
+
+--*/
+
+{
+ PDATA_ENTRY DataEntry;
+ PIRP IrpToComplete;
+
+ //
+ // The following array indicates storage that needs to be deallocated
+ // on an abnormal unwind.
+ //
+
+ PVOID Unwind[2] = { NULL, NULL };
+
+ ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
+
+ DebugTrace(+1, Dbg, "NpAddDataQueueEntry, DataQueue = %08lx\n", DataQueue);
+
+ IrpToComplete = NULL;
+
+ try {
+
+ //
+ // Case on the type of operation we are doing
+ //
+
+ switch (Type) {
+
+ case Unbuffered:
+
+ ASSERT(ARGUMENT_PRESENT(Irp));
+
+ //
+ // Allocate a data entry from the Irp
+ //
+
+ DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( Irp );
+
+ DataEntry->DataEntryType = Unbuffered;
+ DataEntry->From = InIrp;
+ DataEntry->Irp = Irp;
+ DataEntry->DataSize = DataSize;
+ DataEntry->DataPointer = Irp->AssociatedIrp.SystemBuffer;
+
+ DataEntry->SecurityClientContext = NULL;
+
+ ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
+
+ break;
+
+ case Buffered:
+
+ //
+ // Check if this is the reader or writer
+ //
+
+ if (Who == ReadEntries) {
+
+ ASSERT(ARGUMENT_PRESENT(Irp));
+
+ //
+ // Allocate a data entry from the Irp, and allocate a new
+ // system buffer
+ //
+
+ DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( Irp );
+
+ DataEntry->DataEntryType = Buffered;
+ DataEntry->Irp = Irp;
+ DataEntry->DataSize = DataSize;
+
+ if ((DataQueue->Quota - DataQueue->QuotaUsed) >= DataSize) {
+
+ DataEntry->DataPointer = Unwind[0] = (DataSize != 0 ? FsRtlAllocatePool( NonPagedPool, DataSize ) : NULL);
+
+ DataQueue->QuotaUsed += DataSize;
+
+ DataEntry->From = PipeQuota;
+
+ } else {
+
+ DataEntry->DataPointer = Unwind[1] = (DataSize != 0 ? FsRtlAllocatePoolWithQuota( NonPagedPool, DataSize ) : NULL);
+
+ DataEntry->From = UserQuota;
+ }
+
+ DataEntry->SecurityClientContext = NULL;
+
+ //
+ // Modify the Irp to be buffered I/O, deallocate the buffer, copy
+ // the buffer on completion, and to reference the new system
+ // buffer
+ //
+
+ if (DataSize != 0) {
+
+ Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
+ Irp->AssociatedIrp.SystemBuffer = DataEntry->DataPointer;
+ }
+
+ ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
+
+ } else {
+
+ //
+ // This is a writer entry
+ //
+
+ //
+ // If there is enough quota left in the pipe then we will
+ // allocate the data entry and data buffer from the pipe quota
+ //
+
+ if ((DataQueue->Quota - DataQueue->QuotaUsed) >= sizeof(DATA_ENTRY) + DataSize) {
+
+ DataEntry = Unwind[0] = FsRtlAllocatePool( NonPagedPool, sizeof(DATA_ENTRY) );
+
+ DataEntry->DataPointer = Unwind[1] = (DataSize != 0 ? FsRtlAllocatePool( NonPagedPool, DataSize ) : NULL);
+
+ DataQueue->QuotaUsed += sizeof(DATA_ENTRY) + DataSize;
+
+ DataEntry->DataEntryType = Buffered;
+ DataEntry->From = PipeQuota;
+ DataEntry->Irp = NULL;
+ DataEntry->DataSize = DataSize;
+
+ DataEntry->SecurityClientContext = NULL;
+
+ //
+ // Safely copy the user buffer to the new system buffer using either
+ // the irp user buffer is supplied of the data pointer we were given
+ //
+
+ if (ARGUMENT_PRESENT(Irp)) { DataPointer = Irp->UserBuffer; }
+
+ try {
+
+ RtlCopyMemory( DataEntry->DataPointer, DataPointer, DataSize );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
+ }
+
+ IrpToComplete = Irp;
+
+ ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
+
+ } else {
+
+ ASSERT(ARGUMENT_PRESENT(Irp));
+
+ //
+ // There isn't enough pipe quota to do this so we will
+ // use the user quota
+ //
+ // Allocate a data entry from the Irp, and allocate a new
+ // system buffer
+ //
+
+ DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( Irp );
+
+ DataEntry->DataEntryType = Buffered;
+ DataEntry->From = UserQuota;
+ DataEntry->Irp = Irp;
+ DataEntry->DataSize = DataSize;
+
+ DataEntry->SecurityClientContext = NULL;
+
+ DataEntry->DataPointer = Unwind[0] = (DataSize != 0 ? FsRtlAllocatePoolWithQuota( NonPagedPool, DataSize ) : NULL);
+
+ //
+ // Safely copy the user buffer to the new system buffer
+ //
+
+ try {
+
+ RtlCopyMemory( DataEntry->DataPointer, Irp->UserBuffer, DataSize );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
+ }
+
+ //
+ // Modify the Irp to be buffered I/O, deallocate the buffer
+ // and to reference the new system buffer
+ //
+
+ if (DataSize != 0) {
+
+ Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
+ Irp->AssociatedIrp.SystemBuffer = DataEntry->DataPointer;
+ }
+
+ ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
+ }
+ }
+
+ break;
+
+ case Flush:
+ case Close:
+
+ ASSERT(ARGUMENT_PRESENT(Irp));
+
+ //
+ // Allocate a data entry from the Irp
+ //
+
+ DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( Irp );
+
+ DataEntry->DataEntryType = Type;
+ DataEntry->From = InIrp;
+ DataEntry->Irp = Irp;
+ DataEntry->DataSize = 0;
+ DataEntry->DataPointer = NULL;
+
+ DataEntry->SecurityClientContext = NULL;
+
+ ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
+
+ break;
+ }
+
+ ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
+
+ //
+ // Now data entry points to a new data entry to add to the data queue
+ // Check if the queue is empty otherwise we will add this entry to
+ // the end of the queue
+ //
+
+ DataEntry->Next = NULL;
+
+ if (DataQueue->QueueState == Empty) {
+
+ DataQueue->QueueState = Who;
+ DataQueue->BytesInQueue = DataEntry->DataSize;
+ DataQueue->EntriesInQueue = 1;
+ DataQueue->FrontOfQueue = DataEntry;
+ DataQueue->EndOfQueue = DataEntry;
+
+ } else {
+
+ ASSERT( DataQueue->QueueState == Who );
+
+ DataQueue->BytesInQueue += DataEntry->DataSize;
+ DataQueue->EntriesInQueue += 1;
+ DataQueue->EndOfQueue->Next = DataEntry;
+
+ DataQueue->EndOfQueue = DataEntry;
+ }
+
+ } finally {
+
+ //
+ // If this is an abnormal termination then deallocate any storage
+ // that we may have allocated
+ //
+
+ if (AbnormalTermination()) {
+
+ if (Unwind[0] != NULL) { ExFreePool( Unwind[0] ); }
+ if (Unwind[1] != NULL) { ExFreePool( Unwind[1] ); }
+
+ } else {
+
+ if (IrpToComplete != NULL) {
+
+ NpCompleteRequest( IrpToComplete, STATUS_SUCCESS );
+
+ } else if (ARGUMENT_PRESENT(Irp)) {
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ Irp->IoStatus.Status = (ULONG)DataQueue;
+
+ if (Irp->Cancel) {
+
+ //
+ // Indicate in the first parameter that we're calling the
+ // cancel routine and not the I/O system. Therefore
+ // the routine won't take out the VCB exclusive.
+ //
+
+ NpCancelDataQueueIrp( ((PVOID)0x1), Irp );
+
+ } else {
+
+ IoSetCancelRoutine( Irp, NpCancelDataQueueIrp );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ }
+ }
+ }
+
+ DumpDataQueue( "After AddDataQueueEntry\n", DataQueue );
+ DebugTrace(-1, Dbg, "NpAddDataQueueEntry -> %08lx\n", DataEntry);
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return DataEntry;
+}
+
+
+PIRP
+NpRemoveDataQueueEntry (
+ IN PDATA_QUEUE DataQueue
+ )
+
+/*++
+
+Routine Description:
+
+ This routines remove the first entry from the front of the indicated
+ data queue, and possibly returns the Irp associated with the entry if
+ it wasn't already completed when we did the insert.
+
+ If the data entry we are removing indicates buffered I/O then we also
+ need to deallocate the data buffer besides the data entry but only
+ if the Irp is null. Note that the data entry might be stored in an IRP.
+ If it is then we are going to return the IRP it is stored in.
+
+Arguments:
+
+ DataQueue - Supplies a pointer to the data queue being modifed
+
+Return Value:
+
+ PIRP - Possibly returns a pointer to an IRP.
+
+--*/
+
+{
+ PDATA_ENTRY DataEntry;
+
+ DATA_ENTRY_TYPE DataEntryType;
+ FROM From;
+ PIRP Irp;
+ ULONG DataSize;
+ PVOID DataPointer;
+ PSECURITY_CLIENT_CONTEXT ClientContext;
+
+ DebugTrace(+1, Dbg, "NpRemoveDataQueueEntry, DataQueue = %08lx\n", DataQueue);
+
+ //
+ // Check if the queue is empty, and if so then we simply return null
+ //
+
+ if (DataQueue->QueueState == Empty) {
+
+ Irp = NULL;
+
+ } else {
+
+ //
+ // Reference the front of the data queue, and remove the entry
+ // from the queue itself.
+ //
+
+ DataEntry = DataQueue->FrontOfQueue;
+ DataQueue->FrontOfQueue = DataEntry->Next;
+ DataQueue->BytesInQueue -= DataEntry->DataSize;
+ DataQueue->EntriesInQueue -= 1;
+
+ //
+ // Now if the queue is empty we need to reset the end of queue and
+ // queue state
+ //
+
+ if (DataQueue->FrontOfQueue == NULL) {
+
+ DataQueue->EndOfQueue = NULL;
+ DataQueue->QueueState = Empty;
+ }
+
+ //
+ // Capture some of the fields from the data entry to make our
+ // other references a little easier
+ //
+
+ DataEntryType = DataEntry->DataEntryType;
+ From = DataEntry->From;
+ Irp = DataEntry->Irp;
+ DataSize = DataEntry->DataSize;
+ DataPointer = DataEntry->DataPointer;
+ ClientContext = DataEntry->SecurityClientContext;
+
+ //
+ // Check if we should delete the client context
+ //
+
+ if (ClientContext != NULL) {
+
+ SeDeleteClientSecurity( ClientContext );
+ ExFreePool( ClientContext );
+ }
+
+ //
+ // Check if we need to deallocate the data buffer, we only need
+ // to deallocate it if it is buffered and the Irp is null
+ //
+
+ if (DataEntryType == Buffered) {
+
+ if ((Irp == NULL) && (DataPointer != NULL)) {
+
+ ExFreePool( DataPointer );
+ }
+
+ //
+ // Now the preceding call returned the user's quota or it
+ // simply deallocated the buffer. If it only deallocated
+ // the buffer then we need to credit our quota
+ //
+
+ if (From == PipeQuota) {
+
+ DataQueue->QuotaUsed -= DataSize;
+ }
+ }
+
+ //
+ // Now check if we still have an IRP to return. If we do then
+ // we know that this data entry is located in the current IRP
+ // stack location and we need to zero out the data entry (skipping
+ // over the spare field), otherwise we got allocated from either
+ // the pipe or user quota, and we need to deallocate it ourselves.
+ //
+ // Note that we'll keep the data entry type field intact so that
+ // out caller will know if this is an internal read operation.
+ //
+
+ if (Irp != NULL) {
+
+ DataEntry->From = 0;
+ DataEntry->Next = 0;
+ DataEntry->Irp = 0;
+ DataEntry->DataSize = 0;
+ DataEntry->DataPointer = 0;
+
+ DataEntry->SecurityClientContext = NULL;
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ IoSetCancelRoutine( Irp, NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ } else {
+
+ if (DataPointer != NULL) {
+
+ ExFreePool( DataEntry );
+ }
+
+ //
+ // Now the preceding call returned the user's quota or it
+ // simply deallocated the buffer. If it only deallocated
+ // the buffer then we need to credit our quota
+ //
+
+ if (From == PipeQuota) {
+
+ DataQueue->QuotaUsed -= sizeof(DATA_ENTRY);
+ }
+ }
+ }
+
+ //
+ // In all cases we'll also zero out the next byte offset.
+ //
+
+ DataQueue->NextByteOffset = 0;
+
+ //
+ // And return to our caller
+ //
+
+ DumpDataQueue( "After RemoveDataQueueEntry\n", DataQueue );
+ DebugTrace(-1, Dbg, "NpRemoveDataQueueEntry -> %08lx\n", Irp);
+
+ return Irp;
+}
+
+
+PDATA_ENTRY
+NpGetNextRealDataQueueEntry (
+ IN PDATA_QUEUE DataQueue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will returns a pointer to the next real data queue entry
+ in the indicated data queue. A real entry is either a read or write
+ entry (i.e., buffered or unbuffered). It will complete (as necessary)
+ any flush and close Irps that are in the queue until either the queue
+ is empty or a real data queue entry is at the front of the queue.
+
+Arguments:
+
+ DataQueue - Supplies a pointer to the data queue being modified
+
+Return Value:
+
+ PDATA_ENTRY - Returns a pointer to the next data queue entry or NULL
+ if there isn't any.
+
+--*/
+
+{
+ PDATA_ENTRY DataEntry;
+ PIRP Irp;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpGetNextRealDataQueueEntry, DataQueue = %08lx\n", DataQueue);
+
+ //
+ // While the next data queue entry at the head of the data queue is not
+ // a real data queue entry we'll dequeue that entry and complete
+ // its corresponding IRP.
+ //
+
+ for (DataEntry = NpGetNextDataQueueEntry( DataQueue, NULL);
+
+ (DataEntry != NULL) &&
+ ((DataEntry->DataEntryType != Buffered) &&
+ (DataEntry->DataEntryType != Unbuffered));
+
+ DataEntry = NpGetNextDataQueueEntry( DataQueue, NULL)) {
+
+ //
+ // We have a non real data queue entry that needs to be removed
+ // and completed.
+ //
+
+ Irp = NpRemoveDataQueueEntry( DataQueue );
+
+ if (Irp != NULL) {
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ }
+ }
+
+ //
+ // At this point we either have an empty data queue and data entry is
+ // null, or we have a real data queue entry. In either case it
+ // is time to return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpGetNextRealDataQueueEntry -> %08lx\n", DataEntry);
+
+ return DataEntry;
+}
+
+
+//
+// Local support routine
+//
+
+VOID
+NpCancelDataQueueIrp (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the cancel function for an IRP saved in a
+ data queue
+
+Arguments:
+
+ DeviceObject - Generally ignored but the low order bit is a flag indicating
+ if we are being called locally (i.e., not from the I/O system) and
+ therefore don't need to take out the VCB.
+
+ Irp - Supplies the Irp being cancelled. A pointer to the data queue
+ structure is stored in the information field of the Irp Iosb
+ field.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDATA_QUEUE DataQueue;
+
+ PDATA_ENTRY DataEntry;
+ PDATA_ENTRY *Previous;
+
+ //
+ // The status field is used to store a pointer to the data queue
+ // containing this irp
+ //
+
+ DataQueue = (PDATA_QUEUE)Irp->IoStatus.Status;
+
+ //
+ // We now need to void the cancel routine and release the io cancel spinlock
+ //
+
+ IoSetCancelRoutine( Irp, NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ //
+ // Get exclusive access to the named pipe vcb so we can now do our work
+ // but only if we need to
+ //
+
+ if (DeviceObject != (PVOID)0x1) { NpAcquireExclusiveVcb(); }
+
+ try {
+
+ //
+ // Scan through the data queue looking for entries that have Irps
+ // that have been cancelled. We use previous to point to the pointer to
+ // the data entry we're examining. We cannot do this in a for loop
+ // because we'll have a tough time setting up ourselves for another iteration
+ // when we remove an entry
+ //
+
+ Previous = &DataQueue->FrontOfQueue;
+ DataEntry = *Previous;
+
+ while (DataEntry != NULL) {
+
+ //
+ // If the data entry contains an Irp and the irp is cancelled then
+ // we have some work do to
+ //
+
+ if ((DataEntry->Irp != NULL) && (DataEntry->Irp->Cancel)) {
+
+ DATA_ENTRY_TYPE DataEntryType;
+ FROM From;
+ PIRP Irp;
+ ULONG DataSize;
+ PVOID DataPointer;
+ PSECURITY_CLIENT_CONTEXT ClientContext;
+
+ //
+ // First remove this data entry from the queue
+ // Later we will fixup Data entry to the next entry
+ //
+
+ *Previous = DataEntry->Next;
+
+ //
+ // If the queue is now empty then we need to fix the queue
+ // state and end of queue pointer
+ //
+
+ if (DataQueue->FrontOfQueue == NULL) {
+
+ DataQueue->EndOfQueue = NULL;
+ DataQueue->QueueState = Empty;
+
+ //
+ // If we removed the last entry in the list then we need to update
+ // the end of the queue
+ //
+
+ } else if (DataEntry == DataQueue->EndOfQueue) {
+
+ DataQueue->EndOfQueue = (PDATA_ENTRY)Previous;
+ }
+
+ //
+ // Capture some of the fields from the data entry to make our
+ // other references a little easier
+ //
+
+ DataEntryType = DataEntry->DataEntryType;
+ From = DataEntry->From;
+ Irp = DataEntry->Irp;
+ DataSize = DataEntry->DataSize;
+ DataPointer = DataEntry->DataPointer;
+ ClientContext = DataEntry->SecurityClientContext;
+
+ //
+ // Check if we should delete the client context
+ //
+
+ if (ClientContext != NULL) {
+
+ SeDeleteClientSecurity( ClientContext );
+ ExFreePool( ClientContext );
+ }
+
+ //
+ // Check if we need to return pipe quota for a buffered entry.
+ //
+
+ if ((DataEntryType == Buffered) && (From == PipeQuota)) {
+
+ DataQueue->QuotaUsed -= DataSize;
+ }
+
+ //
+ // Update the data queue header information
+ //
+
+ DataQueue->BytesInQueue -= DataSize;
+ DataQueue->EntriesInQueue -= 1;
+
+ //
+ // Zero our the data entry
+ //
+
+ DataEntry->From = 0;
+ DataEntry->Next = 0;
+ DataEntry->Irp = 0;
+ DataEntry->DataSize = 0;
+ DataEntry->DataPointer = 0;
+
+ DataEntry->SecurityClientContext = NULL;
+
+ //
+ // If what we removed is in the front of the queue then we must
+ // reset the next byte offset
+ //
+
+ if (Previous == &DataQueue->FrontOfQueue) {
+
+ DataQueue->NextByteOffset = 0;
+ }
+
+ //
+ // Finally complete the request saying that it has been cancelled.
+ //
+
+ NpCompleteRequest( Irp, STATUS_CANCELLED );
+
+ //
+ // And because the data entry is gone we now need to reset
+ // it so we can continue our while loop
+ //
+
+ DataEntry = *Previous;
+
+ } else {
+
+ //
+ // Skip over to the next data entry
+ //
+
+ Previous = &DataEntry->Next;
+ DataEntry = DataEntry->Next;
+ }
+ }
+
+ } finally {
+
+ if (DeviceObject != (PVOID)0x1) { NpReleaseVcb(); }
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return;
+}
diff --git a/private/ntos/npfs/deviosup.c b/private/ntos/npfs/deviosup.c
new file mode 100644
index 000000000..e476f860b
--- /dev/null
+++ b/private/ntos/npfs/deviosup.c
@@ -0,0 +1,141 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ DevIoSup.c
+
+Abstract:
+
+ This module implements the memory locking routines for Npfs.
+
+Author:
+
+ Brian Andrew [BrianAn] 03-Apr-1991
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// Local debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_DEVIOSUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpLockUserBuffer)
+#pragma alloc_text(PAGE, NpMapUserBuffer)
+#endif
+
+
+PVOID
+NpMapUserBuffer (
+ IN OUT PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine conditionally maps the user buffer for the current I/O
+ request in the specified mode. If the buffer is already mapped, it
+ just returns its address.
+
+Arguments:
+
+ Irp - Pointer to the Irp for the request.
+
+Return Value:
+
+ Mapped address
+
+--*/
+
+{
+ PAGED_CODE();
+
+ //
+ // If there is no Mdl, then we must be in the Fsd, and we can simply
+ // return the UserBuffer field from the Irp.
+ //
+
+ if (Irp->MdlAddress == NULL) {
+
+ return Irp->UserBuffer;
+
+ } else {
+
+ return MmGetSystemAddressForMdl( Irp->MdlAddress );
+ }
+}
+
+
+VOID
+NpLockUserBuffer (
+ IN OUT PIRP Irp,
+ IN LOCK_OPERATION Operation,
+ IN ULONG BufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine locks the specified buffer for the specified type of
+ access. The file system requires this routine since it does not
+ ask the I/O system to lock its buffers for direct I/O. This routine
+ may only be called from the Fsd while still in the user context.
+
+Arguments:
+
+ Irp - Pointer to the Irp for which the buffer is to be locked.
+
+ Operation - IoWriteAccess for read operations, or IoReadAccess for
+ write operations.
+
+ BufferLength - Length of user buffer.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PMDL Mdl;
+
+ PAGED_CODE();
+
+ if (Irp->MdlAddress == NULL) {
+
+ //
+ // This read is bound for the current process. Perform the
+ // same functions as above, only do not switch processes.
+ //
+
+ Mdl = IoAllocateMdl( Irp->UserBuffer, BufferLength, FALSE, TRUE, Irp );
+
+ if (Mdl == NULL) {
+
+ ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
+ }
+
+ try {
+
+ MmProbeAndLockPages( Mdl,
+ Irp->RequestorMode,
+ Operation );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ IoFreeMdl( Mdl );
+ Irp->MdlAddress = NULL;
+ ExRaiseStatus( FsRtlNormalizeNtstatus( GetExceptionCode(),
+ STATUS_INVALID_USER_BUFFER ));
+ }
+ }
+}
diff --git a/private/ntos/npfs/dir.c b/private/ntos/npfs/dir.c
new file mode 100644
index 000000000..ec660c487
--- /dev/null
+++ b/private/ntos/npfs/dir.c
@@ -0,0 +1,882 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Dir.c
+
+Abstract:
+
+ This module implements the File Directory routines for the Named Pipe
+ file system by the dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 28-Dec-1989
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (NPFS_BUG_CHECK_DIR)
+
+//
+// Local debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_DIR)
+
+NTSTATUS
+NpCommonDirectoryControl (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpQueryDirectory (
+ IN PROOT_DCB RootDcb,
+ IN PROOT_DCB_CCB Ccb,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpNotifyChangeDirectory (
+ IN PROOT_DCB RootDcb,
+ IN PROOT_DCB_CCB Ccb,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCheckForNotify)
+#pragma alloc_text(PAGE, NpCommonDirectoryControl)
+#pragma alloc_text(PAGE, NpFsdDirectoryControl)
+#pragma alloc_text(PAGE, NpNotifyChangeDirectory)
+#pragma alloc_text(PAGE, NpQueryDirectory)
+#endif
+
+
+NTSTATUS
+NpFsdDirectoryControl (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the FSD routine that handles directory control
+ functions (i.e., query and notify).
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object for the directory function.
+
+ Irp - Supplies the IRP to process
+
+Return Value:
+
+ NTSTATUS - The appropriate result status
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdDirectoryControl\n", 0);
+
+ //
+ // Call the common Direcotry Control routine.
+ //
+
+ FsRtlEnterFileSystem();
+ NpAcquireExclusiveVcb( );
+
+ try {
+
+ Status = NpCommonDirectoryControl( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdDirectoryControl -> %08lx\n", Status );
+
+ return Status;
+}
+
+VOID
+NpCheckForNotify (
+ IN PDCB Dcb,
+ IN BOOLEAN CheckAllOutstandingIrps
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the notify queues of a dcb and completes any
+ outstanding IRPS.
+
+ Note that the caller of this procedure must guarantee that the DCB
+ is acquired for exclusive access.
+
+Arguments:
+
+ Dcb - Supplies the Dcb to check if is has any notify Irps outstanding
+
+ CheckAllOutstandingIrps - Indicates if only the NotifyFullQueue should be
+ checked. If TRUE then all notify queues are checked, and if FALSE
+ then only the NotifyFullQueue is checked.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY Links;
+ PIRP Irp;
+
+ PAGED_CODE();
+
+ //
+ // We'll always signal the notify full queue entries. They want
+ // to be notified if every any change is made to a directory
+ //
+
+ while (!IsListEmpty( &Dcb->Specific.Dcb.NotifyFullQueue )) {
+
+ //
+ // Remove the Irp from the head of the queue, and complete it
+ // with success.
+ //
+
+ Links = RemoveHeadList( &Dcb->Specific.Dcb.NotifyFullQueue );
+
+ Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ }
+
+ //
+ // Now check if we should also do the partial notify queue.
+ //
+
+ if (CheckAllOutstandingIrps) {
+
+ while (!IsListEmpty( &Dcb->Specific.Dcb.NotifyPartialQueue )) {
+
+ //
+ // Remove the Irp from the head of the queue, and complete it
+ // with success.
+ //
+
+ Links = RemoveHeadList( &Dcb->Specific.Dcb.NotifyPartialQueue );
+
+ Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ }
+ }
+
+ return;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpCommonDirectoryControl (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the common code for directory control functions.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the named pipe device object
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PIO_STACK_LOCATION IrpSp;
+
+ PFCB Fcb;
+ PROOT_DCB_CCB Ccb;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonDirectoryControl...\n", 0);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is not the root dcb then its an illegal parameter.
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject,
+ &Fcb,
+ (PCCB *)&Ccb,
+ NULL ) != NPFS_NTC_ROOT_DCB) {
+
+ DebugTrace(0, Dbg, "Not a directory\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ Status = STATUS_INVALID_PARAMETER;
+
+ DebugTrace(-1, Dbg, "NpCommonDirectoryControl -> %08lx\n", Status );
+ return Status;
+ }
+
+ //
+ // We know this is a directory control so we'll case on the
+ // minor function, and call the appropriate work routines.
+ //
+
+ switch (IrpSp->MinorFunction) {
+
+ case IRP_MN_QUERY_DIRECTORY:
+
+ Status = NpQueryDirectory( Fcb, Ccb, Irp );
+ break;
+
+ case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
+
+ Status = NpNotifyChangeDirectory( Fcb, Ccb, Irp );
+ break;
+
+ default:
+
+ //
+ // For all other minor function codes we say they're invalid
+ // and complete the request.
+ //
+
+ DebugTrace(0, DEBUG_TRACE_ERROR, "Invalid FS Control Minor Function Code %08lx\n", IrpSp->MinorFunction);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_DEVICE_REQUEST );
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ DebugTrace(-1, Dbg, "NpCommonDirectoryControl -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryDirectory (
+ IN PROOT_DCB RootDcb,
+ IN PROOT_DCB_CCB Ccb,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the work routine for querying a directory.
+
+Arugments:
+
+ RootDcb - Supplies the dcb being queried
+
+ Ccb - Supplies the context of the caller
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The return status for the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ PUCHAR Buffer;
+ CLONG SystemBufferLength;
+
+ UNICODE_STRING FileName;
+ ULONG FileIndex;
+ FILE_INFORMATION_CLASS FileInformationClass;
+ BOOLEAN RestartScan;
+ BOOLEAN ReturnSingleEntry;
+ BOOLEAN IndexSpecified;
+
+ static WCHAR Star = L'*';
+
+ BOOLEAN CaseInsensitive = TRUE; //*** Make searches case insensitive
+
+ ULONG CurrentIndex;
+
+ ULONG LastEntry;
+ ULONG NextEntry;
+
+ PLIST_ENTRY Links;
+ PFCB Fcb;
+
+ PFILE_DIRECTORY_INFORMATION DirInfo;
+ PFILE_NAMES_INFORMATION NamesInfo;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpQueryDirectory\n", 0 );
+ DebugTrace( 0, Dbg, "RootDcb = %08lx\n", RootDcb);
+ DebugTrace( 0, Dbg, "Ccb = %08lx\n", Ccb);
+ DebugTrace( 0, Dbg, "SystemBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
+ DebugTrace( 0, Dbg, "Length = %08lx\n", IrpSp->Parameters.QueryDirectory.Length);
+ DebugTrace( 0, Dbg, "FileName = %Z\n", IrpSp->Parameters.QueryDirectory.FileName);
+ DebugTrace( 0, Dbg, "FileIndex = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex);
+ DebugTrace( 0, Dbg, "FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
+ DebugTrace( 0, Dbg, "RestartScan = %08lx\n", FlagOn(IrpSp->Flags, SL_RESTART_SCAN));
+ DebugTrace( 0, Dbg, "ReturnSingleEntry = %08lx\n", FlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY));
+ DebugTrace( 0, Dbg, "IndexSpecified = %08lx\n", FlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED));
+
+ //
+ // Save references to the input parameters within the Irp
+ //
+
+ SystemBufferLength = IrpSp->Parameters.QueryDirectory.Length;
+
+ FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
+
+ FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
+
+ RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
+ ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
+ IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
+
+ if (IrpSp->Parameters.QueryDirectory.FileName != NULL) {
+
+ FileName = *(PUNICODE_STRING)IrpSp->Parameters.QueryDirectory.FileName;
+
+ } else {
+
+ FileName.Length = 0;
+ FileName.Buffer = NULL;
+ }
+
+ //
+ // Check if the ccb already has a query template attached. If it
+ // does not already have one then we either use the string we are
+ // given or we attach our own containing "*"
+ //
+
+ if (Ccb->QueryTemplate == NULL) {
+
+ //
+ // This is our first time calling query directory so we need
+ // to either set the query template to the user specified string
+ // or to "*"
+ //
+
+ if (FileName.Buffer == NULL) {
+
+ DebugTrace(0, Dbg, "Set template to *\n", 0);
+
+ FileName.Length = 2;
+ FileName.Buffer = &Star;
+ }
+
+ DebugTrace(0, Dbg, "Set query template -> %Z\n", &FileName);
+
+ //
+ // Allocate space for the query template
+ //
+
+ Ccb->QueryTemplate = FsRtlAllocatePool( PagedPool,
+ sizeof(UNICODE_STRING) + FileName.Length );
+
+ //
+ // Initialize the query template and copy over the string
+ //
+
+ Ccb->QueryTemplate->Length = FileName.Length;
+ Ccb->QueryTemplate->Buffer = (PWCH)Ccb->QueryTemplate +
+ sizeof(UNICODE_STRING) / sizeof(WCHAR);
+
+ RtlCopyMemory( Ccb->QueryTemplate->Buffer,
+ FileName.Buffer,
+ FileName.Length );
+
+ //
+ // Now zero out the FileName so we won't think we're to use it
+ // as a subsearch string.
+ //
+
+ FileName.Length = 0;
+ FileName.Buffer = NULL;
+ }
+
+ //
+ // Check if we were given an index to start with or if we need to
+ // restart the scan or if we should use the index that was saved in
+ // the ccb
+ //
+
+ if (RestartScan) {
+
+ FileIndex = 0;
+
+ } else if (!IndexSpecified) {
+
+ FileIndex = Ccb->IndexOfLastCcbReturned + 1;
+ }
+
+ //
+ // Now we are committed to completing the Irp, we do that in
+ // the finally clause of the following try.
+ //
+
+ try {
+
+ ULONG BaseLength;
+ ULONG LengthAdded;
+
+ //
+ // Map the user buffer.
+ //
+
+ Buffer = NpMapUserBuffer( Irp );
+
+ //
+ // At this point we are about to enter our query loop. We have
+ // already decided which Fcb index we need to return. The variables
+ // LastEntry and NextEntry are used to index into the user buffer.
+ // LastEntry is the last entry we added to the user buffer, and
+ // NextEntry is the current one we're working on. CurrentIndex
+ // is the Fcb index that we are looking at next. Logically the
+ // way the loop works is as follows.
+ //
+ // Scan all of the Fcb in the directory
+ //
+ // if the Fcb matches the query template then
+ //
+ // if the CurrentIndex is >= the FileIndex then
+ //
+ // process this fcb, and decide if we should
+ // continue the main loop
+ //
+ // end if
+ //
+ // Increment the current index
+ //
+ // end if
+ //
+ // end scan
+ //
+
+ CurrentIndex = 0;
+
+ LastEntry = 0;
+ NextEntry =0;
+
+ switch (FileInformationClass) {
+
+ case FileDirectoryInformation:
+
+ BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
+ FileName[0] );
+ break;
+
+ case FileFullDirectoryInformation:
+
+ BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
+ FileName[0] );
+ break;
+
+ case FileNamesInformation:
+
+ BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
+ FileName[0] );
+ break;
+
+ case FileBothDirectoryInformation:
+
+ BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
+ FileName[0] );
+ break;
+
+ default:
+
+ try_return( Status = STATUS_INVALID_INFO_CLASS );
+ }
+
+ for (Links = RootDcb->Specific.Dcb.ParentDcbQueue.Flink;
+ Links != &RootDcb->Specific.Dcb.ParentDcbQueue;
+ Links = Links->Flink) {
+
+ Fcb = CONTAINING_RECORD(Links, FCB, ParentDcbLinks);
+
+ ASSERT(Fcb->NodeTypeCode == NPFS_NTC_FCB);
+
+ DebugTrace(0, Dbg, "Top of Loop\n", 0);
+ DebugTrace(0, Dbg, "Fcb = %08lx\n", Fcb);
+ DebugTrace(0, Dbg, "CurrentIndex = %08lx\n", CurrentIndex);
+ DebugTrace(0, Dbg, "FileIndex = %08lx\n", FileIndex);
+ DebugTrace(0, Dbg, "LastEntry = %08lx\n", LastEntry);
+ DebugTrace(0, Dbg, "NextEntry = %08lx\n", NextEntry);
+
+ //
+ // Check if the Fcb represents a named pipe that is part of
+ // our query template
+ //
+
+ if (FsRtlIsNameInExpression( Ccb->QueryTemplate,
+ &Fcb->LastFileName,
+ CaseInsensitive,
+ NULL )) {
+
+ //
+ // The fcb is in the query template so now check if
+ // this is the index we should start returning
+ //
+
+ if (CurrentIndex >= FileIndex) {
+
+ ULONG BytesToCopy;
+ ULONG BytesRemainingInBuffer;
+
+ //
+ // Here are the rules concerning filling up the buffer:
+ //
+ // 1. The Io system garentees that there will always be
+ // enough room for at least one base record.
+ //
+ // 2. If the full first record (including file name) cannot
+ // fit, as much of the name as possible is copied and
+ // STATUS_BUFFER_OVERFLOW is returned.
+ //
+ // 3. If a subsequent record cannot completely fit into the
+ // buffer, none of it (as in 0 bytes) is copied, and
+ // STATUS_SUCCESS is returned. A subsequent query will
+ // pick up with this record.
+ //
+
+ BytesRemainingInBuffer = SystemBufferLength - NextEntry;
+
+ if ( (NextEntry != 0) &&
+ ( (BaseLength + Fcb->LastFileName.Length > BytesRemainingInBuffer) ||
+ (SystemBufferLength < NextEntry) ) ) {
+
+ DebugTrace(0, Dbg, "Next entry won't fit\n", 0);
+
+ try_return( Status = STATUS_SUCCESS );
+ }
+
+ ASSERT( BytesRemainingInBuffer >= BaseLength );
+
+ //
+ // See how much of the name we will be able to copy into
+ // the system buffer. This also dictates out return
+ // value.
+ //
+
+ if ( BaseLength + Fcb->LastFileName.Length <=
+ BytesRemainingInBuffer ) {
+
+ BytesToCopy = Fcb->LastFileName.Length;
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ BytesToCopy = BytesRemainingInBuffer - BaseLength;
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ //
+ // Note how much of buffer we are consuming and zero
+ // the base part of the structure.
+ //
+
+ LengthAdded = BaseLength + BytesToCopy;
+
+ RtlZeroMemory( &Buffer[NextEntry], BaseLength );
+
+ //
+ // Now fill the base parts of the strucure that are
+ // applicable.
+ //
+
+ switch (FileInformationClass) {
+
+ case FileBothDirectoryInformation:
+
+ //
+ // We don't need short name
+ //
+
+ DebugTrace(0, Dbg, "Getting directory full information\n", 0);
+
+ case FileFullDirectoryInformation:
+
+ //
+ // We don't use EaLength, so fill in nothing here.
+ //
+
+ DebugTrace(0, Dbg, "Getting directory full information\n", 0);
+
+ case FileDirectoryInformation:
+
+ DebugTrace(0, Dbg, "Getting directory information\n", 0);
+
+ //
+ // The eof indicates the number of instances and
+ // allocation size is the maximum allowed
+ //
+
+ DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];
+
+ DirInfo->EndOfFile.QuadPart = Fcb->OpenCount;
+ DirInfo->AllocationSize.QuadPart = Fcb->Specific.Fcb.MaximumInstances;
+
+ DirInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;
+
+ DirInfo->FileNameLength = Fcb->LastFileName.Length;
+
+ break;
+
+ case FileNamesInformation:
+
+ DebugTrace(0, Dbg, "Getting names information\n", 0);
+
+
+ NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];
+
+ NamesInfo->FileNameLength = Fcb->LastFileName.Length;
+
+ break;
+
+ default:
+
+ NpBugCheck( FileInformationClass, 0, 0 );
+ }
+
+ RtlCopyMemory( &Buffer[NextEntry + BaseLength],
+ Fcb->LastFileName.Buffer,
+ BytesToCopy );
+
+ //
+ // Update the ccb to the index we've just used
+ //
+
+ Ccb->IndexOfLastCcbReturned = CurrentIndex;
+
+ //
+ // And indicate how much of the system buffer we have
+ // currently used up. We must compute this value before
+ // we long align outselves for the next entry
+ //
+
+ Irp->IoStatus.Information = NextEntry + LengthAdded;
+
+ //
+ // Setup the previous next entry offset
+ //
+
+ *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;
+
+ //
+ // Check if the last entry didn't completely fit
+ //
+
+ if ( Status == STATUS_BUFFER_OVERFLOW ) {
+
+ try_return( NOTHING );
+ }
+
+ //
+ // Check if we are only to return a single entry
+ //
+
+ if (ReturnSingleEntry) {
+
+ try_return( Status = STATUS_SUCCESS );
+ }
+
+ //
+ // Set ourselves up for the next iteration
+ //
+
+ LastEntry = NextEntry;
+ NextEntry += (ULONG)QuadAlign( LengthAdded );
+ }
+
+ //
+ // Increment the current index by one
+ //
+
+ CurrentIndex += 1;
+ }
+ }
+
+ //
+ // At this point we've scanned the entire list of Fcb so if
+ // the NextEntry is zero then we haven't found anything so we
+ // will return no more files, otherwise we return success.
+ //
+
+ if (NextEntry == 0) {
+
+ Status = STATUS_NO_MORE_FILES;
+
+ } else {
+
+ Status = STATUS_SUCCESS;
+ }
+
+ try_exit: NOTHING;
+ } finally {
+
+ if (!AbnormalTermination()) {
+
+ NpCompleteRequest( Irp, Status );
+ }
+
+ DebugTrace(-1, Dbg, "NpQueryDirectory -> %08lx\n", Status);
+ }
+
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpNotifyChangeDirectory (
+ IN PROOT_DCB RootDcb,
+ IN PROOT_DCB_CCB Ccb,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for doing the notify change directory.
+
+Arugments:
+
+ RootDcb - Supplies the dcb being queried
+
+ Ccb - Supplies the context of the caller
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - STATUS_PENDING
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+
+ UNREFERENCED_PARAMETER( Ccb );
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpNotifyChangeDirectory\n", 0 );
+ DebugTrace( 0, Dbg, "RootDcb = %08lx", RootDcb);
+ DebugTrace( 0, Dbg, "Ccb = %08lx", Ccb);
+
+ //
+ // Mark the Irp pending.
+ //
+
+ IoMarkIrpPending( Irp );
+
+ //
+ // BUGBUG - For now, simply place the packet on one of the old queues,
+ // full or partial, based on whether or not changes to anything
+ // other than names were requested. In the future, the filter
+ // must actually be implemented.
+ //
+
+ if (IrpSp->Parameters.NotifyDirectory.CompletionFilter &
+ ~FILE_NOTIFY_CHANGE_NAME) {
+
+ InsertTailList( &RootDcb->Specific.Dcb.NotifyFullQueue,
+ &Irp->Tail.Overlay.ListEntry );
+
+ } else {
+
+ InsertTailList( &RootDcb->Specific.Dcb.NotifyPartialQueue,
+ &Irp->Tail.Overlay.ListEntry );
+ }
+
+ //
+ // return to our caller a value of status pending
+ //
+
+ DebugTrace(-1, Dbg, "NpNotifyChangeDirectory -> STATUS_PENDING\n", 0);
+
+ return STATUS_PENDING;
+}
diff --git a/private/ntos/npfs/dumpsup.c b/private/ntos/npfs/dumpsup.c
new file mode 100644
index 000000000..54a7aa35a
--- /dev/null
+++ b/private/ntos/npfs/dumpsup.c
@@ -0,0 +1,491 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ DumpSup.c
+
+Abstract:
+
+ This module implements a collection of data structure dump routines
+ for debugging the Named Pipe file system
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+#ifdef NPDBG
+
+VOID NpDumpEventTableEntry(IN PEVENT_TABLE_ENTRY Ptr);
+VOID NpDumpDataQueue(IN PDATA_QUEUE Ptr);
+VOID NpDumpDataEntry(IN PDATA_ENTRY Ptr);
+
+VOID NpDump(IN PVOID Ptr);
+VOID NpDumpVcb(IN PVCB Ptr);
+VOID NpDumpRootDcb(IN PROOT_DCB Ptr);
+VOID NpDumpFcb(IN PFCB Ptr);
+VOID NpDumpCcb(IN PCCB Ptr);
+VOID NpDumpNonpagedCcb(IN PNONPAGED_CCB Ptr);
+VOID NpDumpRootDcbCcb(IN PROOT_DCB_CCB Ptr);
+
+ULONG NpDumpCurrentColumn;
+
+#define DumpNewLine() { \
+ DbgPrint("\n"); \
+ NpDumpCurrentColumn = 1; \
+}
+
+#define DumpLabel(Label,Width) { \
+ ULONG i; \
+ CHAR _Str[20]; \
+ for(i=0;i<2;i++) { _Str[i] = UCHAR_SP;} \
+ strncpy(&_Str[2],#Label,Width); \
+ for(i=strlen(_Str);i<Width;i++) {_Str[i] = UCHAR_SP;} \
+ _Str[Width] = '\0'; \
+ DbgPrint("%s", _Str); \
+}
+
+#define DumpField(Field) { \
+ if ((NpDumpCurrentColumn + 18 + 9 + 9) > 80) {DumpNewLine();} \
+ NpDumpCurrentColumn += 18 + 9 + 9; \
+ DumpLabel(Field,18); \
+ DbgPrint(":%8lx", Ptr->Field); \
+ DbgPrint(" "); \
+}
+
+#define DumpListEntry(Links) { \
+ if ((NpDumpCurrentColumn + 18 + 9 + 9) > 80) {DumpNewLine();} \
+ NpDumpCurrentColumn += 18 + 9 + 9; \
+ DumpLabel(Links,18); \
+ DbgPrint(":%8lx", Ptr->Links.Flink); \
+ DbgPrint(":%8lx", Ptr->Links.Blink); \
+}
+
+#define DumpName(Field,Width) { \
+ ULONG i; \
+ WCHAR _String[64]; \
+ if ((NpDumpCurrentColumn + 18 + Width) > 80) {DumpNewLine();} \
+ NpDumpCurrentColumn += 18 + Width; \
+ DumpLabel(Field,18); \
+ for(i=0;i<Width/2;i++) {_String[i] = Ptr->Field[i];} \
+ _String[Width] = '\0'; \
+ DbgPrint("%s", _String); \
+}
+
+#define TestForNull(Name) { \
+ if (Ptr == NULL) { \
+ DbgPrint("%s - Cannot dump a NULL pointer\n", Name); \
+ return; \
+ } \
+}
+
+
+VOID NpDumpEventTableEntry (
+ IN PEVENT_TABLE_ENTRY Ptr
+ )
+
+{
+ TestForNull ("NpDumpEventTableEntry");
+
+ DumpNewLine ();
+ DbgPrint ("EventTableEntry@ %08lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (Ccb);
+ DumpField (NamedPipeEnd);
+ DumpField (EventHandle);
+ DumpField (Event);
+ DumpField (KeyValue);
+ DumpField (Process);
+ DumpNewLine ();
+
+ return;
+}
+
+
+VOID NpDumpDataQueue (
+ IN PDATA_QUEUE Ptr
+ )
+
+{
+ PDATA_ENTRY Entry;
+
+ TestForNull ("NpDumpDataQueue");
+
+ DumpNewLine ();
+ DbgPrint ("DataQueue@ %08lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (QueueState);
+ DumpField (BytesInQueue);
+ DumpField (EntriesInQueue);
+ DumpField (Quota);
+ DumpField (QuotaUsed);
+ DumpField (FrontOfQueue);
+ DumpField (EndOfQueue);
+ DumpField (NextByteOffset);
+ DumpNewLine ();
+
+ for (Entry = Ptr->FrontOfQueue;
+ Entry != NULL;
+ Entry = Entry->Next) {
+
+ NpDumpDataEntry( Entry );
+ }
+
+ return;
+}
+
+
+VOID NpDumpDataEntry (
+ IN PDATA_ENTRY Ptr
+ )
+
+{
+ TestForNull ("NpDumpDataEntry");
+
+ DumpNewLine ();
+ DbgPrint ("DataEntry@ %08lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (DataEntryType);
+ DumpField (From);
+ DumpField (Next);
+ DumpField (Irp);
+ DumpField (DataSize);
+ DumpField (DataPointer);
+ DumpField (SecurityClientContext);
+ DumpNewLine ();
+
+ return;
+}
+
+
+VOID NpDump (
+ IN PVOID Ptr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the type of internal record reference by ptr and
+ calls the appropriate dump routine.
+
+Arguments:
+
+ Ptr - Supplies the pointer to the record to be dumped
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ TestForNull("NpDump");
+
+ //
+ // We'll switch on the node type code
+ //
+
+ switch (NodeType(Ptr)) {
+
+ case NPFS_NTC_VCB: NpDumpVcb(Ptr); break;
+ case NPFS_NTC_ROOT_DCB: NpDumpRootDcb(Ptr); break;
+ case NPFS_NTC_FCB: NpDumpFcb(Ptr); break;
+ case NPFS_NTC_CCB: NpDumpCcb(Ptr); break;
+ case NPFS_NTC_NONPAGED_CCB: NpDumpNonpagedCcb(Ptr); break;
+ case NPFS_NTC_ROOT_DCB_CCB: NpDumpRootDcbCcb(Ptr); break;
+
+ default :
+ DbgPrint("NpDump - Unknown Node type code %8lx\n", *((PNODE_TYPE_CODE)(Ptr)));
+ break;
+ }
+
+ return;
+}
+
+
+VOID NpDumpVcb (
+ IN PVCB Ptr
+ )
+
+/*++
+
+Routine Description:
+
+ Dump an Vcb structure
+
+Arguments:
+
+ Ptr - Supplies the Device record to be dumped
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ TestForNull ("NpDumpVcb");
+
+ DumpNewLine ();
+ DbgPrint ("Vcb@ %lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (NodeTypeCode);
+ DumpField (NodeByteSize);
+ DumpField (RootDcb);
+ DumpField (OpenCount);
+ DumpField (OpenUnderlingCount);
+ DumpNewLine ();
+
+ NpDump (Ptr->RootDcb);
+
+ return;
+}
+
+
+VOID NpDumpRootDcb (
+ IN PROOT_DCB Ptr
+ )
+
+/*++
+
+Routine Description:
+
+ Dump a root dcb structure
+
+Arguments:
+
+ Ptr - Supplies the Root Dcb record to be dumped
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PLIST_ENTRY Links;
+
+ TestForNull ("NpDumpRootDcb");
+
+ DumpNewLine ();
+ DbgPrint ("RootDcb@ %lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (NodeTypeCode);
+ DumpField (NodeByteSize);
+ DumpListEntry (ParentDcbLinks);
+ DumpField (ParentDcb);
+ DumpField (OpenCount);
+ DumpField (FullFileName.Length);
+ DumpField (FullFileName.Buffer);
+ DumpName (FullFileName.Buffer, 32);
+ DumpField (LastFileName.Length);
+ DumpField (LastFileName.Buffer);
+ DumpListEntry (Specific.Dcb.NotifyFullQueue);
+ DumpListEntry (Specific.Dcb.NotifyPartialQueue);
+ DumpListEntry (Specific.Dcb.ParentDcbQueue);
+ DumpNewLine ();
+
+ for (Links = Ptr->Specific.Dcb.ParentDcbQueue.Flink;
+ Links != &Ptr->Specific.Dcb.ParentDcbQueue;
+ Links = Links->Flink) {
+ NpDump(CONTAINING_RECORD(Links, FCB, ParentDcbLinks));
+ }
+
+ return;
+}
+
+
+VOID NpDumpFcb (
+ IN PFCB Ptr
+ )
+
+/*++
+
+Routine Description:
+
+ Dump an Fcb structure
+
+Arguments:
+
+ Ptr - Supplies the Fcb record to be dumped
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PLIST_ENTRY Links;
+
+ TestForNull ("NpDumpFcb");
+
+ DumpNewLine ();
+ DbgPrint ("Fcb@ %lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (NodeTypeCode);
+ DumpField (NodeByteSize);
+ DumpListEntry (ParentDcbLinks);
+ DumpField (ParentDcb);
+ DumpField (OpenCount);
+ DumpField (FullFileName.Length);
+ DumpField (FullFileName.Buffer);
+ DumpName (FullFileName.Buffer, 32);
+ DumpField (LastFileName.Length);
+ DumpField (LastFileName.Buffer);
+ DumpField (Specific.Fcb.NamedPipeConfiguration);
+ DumpField (Specific.Fcb.NamedPipeType);
+ DumpField (Specific.Fcb.MaximumInstances);
+ DumpField (Specific.Fcb.DefaultTimeOut.LowPart);
+ DumpField (Specific.Fcb.DefaultTimeOut.HighPart);
+ DumpListEntry (Specific.Fcb.CcbQueue);
+ DumpNewLine ();
+
+ for (Links = Ptr->Specific.Fcb.CcbQueue.Flink;
+ Links != &Ptr->Specific.Fcb.CcbQueue;
+ Links = Links->Flink) {
+ NpDump(CONTAINING_RECORD(Links, CCB, CcbLinks));
+ }
+
+ return;
+}
+
+
+VOID NpDumpCcb (
+ IN PCCB Ptr
+ )
+
+/*++
+
+Routine Description:
+
+ Dump a Ccb structure
+
+Arguments:
+
+ Ptr - Supplies the Ccb record to be dumped
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ TestForNull ("NpDumpCcb");
+
+ DumpNewLine ();
+ DbgPrint ("Ccb@ %lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (NodeTypeCode);
+ DumpField (NodeByteSize);
+ DumpField (Fcb);
+ DumpField (FileObject[0]);
+ DumpField (FileObject[1]);
+ DumpField (NamedPipeState);
+ DumpField (ReadMode[0]);
+ DumpField (ReadMode[1]);
+ DumpField (CompletionMode[0]);
+ DumpField (CompletionMode[1]);
+ DumpField (CreatorProcess);
+ DumpField (SecurityClientContext);
+ DumpNewLine ();
+
+ NpDumpDataQueue(&Ptr->DataQueue[0]);
+ NpDumpDataQueue(&Ptr->DataQueue[1]);
+
+ NpDump (Ptr->NonpagedCcb);
+
+ return;
+}
+
+
+VOID NpDumpNonpagedCcb (
+ IN PNONPAGED_CCB Ptr
+ )
+
+/*++
+
+Routine Description:
+
+ Dump a Nonpaged Ccb structure
+
+Arguments:
+
+ Ptr - Supplies the Nonpaged Ccb record to be dumped
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ TestForNull ("NpDumpNonpagedCcb");
+
+ DumpNewLine ();
+ DbgPrint ("NonpagedCcb@ %lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (NodeTypeCode);
+ DumpField (NodeByteSize);
+ DumpField (EventTableEntry[0]);
+ DumpField (EventTableEntry[1]);
+ DumpListEntry (ListeningQueue);
+ DumpNewLine ();
+
+ return;
+}
+
+
+VOID NpDumpRootDcbCcb (
+ IN PROOT_DCB_CCB Ptr
+ )
+
+/*++
+
+Routine Description:
+
+ Dump a Root Dcb Ccb structure
+
+Arguments:
+
+ Ptr - Supplies the Root Dcb Ccb record to be dumped
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ TestForNull ("NpDumpRootDcbCcb");
+
+ DumpNewLine ();
+ DbgPrint ("RootDcbCcb@ %lx", (Ptr));
+ DumpNewLine ();
+
+ DumpField (NodeTypeCode);
+ DumpField (NodeByteSize);
+ DumpField (IndexOfLastCcbReturned);
+ DumpNewLine ();
+
+ return;
+}
+
+#endif // NPDBG
diff --git a/private/ntos/npfs/eventsup.c b/private/ntos/npfs/eventsup.c
new file mode 100644
index 000000000..438fde7da
--- /dev/null
+++ b/private/ntos/npfs/eventsup.c
@@ -0,0 +1,391 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ EventSup.c
+
+Abstract:
+
+ This module implements the Named Pipe Event support routines.
+
+Author:
+
+ Gary Kimura [GaryKi] 30-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_EVENTSUP)
+
+
+//
+// Local procedures
+//
+
+
+PEVENT_TABLE_ENTRY
+NpAddEventTableEntry (
+ IN PEVENT_TABLE EventTable,
+ IN PCCB Ccb,
+ IN NAMED_PIPE_END NamedPipeEnd,
+ IN HANDLE EventHandle,
+ IN ULONG KeyValue,
+ IN PEPROCESS Process,
+ IN KPROCESSOR_MODE PreviousMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a new entry into the event table. If an entry already
+ exists it overwrites the existing entry.
+
+Arguments:
+
+ EventTable - Supplies the event table being modified
+
+ Ccb - Supplies a pointer to the ccb to store in event table entry
+
+ NamedPipeEnd - Indicates the server or client end for the event
+
+ EventHandle - Supplies the handle to the event being added. The object
+ is referenced by this procedure
+
+ KeyValue - Supplies a key value to associate with the event
+
+ Process - Supplies a pointer to the process adding the event
+
+ PreviousMode - Supplies the mode of the user initiating the action
+
+Return Value:
+
+ PEVENT_TABLE_ENTRY - Returns a pointer to the newly added event.
+ This is an actual pointer to the table entry.
+
+ This procedure also will raise status if the event handle cannot be
+ accessed by the caller
+
+--*/
+
+{
+ NTSTATUS Status;
+ KIRQL OldIrql;
+
+ EVENT_TABLE_ENTRY Template;
+ PEVENT_TABLE_ENTRY EventTableEntry;
+ PVOID Event;
+
+ DebugTrace(+1, Dbg, "NpAddEventTableEntry, EventTable = %08lx\n", EventTable);
+
+ //
+ // Reference the event object by handle.
+ //
+
+ if (!NT_SUCCESS(Status = ObReferenceObjectByHandle( EventHandle,
+ EVENT_MODIFY_STATE,
+ NULL,
+ PreviousMode,
+ &Event,
+ NULL ))) {
+
+ ExRaiseStatus( Status );
+ }
+
+ //
+ // Set up the template event entry to lookup
+ //
+
+ Template.Ccb = Ccb;
+ Template.NamedPipeEnd = NamedPipeEnd;
+ Template.EventHandle = EventHandle;
+ Template.Event = Event;
+ Template.KeyValue = KeyValue;
+ Template.Process = Process;
+
+ //
+ // Now insert this new entry into the event table
+ //
+
+ EventTableEntry = RtlInsertElementGenericTable( &EventTable->Table,
+ &Template,
+ sizeof(EVENT_TABLE_ENTRY),
+ NULL );
+
+ //
+ // Copy over the template again just in case we were given an
+ // old entry
+ //
+
+ *EventTableEntry = Template;
+
+ DebugTrace(-1, Dbg, "NpAddEventTableEntry -> %08lx\n", EventTableEntry);
+
+ //
+ // And now return to our caller
+ //
+
+ return EventTableEntry;
+}
+
+
+VOID
+NpDeleteEventTableEntry (
+ IN PEVENT_TABLE EventTable,
+ IN PEVENT_TABLE_ENTRY Template
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes an entry from the event table, it also dereferences
+ the event object that was referenced when the object was inserted
+
+Arguments:
+
+ EventTable - Supplies a pointer to the event table being modified
+
+ Template - Supplies a copy of the event table entry we are lookin up.
+ Note that this can also be a pointer to the actual event table entry.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ DebugTrace(+1, Dbg, "NpDeleteEventTableEntry, EventTable = %08lx\n", EventTable);
+
+ //
+ // Only do the work if we are given a non null template
+ //
+
+ if (!ARGUMENT_PRESENT(Template)) {
+
+ DebugTrace(-1, Dbg, "NpDeleteEventTableEntry -> VOID\n", 0);
+
+ return;
+ }
+
+ //
+ // Dereference the event object
+ //
+
+ ObDereferenceObject(Template->Event);
+
+ //
+ // Now remove this element from the generic table
+ //
+
+ (VOID)RtlDeleteElementGenericTable( &EventTable->Table,
+ Template );
+
+ DebugTrace(-1, Dbg, "NpDeleteEventTableEntry -> VOID\n", 0);
+
+ //
+ // And now return to our caller
+ //
+
+ return;
+}
+
+
+PEVENT_TABLE_ENTRY
+NpGetNextEventTableEntry (
+ IN PEVENT_TABLE EventTable,
+ IN PVOID *RestartKey
+ )
+
+/*++
+
+Routine Description:
+
+ This routine enumerates the events stored within an event table.
+
+Arguments:
+
+ EventTable - Supplies a pointer to the event being enumerated
+
+ Restart - Indicates if the enumeration should restart or continue
+
+Return Value:
+
+ PEVENT_TABLE_ENTRY - Returns a pointer to the next event table entry
+ in the table, or NULL if the enumeration is complete.
+
+--*/
+
+{
+ KIRQL OldIrql;
+ PEVENT_TABLE_ENTRY EventTableEntry;
+
+ DebugTrace(+1, Dbg, "NpGetNextEventTableEntry, EventTable = %08lx\n", EventTable);
+
+ //
+ // Lookup the next element in the table
+ //
+
+ EventTableEntry = RtlEnumerateGenericTableWithoutSplaying( &EventTable->Table, RestartKey );
+
+ DebugTrace(-1, Dbg, "NpGetNextEventTableEntry -> %08lx\n", EventTableEntry);
+
+ //
+ // And now return to our caller
+ //
+
+ return EventTableEntry;
+}
+
+
+//
+// Local support routines
+//
+
+RTL_GENERIC_COMPARE_RESULTS
+NpEventTableCompareRoutine (
+ IN PRTL_GENERIC_TABLE EventTable,
+ IN PVOID FirstStruct,
+ IN PVOID SecondStruct
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the comparsion routine for the Event Table which is
+ implemented as a generic table.
+
+Arguments:
+
+ EventTable - Supplies a pointer to the event table which is involved
+ in this action
+
+ FirstStruct - Supplies a pointer to the first event table entry to examine
+
+ SecondStruct - Supplies a pointer to the second event table entry to
+ examine
+
+Return Value:
+
+ RTL_GENERIC_COMPARE_RESULTS - GenericLessThan if FirstEntry is less than
+ SecondEntry, GenericGreaterThan if FirstEntry is greater than
+ SecondEntry, and GenericEqual otherwise.
+
+--*/
+
+{
+ PEVENT_TABLE_ENTRY FirstEntry = FirstStruct;
+ PEVENT_TABLE_ENTRY SecondEntry = SecondStruct;
+
+ UNREFERENCED_PARAMETER( EventTable );
+
+ //
+ // We'll compare first the pointer to the ccb and then compare the
+ // pipe end types. This will guarantee a unique ordering based on
+ // the pipe instance and pipe end (i.e., server and client end).
+ //
+
+ if (FirstEntry->Ccb < SecondEntry->Ccb) {
+
+ return GenericLessThan;
+
+ } else if (FirstEntry->Ccb > SecondEntry->Ccb) {
+
+ return GenericGreaterThan;
+
+ } else if (FirstEntry->NamedPipeEnd < SecondEntry->NamedPipeEnd) {
+
+ return GenericLessThan;
+
+ } else if (FirstEntry->NamedPipeEnd > SecondEntry->NamedPipeEnd) {
+
+ return GenericGreaterThan;
+
+ } else {
+
+ return GenericEqual;
+ }
+}
+
+
+//
+// Local support routines
+//
+
+PVOID
+NpEventTableAllocate (
+ IN PRTL_GENERIC_TABLE EventTable,
+ IN CLONG ByteSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the generic allocation routine for the event table.
+
+Arguments:
+
+ EventTable - Supplies a pointer to the event table being used
+
+ ByteSize - Supplies the size, in bytes, to allocate.
+
+Return Value:
+
+ PVOID - Returns a pointer to the newly allocated buffer.
+
+--*/
+
+{
+ return FsRtlAllocatePool( (POOL_TYPE)EventTable->TableContext, ByteSize );
+}
+
+
+//
+// Local support routines
+//
+
+VOID
+NpEventTableDeallocate (
+ IN PRTL_GENERIC_TABLE EventTable,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the generic deallocation routine for the event table.
+
+Arguments:
+
+ EventTable - Supplies a pointer to the event table being used
+
+ Buffer - Supplies the buffer being deallocated
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( EventTable );
+
+ ExFreePool( Buffer );
+
+ return;
+}
diff --git a/private/ntos/npfs/fileinfo.c b/private/ntos/npfs/fileinfo.c
new file mode 100644
index 000000000..0f2f8d323
--- /dev/null
+++ b/private/ntos/npfs/fileinfo.c
@@ -0,0 +1,1412 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ FileInfo.c
+
+Abstract:
+
+ This module implements the File Info routines for NPFS called by the
+ dispatch driver. There are two entry points NpFsdQueryInformation
+ and NpFsdSetInformation.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (NPFS_BUG_CHECK_FILEINFO)
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_FILEINFO)
+
+//
+// local procedure prototypes
+//
+
+NTSTATUS
+NpCommonQueryInformation (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+
+NTSTATUS
+NpCommonSetInformation (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpQueryBasicInfo (
+ IN PCCB Ccb,
+ IN PFILE_BASIC_INFORMATION Buffer,
+ IN OUT PULONG Length
+ );
+
+NTSTATUS
+NpQueryStandardInfo (
+ IN PCCB Ccb,
+ IN PFILE_STANDARD_INFORMATION Buffer,
+ IN OUT PULONG Length
+ );
+
+NTSTATUS
+NpQueryInternalInfo (
+ IN PCCB Ccb,
+ IN PFILE_INTERNAL_INFORMATION Buffer,
+ IN OUT PULONG Length
+ );
+
+NTSTATUS
+NpQueryEaInfo (
+ IN PCCB Ccb,
+ IN PFILE_EA_INFORMATION Buffer,
+ IN OUT PULONG Length
+ );
+
+NTSTATUS
+NpQueryNameInfo (
+ IN PCCB Ccb,
+ IN PFILE_NAME_INFORMATION Buffer,
+ IN OUT PULONG Length
+ );
+
+NTSTATUS
+NpQueryPositionInfo (
+ IN PCCB Ccb,
+ IN PFILE_POSITION_INFORMATION Buffer,
+ IN OUT PULONG Length,
+ IN NAMED_PIPE_END NamedPipeEnd
+ );
+
+NTSTATUS
+NpQueryPipeInfo (
+ IN PFCB Fcb,
+ IN PCCB Ccb,
+ IN PFILE_PIPE_INFORMATION Buffer,
+ IN OUT PULONG Length,
+ IN NAMED_PIPE_END NamedPipeEnd
+ );
+
+NTSTATUS
+NpQueryPipeLocalInfo (
+ IN PFCB Fcb,
+ IN PCCB Ccb,
+ IN PFILE_PIPE_LOCAL_INFORMATION Buffer,
+ IN OUT PULONG Length,
+ IN NAMED_PIPE_END NamedPipeEnd
+ );
+
+NTSTATUS
+NpSetBasicInfo (
+ IN PCCB Ccb,
+ IN PFILE_BASIC_INFORMATION Buffer
+ );
+
+NTSTATUS
+NpSetPipeInfo (
+ IN PFCB Fcb,
+ IN PCCB Ccb,
+ IN PFILE_PIPE_INFORMATION Buffer,
+ IN NAMED_PIPE_END NamedPipeEnd
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonQueryInformation)
+#pragma alloc_text(PAGE, NpCommonSetInformation)
+#pragma alloc_text(PAGE, NpFsdQueryInformation)
+#pragma alloc_text(PAGE, NpFsdSetInformation)
+#pragma alloc_text(PAGE, NpQueryBasicInfo)
+#pragma alloc_text(PAGE, NpQueryEaInfo)
+#pragma alloc_text(PAGE, NpQueryInternalInfo)
+#pragma alloc_text(PAGE, NpQueryNameInfo)
+#pragma alloc_text(PAGE, NpQueryPipeInfo)
+#pragma alloc_text(PAGE, NpQueryPipeLocalInfo)
+#pragma alloc_text(PAGE, NpQueryPositionInfo)
+#pragma alloc_text(PAGE, NpQueryStandardInfo)
+#pragma alloc_text(PAGE, NpSetBasicInfo)
+#pragma alloc_text(PAGE, NpSetPipeInfo)
+#endif
+
+
+NTSTATUS
+NpFsdQueryInformation (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtQueryInformationFile API
+ calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdQueryInformation\n", 0);
+
+ //
+ // Call the common Query Information routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireSharedVcb();
+
+ try {
+
+ Status = NpCommonQueryInformation( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdQueryInformation -> %08lx\n", Status );
+
+ return Status;
+}
+
+
+NTSTATUS
+NpFsdSetInformation (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtSetInformationFile API
+ calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdSetInformation\n", 0);
+
+ //
+ // Call the common Set Information routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireExclusiveVcb();
+
+ try {
+
+ Status = NpCommonSetInformation( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdSetInformation -> %08lx\n", Status );
+
+ return Status;
+}
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonQueryInformation (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for creating/opening a file.
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status;
+
+ ULONG Length;
+ FILE_INFORMATION_CLASS FileInformationClass;
+ PVOID Buffer;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PFCB Fcb;
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PFILE_ALL_INFORMATION AllInfo;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonQueryInformation...\n", 0);
+ DebugTrace( 0, Dbg, " Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, " ->Length = %08lx\n", IrpSp->Parameters.QueryFile.Length);
+ DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", IrpSp->Parameters.QueryFile.FileInformationClass);
+ DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
+
+ //
+ // Get the ccb and figure out who we are, and make sure we're not
+ // disconnected.
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ &Fcb,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ Status = STATUS_PIPE_DISCONNECTED;
+
+ DebugTrace(-1, Dbg, "NpCommonQueryInformation -> %08lx\n", Status );
+ return Status;
+ }
+
+ //
+ // Case on the type of the context, We can only query information
+ // on an Fcb, Dcb, or Root Dcb. If we are not passed on of these
+ // we immediately tell the caller that there is an invalid parameter.
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "Node type code is not ccb\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpCommonQueryInformation -> STATUS_INVALID_PARAMETER\n", 0);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Reference our input parameter to make things easier
+ //
+
+ Length = IrpSp->Parameters.QueryFile.Length;
+ FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
+ Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Based on the information class we'll do different actions. Each
+ // of the procedure that we're calling fill up as much of the
+ // buffer as possible and return the remaining length, and status
+ // This is done so that we can use them to build up the
+ // FileAllInformation request. These procedures do not complete the
+ // Irp, instead this procedure must complete the Irp.
+ //
+
+ switch (FileInformationClass) {
+
+ case FileAllInformation:
+
+ //
+ // For the all information class we'll typecast a local
+ // pointer to the output buffer and then call the
+ // individual routines to fill in the buffer.
+ //
+
+ AllInfo = Buffer;
+
+ Length -= (sizeof(FILE_ACCESS_INFORMATION)
+ + sizeof(FILE_MODE_INFORMATION)
+ + sizeof(FILE_ALIGNMENT_INFORMATION));
+
+ //
+ // Only the QueryName call can return non-success
+ //
+
+ (VOID)NpQueryBasicInfo( Ccb, &AllInfo->BasicInformation, &Length );
+ (VOID)NpQueryStandardInfo( Ccb, &AllInfo->StandardInformation, &Length );
+ (VOID)NpQueryInternalInfo( Ccb, &AllInfo->InternalInformation, &Length );
+ (VOID)NpQueryEaInfo( Ccb, &AllInfo->EaInformation, &Length );
+ (VOID)NpQueryPositionInfo( Ccb, &AllInfo->PositionInformation, &Length, NamedPipeEnd );
+
+ Status = NpQueryNameInfo( Ccb, &AllInfo->NameInformation, &Length );
+
+ break;
+
+ case FileBasicInformation:
+
+ Status = NpQueryBasicInfo( Ccb, Buffer, &Length );
+ break;
+
+ case FileStandardInformation:
+
+ Status = NpQueryStandardInfo( Ccb, Buffer, &Length );
+ break;
+
+ case FileInternalInformation:
+
+ Status = NpQueryInternalInfo( Ccb, Buffer, &Length );
+ break;
+
+ case FileEaInformation:
+
+ Status = NpQueryEaInfo( Ccb, Buffer, &Length );
+ break;
+
+ case FilePositionInformation:
+
+ Status = NpQueryPositionInfo( Ccb, Buffer, &Length, NamedPipeEnd );
+ break;
+
+ case FileNameInformation:
+
+ Status = NpQueryNameInfo( Ccb, Buffer, &Length );
+ break;
+
+ case FilePipeInformation:
+
+ Status = NpQueryPipeInfo( Fcb, Ccb, Buffer, &Length, NamedPipeEnd );
+ break;
+
+ case FilePipeLocalInformation:
+
+ Status = NpQueryPipeLocalInfo( Fcb, Ccb, Buffer, &Length, NamedPipeEnd );
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Set the information field to the number of bytes actually filled in
+ // and then complete the request
+ //
+
+ Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length - Length;
+ NpCompleteRequest( Irp, Status );
+
+ DebugTrace(-1, Dbg, "NpCommonQueryInformation -> %08lx\n", Status );
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonSetInformation (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for creating/opening a file.
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status;
+
+ ULONG Length;
+ FILE_INFORMATION_CLASS FileInformationClass;
+ PVOID Buffer;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PFCB Fcb;
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PAGED_CODE();
+
+ //
+ // Get the current Irp stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonSetInformation...\n", 0);
+ DebugTrace( 0, Dbg, " Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, " ->Length = %08lx\n", IrpSp->Parameters.SetFile.Length);
+ DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", IrpSp->Parameters.SetFile.FileInformationClass);
+ DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
+
+ //
+ // Get the ccb and figure out who we are, and make sure we're not
+ // disconnected.
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ &Fcb,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ Status = STATUS_PIPE_DISCONNECTED;
+
+ DebugTrace(-1, Dbg, "NpCommonSetInformation -> %08lx\n", Status );
+ return Status;
+ }
+
+ //
+ // Case on the type of the context, We can only query information
+ // on an Fcb, Dcb, or Root Dcb. If we are not passed on of these
+ // we immediately tell the caller that there is an invalid parameter.
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpCommonQueryInformation -> STATUS_INVALID_PARAMETER\n", 0);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Reference our input parameter to make things easier
+ //
+
+ Length = IrpSp->Parameters.SetFile.Length;
+ FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
+ Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Based on the information class we'll do differnt actions. Each
+ // procedure that we're calling will complete the request.
+ //
+
+ switch (FileInformationClass) {
+
+ case FileBasicInformation:
+
+ Status = NpSetBasicInfo( Ccb, Buffer );
+ break;
+
+ case FilePipeInformation:
+
+ Status = NpSetPipeInfo( Fcb, Ccb, Buffer, NamedPipeEnd );
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // complete the request
+ //
+
+ NpCompleteRequest( Irp, Status );
+
+ DebugTrace(-1, Dbg, "NpCommonSetInformation -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryBasicInfo (
+ IN PCCB Ccb,
+ IN PFILE_BASIC_INFORMATION Buffer,
+ IN OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the query basic information operation.
+
+Arguments:
+
+ Ccb - Supplies the Ccb of the named pipe being queried
+
+ Buffer - Supplies a pointer to the buffer where the information is
+ to be returned
+
+ Length - Supplies the length of the buffer in bytes. This variable
+ upon return will receive the remaining bytes free in the buffer.
+
+Return Value:
+
+ NTSTATUS - The result of this query
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( Ccb );
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpQueryBasicInfo...\n", 0);
+
+ //
+ // Update the length field, and zero out the buffer
+ //
+
+ *Length -= sizeof( FILE_BASIC_INFORMATION );
+ RtlZeroMemory( Buffer, sizeof(FILE_BASIC_INFORMATION) );
+
+ //
+ // Set the various fields in the record
+ //
+ //**** need to add the time fields to the fcb/ccb
+ //
+
+ Buffer->CreationTime.LowPart = 0; Buffer->CreationTime.HighPart = 0;
+ Buffer->LastAccessTime.LowPart = 0; Buffer->LastAccessTime.HighPart = 0;
+ Buffer->LastWriteTime.LowPart = 0; Buffer->LastWriteTime.HighPart = 0;
+ Buffer->ChangeTime.LowPart = 0; Buffer->ChangeTime.HighPart = 0;
+
+ Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
+
+ //
+ // and return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryStandardInfo (
+ IN PCCB Ccb,
+ IN PFILE_STANDARD_INFORMATION Buffer,
+ IN OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the query standard information operation.
+
+Arguments:
+
+ Ccb - Supplies the Ccb of the named pipe being queried
+
+ Buffer - Supplies a pointer to the buffer where the information is
+ to be returned
+
+ Length - Supplies the length of the buffer in bytes. This variable
+ upon return will receive the remaining bytes free in the buffer.
+
+Return Value:
+
+ NTSTATUS - The result of this query
+
+--*/
+
+{
+ PDATA_QUEUE Inbound;
+ PDATA_QUEUE Outbound;
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpQueryStandardInfo...\n", 0);
+
+ //
+ // Update the length field, and zero out the buffer
+ //
+
+ *Length -= sizeof( FILE_STANDARD_INFORMATION );
+ RtlZeroMemory( Buffer, sizeof(FILE_STANDARD_INFORMATION) );
+
+ //
+ // Set the various fields in the record
+ //
+
+ Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ //
+ // The allocation size is the amount of quota we've charged this pipe
+ // instance
+ //
+
+ Buffer->AllocationSize.QuadPart = Inbound->Quota + Outbound->Quota;
+
+ //
+ // The Eof is the number of writen bytes ready to be read from the inbound
+ // queue
+ //
+
+ if (NpIsDataQueueWriters( Inbound )) {
+
+ Buffer->EndOfFile.QuadPart = Inbound->BytesInQueue;
+ }
+
+ Buffer->NumberOfLinks = 1;
+ Buffer->DeletePending = TRUE;
+ Buffer->Directory = FALSE;
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryInternalInfo (
+ IN PCCB Ccb,
+ IN PFILE_INTERNAL_INFORMATION Buffer,
+ IN OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the query internal information operation.
+
+Arguments:
+
+ Ccb - Supplies the Ccb of the named pipe being queried
+
+ Buffer - Supplies a pointer to the buffer where the information is
+ to be returned
+
+ Length - Supplies the length of the buffer in bytes. This variable
+ upon return will receive the remaining bytes free in the buffer.
+
+Return Value:
+
+ NTSTATUS - The result of this query
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpQueryInternalInfo...\n", 0);
+
+ //
+ // Update the length field, and zero out the buffer
+ //
+
+ *Length -= sizeof(FILE_INTERNAL_INFORMATION);
+ RtlZeroMemory(Buffer, sizeof(FILE_INTERNAL_INFORMATION));
+
+ //
+ // Set the internal index number to be the fnode lbn;
+ //
+
+ Buffer->IndexNumber.LowPart = (ULONG)Ccb;
+ Buffer->IndexNumber.HighPart = 0;
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryEaInfo (
+ IN PCCB Ccb,
+ IN PFILE_EA_INFORMATION Buffer,
+ IN OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the query Ea information operation.
+
+Arguments:
+
+ Ccb - Supplies the Ccb of the named pipe being queried
+
+ Buffer - Supplies a pointer to the buffer where the information is
+ to be returned
+
+ Length - Supplies the length of the buffer in bytes. This variable
+ upon return will receive the remaining bytes free in the buffer.
+
+Return Value:
+
+ NTSTATUS - The result of this query
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( Ccb );
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpQueryEaInfo...\n", 0);
+
+ //
+ // Update the length field, and zero out the buffer
+ //
+
+ *Length -= sizeof(FILE_EA_INFORMATION);
+ RtlZeroMemory(Buffer, sizeof(FILE_EA_INFORMATION));
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryNameInfo (
+ IN PCCB Ccb,
+ IN PFILE_NAME_INFORMATION Buffer,
+ IN OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the query name information operation.
+
+Arguments:
+
+ Ccb - Supplies the Ccb of the named pipe being queried
+
+ Buffer - Supplies a pointer to the buffer where the information is
+ to be returned
+
+ Length - Supplies the length of the buffer in bytes. This variable
+ upon return will receive the remaining bytes free in the buffer.
+
+Return Value:
+
+ NTSTATUS - The result of this query
+
+--*/
+
+{
+ ULONG bytesToCopy;
+ ULONG fileNameSize;
+
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpQueryNameInfo...\n", 0);
+
+ //
+ // See if the buffer is large enough, and decide how many bytes to copy.
+ //
+
+ *Length -= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName[0] );
+
+ fileNameSize = Ccb->Fcb->FullFileName.Length;
+
+ if ( *Length >= fileNameSize ) {
+
+ status = STATUS_SUCCESS;
+
+ bytesToCopy = fileNameSize;
+
+ } else {
+
+ status = STATUS_BUFFER_OVERFLOW;
+
+ bytesToCopy = *Length;
+ }
+
+ //
+ // Copy over the file name and its length.
+ //
+
+ RtlCopyMemory(
+ Buffer->FileName,
+ Ccb->Fcb->FullFileName.Buffer,
+ bytesToCopy);
+
+ Buffer->FileNameLength = bytesToCopy;
+
+ *Length -= bytesToCopy;
+
+ return status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryPositionInfo (
+ IN PCCB Ccb,
+ IN PFILE_POSITION_INFORMATION Buffer,
+ IN OUT PULONG Length,
+ IN NAMED_PIPE_END NamedPipeEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the query position information operation.
+
+Arguments:
+
+ Ccb - Supplies the Ccb of the named pipe being queried
+
+ Buffer - Supplies a pointer to the buffer where the information is
+ to be returned
+
+ Length - Supplies the length of the buffer in bytes. This variable
+ upon return will receive the remaining bytes free in the buffer.
+
+ NamedPipeEnd - Indicates if the server or client is calling
+
+Return Value:
+
+ NTSTATUS - The result of this query
+
+--*/
+
+{
+ PDATA_QUEUE Inbound;
+ PDATA_QUEUE Outbound;
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "PbQueryPositionInfo...\n", 0);
+
+ //
+ // Update the length field, and zero out the buffer
+ //
+
+ *Length -= sizeof(FILE_POSITION_INFORMATION);
+ RtlZeroMemory(Buffer, sizeof(FILE_POSITION_INFORMATION));
+
+ Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ //
+ // The current byte offset is the number of bytes available in the
+ // read end of the caller's buffer. The client read from the outbound
+ // end and the server reads from the inbound end.
+ //
+
+ if (NamedPipeEnd == FILE_PIPE_CLIENT_END) {
+
+ if (NpIsDataQueueWriters( Outbound )) {
+
+ Buffer->CurrentByteOffset.QuadPart = Outbound->BytesInQueue;
+ }
+
+ } else {
+
+ if (NpIsDataQueueWriters( Inbound )) {
+
+ Buffer->CurrentByteOffset.QuadPart = Inbound->BytesInQueue;
+ }
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryPipeInfo (
+ IN PFCB Fcb,
+ IN PCCB Ccb,
+ IN PFILE_PIPE_INFORMATION Buffer,
+ IN OUT PULONG Length,
+ IN NAMED_PIPE_END NamedPipeEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the query pipe information operation.
+
+Arguments:
+
+ Fcb - Supplies the Fcb of the named pipe being queried
+
+ Ccb - Supplies the Ccb of the named pipe being queried
+
+ Buffer - Supplies a pointer to the buffer where the information is
+ to be returned
+
+ Length - Supplies the length of the buffer in bytes. This variable
+ upon return will receive the remaining bytes free in the buffer.
+
+ NamedPipeEnd - Indicates if the server or client is calling
+
+Return Value:
+
+ NTSTATUS - The result of this query
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( Fcb );
+ UNREFERENCED_PARAMETER( Ccb );
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "PbQueryPipeInfo...\n", 0);
+
+ //
+ // Update the length field, and zero out the buffer
+ //
+
+ *Length -= sizeof(FILE_PIPE_INFORMATION);
+ RtlZeroMemory(Buffer, sizeof(FILE_PIPE_INFORMATION));
+
+ //
+ // Set the fields in the record
+ //
+
+ Buffer->ReadMode = Ccb->ReadMode[ NamedPipeEnd ];
+ Buffer->CompletionMode = Ccb->CompletionMode[ NamedPipeEnd ];
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryPipeLocalInfo (
+ IN PFCB Fcb,
+ IN PCCB Ccb,
+ IN PFILE_PIPE_LOCAL_INFORMATION Buffer,
+ IN OUT PULONG Length,
+ IN NAMED_PIPE_END NamedPipeEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the query pipe information operation.
+
+Arguments:
+
+ Fcb - Supplies the Fcb of the named pipe being queried
+
+ Ccb - Supplies the Ccb of the named pipe being queried
+
+ Buffer - Supplies a pointer to the buffer where the information is
+ to be returned
+
+ Length - Supplies the length of the buffer in bytes. This variable
+ upon return will receive the remaining bytes free in the buffer.
+
+ NamedPipeEnd - Indicates if the server or client is calling
+
+Return Value:
+
+ NTSTATUS - The result of this query
+
+--*/
+
+{
+ PDATA_QUEUE Inbound;
+ PDATA_QUEUE Outbound;
+
+ UNREFERENCED_PARAMETER( Ccb );
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "PbQueryPipeLocalInfo...\n", 0);
+
+ //
+ // Update the length field, and zero out the buffer
+ //
+
+ *Length -= sizeof(FILE_PIPE_LOCAL_INFORMATION);
+ RtlZeroMemory(Buffer, sizeof(FILE_PIPE_LOCAL_INFORMATION));
+
+ Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ //
+ // Set the fields in the record
+ //
+
+ Buffer->NamedPipeType = Fcb->Specific.Fcb.NamedPipeType;
+ Buffer->NamedPipeConfiguration = Fcb->Specific.Fcb.NamedPipeConfiguration;
+ Buffer->MaximumInstances = Fcb->Specific.Fcb.MaximumInstances;
+ Buffer->CurrentInstances = Fcb->OpenCount;
+ Buffer->InboundQuota = Inbound->Quota;
+ Buffer->OutboundQuota = Outbound->Quota;
+ Buffer->NamedPipeState = Ccb->NamedPipeState;
+ Buffer->NamedPipeEnd = NamedPipeEnd;
+
+ //
+ // The read data available and write quota available depend on which
+ // end of the pipe is doing the query. The client reads from the outbound
+ // queue, and writes to the inbound queue.
+ //
+
+ if (NamedPipeEnd == FILE_PIPE_CLIENT_END) {
+
+ if (NpIsDataQueueWriters( Outbound )) {
+
+ Buffer->ReadDataAvailable = Outbound->BytesInQueue;
+ }
+
+ Buffer->WriteQuotaAvailable = Inbound->Quota - Inbound->QuotaUsed;
+
+ } else {
+
+ if (NpIsDataQueueWriters( Inbound )) {
+
+ Buffer->ReadDataAvailable = Inbound->BytesInQueue;
+ }
+
+ Buffer->WriteQuotaAvailable = Outbound->Quota - Outbound->QuotaUsed;
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpSetBasicInfo (
+ IN PCCB Ccb,
+ IN PFILE_BASIC_INFORMATION Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the basic information for a named pipe.
+
+Arguments:
+
+ Ccb - Supplies the ccb for the named pipe being modified
+
+ Buffer - Supplies the buffer containing the data being set
+
+Return Value:
+
+ NTSTATUS - Returns our completion status
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( Ccb );
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpSetBasicInfo...\n", 0);
+
+ if (((PLARGE_INTEGER)&Buffer->CreationTime)->QuadPart != 0) {
+
+ //
+ // Modify the creation time
+ //
+
+ //**** need to add time fields
+ }
+
+ if (((PLARGE_INTEGER)&Buffer->LastAccessTime)->QuadPart != 0) {
+
+ //
+ // Modify the last access time
+ //
+
+ //**** need to add time fields
+ }
+
+ if (((PLARGE_INTEGER)&Buffer->LastWriteTime)->QuadPart != 0) {
+
+ //
+ // Modify the last write time
+ //
+
+ //**** need to add time fields
+ }
+
+ if (((PLARGE_INTEGER)&Buffer->ChangeTime)->QuadPart != 0) {
+
+ //
+ // Modify the change time
+ //
+
+ //**** need to add time fields
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpSetPipeInfo (
+ IN PFCB Fcb,
+ IN PCCB Ccb,
+ IN PFILE_PIPE_INFORMATION Buffer,
+ IN NAMED_PIPE_END NamedPipeEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the pipe information for a named pipe.
+
+Arguments:
+
+ Fcb - Supplies the Fcb for the named pipe being modified
+
+ Ccb - Supplies the ccb for the named pipe being modified
+
+ Buffer - Supplies the buffer containing the data being set
+
+ NamedPipeEnd - Supplies the server/client end doing the operation
+
+Return Value:
+
+ NTSTATUS - Returns our completion status
+
+--*/
+
+{
+ PDATA_QUEUE ReadQueue;
+ PDATA_QUEUE WriteQueue;
+
+ UNREFERENCED_PARAMETER( Ccb );
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpSetPipeInfo...\n", 0);
+
+ //
+ // If the caller requests message mode reads but the pipe is
+ // byte stream then its an invalid parameter
+ //
+
+ if ((Buffer->ReadMode == FILE_PIPE_MESSAGE_MODE) &&
+ (Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_BYTE_STREAM_MODE)) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Get a reference to our read queue
+ //
+
+ switch (NamedPipeEnd) {
+
+ case FILE_PIPE_SERVER_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ break;
+
+ case FILE_PIPE_CLIENT_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ break;
+
+ default:
+
+ NpBugCheck( NamedPipeEnd, 0, 0 );
+ }
+
+ //
+ // If the completion mode is complete operations and the current mode
+ // is queue operations and there and the data queues are not empty
+ // then its pipe busy
+ //
+
+ if ((Buffer->CompletionMode == FILE_PIPE_COMPLETE_OPERATION)
+
+ &&
+
+ (Ccb->CompletionMode[ NamedPipeEnd ] == FILE_PIPE_QUEUE_OPERATION)
+
+ &&
+
+ ((NpIsDataQueueReaders(ReadQueue)) ||
+ (NpIsDataQueueWriters(WriteQueue)))) {
+
+ return STATUS_PIPE_BUSY;
+ }
+
+ //
+ // Everything is fine so update the pipe
+ //
+
+ Ccb->ReadMode[ NamedPipeEnd ] = Buffer->ReadMode;
+ Ccb->CompletionMode[ NamedPipeEnd ] = Buffer->CompletionMode;
+
+ //
+ // Check for notify
+ //
+
+ NpCheckForNotify( Fcb->ParentDcb, FALSE );
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
diff --git a/private/ntos/npfs/filobsup.c b/private/ntos/npfs/filobsup.c
new file mode 100644
index 000000000..a2c9b1196
--- /dev/null
+++ b/private/ntos/npfs/filobsup.c
@@ -0,0 +1,272 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ FilObSup.c
+
+Abstract:
+
+ This module implements the Named Pipe File object support routines.
+
+Author:
+
+ Gary Kimura [GaryKi] 30-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (NPFS_BUG_CHECK_FILOBSUP)
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_FILOBSUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpDecodeFileObject)
+#pragma alloc_text(PAGE, NpSetFileObject)
+#endif
+
+
+VOID
+NpSetFileObject (
+ IN PFILE_OBJECT FileObject OPTIONAL,
+ IN PVOID FsContext,
+ IN PVOID FsContext2,
+ IN NAMED_PIPE_END NamedPipeEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the file system pointers within the file object
+ and handles the indicator for storing the named pipe end.
+
+Arguments:
+
+ FileObject - Supplies a pointer to the file object being modified, and
+ can optionally be null.
+
+ FsContext - Supplies a pointer to either a ccb, vcb, or root_dcb
+ structure.
+
+ FsContext2 - Supplies a pointer to either a nonpaged ccb, root_dcb_ccb,
+ or is null
+
+ NamedPipeEnd - Supplies the indication if this is either the server end
+ or client end file object. This is only applicable if the
+ fscontext points to a ccb.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN GotCcb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpSetFileObject, FileObject = %08lx\n", FileObject );
+
+ //
+ // If no file object was given, do nothing.
+ //
+
+ if (ARGUMENT_PRESENT( FileObject )) {
+
+ //
+ // Check if we need to add in the named pipe end to the
+ // fscontext pointer. We only need to 'OR' in a 1 if this is
+ // the server end and fscontext points to a ccb. Also remember
+ // now if this is a pointer is a ccb, so that we can later set
+ // the fo_named_pipe flag
+ //
+
+ if ((FsContext != NULL) &&
+ (*(PNODE_TYPE_CODE)FsContext == NPFS_NTC_CCB)) {
+
+ GotCcb = TRUE;
+
+ if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
+
+ FsContext = (PVOID)((ULONG)FsContext | 0x00000001);
+ }
+
+ } else {
+
+ GotCcb = FALSE;
+ }
+
+ //
+ // Now set the fscontext fields of the file object, and conditionally
+ // set the named pipe flag in the file object if necessary.
+ //
+
+ FileObject->FsContext = FsContext;
+ FileObject->FsContext2 = FsContext2;
+
+ //
+ // Set the private cache map to 1 and that what we will get our
+ // fast I/O routines called
+ //
+
+ FileObject->PrivateCacheMap = (PVOID)1;
+
+ if (GotCcb) {
+
+ FileObject->Flags |= FO_NAMED_PIPE;
+ }
+ }
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpSetFileObject -> VOID\n", 0);
+
+ return;
+}
+
+
+NODE_TYPE_CODE
+NpDecodeFileObject (
+ IN PFILE_OBJECT FileObject,
+ OUT PFCB *Fcb OPTIONAL,
+ OUT PCCB *Ccb,
+ OUT PNAMED_PIPE_END NamedPipeEnd OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure takes a pointer to a file object, that has already been
+ opened by the named pipe file system and figures out what it really
+ is opened.
+
+Arguments:
+
+ FileObject - Supplies the file object pointer being interrogated
+
+ Fcb - Receives a pointer to the Fcb for the file object, if we can
+ find it.
+
+ Ccb - Receives a pointer to the Ccb for the file object, if we can
+ find it
+
+ NamedPipeEnd - Receives a value indicating if this is a server
+ or client end file object.
+
+Return Value:
+
+ NODE_TYPE_CODE - Returns the node type code for a Vcb, RootDcb, Ccb,
+ or zero.
+
+ Vcb - indicates that file object opens the named pipe driver.
+ Fcb and Ccb are NOT returned.
+
+ RootDcb - indicates that the file object is for the root directory.
+ Fcb (RootDcb), and Ccb (RootDcbCcb) are set.
+
+ Ccb - indicates that the file object is for a named pipe instance.
+ Ccb is set, while Fcb is optionally set.
+
+ Zero - indicates that the file object was for a named pipe instance
+ but became disconnected. Fcb, Ccb, and NamedPipeEnd are NOT
+ returned.
+
+--*/
+
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ PVOID FsContext;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpDecodeFileObject, FileObject = %08lx\n", FileObject);
+
+ //
+ // Reference the fs context fields of the file object.
+ //
+
+ FsContext = FileObject->FsContext;
+
+ //
+ // If the fscontext field is null then we been disconnected.
+ //
+
+ if ((FsContext == NULL) || ((ULONG)FsContext == 1)) {
+
+ NodeTypeCode = 0;
+
+ } else {
+
+ //
+ // We're actually pointing to something so first extract the
+ // named pipe end information and then we can reference through
+ // the fscontext pointer after we clean it up.
+ //
+
+ if (ARGUMENT_PRESENT(NamedPipeEnd)) {
+ if (FlagOn((ULONG)FsContext, 0x00000001)) {
+ *NamedPipeEnd = FILE_PIPE_SERVER_END;
+ } else {
+ *NamedPipeEnd = FILE_PIPE_CLIENT_END;
+ }
+ }
+
+ FsContext = (PVOID)((ULONG)FsContext & 0xfffffffe);
+
+ //
+ // Now we can case on the node type code of the fscontext pointer
+ // and set the appropriate out pointers
+ //
+
+ NodeTypeCode = *(PNODE_TYPE_CODE)FsContext;
+
+ switch (NodeTypeCode) {
+
+ case NPFS_NTC_VCB:
+
+ break;
+
+ case NPFS_NTC_ROOT_DCB:
+
+ *Ccb = FileObject->FsContext2;
+ if (ARGUMENT_PRESENT(Fcb)) { *Fcb = FsContext; }
+ break;
+
+ case NPFS_NTC_CCB:
+
+ *Ccb = FsContext;
+ if (ARGUMENT_PRESENT(Fcb)) { *Fcb = ((PCCB)FsContext)->Fcb; }
+ break;
+
+ default:
+
+ NpBugCheck( NodeTypeCode, 0, 0 );
+ }
+ }
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpDecodeFileObject -> %08lx\n", NodeTypeCode);
+
+ return NodeTypeCode;
+}
+
diff --git a/private/ntos/npfs/flushbuf.c b/private/ntos/npfs/flushbuf.c
new file mode 100644
index 000000000..32bd7d923
--- /dev/null
+++ b/private/ntos/npfs/flushbuf.c
@@ -0,0 +1,239 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ FlushBuf.c
+
+Abstract:
+
+ This module implements the File Flush Buffers routine for NPFS called by
+ the dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_FLUSH_BUFFERS)
+
+//
+// local procedure prototypes
+//
+
+NTSTATUS
+NpCommonFlushBuffers (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonFlushBuffers)
+#pragma alloc_text(PAGE, NpFsdFlushBuffers)
+#endif
+
+
+NTSTATUS
+NpFsdFlushBuffers (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtFlushBuffersFile API calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdFlushBuffers\n", 0);
+
+ //
+ // Call the common Flush routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireSharedVcb();
+
+ try {
+
+ Status = NpCommonFlushBuffers( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdFlushBuffers -> %08lx\n", Status );
+
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonFlushBuffers (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for Flushing buffers for a file.
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PDATA_QUEUE WriteQueue;
+
+ //
+ // Get the current stack location
+ //
+
+ PAGED_CODE();
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonFlushBuffers\n", 0);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is not a ccb then the pipe has been disconnected. We don't need the
+ // Fcb back from the call
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd ) != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ Status = STATUS_PIPE_DISCONNECTED;
+
+ DebugTrace(-1, Dbg, "NpCommonFlushBuffers -> %08lx\n", Status );
+ return Status;
+ }
+
+ NpAcquireExclusiveCcb(Ccb);
+
+ try {
+
+ //
+ // Figure out the data queue that the flush buffer is
+ // targetted at. It is the queue that we do writes into
+ //
+
+ if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
+
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ } else {
+
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ }
+
+ //
+ // Now from the write queue check if contains write entries. If
+ // it does not contain write entries then we immediately complete
+ // this irp with success because there isn't anything to flush
+ //
+
+ if (!NpIsDataQueueWriters( WriteQueue )) {
+
+ DebugTrace(0, Dbg, "Pipe does not contain write entries\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ try_return(Status = STATUS_SUCCESS);
+ }
+
+ //
+ // Otherwise the queue is full of writes so we simply
+ // enqueue this irp to the back to the queue and set our
+ // return status to pending, also mark the irp pending
+ //
+
+ IoMarkIrpPending( Irp );
+
+ (VOID)NpAddDataQueueEntry( WriteQueue,
+ WriteEntries,
+ Flush,
+ 0,
+ Irp,
+ NULL );
+ Status = STATUS_PENDING;
+
+ try_exit: NOTHING;
+ } finally {
+ NpReleaseCcb(Ccb);
+ }
+
+
+ DebugTrace(-1, Dbg, "NpCommonFlushBuffers -> %08lx\n", Status);
+ return Status;
+}
+
diff --git a/private/ntos/npfs/fsctrl.c b/private/ntos/npfs/fsctrl.c
new file mode 100644
index 000000000..1d86754a5
--- /dev/null
+++ b/private/ntos/npfs/fsctrl.c
@@ -0,0 +1,3296 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ FsContrl.c
+
+Abstract:
+
+ This module implements the File System Control routine for NPFS called by
+ the dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (NPFS_BUG_CHECK_FSCTRL)
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_FSCONTRL)
+
+
+//
+// Local procedure prototypes
+//
+
+NTSTATUS
+NpCommonFileSystemControl (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpAssignEvent (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpDisconnect (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpListen (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpPeek (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpQueryEvent (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpTransceive (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpWaitForNamedPipe (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpImpersonate (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpInternalRead (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp,
+ IN BOOLEAN ReadOverflowOperation
+ );
+
+NTSTATUS
+NpInternalWrite (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpInternalTransceive (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpQueryClientProcess (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpSetClientProcess (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpCompleteTransceiveIrp (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpAssignEvent)
+#pragma alloc_text(PAGE, NpCommonFileSystemControl)
+#pragma alloc_text(PAGE, NpCompleteTransceiveIrp)
+#pragma alloc_text(PAGE, NpDisconnect)
+#pragma alloc_text(PAGE, NpFsdFileSystemControl)
+#pragma alloc_text(PAGE, NpImpersonate)
+#pragma alloc_text(PAGE, NpInternalRead)
+#pragma alloc_text(PAGE, NpInternalTransceive)
+#pragma alloc_text(PAGE, NpInternalWrite)
+#pragma alloc_text(PAGE, NpListen)
+#pragma alloc_text(PAGE, NpPeek)
+#pragma alloc_text(PAGE, NpQueryClientProcess)
+#pragma alloc_text(PAGE, NpQueryEvent)
+#pragma alloc_text(PAGE, NpSetClientProcess)
+#pragma alloc_text(PAGE, NpTransceive)
+#pragma alloc_text(PAGE, NpWaitForNamedPipe)
+#endif
+
+//
+// Define a structure used for posting DPC requests to an ExWorkerThread.
+//
+
+typedef struct _FSP_CONTEXT {
+
+ WORK_QUEUE_ITEM Item;
+ PNPFS_DEVICE_OBJECT NpfsDeviceObject;
+ PIRP Irp;
+
+} FSP_CONTEXT;
+
+typedef FSP_CONTEXT *PFSP_CONTEXT;
+
+
+NTSTATUS
+NpFsdFileSystemControl (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtFsControlFile API calls.
+
+Arguments
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdFileSystemControl\n", 0);
+
+ //
+ // Call the common FsControl routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ try {
+
+ Status = NpCommonFileSystemControl( NpfsDeviceObject,
+ Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdFileSystemControl -> %08lx\n", Status );
+
+ return Status;
+}
+
+
+//
+// Internal Support Routine
+//
+
+NTSTATUS
+NpCommonFileSystemControl (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the common code for handling/dispatching an fsctl
+ function.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the named pipe device object
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+ BOOLEAN ReadOverflowOperation;
+
+ PAGED_CODE();
+
+ //
+ // Reference our input parameters to make things easier
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonFileSystemControl\n", 0);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, "OutputBufferLength = %08lx\n", IrpSp->Parameters.FileSystemControl.OutputBufferLength);
+ DebugTrace( 0, Dbg, "InputBufferLength = %08lx\n", IrpSp->Parameters.FileSystemControl.InputBufferLength);
+ DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", IrpSp->Parameters.FileSystemControl.FsControlCode);
+
+ //
+ // Case on the type of function we're trying to do. In each case
+ // we'll call a local work routine to do the actual work.
+ //
+
+ ReadOverflowOperation = FALSE;
+
+ switch (IrpSp->Parameters.FileSystemControl.FsControlCode) {
+
+ case FSCTL_PIPE_ASSIGN_EVENT:
+
+ NpAcquireExclusiveVcb();
+ Status = NpAssignEvent( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_DISCONNECT:
+
+ NpAcquireExclusiveVcb();
+ Status = NpDisconnect( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_LISTEN:
+
+ NpAcquireSharedVcb();
+ Status = NpListen( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_PEEK:
+
+ NpAcquireExclusiveVcb();
+ Status = NpPeek( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_QUERY_EVENT:
+
+ NpAcquireExclusiveVcb();
+ Status = NpQueryEvent( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_TRANSCEIVE:
+
+ NpAcquireSharedVcb();
+ Status = NpTransceive( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_WAIT:
+
+ NpAcquireExclusiveVcb();
+ Status = NpWaitForNamedPipe( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_IMPERSONATE:
+
+ NpAcquireExclusiveVcb();
+ Status = NpImpersonate( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
+
+ ReadOverflowOperation = TRUE;
+
+ case FSCTL_PIPE_INTERNAL_READ:
+
+ NpAcquireSharedVcb();
+ Status = NpInternalRead( NpfsDeviceObject, Irp, ReadOverflowOperation );
+ break;
+
+ case FSCTL_PIPE_INTERNAL_WRITE:
+
+ NpAcquireSharedVcb();
+ Status = NpInternalWrite( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
+
+ NpAcquireSharedVcb();
+ Status = NpInternalTransceive( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
+
+ NpAcquireSharedVcb();
+ Status = NpQueryClientProcess( NpfsDeviceObject, Irp );
+ break;
+
+ case FSCTL_PIPE_SET_CLIENT_PROCESS:
+
+ NpAcquireExclusiveVcb();
+ Status = NpSetClientProcess( NpfsDeviceObject, Irp );
+ break;
+
+ default:
+
+ NpAcquireExclusiveVcb();
+ NpCompleteRequest( Irp, Status = STATUS_NOT_SUPPORTED );
+ break;
+ }
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpCommonFileSystemControl -> %08lx\n", Status);
+
+ return Status;
+}
+
+
+//
+// Local support routine
+//
+
+NTSTATUS
+NpAssignEvent (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the assign event control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the Irp specifying the function
+
+Return Value:
+
+ NTSTATUS - An appropriate return status
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG InputBufferLength;
+ ULONG FsControlCode;
+
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PFILE_PIPE_ASSIGN_EVENT_BUFFER EventBuffer;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpAssignEvent...\n", 0);
+
+ InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+ FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is not a ccb then the pipe has been disconnected.
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd ) != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ //
+ // Reference the system buffer as an assign event buffer and make
+ // sure it's large enough
+ //
+
+ if (InputBufferLength < sizeof(FILE_PIPE_ASSIGN_EVENT_BUFFER)) {
+
+ DebugTrace(0, Dbg, "System buffer size is too small\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ EventBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // First thing we do is delete the old event if there is one
+ // for this end of the pipe
+ //
+
+ NpDeleteEventTableEntry( &NpVcb->EventTable,
+ NonpagedCcb->EventTableEntry[ NamedPipeEnd ] );
+
+ NonpagedCcb->EventTableEntry[ NamedPipeEnd ] = NULL;
+
+ //
+ // Now if the new event handle is not null then we'll add the new
+ // event to the event table
+ //
+
+ if (EventBuffer->EventHandle != NULL) {
+
+ NonpagedCcb->EventTableEntry[ NamedPipeEnd ] =
+ NpAddEventTableEntry( &NpVcb->EventTable,
+ Ccb,
+ NamedPipeEnd,
+ EventBuffer->EventHandle,
+ EventBuffer->KeyValue,
+ PsGetCurrentProcess(),
+ Irp->RequestorMode );
+ }
+
+ //
+ // Complete the Irp with success
+ //
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+
+ DebugTrace(-1, Dbg, "NpAssignEvent -> STATUS_SUCCESS\n", 0);
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpDisconnect (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the disconnect control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG FsControlCode;
+
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpDisconnect...\n", 0);
+
+ FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is not a ccb then the pipe has been disconnected.
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd ) != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Make sure that this is only the server that is doing this
+ // action.
+ //
+
+ if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
+
+ DebugTrace(0, Dbg, "Not the server end\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_ILLEGAL_FUNCTION );
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+
+ NpAcquireExclusiveCcb(Ccb);
+
+ //
+ // Now call the state support routine to set the ccb to
+ // a disconnected state and remove the client's cached security
+ // context.
+ //
+
+ Status = NpSetDisconnectedPipeState( Ccb );
+
+ NpUninitializeSecurity( Ccb );
+
+ NpReleaseCcb(Ccb);
+
+ //
+ // Complete the Irp with our returned status
+ //
+
+ NpCompleteRequest( Irp, Status );
+
+ DebugTrace(-1, Dbg, "NpDisconnect -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpListen (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the listen control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG FsControlCode;
+
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpListen...\n", 0);
+
+ FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is not a ccb then the pipe has been disconnected.
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd ) != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_ILLEGAL_FUNCTION );
+
+ DebugTrace(-1, Dbg, "NpListen -> STATUS_ILLEGAL_FUNCTION\n", 0 );
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+
+ //
+ // Make sure that this is only the server that is doing this
+ // action.
+ //
+
+ if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
+
+ DebugTrace(0, Dbg, "Not the server end\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_ILLEGAL_FUNCTION );
+
+ DebugTrace(-1, Dbg, "NpListen -> STATUS_ILLEGAL_FUNCTION\n", 0 );
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+
+ NpAcquireExclusiveCcb(Ccb);
+
+ //
+ // Now call the state support routine to set the ccb to
+ // a listening state. This routine will complete the Irp
+ // for us.
+ //
+
+ Status = NpSetListeningPipeState( Ccb, Irp );
+
+ NpReleaseCcb(Ccb);
+
+ DebugTrace(-1, Dbg, "NpListen -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpPeek (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the peek control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG OutputBufferLength;
+ ULONG FsControlCode;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PFILE_PIPE_PEEK_BUFFER PeekBuffer;
+
+ PDATA_QUEUE ReadQueue;
+ READ_MODE ReadMode;
+
+ ULONG LengthWritten;
+
+ PDATA_ENTRY DataEntry;
+
+ PUCHAR ReadBuffer;
+ ULONG ReadLength;
+ ULONG ReadRemaining;
+
+ PAGED_CODE();
+
+ //
+ // Get the current Irp stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpPeek...\n", 0);
+
+ //
+ // Extract the important fields from the IrpSp
+ //
+
+ OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+ FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
+
+ DebugTrace( 0, Dbg, "OutputBufferLength = %08lx\n", OutputBufferLength);
+ DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", FsControlCode);
+
+ //
+ // Decode the file object to figure out who we are. The results
+ // have a disconnected pipe if we get back an undefined ntc
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "FileObject has been disconnected\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+
+ DebugTrace(-1, Dbg, "NpPeek -> STATUS_PIPE_DISCONNECTED\n", 0 );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Now make sure the node type code is for a ccb otherwise it is an
+ // invalid parameter
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a ccb\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpPeek -> STATUS_INVALID_PARAMETER\n", 0 );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ //
+ // Reference the system buffer as a peek buffer and make sure it's
+ // large enough
+ //
+
+ if (OutputBufferLength < (ULONG)FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0])) {
+
+ DebugTrace(0, Dbg, "Output buffer is too small\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpPeek -> STATUS_INVALID_PARAMETER\n", 0 );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ PeekBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Now the data queue that we read from is based on the named pipe
+ // end. The server reads from the inbound queue and the client reads
+ // from the outbound queue
+ //
+
+ switch (NamedPipeEnd) {
+
+ case FILE_PIPE_SERVER_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ //ReadMode = Ccb->ReadMode[ FILE_PIPE_SERVER_END ];
+
+ break;
+
+ case FILE_PIPE_CLIENT_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+ //ReadMode = Ccb->ReadMode[ FILE_PIPE_CLIENT_END ];
+
+ break;
+
+ default:
+
+ NpBugCheck( NamedPipeEnd, 0, 0 );
+ }
+
+ //
+ // Our read mode is really based upon the pipe type and not the set
+ // read mode for the pipe end.
+ //
+
+ if (Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) {
+
+ ReadMode = FILE_PIPE_MESSAGE_MODE;
+
+ } else {
+
+ ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
+ }
+
+ DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
+ DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode);
+
+ //
+ // If the state of the pipe is not in the connected or closing
+ // state then it is an invalid pipe state
+ //
+
+ if ((Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) &&
+ (Ccb->NamedPipeState != FILE_PIPE_CLOSING_STATE)) {
+
+ DebugTrace(0, Dbg, "pipe not connected or closing\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PIPE_STATE );
+ return STATUS_INVALID_PIPE_STATE;
+ }
+
+ //
+ // If the state of the pipe is closing and the queue does
+ // not contain any writers then we return eof
+ //
+
+ if ((Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) &&
+ (!NpIsDataQueueWriters( ReadQueue ))) {
+
+ DebugTrace(0, Dbg, "pipe closing and is empty\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_BROKEN );
+ return STATUS_PIPE_BROKEN;
+ }
+
+ //
+ // Zero out the standard header part of the peek buffer and
+ // set the length written to the amount we've just zeroed out
+ //
+
+ RtlZeroMemory( PeekBuffer, FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]) );
+ LengthWritten = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
+
+ //
+ // Set the named pipe state
+ //
+
+ PeekBuffer->NamedPipeState = Ccb->NamedPipeState;
+
+ //
+ // There is only data available if the read queue contains
+ // write entries otherwise the rest of record is all zero.
+ //
+
+ if (NpIsDataQueueWriters( ReadQueue )) {
+
+ //
+ // Now find the first real entry in the read queue. The
+ // first entry actually better be a real one.
+ //
+
+ DataEntry = NpGetNextDataQueueEntry( ReadQueue, NULL );
+
+ ASSERT( (DataEntry->DataEntryType == Buffered) ||
+ (DataEntry->DataEntryType == Unbuffered) );
+
+ //
+ // Indicate how many bytes are available to read
+ //
+
+ PeekBuffer->ReadDataAvailable = ReadQueue->BytesInQueue;
+
+ //
+ // The number of messages a message length is only filled
+ // in for a message mode pipe
+ //
+
+ if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
+
+ PeekBuffer->NumberOfMessages = ReadQueue->EntriesInQueue;
+ PeekBuffer->MessageLength = DataEntry->DataSize - ReadQueue->NextByteOffset;
+ }
+
+ //
+ // Now we are ready to copy over the data from the read queue
+ // into the peek buffer. First establish how much room we
+ // have in the peek buffer and who much is remaining.
+ //
+
+ ReadBuffer = &PeekBuffer->Data[0];
+ ReadLength = OutputBufferLength - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
+ ReadRemaining = ReadLength;
+
+ DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
+ DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
+
+ //
+ // Now read the data queue.
+ //
+
+ if ( ReadLength != 0 ) {
+ IO_STATUS_BLOCK Iosb;
+
+ Iosb = NpReadDataQueue( ReadQueue,
+ TRUE,
+ FALSE,
+ ReadBuffer,
+ ReadLength,
+ ReadMode,
+ Ccb );
+
+ Status = Iosb.Status;
+ LengthWritten += Iosb.Information;
+
+ } else {
+
+ if ( PeekBuffer->ReadDataAvailable == 0) {
+
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ }
+
+ } else {
+
+ Status = STATUS_SUCCESS;
+ }
+
+ //
+ // Complete the request. The amount of information copied
+ // is stored in length written
+ //
+
+ Irp->IoStatus.Information = LengthWritten;
+
+ NpCompleteRequest(Irp, Status);
+
+ DebugTrace(-1, Dbg, "NpPeek -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpQueryEvent (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the query event control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the Irp specifying the function
+
+Return Value:
+
+ NTSTATUS - An appropriate return status
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG InputBufferLength;
+ ULONG OutputBufferLength;
+ ULONG FsControlCode;
+
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ HANDLE EventHandle;
+ PFILE_PIPE_EVENT_BUFFER EventArray;
+ PFILE_PIPE_EVENT_BUFFER EventBuffer;
+ ULONG EventArrayMaximumCount;
+ ULONG EventCount;
+
+ PEPROCESS Process;
+
+ PEVENT_TABLE_ENTRY Ete;
+ PDATA_QUEUE ReadQueue;
+ PDATA_QUEUE WriteQueue;
+
+ PVOID RestartKey;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpQueryEvent...\n", 0);
+
+ InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+ OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+ FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is not a Vcb then its an invalid parameter
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd ) != NPFS_NTC_VCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not the named pipe driver\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Reference the system buffer as a handle and make sure it's large
+ // enough
+ //
+
+ if (InputBufferLength < sizeof(HANDLE)) {
+
+ DebugTrace(0, Dbg, "Input System buffer size is too small\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ EventHandle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Reference the system buffer as an output event buffer, and compute
+ // how many event buffer records we can put in the buffer.
+ //
+
+ EventArray = Irp->AssociatedIrp.SystemBuffer;
+ EventArrayMaximumCount = OutputBufferLength / sizeof(FILE_PIPE_EVENT_BUFFER);
+ EventCount = 0;
+
+ //
+ // Get our current process pointer that we'll need for our search
+ //
+
+ Process = PsGetCurrentProcess();
+
+ //
+ // Now enumerate the event table entries in the event table
+ //
+
+ RestartKey = NULL;
+ for (Ete = NpGetNextEventTableEntry( &NpVcb->EventTable, &RestartKey);
+ Ete != NULL;
+ Ete = NpGetNextEventTableEntry( &NpVcb->EventTable, &RestartKey)) {
+
+ //
+ // Check if the event table entry matches the event handle
+ // and the process
+ //
+
+ if ((Ete->EventHandle == EventHandle) &&
+ (Ete->Process == Process)) {
+
+ //
+ // Now based on the named pipe end we treat the inbound/
+ // outbound as a read/write queue.
+ //
+
+ NpAcquireExclusiveCcb(Ete->Ccb);
+
+ switch (Ete->NamedPipeEnd) {
+
+ case FILE_PIPE_CLIENT_END:
+
+ ReadQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+ WriteQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ break;
+
+ case FILE_PIPE_SERVER_END:
+
+ ReadQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ WriteQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ break;
+
+ default:
+
+ NpBugCheck( Ete->NamedPipeEnd, 0, 0 );
+ }
+
+ //
+ // Now if there is any data in the read queue to be read
+ // we fill in the buffer
+ //
+
+ if (NpIsDataQueueWriters(ReadQueue)) {
+
+ //
+ // First make sure there is enough room in the
+ // EventBuffer to hold another entry
+ //
+
+ if (EventCount >= EventArrayMaximumCount) {
+
+ DebugTrace(0, Dbg, "The event buffer is full\n", 0);
+
+ NpReleaseCcb(Ete->Ccb);
+ break;
+ }
+
+ //
+ // Reference the event buffer and increment the
+ // counter
+ //
+
+ EventBuffer = &EventArray[EventCount];
+ EventCount += 1;
+
+ //
+ // Fill in the event buffer entry
+ //
+
+ EventBuffer->NamedPipeState = Ete->Ccb->NamedPipeState;
+ EventBuffer->EntryType = FILE_PIPE_READ_DATA;
+ EventBuffer->ByteCount = ReadQueue->BytesInQueue;
+ EventBuffer->KeyValue = Ete->KeyValue;
+ EventBuffer->NumberRequests = ReadQueue->EntriesInQueue;
+ }
+
+ //
+ // We'll always fill in a write space buffer. The amount
+ // will either be bytes of write space available or
+ // the quota of write space that we can use.
+ //
+
+ //
+ // First make sure there is enough room in the
+ // EventBuffer to hold another entry
+ //
+
+ if (EventCount >= EventArrayMaximumCount) {
+
+ DebugTrace(0, Dbg, "The event buffer is full\n", 0);
+
+ NpReleaseCcb(Ete->Ccb);
+ break;
+ }
+
+ //
+ // Reference the event buffer and increment the
+ // counter
+ //
+
+ EventBuffer = &EventArray[EventCount];
+ EventCount += 1;
+
+ //
+ // Fill in the event buffer entry
+ //
+
+ EventBuffer->NamedPipeState = Ete->Ccb->NamedPipeState;
+ EventBuffer->EntryType = FILE_PIPE_WRITE_SPACE;
+ EventBuffer->KeyValue = Ete->KeyValue;
+
+ //
+ // Now either we put in the write space available or
+ // we put in the quota available
+ //
+
+ if (NpIsDataQueueReaders(WriteQueue)) {
+
+ EventBuffer->ByteCount = WriteQueue->BytesInQueue;
+ EventBuffer->NumberRequests = WriteQueue->EntriesInQueue;
+
+ } else {
+
+ EventBuffer->ByteCount = WriteQueue->Quota - WriteQueue->QuotaUsed;
+ EventBuffer->NumberRequests = 0;
+ }
+
+ NpReleaseCcb(Ete->Ccb);
+ }
+ }
+
+ //
+ // Set the information field to be the number of bytes of output
+ // data we've fill into the system buffer
+ //
+
+ Irp->IoStatus.Information = EventCount * sizeof(FILE_PIPE_EVENT_BUFFER);
+
+ //
+ // And complete the Irp with success
+ //
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+
+ DebugTrace(-1, Dbg, "NpQueryEvent -> STATUS_SUCCESS\n", 0);
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpTransceive (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the transceive named pipe control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ static IO_STATUS_BLOCK Iosb;
+ NTSTATUS Status;
+
+ PIO_STACK_LOCATION IrpSp;
+ PETHREAD UserThread;
+
+ PUCHAR WriteBuffer;
+ ULONG WriteLength;
+
+ PUCHAR ReadBuffer;
+ ULONG ReadLength;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PDATA_QUEUE ReadQueue;
+ PDATA_QUEUE WriteQueue;
+ PEVENT_TABLE_ENTRY Event;
+ READ_MODE ReadMode;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ ULONG WriteRemaining;
+
+ PIRP WriteIrp;
+
+ PDATA_ENTRY DataEntry;
+
+ //
+ // The following variable is used during abnormal unwind
+ //
+
+ PVOID UnwindStorage = NULL;
+
+ PAGED_CODE();
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpTransceive\n", 0);
+ DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
+
+ WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+ WriteBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
+
+ ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+ ReadBuffer = Irp->UserBuffer;
+
+ //
+ // Now if the requestor mode is user mode we need to probe the buffers
+ // We do now need to have an exception handler here because our top
+ // level caller already has one that will complete the Irp with
+ // the appropriate status if we access violate.
+ //
+
+ if (Irp->RequestorMode != KernelMode) {
+
+ try {
+
+ ProbeForRead( WriteBuffer, WriteLength, sizeof(UCHAR) );
+ ProbeForWrite( ReadBuffer, ReadLength, sizeof(UCHAR) );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
+ }
+ }
+
+ //
+ // Get the Ccb and figure out who we are, and make sure we're not
+ // disconnected
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+
+ DebugTrace(-1, Dbg, "NpTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Now we only will allow transceive operations on the pipe and not a
+ // directory or the device
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ NpAcquireExclusiveCcb(Ccb);
+ WriteIrp = NULL;
+
+ try {
+
+ //
+ // Check that the pipe is in the connected state
+ //
+
+ if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) {
+
+ DebugTrace(0, Dbg, "Pipe not connected\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PIPE_STATE );
+ try_return( Status = STATUS_INVALID_PIPE_STATE );
+ }
+
+ //
+ // Figure out the read/write queue, read mode, and event based
+ // on the end of the named pipe doing the transceive.
+ //
+
+ switch (NamedPipeEnd) {
+
+ case FILE_PIPE_SERVER_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+ ReadMode = Ccb->ReadMode[ FILE_PIPE_SERVER_END ];
+
+ break;
+
+ case FILE_PIPE_CLIENT_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
+ ReadMode = Ccb->ReadMode[ FILE_PIPE_CLIENT_END ];
+
+ break;
+
+ default:
+
+ NpBugCheck( NamedPipeEnd, 0, 0 );
+ }
+
+ //
+ // We only allow a transceive on a message mode, full duplex pipe.
+ //
+
+ NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
+
+ if ((NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX) ||
+ (ReadMode != FILE_PIPE_MESSAGE_MODE)) {
+
+ DebugTrace(0, Dbg, "Bad pipe configuration or read mode\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_READ_MODE );
+ try_return( Status = STATUS_INVALID_READ_MODE );
+ }
+
+ //
+ // Check that the read queue is empty.
+ //
+
+ if (!NpIsDataQueueEmpty( ReadQueue )) {
+
+ DebugTrace(0, Dbg, "Read queue is not empty\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_BUSY );
+ try_return( Status = STATUS_PIPE_BUSY );
+ }
+
+ //
+ // Do the transceive write operation. We first try and push the data
+ // from the write buffer into any waiting readers in the write queue
+ // and if that succeeds then we can go on and do the read operation
+ // otherwise we need to make a copy of irp and to enqueue as
+ // a data entry into the write queue.
+ //
+ // Now we'll call our common write data queue routine to
+ // transfer data out of our write buffer into the data queue.
+ // If the result of the call is FALSE then we still have some
+ // write data to put into the write queue.
+ //
+
+ UserThread = Irp->Tail.Overlay.Thread;
+
+ if (!NpWriteDataQueue( WriteQueue,
+ ReadMode,
+ WriteBuffer,
+ WriteLength,
+ Ccb->Fcb->Specific.Fcb.NamedPipeType,
+ &WriteRemaining,
+ Ccb,
+ NamedPipeEnd,
+ UserThread )) {
+
+ PIO_STACK_LOCATION WriteIrpSp;
+
+ ASSERT( !NpIsDataQueueReaders( WriteQueue ));
+
+ DebugTrace(0, Dbg, "Add write to data queue\n", 0);
+
+ //
+ // We need to do some more write processing. So to handle
+ // this case we'll allocate a new irp and set its system
+ // buffer to be the remaining part of the write buffer
+ //
+
+ if ((WriteIrp = IoAllocateIrp( NpfsDeviceObject->DeviceObject.StackSize, FALSE )) == NULL) {
+
+ ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
+ }
+
+ IoSetCompletionRoutine( WriteIrp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE );
+
+ WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
+
+ if (WriteRemaining > 0) {
+
+ WriteIrp->AssociatedIrp.SystemBuffer = UnwindStorage = FsRtlAllocatePoolWithQuota( NonPagedPool,
+ WriteRemaining );
+
+ //
+ // Safely do the copy
+ //
+
+ try {
+
+ RtlCopyMemory( WriteIrp->AssociatedIrp.SystemBuffer,
+ &WriteBuffer[ WriteLength - WriteRemaining ],
+ WriteRemaining );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
+ }
+
+ } else {
+
+ WriteIrp->AssociatedIrp.SystemBuffer = UnwindStorage = NULL;
+ }
+
+ //
+ // Set the current stack location, and set in the amount we are
+ // try to write.
+ //
+
+ WriteIrp->CurrentLocation -= 1;
+ WriteIrp->Tail.Overlay.CurrentStackLocation = WriteIrpSp;
+ WriteIrpSp->Parameters.Write.Length = WriteRemaining;
+ WriteIrp->IoStatus.Information = WriteRemaining;
+
+ //
+ // Set it up to do buffered I/O and deallocate the buffer
+ // on completion.
+
+ if (WriteRemaining > 0) {
+
+ WriteIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
+ }
+
+ WriteIrp->UserIosb = &Iosb;
+
+ //
+ // Add this write request to the write queue
+ //
+
+ DataEntry = NpAddDataQueueEntry( WriteQueue,
+ WriteEntries,
+ Unbuffered,
+ WriteRemaining,
+ WriteIrp,
+ NULL );
+
+ //
+ // And set the security part of the data entry
+ //
+
+ NpSetDataEntryClientContext( NamedPipeEnd,
+ Ccb,
+ DataEntry,
+ UserThread );
+
+ //
+ // Now null out the write irp variable so that we know not
+ // to deallocate it on an error
+ //
+
+ WriteIrp = NULL;
+ UnwindStorage = NULL;
+ }
+
+ //
+ // Now we need to advance the write queue to the next read irp to
+ // skip over flushes and closes
+ //
+
+ //****NpWriteDataQueue does this for us**** (VOID)NpGetNextRealDataQueueEntry( WriteQueue );
+
+ //
+ // And because we've done something we need to signal the
+ // other ends event
+ //
+
+ NpSignalEventTableEntry( Event );
+
+ //
+ // Do the transceive read operation. This is just like a
+ // buffered read.
+ //
+ // Now we know that the read queue is empty so we'll enqueue this
+ // Irp to the read queue and return status pending, also mark the
+ // irp pending
+ //
+
+ ASSERT( NpIsDataQueueEmpty( ReadQueue ));
+
+ (VOID)NpAddDataQueueEntry( ReadQueue,
+ ReadEntries,
+ Buffered,
+ ReadLength,
+ Irp,
+ NULL );
+
+ IoMarkIrpPending( Irp );
+
+ (VOID)NpGetNextRealDataQueueEntry( ReadQueue );
+
+ //
+ // And because we've done something we need to signal the
+ // other ends event
+ //
+
+ NpSignalEventTableEntry( Event );
+
+ Status = STATUS_PENDING;
+
+ try_exit: NOTHING;
+ } finally {
+
+ NpReleaseCcb(Ccb);
+ if (WriteIrp != NULL) { IoFreeIrp( WriteIrp ); }
+ if (UnwindStorage != NULL) { ExFreePool( UnwindStorage ); }
+ }
+
+ DebugTrace(-1, Dbg, "NpTransceive -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpWaitForNamedPipe (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the wait for named pipe control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG InputBufferLength;
+ ULONG FsControlCode;
+
+ PFCB Fcb;
+ PCCB Ccb;
+
+ PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
+ UNICODE_STRING Name;
+ PVOID LocalBuffer;
+
+ PLIST_ENTRY Links;
+
+ BOOLEAN CaseInsensitive = TRUE; //**** Make all searches case insensitive
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpWaitForNamedPipe...\n", 0);
+
+ //
+ // Extract the important fields from the IrpSp
+ //
+
+ InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+ FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
+
+ Name.Buffer = NULL;
+ LocalBuffer = NULL;
+
+ try {
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is an error if the we weren't given a Vcb.
+ //
+
+ {
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ if (NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd ) != NPFS_NTC_ROOT_DCB) {
+
+ DebugTrace(0, Dbg, "File Object is not for the named pipe root directory\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_ILLEGAL_FUNCTION );
+ try_return( Status = STATUS_ILLEGAL_FUNCTION );
+ }
+ }
+
+ //
+ // Reference the system buffer as a wait for buffer and make
+ // sure it's large enough
+ //
+
+ if (InputBufferLength < sizeof(FILE_PIPE_WAIT_FOR_BUFFER)) {
+
+ DebugTrace(0, Dbg, "System buffer size is too small\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ try_return( Status = STATUS_INVALID_PARAMETER );
+ }
+
+ WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Check for an invalid buffer
+ //
+
+ if (FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + WaitBuffer->NameLength >
+ InputBufferLength) {
+
+ DebugTrace(0, Dbg, "System buffer size is too small\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ try_return( Status = STATUS_INVALID_PARAMETER );
+ }
+
+ //
+ // Set up the local variable Name to be the name we're looking
+ // for
+ //
+
+ Name.Length = (USHORT)(WaitBuffer->NameLength + 2);
+ Name.Buffer = LocalBuffer = FsRtlAllocatePool( PagedPool, Name.Length );
+
+ Name.Buffer[0] = L'\\';
+
+ RtlCopyMemory( &Name.Buffer[1],
+ &WaitBuffer->Name[0],
+ WaitBuffer->NameLength );
+
+ //
+ // If the name is an alias, translate it.
+ //
+
+ Status = NpTranslateAlias( &Name );
+ if ( !NT_SUCCESS(Status) ) {
+ NpCompleteRequest( Irp, Status );
+ try_return( NOTHING );
+ }
+
+ //
+ // Now check to see if we can find a named pipe with the right
+ // name
+ //
+
+ Fcb = NpFindPrefix( &Name, CaseInsensitive, &Name );
+
+ //
+ // If the Fcb is null then we can't wait for it, Also if the
+ // Fcb is not an Fcb then we also have nothing to wait for
+ //
+
+ if (NodeType(Fcb) != NPFS_NTC_FCB) {
+
+ DebugTrace(0, Dbg, "Bad nonexistent named pipe name", 0);
+
+ NpCompleteRequest( Irp, STATUS_OBJECT_NAME_NOT_FOUND );
+ try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
+ }
+
+ //
+ // Now we need to search to see if we find a ccb already in the
+ // listening state
+ // First try and find a ccb that is in the listening state
+ // If we exit the loop with ccb null then we haven't found
+ // one
+ //
+
+ Ccb = NULL;
+ for (Links = Fcb->Specific.Fcb.CcbQueue.Flink;
+ Links != &Fcb->Specific.Fcb.CcbQueue;
+ Links = Links->Flink) {
+
+ Ccb = CONTAINING_RECORD( Links, CCB, CcbLinks );
+
+ if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) {
+
+ break;
+ }
+
+ Ccb = NULL;
+ }
+
+ //
+ // Check if we found one
+ //
+
+ if (Ccb != NULL) {
+
+ DebugTrace(0, Dbg, "Found a ccb in listening state\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ try_return( Status = STATUS_SUCCESS );
+ }
+
+ //
+ // We weren't able to find one so we need to add a new waiter
+ // Mark the irp pending and add this to the wait queue
+ //
+
+ IoMarkIrpPending( Irp );
+
+ try {
+
+ NpAddWaiter( &NpVcb->WaitQueue,
+ Fcb->Specific.Fcb.DefaultTimeOut,
+ Irp );
+ } finally {
+
+ //
+ // If we bomb out trying to add the waiter then we better
+ // not mark this irp as pending. We have to do it after the
+ // fact because once the irp is successfully in the wait queue
+ // it is out of our hands.
+ //
+
+ if (AbnormalTermination()) {
+
+ IoGetCurrentIrpStackLocation((Irp))->Control &= ~SL_PENDING_RETURNED;
+ }
+ }
+
+ Status = STATUS_PENDING;
+
+ try_exit: NOTHING;
+ } finally {
+
+ if (LocalBuffer != NULL) { ExFreePool( LocalBuffer ); }
+ }
+
+ DebugTrace(-1, Dbg, "NpWaitForNamedPipe -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpImpersonate (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the impersonate of the named pipe
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ UNREFERENCED_PARAMETER( NpfsDeviceObject );
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpImpersonate...\n", 0);
+
+ //
+ // Decode the file object to figure out who we are. If the result
+ // is an error if the we weren't given a Vcb.
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd ) != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "File Object is not a named pipe\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_ILLEGAL_FUNCTION );
+
+ DebugTrace(-1, Dbg, "NpImpersonate -> STATUS_ILLEGAL_FUNCTION\n", 0 );
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+
+ //
+ // Make sure that we are the server end and not the client end
+ //
+
+ if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
+
+ DebugTrace(0, Dbg, "Not the server end\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_ILLEGAL_FUNCTION );
+
+ DebugTrace(-1, Dbg, "NpImpersonate -> STATUS_ILLEGAL_FUNCTION\n", 0 );
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+
+ //
+ // set up the impersonation
+ //
+
+ Status = NpImpersonateClientContext( Ccb );
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+
+ DebugTrace(-1, Dbg, "NpImpersonate -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpInternalRead (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp,
+ IN BOOLEAN ReadOverflowOperation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the unbuffered read named pipe control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+ ReadOverflowOperation - Used to indicate if the read being processed is a read overflow
+ operation.
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PIO_STACK_LOCATION IrpSp;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ PIRP ReadIrp;
+ PUCHAR ReadBuffer;
+ ULONG ReadLength;
+ ULONG ReadRemaining;
+ READ_MODE ReadMode;
+ COMPLETION_MODE CompletionMode;
+ PDATA_QUEUE ReadQueue;
+ PEVENT_TABLE_ENTRY Event;
+
+ PAGED_CODE();
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpInternalRead\n", 0);
+ DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
+
+ //
+ // Get the Ccb and figure out who we are, and make sure we're not
+ // disconnected
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+
+ DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_DISCONNECTED\n", 0 );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Now we only will allow Read operations on the pipe and not a directory
+ // or the device
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_INVALID_PARAMETER\n", 0 );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ NpAcquireExclusiveCcb(Ccb);
+
+ //
+ // Check if the pipe is not in the connected state.
+ //
+
+ switch (Ccb->NamedPipeState) {
+
+ case FILE_PIPE_DISCONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe in disconnected state\n", 0);
+
+ NpReleaseCcb(Ccb);
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+
+ DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_DISCONNECTED\n", 0 );
+ return STATUS_PIPE_DISCONNECTED;
+
+ case FILE_PIPE_LISTENING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe in listening state\n", 0);
+
+ NpReleaseCcb(Ccb);
+ NpCompleteRequest( Irp, STATUS_PIPE_LISTENING );
+
+ DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_LISTENING\n", 0 );
+ return STATUS_PIPE_LISTENING;
+
+ case FILE_PIPE_CONNECTED_STATE:
+ case FILE_PIPE_CLOSING_STATE:
+
+ break;
+
+ default:
+
+ DebugTrace(0, Dbg, "Illegal pipe state = %08lx\n", Ccb->NamedPipeState);
+ NpBugCheck( Ccb->NamedPipeState, 0, 0 );
+ }
+
+ //
+ // We only allow a read by the server on a non outbound only pipe
+ // and by the client on a non inbound only pipe
+ //
+
+ NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
+
+ if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
+ (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))
+
+ ||
+
+ ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
+ (NamedPipeConfiguration == FILE_PIPE_INBOUND))) {
+
+ DebugTrace(0, Dbg, "Trying to read to the wrong pipe configuration\n", 0);
+
+ NpReleaseCcb(Ccb);
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_INVALID_PARAMETER\n", 0 );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Reference our input parameters to make things easier, and
+ // initialize our main variables that describe the Read command
+ //
+
+ ReadIrp = Irp;
+ ReadBuffer = Irp->AssociatedIrp.SystemBuffer;
+ ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+ ReadRemaining = ReadLength;
+ ReadMode = Ccb->ReadMode[ NamedPipeEnd ];
+ CompletionMode = Ccb->CompletionMode[ NamedPipeEnd ];
+
+ //
+ // Now the data queue that we read from into and the event that we signal
+ // are based on the named pipe end. The server read from the inbound
+ // queue and signals the client event. The client does just the
+ // opposite.
+ //
+
+ switch (NamedPipeEnd) {
+
+ case FILE_PIPE_SERVER_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+
+ break;
+
+ case FILE_PIPE_CLIENT_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
+
+ break;
+
+ default:
+
+ NpBugCheck( NamedPipeEnd, 0, 0 );
+ }
+
+ DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
+ DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
+ DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode);
+ DebugTrace(0, Dbg, "CompletionMode = %08lx\n", CompletionMode);
+ DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
+ DebugTrace(0, Dbg, "Event = %08lx\n", Event);
+
+ //
+ // if the read queue does not contain any write entries
+ // then we either need to enqueue this operation or
+ // fail immediately
+ //
+
+ if (!NpIsDataQueueWriters( ReadQueue )) {
+
+ //
+ // Check if the other end of the pipe is closing, and if
+ // so then we complete it with end of file.
+ // Otherwise check to see if we should enqueue the irp
+ // or complete the operation and tell the user the pipe is empty.
+ //
+
+ if (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) {
+
+ DebugTrace(0, Dbg, "Complete the irp with eof\n", 0);
+
+ NpCompleteRequest( ReadIrp, STATUS_PIPE_BROKEN );
+
+ Status = STATUS_PIPE_BROKEN;
+
+ } else if (CompletionMode == FILE_PIPE_QUEUE_OPERATION) {
+
+ DebugTrace(0, Dbg, "Put the irp into the read queue\n", 0);
+
+ (VOID)NpAddDataQueueEntry( ReadQueue,
+ ReadEntries,
+ Unbuffered,
+ ReadLength,
+ ReadIrp,
+ NULL );
+
+ IoMarkIrpPending( Irp );
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ DebugTrace(0, Dbg, "Complete the irp with pipe empty\n", 0);
+
+ NpCompleteRequest( ReadIrp, STATUS_PIPE_EMPTY );
+
+ Status = STATUS_PIPE_EMPTY;
+ }
+
+ } else {
+
+ //
+ // otherwise there we have a read irp against a read queue
+ // that contains one or more write entries.
+ //
+
+ ReadIrp->IoStatus = NpReadDataQueue( ReadQueue,
+ FALSE,
+ ReadOverflowOperation,
+ ReadBuffer,
+ ReadLength,
+ ReadMode,
+ Ccb );
+
+ Status = ReadIrp->IoStatus.Status;
+
+ //
+ // Now set the remaining byte count in the allocation size of
+ // the Irp.
+ //
+
+ ReadIrp->Overlay.AllocationSize.QuadPart = ReadQueue->BytesInQueue;
+
+ //
+ // Finish up the read irp.
+ //
+
+ NpCompleteRequest( ReadIrp, Status );
+ }
+
+ //
+ // Now we need to advance the read queue to the next write irp to
+ // skip over flushes and closes
+ //
+
+ (VOID)NpGetNextRealDataQueueEntry( ReadQueue );
+
+ //
+ // And because we've done something we need to signal the
+ // other ends event
+ //
+
+ NpSignalEventTableEntry( Event );
+
+ NpReleaseCcb(Ccb);
+
+ DebugTrace(-1, Dbg, "NpInternalRead -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpInternalWrite (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the unbuffered write named pipe control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PIO_STACK_LOCATION IrpSp;
+ PETHREAD UserThread;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ PIRP WriteIrp;
+ PUCHAR WriteBuffer;
+ ULONG WriteLength;
+ ULONG WriteRemaining;
+ PDATA_QUEUE WriteQueue;
+
+ PEVENT_TABLE_ENTRY Event;
+ READ_MODE ReadMode;
+
+ PDATA_ENTRY DataEntry;
+
+ PAGED_CODE();
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpInternalWrite\n", 0);
+ DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
+
+ //
+ // Get the Ccb and figure out who we are, and make sure we're not
+ // disconnected
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+
+ DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0 );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Now we only will allow write operations on the pipe and not a directory
+ // or the device
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0);
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ NpAcquireExclusiveCcb(Ccb);
+
+ //
+ // We only allow a write by the server on a non inbound only pipe
+ // and by the client on a non outbound only pipe
+ //
+
+ NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
+
+ if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
+ (NamedPipeConfiguration == FILE_PIPE_INBOUND))
+
+ ||
+
+ ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
+ (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))) {
+
+ DebugTrace(0, Dbg, "Trying to write to the wrong pipe configuration\n", 0);
+
+ NpReleaseCcb(Ccb);
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0);
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Reference our input parameters to make things easier, and
+ // initialize our main variables that describe the write command
+ //
+
+ WriteIrp = Irp;
+ WriteBuffer = Irp->AssociatedIrp.SystemBuffer;
+ WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+
+ //
+ // Set up the amount of data we will have written by the time this
+ // irp gets completed
+ //
+
+ WriteIrp->IoStatus.Information = WriteLength;
+
+ //
+ // Now the data queue that we write into and the event that we signal
+ // are based on the named pipe end. The server writes to the outbound
+ // queue and signals the client event. The client does just the
+ // opposite. We also need to figure out the read mode for the opposite
+ // end of the pipe.
+ //
+
+ switch (NamedPipeEnd) {
+
+ case FILE_PIPE_SERVER_END:
+
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+ ReadMode = Ccb->ReadMode[ FILE_PIPE_CLIENT_END ];
+
+ break;
+
+ case FILE_PIPE_CLIENT_END:
+
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
+ ReadMode = Ccb->ReadMode[ FILE_PIPE_SERVER_END ];
+
+ break;
+
+ default:
+
+ NpBugCheck( NamedPipeEnd, 0, 0 );
+ }
+
+ //
+ // Check if the pipe is not in the connected state.
+ //
+
+ switch (Ccb->NamedPipeState) {
+
+ case FILE_PIPE_DISCONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe in disconnected state\n", 0);
+
+ NpReleaseCcb(Ccb);
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ return STATUS_PIPE_DISCONNECTED;
+
+ case FILE_PIPE_LISTENING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe in listening state\n", 0);
+
+ NpReleaseCcb(Ccb);
+ NpCompleteRequest( Irp, STATUS_PIPE_LISTENING );
+ return STATUS_PIPE_LISTENING;
+
+ case FILE_PIPE_CONNECTED_STATE:
+
+ break;
+
+ case FILE_PIPE_CLOSING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe in closing state\n", 0);
+
+ NpReleaseCcb(Ccb);
+ NpCompleteRequest( Irp, STATUS_PIPE_CLOSING );
+ return STATUS_PIPE_CLOSING;
+
+ default:
+
+ DebugTrace(0, Dbg, "Illegal pipe state = %08lx\n", Ccb->NamedPipeState);
+ NpBugCheck( Ccb->NamedPipeState, 0, 0 );
+ }
+
+ //
+ // Check if this is a message type pipe and the operation type is complete
+ // operation, If so then we also check that the queued reads is enough to
+ // complete the message otherwise we need to abort the write irp immediately.
+ //
+
+ if ((Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) &&
+ (Ccb->CompletionMode[NamedPipeEnd] == FILE_PIPE_COMPLETE_OPERATION)) {
+
+ //
+ // If the pipe contains readers and amount to read is less than the write
+ // length then we cannot do it the write.
+ // Or if pipe does not contain reads then we also cannot do the write.
+ //
+
+ if ((NpIsDataQueueReaders( WriteQueue ) &&
+ (WriteQueue->BytesInQueue < (WriteLength + sizeof(DATA_ENTRY))))
+
+ ||
+
+ (!NpIsDataQueueReaders( WriteQueue ))) {
+
+ DebugTrace(0, Dbg, "Cannot complete the message without blocking\n", 0);
+
+ NpReleaseCcb(Ccb);
+ Irp->IoStatus.Information = 0;
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ return STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // Now we'll call our common write data queue routine to
+ // transfer data out of our write buffer into the data queue.
+ // If the result of the call is FALSE then we still have some
+ // write data to put into the write queue.
+ //
+
+ UserThread = Irp->Tail.Overlay.Thread;
+
+ if (!NpWriteDataQueue( WriteQueue,
+ ReadMode,
+ WriteBuffer,
+ WriteLength,
+ Ccb->Fcb->Specific.Fcb.NamedPipeType,
+ &WriteRemaining,
+ Ccb,
+ NamedPipeEnd,
+ UserThread )) {
+
+ ASSERT( !NpIsDataQueueReaders( WriteQueue ));
+
+ ASSERT((Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_BYTE_STREAM_TYPE) ||
+ (Ccb->CompletionMode[NamedPipeEnd] == FILE_PIPE_QUEUE_OPERATION) ||
+ (WriteRemaining <= (WriteQueue->Quota - WriteQueue->QuotaUsed)));
+
+ //
+ // Check if the operation is not to block and if so then we
+ // will complete the operation now with what we're written, if what is
+ // left will not fit in the quota for the file
+ //
+
+ if (Ccb->CompletionMode[NamedPipeEnd] == FILE_PIPE_COMPLETE_OPERATION) {
+
+ DebugTrace(0, Dbg, "Complete the byte stream write immediately\n", 0);
+
+ Irp->IoStatus.Information = WriteLength - WriteRemaining;
+
+ NpCompleteRequest( Irp, Status = STATUS_SUCCESS );
+
+ } else {
+
+ DebugTrace(0, Dbg, "Add write to data queue\n", 0);
+
+ IoMarkIrpPending( Irp );
+
+ //
+ // Add this write request to the write queue
+ //
+
+ try {
+
+ DataEntry = NpAddDataQueueEntry( WriteQueue,
+ WriteEntries,
+ Unbuffered,
+ WriteLength,
+ Irp,
+ NULL );
+
+ //
+ // And set the security part of the data entry
+ //
+
+ NpSetDataEntryClientContext( NamedPipeEnd,
+ Ccb,
+ DataEntry,
+ UserThread );
+
+ } finally {
+
+ if (AbnormalTermination()) {
+
+ IoGetCurrentIrpStackLocation((Irp))->Control &= ~SL_PENDING_RETURNED;
+ }
+ }
+
+ //
+ // Now if the remaining length is not equal to the original
+ // write length then this must have been the first write entry
+ // into the data queue and we need to set the Next Byte
+ // field
+ //
+
+ if (WriteLength > WriteRemaining) {
+
+ WriteQueue->NextByteOffset = WriteLength - WriteRemaining;
+ }
+
+ //
+ // Set our status for the write irp to pending
+ //
+
+ Status = STATUS_PENDING;
+ }
+
+ } else {
+
+ DebugTrace(0, Dbg, "Complete the Write Irp\n", 0);
+
+
+ //
+ // The write irp is finished so we can complete it now
+ //
+
+ NpCompleteRequest( WriteIrp, STATUS_SUCCESS );
+
+ //
+ // Set our status for the write irp to success
+ //
+
+ Status = STATUS_SUCCESS;
+ }
+
+ //
+ // Now we need to advance the write queue to the next read irp to
+ // skip over flushes and closes
+ //
+
+ //****NpWriteDataQueue does this for us**** (VOID)NpGetNextRealDataQueueEntry( WriteQueue );
+
+ //
+ // And because we've done something we need to signal the
+ // other ends event
+ //
+
+ NpSignalEventTableEntry( Event );
+
+ NpReleaseCcb(Ccb);
+
+ DebugTrace(-1, Dbg, "NpInternalWrite -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Local Support Routine
+//
+
+NTSTATUS
+NpInternalTransceive (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the internal (i.e., unbuffered) transceive named pipe
+ control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ static IO_STATUS_BLOCK Iosb;
+ NTSTATUS Status;
+
+ PIO_STACK_LOCATION IrpSp;
+ PETHREAD UserThread;
+
+ PUCHAR WriteBuffer;
+ ULONG WriteLength;
+
+ PUCHAR ReadBuffer;
+ ULONG ReadLength;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PDATA_QUEUE ReadQueue;
+ PDATA_QUEUE WriteQueue;
+ PEVENT_TABLE_ENTRY Event;
+ READ_MODE ReadMode;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ ULONG WriteRemaining;
+
+ PIRP WriteIrp;
+ PDATA_ENTRY DataEntry;
+
+ //
+ // The following variable is used for abnormal unwind
+ //
+
+ PVOID UnwindStorage = NULL;
+
+ PAGED_CODE();
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpInternalTransceive\n", 0);
+ DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
+
+ WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+ WriteBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
+
+ ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+ ReadBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Get the Ccb and figure out who we are, and make sure we're not
+ // disconnected
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+
+ DebugTrace(-1, Dbg, "NpInternalTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Now we only will allow transceive operations on the pipe and not a
+ // directory or the device
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+
+ DebugTrace(-1, Dbg, "NpInternalTransceive -> STATUS_INVALID_PARAMETER\n", 0 );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ WriteIrp = NULL;
+ NpAcquireExclusiveCcb(Ccb);
+
+ try {
+
+ //
+ // Check that the pipe is in the connected state
+ //
+
+ if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) {
+
+ DebugTrace(0, Dbg, "Pipe not connected\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PIPE_STATE );
+ try_return( Status = STATUS_INVALID_PIPE_STATE );
+ }
+
+ //
+ // Figure out the read/write queue, read mode, and event based
+ // on the end of the named pipe doing the transceive.
+ //
+
+ switch (NamedPipeEnd) {
+
+ case FILE_PIPE_SERVER_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+ ReadMode = Ccb->ReadMode[ FILE_PIPE_SERVER_END ];
+
+ break;
+
+ case FILE_PIPE_CLIENT_END:
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
+ ReadMode = Ccb->ReadMode[ FILE_PIPE_CLIENT_END ];
+
+ break;
+
+ default:
+
+ NpBugCheck( NamedPipeEnd, 0, 0 );
+ }
+
+ //
+ // We only allow a transceive on a message mode, full duplex pipe.
+ //
+
+ NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
+
+ if ((NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX) ||
+ (ReadMode != FILE_PIPE_MESSAGE_MODE)) {
+
+ DebugTrace(0, Dbg, "Bad pipe configuration or read mode\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_READ_MODE );
+ try_return( Status = STATUS_INVALID_READ_MODE );
+ }
+
+ //
+ // Check that the read queue is empty.
+ //
+
+ if (!NpIsDataQueueEmpty( ReadQueue )) {
+
+ DebugTrace(0, Dbg, "Read queue is not empty\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_BUSY );
+ try_return( Status = STATUS_PIPE_BUSY );
+ }
+
+ //
+ // Do the transceive write operation. We first try and push the data
+ // from the write buffer into any waiting readers in the write queue
+ // and if that succeeds then we can go on and do the read operation
+ // otherwise we need to make a copy of irp and to enqueue as
+ // a data entry into the write queue.
+ //
+ // Now we'll call our common write data queue routine to
+ // transfer data out of our write buffer into the data queue.
+ // If the result of the call is FALSE then we still have some
+ // write data to put into the write queue.
+ //
+
+ UserThread = Irp->Tail.Overlay.Thread;
+
+ if (!NpWriteDataQueue( WriteQueue,
+ ReadMode,
+ WriteBuffer,
+ WriteLength,
+ Ccb->Fcb->Specific.Fcb.NamedPipeType,
+ &WriteRemaining,
+ Ccb,
+ NamedPipeEnd,
+ UserThread )) {
+
+ PIO_STACK_LOCATION WriteIrpSp;
+
+ ASSERT( !NpIsDataQueueReaders( WriteQueue ));
+
+ DebugTrace(0, Dbg, "Add write to data queue\n", 0);
+
+ //
+ // We need to do some more write processing. So to handle
+ // this case we'll allocate a new irp and set its system
+ // buffer to be the remaining part of the write buffer
+ //
+
+ if ((WriteIrp = IoAllocateIrp( NpfsDeviceObject->DeviceObject.StackSize, FALSE )) == NULL) {
+
+ ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
+ }
+
+ IoSetCompletionRoutine( WriteIrp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE );
+
+ WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
+
+ if (WriteRemaining > 0) {
+
+ WriteIrp->AssociatedIrp.SystemBuffer = UnwindStorage = FsRtlAllocatePool( NonPagedPool,
+ WriteRemaining );
+ //
+ // Safely do the copy
+ //
+
+ try {
+
+ RtlCopyMemory( WriteIrp->AssociatedIrp.SystemBuffer,
+ &WriteBuffer[ WriteLength - WriteRemaining ],
+ WriteRemaining );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
+ }
+
+ } else {
+
+ WriteIrp->AssociatedIrp.SystemBuffer = UnwindStorage = NULL;
+ }
+
+ //
+ // Set the current stack location
+ //
+
+ WriteIrp->CurrentLocation -= 1;
+ WriteIrp->Tail.Overlay.CurrentStackLocation = WriteIrpSp;
+
+ //
+ // Set it up to do buffered I/O and deallocate the buffer
+ // on completion.
+
+ if (WriteRemaining > 0) {
+
+ WriteIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
+ }
+
+ WriteIrp->UserIosb = &Iosb;
+
+ //
+ // Add this write request to the write queue
+ //
+
+ DataEntry = NpAddDataQueueEntry( WriteQueue,
+ WriteEntries,
+ Unbuffered,
+ WriteRemaining,
+ WriteIrp,
+ NULL );
+
+ //
+ // And set the security part of the data entry
+ //
+
+ NpSetDataEntryClientContext( NamedPipeEnd,
+ Ccb,
+ DataEntry,
+ UserThread );
+
+ //
+ // Now null out the write irp variable so that we know not
+ // to deallocate it on an error
+ //
+
+ WriteIrp = NULL;
+ UnwindStorage = NULL;
+ }
+
+ //
+ // Now we need to advance the write queue to the next read irp to
+ // skip over flushes and closes
+ //
+
+ //****NpWriteDataQueue does this for us**** (VOID)NpGetNextRealDataQueueEntry( WriteQueue );
+
+ //
+ // And because we've done something we need to signal the
+ // other ends event
+ //
+
+ NpSignalEventTableEntry( Event );
+
+ //
+ // Do the transceive read operation. This is just like an
+ // unbuffered read.
+ //
+ // Now we know that the read queue is empty so we'll enqueue this
+ // Irp to the read queue and return status pending, also mark the
+ // irp pending
+ //
+
+ ASSERT( NpIsDataQueueEmpty( ReadQueue ));
+
+ (VOID)NpAddDataQueueEntry( ReadQueue,
+ ReadEntries,
+ Unbuffered,
+ ReadLength,
+ Irp,
+ NULL );
+
+ IoMarkIrpPending( Irp );
+
+ (VOID)NpGetNextRealDataQueueEntry( ReadQueue );
+
+ //
+ // And because we've done something we need to signal the
+ // other ends event
+ //
+
+ NpSignalEventTableEntry( Event );
+
+ Status = STATUS_PENDING;
+
+ try_exit: NOTHING;
+ } finally {
+
+ NpReleaseCcb(Ccb);
+ if (WriteIrp != NULL) { IoFreeIrp( WriteIrp ); }
+ if (UnwindStorage != NULL) { ExFreePool( UnwindStorage ); }
+ }
+
+ DebugTrace(-1, Dbg, "NpInternalTransceive -> %08lx\n", Status);
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryClientProcess (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the query client process named pipe control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG OutputBufferLength;
+
+ PCCB Ccb;
+
+ PFILE_PIPE_CLIENT_PROCESS_BUFFER ClientProcessBuffer;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpQueryClientProcess\n", 0);
+
+ OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+
+ //
+ // Decode the file object to figure out who we are.
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, NULL ) != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Make sure the output buffer is large enough
+ //
+
+ if (OutputBufferLength < sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER)) {
+
+ DebugTrace(0, Dbg, "Output System buffer size is too small\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NpAcquireExclusiveCcb(Ccb);
+
+ //
+ // Copy over the client process ID
+ //
+
+ ClientProcessBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ ClientProcessBuffer->ClientSession = Ccb->ClientSession;
+ ClientProcessBuffer->ClientProcess = Ccb->ClientProcess;
+
+ //
+ // Set the information field to the size of the client process
+ // buffer
+ //
+
+ Irp->IoStatus.Information = sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER);
+
+ NpReleaseCcb(Ccb);
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+
+ DebugTrace(-1, Dbg, "NpQueryClientProcess -> STATUS_SUCCESS\n", 0);
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpSetClientProcess (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the set client process named pipe control function
+
+Arguments:
+
+ NpfsDeviceObject - Supplies our device object
+
+ Irp - Supplies the being processed
+
+Return Value:
+
+ NTSTATUS - An apprropriate return status
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG InputBufferLength;
+
+ PCCB Ccb;
+
+ PFILE_PIPE_CLIENT_PROCESS_BUFFER ClientProcessBuffer;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpSetClientProcess\n", 0);
+
+ InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+
+ //
+ // Decode the file object to figure out who we are.
+ //
+
+ if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, NULL ) != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ return STATUS_PIPE_DISCONNECTED;
+ }
+
+ //
+ // Make sure the input buffer is large enough
+ //
+
+ if (InputBufferLength < sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER)) {
+
+ DebugTrace(0, Dbg, "Input System buffer size is too small\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Copy over the client process ID
+ //
+
+ ClientProcessBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ Ccb->ClientSession = ClientProcessBuffer->ClientSession;
+ Ccb->ClientProcess = ClientProcessBuffer->ClientProcess;
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+
+ DebugTrace(-1, Dbg, "NpSetClientProcess -> STATUS_SUCCESS\n", 0);
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCompleteTransceiveIrp (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This is a local i/o completion routine used to complete the special
+ Irps allocated for transcieve. This routine simply deallocate the
+ irp and return status more processing
+
+Arguments:
+
+ DeviceObject - Supplies the device object
+
+ Irp - Supplies the Irp to complete
+
+ Context - Supplies the context for the Irp
+
+Return Value:
+
+ NTSTATUS - STATUS_MORE_PROCESSING_REQUIRED
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( DeviceObject );
+ UNREFERENCED_PARAMETER( Context );
+
+ PAGED_CODE();
+
+ if (Irp->AssociatedIrp.SystemBuffer != NULL) {
+
+ ExFreePool( Irp->AssociatedIrp.SystemBuffer );
+ }
+
+ IoFreeIrp( Irp );
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
diff --git a/private/ntos/npfs/makefile b/private/ntos/npfs/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/npfs/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/npfs/nodetype.h b/private/ntos/npfs/nodetype.h
new file mode 100644
index 000000000..3ace73772
--- /dev/null
+++ b/private/ntos/npfs/nodetype.h
@@ -0,0 +1,143 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ NodeType.h
+
+Abstract:
+
+ This module defines all of the node type codes used in this development
+ shell. Every major data structure in the file system is assigned a node
+ type code that is. This code is the first CSHORT in the structure and is
+ followed by a CSHORT containing the size, in bytes, of the structure.
+
+Author:
+
+ Gary Kimura [GaryKi] 20-Aug-1990
+
+Revision History:
+
+--*/
+
+#ifndef _NODETYPE_
+#define _NODETYPE_
+
+typedef CSHORT NODE_TYPE_CODE;
+typedef NODE_TYPE_CODE *PNODE_TYPE_CODE;
+
+#define NTC_UNDEFINED ((NODE_TYPE_CODE)0x0000)
+
+#define NPFS_NTC_VCB ((NODE_TYPE_CODE)0x0401)
+
+#define NPFS_NTC_ROOT_DCB ((NODE_TYPE_CODE)0x0402)
+
+#define NPFS_NTC_FCB ((NODE_TYPE_CODE)0x0404)
+
+#define NPFS_NTC_CCB ((NODE_TYPE_CODE)0x0406)
+#define NPFS_NTC_NONPAGED_CCB ((NODE_TYPE_CODE)0x0407)
+
+#define NPFS_NTC_ROOT_DCB_CCB ((NODE_TYPE_CODE)0x0408)
+
+typedef CSHORT NODE_BYTE_SIZE;
+
+//
+// So all records start with
+//
+// typedef struct _RECORD_NAME {
+// NODE_TYPE_CODE NodeTypeCode;
+// NODE_BYTE_SIZE NodeByteSize;
+// :
+// } RECORD_NAME;
+// typedef RECORD_NAME *PRECORD_NAME;
+//
+
+#define NodeType(Ptr) ((Ptr) == NULL ? NTC_UNDEFINED : *((PNODE_TYPE_CODE)(Ptr)))
+
+
+//
+// The following definitions are used to generate meaningful blue bugcheck
+// screens. On a bugcheck the file system can output 4 ulongs of useful
+// information. The first ulong will have encoded in it a source file id
+// (in the high word) and the line number of the bugcheck (in the low word).
+// The other values can be whatever the caller of the bugcheck routine deems
+// necessary.
+//
+// Each individual file that calls bugcheck needs to have defined at the
+// start of the file a constant called BugCheckFileId with one of the
+// NPFS_BUG_CHECK_ values defined below and then use NpBugCheck to bugcheck
+// the system.
+//
+
+#define NPFS_BUG_CHECK_CLEANUP (0x00010000)
+#define NPFS_BUG_CHECK_CLOSE (0x00020000)
+#define NPFS_BUG_CHECK_CREATE (0x00030000)
+#define NPFS_BUG_CHECK_CREATENP (0x00040000)
+#define NPFS_BUG_CHECK_DIR (0x00050000)
+#define NPFS_BUG_CHECK_DATASUP (0x00060000)
+#define NPFS_BUG_CHECK_DEVIOSUP (0x00070000)
+#define NPFS_BUG_CHECK_DUMPSUP (0x00080000)
+#define NPFS_BUG_CHECK_EVENTSUP (0x00090000)
+#define NPFS_BUG_CHECK_FILEINFO (0x000a0000)
+#define NPFS_BUG_CHECK_FILOBSUP (0x000b0000)
+#define NPFS_BUG_CHECK_FLUSHBUF (0x000c0000)
+#define NPFS_BUG_CHECK_FSCTRL (0x000d0000)
+#define NPFS_BUG_CHECK_NPINIT (0x000e0000)
+#define NPFS_BUG_CHECK_NPDATA (0x000f0000)
+#define NPFS_BUG_CHECK_PREFXSUP (0x00100000)
+#define NPFS_BUG_CHECK_READ (0x00110000)
+#define NPFS_BUG_CHECK_READSUP (0x00120000)
+#define NPFS_BUG_CHECK_RESRCSUP (0x00130000)
+#define NPFS_BUG_CHECK_SEINFO (0x00140000)
+#define NPFS_BUG_CHECK_SECURSUP (0x00150000)
+#define NPFS_BUG_CHECK_STATESUP (0x00160000)
+#define NPFS_BUG_CHECK_STRUCSUP (0x00170000)
+#define NPFS_BUG_CHECK_VOLINFO (0x00180000)
+#define NPFS_BUG_CHECK_WAITSUP (0x00190000)
+#define NPFS_BUG_CHECK_WRITE (0x001a0000)
+#define NPFS_BUG_CHECK_WRITESUP (0x001b0000)
+
+#define NpBugCheck(A,B,C) { KeBugCheckEx(NPFS_FILE_SYSTEM, BugCheckFileId | __LINE__, A, B, C ); }
+
+
+//
+// In this module we'll also define some globally known constants
+//
+
+#define UCHAR_NUL 0x00
+#define UCHAR_SOH 0x01
+#define UCHAR_STX 0x02
+#define UCHAR_ETX 0x03
+#define UCHAR_EOT 0x04
+#define UCHAR_ENQ 0x05
+#define UCHAR_ACK 0x06
+#define UCHAR_BEL 0x07
+#define UCHAR_BS 0x08
+#define UCHAR_HT 0x09
+#define UCHAR_LF 0x0a
+#define UCHAR_VT 0x0b
+#define UCHAR_FF 0x0c
+#define UCHAR_CR 0x0d
+#define UCHAR_SO 0x0e
+#define UCHAR_SI 0x0f
+#define UCHAR_DLE 0x10
+#define UCHAR_DC1 0x11
+#define UCHAR_DC2 0x12
+#define UCHAR_DC3 0x13
+#define UCHAR_DC4 0x14
+#define UCHAR_NAK 0x15
+#define UCHAR_SYN 0x16
+#define UCHAR_ETB 0x17
+#define UCHAR_CAN 0x18
+#define UCHAR_EM 0x19
+#define UCHAR_SUB 0x1a
+#define UCHAR_ESC 0x1b
+#define UCHAR_FS 0x1c
+#define UCHAR_GS 0x1d
+#define UCHAR_RS 0x1e
+#define UCHAR_US 0x1f
+#define UCHAR_SP 0x20
+
+#endif // _NODETYPE_
+
diff --git a/private/ntos/npfs/npdata.c b/private/ntos/npfs/npdata.c
new file mode 100644
index 000000000..7836dea37
--- /dev/null
+++ b/private/ntos/npfs/npdata.c
@@ -0,0 +1,117 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ NpData.c
+
+Abstract:
+
+ This module declares the global data used by the Named Pipe file system.
+
+Author:
+
+ Gary Kimura [GaryKi] 28-Dec-1989
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (NPFS_BUG_CHECK_NPDATA)
+
+//
+// Local debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_CATCH_EXCEPTIONS)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpExceptionFilter)
+#pragma alloc_text(PAGE, NpProcessException)
+#endif
+
+PVCB NpVcb = NULL;
+
+FAST_IO_DISPATCH NpFastIoDispatch = { sizeof(FAST_IO_DISPATCH),
+ NULL, // FastIoCheck
+ NpFastRead, // Read
+ NpFastWrite, // Write
+ NULL, // QueryBasicInfo
+ NULL, // QueryStandardInfo
+ NULL, // Lock
+ NULL, // UnlockSingle
+ NULL, // UnlockAll
+ NULL }; // UnlockAllByKey
+
+//
+// Lists of pipe name aliases.
+//
+
+SINGLE_LIST_ENTRY NpAliasListByLength[(MAX_LENGTH_ALIAS_ARRAY-MIN_LENGTH_ALIAS_ARRAY)/sizeof(WCHAR)+1] = {NULL};
+SINGLE_LIST_ENTRY NpAliasList = {NULL};
+
+PVOID NpAliases = NULL; // single allocation containing all aliases
+
+
+#ifdef NPDBG
+LONG NpDebugTraceLevel = 0x00000000;
+LONG NpDebugTraceIndent = 0;
+#endif // NPDBG
+
+
+LONG
+NpExceptionFilter (
+ IN NTSTATUS ExceptionCode
+ )
+{
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpExceptionFilter %08lx\n", ExceptionCode);
+ DebugDump("", Dbg, NULL );
+
+ if (FsRtlIsNtstatusExpected( ExceptionCode )) {
+
+ return EXCEPTION_EXECUTE_HANDLER;
+
+ } else {
+
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+}
+
+NTSTATUS
+NpProcessException (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp,
+ IN NTSTATUS ExceptionCode
+ )
+{
+ NTSTATUS FinalExceptionCode;
+
+ PAGED_CODE();
+
+ FinalExceptionCode = ExceptionCode;
+
+ if (FsRtlIsNtstatusExpected( ExceptionCode )) {
+
+ if ( FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) {
+
+ Irp->IoStatus.Information = 0;
+ }
+
+ NpCompleteRequest( Irp, ExceptionCode );
+
+ } else {
+
+ NpBugCheck( ExceptionCode, 0, 0 );
+ }
+
+ return FinalExceptionCode;
+}
diff --git a/private/ntos/npfs/npdata.h b/private/ntos/npfs/npdata.h
new file mode 100644
index 000000000..08e8dc860
--- /dev/null
+++ b/private/ntos/npfs/npdata.h
@@ -0,0 +1,182 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ NpData.c
+
+Abstract:
+
+ This module declares the global data used by the Named Pipe file system.
+
+Author:
+
+ Gary Kimura [GaryKi] 20-Aug-1990
+
+Revision History:
+
+--*/
+
+#ifndef _NPDATA_
+#define _NPDATA_
+
+extern PVCB NpVcb;
+
+//
+// The global structure used to contain our fast I/O callbacks
+//
+
+extern FAST_IO_DISPATCH NpFastIoDispatch;
+
+//
+// Lists of pipe name aliases.
+//
+
+#define MIN_LENGTH_ALIAS_ARRAY (5 * sizeof(WCHAR)) // includes '\'
+#define MAX_LENGTH_ALIAS_ARRAY (9 * sizeof(WCHAR))
+
+extern SINGLE_LIST_ENTRY NpAliasListByLength[(MAX_LENGTH_ALIAS_ARRAY-MIN_LENGTH_ALIAS_ARRAY)/sizeof(WCHAR)+1];
+extern SINGLE_LIST_ENTRY NpAliasList;
+
+extern PVOID NpAliases; // single allocation containing all aliases
+
+//
+// The global Named Pipe debug level variable, its values are:
+//
+// 0x00000000 Always gets printed (used when about to bug check)
+//
+// 0x00000001
+// 0x00000002
+// 0x00000004
+// 0x00000008
+//
+// 0x00000010
+// 0x00000020
+// 0x00000040
+// 0x00000080
+//
+// 0x00000100
+// 0x00000200
+// 0x00000400
+// 0x00000800
+//
+// 0x00001000
+// 0x00002000
+// 0x00004000
+// 0x00008000
+//
+// 0x00010000
+// 0x00020000
+// 0x00040000
+// 0x00080000
+//
+// 0x00100000
+// 0x00200000
+// 0x00400000
+// 0x00800000
+//
+// 0x01000000
+// 0x02000000
+// 0x04000000
+// 0x08000000
+//
+// 0x10000000
+// 0x20000000
+// 0x40000000
+// 0x80000000
+//
+
+#ifdef NPDBG
+
+#define DEBUG_TRACE_ERROR (0x00000001)
+#define DEBUG_TRACE_DEBUG_HOOKS (0x00000002)
+#define DEBUG_TRACE_CATCH_EXCEPTIONS (0x00000004)
+#define DEBUG_TRACE_CREATE (0x00000008)
+#define DEBUG_TRACE_CLOSE (0x00000010)
+#define DEBUG_TRACE_READ (0x00000020)
+#define DEBUG_TRACE_WRITE (0x00000040)
+#define DEBUG_TRACE_FILEINFO (0x00000080)
+#define DEBUG_TRACE_CLEANUP (0x00000100)
+#define DEBUG_TRACE_DIR (0x00000200)
+#define DEBUG_TRACE_FSCONTRL (0x00000400)
+#define DEBUG_TRACE_CREATE_NAMED_PIPE (0x00000800)
+#define DEBUG_TRACE_FLUSH_BUFFERS (0x00001000)
+#define DEBUG_TRACE_VOLINFO (0x00002000)
+#define DEBUG_TRACE_SEINFO (0x00004000)
+#define DEBUG_TRACE_0x00008000 (0x00008000)
+#define DEBUG_TRACE_0x00010000 (0x00010000)
+#define DEBUG_TRACE_SECURSUP (0x00020000)
+#define DEBUG_TRACE_DEVIOSUP (0x00040000)
+#define DEBUG_TRACE_RESRCSUP (0x00080000)
+#define DEBUG_TRACE_READSUP (0x00100000)
+#define DEBUG_TRACE_WRITESUP (0x00200000)
+#define DEBUG_TRACE_STATESUP (0x00400000)
+#define DEBUG_TRACE_FILOBSUP (0x00800000)
+#define DEBUG_TRACE_PREFXSUP (0x01000000)
+#define DEBUG_TRACE_CNTXTSUP (0x02000000)
+#define DEBUG_TRACE_DATASUP (0x04000000)
+#define DEBUG_TRACE_WAITSUP (0x08000000)
+#define DEBUG_TRACE_EVENTSUP (0x10000000)
+#define DEBUG_TRACE_STRUCSUP (0x20000000)
+
+extern LONG NpDebugTraceLevel;
+extern LONG NpDebugTraceIndent;
+
+#define DebugTrace(INDENT,LEVEL,X,Y) { \
+ LONG _i; \
+ if (((LEVEL) == 0) || (NpDebugTraceLevel & (LEVEL))) { \
+ _i = (ULONG)PsGetCurrentThread(); \
+ DbgPrint("%08lx:",_i); \
+ if ((INDENT) < 0) { \
+ NpDebugTraceIndent += (INDENT); \
+ } \
+ if (NpDebugTraceIndent < 0) { \
+ NpDebugTraceIndent = 0; \
+ } \
+ for (_i=0; _i<NpDebugTraceIndent; _i+=1) { \
+ DbgPrint(" "); \
+ } \
+ DbgPrint(X,Y); \
+ if ((INDENT) > 0) { \
+ NpDebugTraceIndent += (INDENT); \
+ } \
+ } \
+}
+
+#define DebugDump(STR,LEVEL,PTR) { \
+ ULONG _i; \
+ VOID NpDump(PVOID Ptr); \
+ if (((LEVEL) == 0) || (NpDebugTraceLevel & (LEVEL))) { \
+ _i = (ULONG)PsGetCurrentThread(); \
+ DbgPrint("%08lx:",_i); \
+ DbgPrint(STR); \
+ if (PTR != NULL) {NpDump(PTR);} \
+ DbgBreakPoint(); \
+ } \
+}
+
+#else
+
+#define DebugTrace(INDENT,LEVEL,X,Y) {NOTHING;}
+#define DebugDump(STR,LEVEL,PTR) {NOTHING;}
+
+#endif // NPDBG
+
+//
+// The following macro is for all people who compile with the DBG switch
+// set, not just fastfat dbg users
+//
+
+#if DBG
+
+#define DbgDoit(X) {X;}
+
+#else
+
+#define DbgDoit(X) {NOTHING;}
+
+#endif // DBG
+
+
+#endif // _NPDATA_
diff --git a/private/ntos/npfs/npfs.prf b/private/ntos/npfs/npfs.prf
new file mode 100644
index 000000000..24024ae35
--- /dev/null
+++ b/private/ntos/npfs/npfs.prf
@@ -0,0 +1 @@
+NpDeleteCcb@4
diff --git a/private/ntos/npfs/npfs.rc b/private/ntos/npfs/npfs.rc
new file mode 100644
index 000000000..ff0ac95c3
--- /dev/null
+++ b/private/ntos/npfs/npfs.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "NPFS Driver"
+#define VER_INTERNALNAME_STR "npfs.sys"
+#define VER_ORIGINALFILENAME_STR "npfs.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/npfs/npinit.c b/private/ntos/npfs/npinit.c
new file mode 100644
index 000000000..3c68a0508
--- /dev/null
+++ b/private/ntos/npfs/npinit.c
@@ -0,0 +1,178 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ NpInit.c
+
+Abstract:
+
+ This module implements the DRIVER_INITIALIZATION routine for the Named
+ Pipe file system.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+//#include <zwapi.h>
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the Named Pipe file system
+ device driver. This routine creates the device object for the named pipe
+ device and performs all other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ NTSTATUS - The function value is the final status from the initialization
+ operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ UNICODE_STRING NameString;
+ PDEVICE_OBJECT DeviceObject;
+ PNPFS_DEVICE_OBJECT NpfsDeviceObject;
+
+ BOOLEAN VcbInitialized;
+
+ PAGED_CODE();
+
+ //
+ // Create the alias lists.
+ //
+
+ Status = NpInitializeAliases( );
+ if (!NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ //
+ // Create the device object.
+ //
+
+ RtlInitUnicodeString( &NameString, L"\\Device\\NamedPipe" );
+
+ Status = IoCreateDevice( DriverObject,
+ sizeof(NPFS_DEVICE_OBJECT)-sizeof(DEVICE_OBJECT),
+ &NameString,
+ FILE_DEVICE_NAMED_PIPE,
+ 0,
+ FALSE,
+ &DeviceObject );
+
+ if (!NT_SUCCESS( Status )) {
+ ExFreePool( NpAliases );
+ return Status;
+ }
+
+ //
+ // Now because we use the irp stack for storing a data entry we need
+ // to bump up the stack size in the device object we just created.
+ //
+
+ DeviceObject->StackSize += 1;
+
+ //
+ // Note that because of the way data copying is done, we set neither
+ // the Direct I/O or Buffered I/O bit in DeviceObject->Flags. If
+ // data is not buffered we may set up for Direct I/O by hand. We do,
+ // however, set the long term request flag so that IRPs that get
+ // allocated for functions such as Listen requests come out of non-paged
+ // pool always.
+ //
+
+ DeviceObject->Flags |= DO_LONG_TERM_REQUESTS;
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)NpFsdCreate;
+ DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = (PDRIVER_DISPATCH)NpFsdCreateNamedPipe;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)NpFsdClose;
+ DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)NpFsdRead;
+ DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)NpFsdWrite;
+ DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)NpFsdQueryInformation;
+ DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)NpFsdSetInformation;
+ DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)NpFsdQueryVolumeInformation;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)NpFsdCleanup;
+ DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)NpFsdFlushBuffers;
+ DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)NpFsdDirectoryControl;
+ DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)NpFsdFileSystemControl;
+ DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = (PDRIVER_DISPATCH)NpFsdQuerySecurityInfo;
+ DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = (PDRIVER_DISPATCH)NpFsdSetSecurityInfo;
+
+#ifdef _PNP_POWER_
+ //
+ // Npfs doesn't need to handle SetPower requests. Local named pipes
+ // won't lose any state. Remote pipes will be lost, by a network driver
+ // will fail PowerQuery if there are open network connections.
+ //
+
+ DeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
+#endif
+
+
+ DriverObject->FastIoDispatch = &NpFastIoDispatch;
+
+ VcbInitialized = FALSE;
+
+ try {
+
+ //
+ // Now initialize the Vcb, and create the root dcb
+ //
+
+ NpfsDeviceObject = (PNPFS_DEVICE_OBJECT)DeviceObject;
+
+ NpVcb = &NpfsDeviceObject->Vcb;
+ NpInitializeVcb( );
+ VcbInitialized = TRUE;
+
+ (VOID)NpCreateRootDcb( );
+
+ } finally {
+
+ if (AbnormalTermination()) {
+
+ if (VcbInitialized) { NpDeleteVcb( ); }
+ }
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return( STATUS_SUCCESS );
+}
diff --git a/private/ntos/npfs/npprocs.h b/private/ntos/npfs/npprocs.h
new file mode 100644
index 000000000..ef16e97f0
--- /dev/null
+++ b/private/ntos/npfs/npprocs.h
@@ -0,0 +1,791 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ NpProcs.h
+
+Abstract:
+
+ This module defines all of the globally used procedures in the Named
+ Pipe file system.
+
+Author:
+
+ Gary Kimura [GaryKi] 20-Aug-1990
+
+Revision History:
+
+--*/
+
+#ifndef _NPPROCS_
+#define _NPPROCS_
+
+#include <NtIfs.h>
+
+//#include <Ntos.h>
+//#include <FsRtl.h>
+//#include <String.h>
+
+#include "NodeType.h"
+#include "NpStruc.h"
+#include "NpData.h"
+
+//
+// Tag all of our allocations if tagging is turned on
+//
+
+#undef FsRtlAllocatePool
+#undef FsRtlAllocatePoolWithQuota
+
+#define FsRtlAllocatePool(a,b) FsRtlAllocatePoolWithTag(a,b,'sfpN')
+#define FsRtlAllocatePoolWithQuota(a,b) FsRtlAllocatePoolWithQuotaTag(a,b,'sfpN')
+
+
+//
+// Data queue support routines, implemented in DataSup.c
+//
+
+VOID
+NpInitializeDataQueue (
+ IN PDATA_QUEUE DataQueue,
+ IN PEPROCESS Process,
+ IN ULONG Quota
+ );
+
+VOID
+NpUninitializeDataQueue (
+ IN PDATA_QUEUE DataQueue,
+ IN PEPROCESS Process
+ );
+
+PDATA_ENTRY
+NpAddDataQueueEntry (
+ IN PDATA_QUEUE DataQueue,
+ IN QUEUE_STATE Who,
+ IN DATA_ENTRY_TYPE Type,
+ IN ULONG DataSize,
+ IN PIRP Irp OPTIONAL,
+ IN PVOID DataPointer OPTIONAL
+ );
+
+PIRP
+NpRemoveDataQueueEntry (
+ IN PDATA_QUEUE DataQueue
+ );
+
+//PDATA_ENTRY
+//NpGetNextDataQueueEntry (
+// IN PDATA_QUEUE DataQueue,
+// IN PDATA_ENTRY PreviousDataEntry OPTIONAL
+// );
+#define NpGetNextDataQueueEntry(_dq,_pde) \
+ ((_pde) != NULL ? ((PDATA_ENTRY)(_pde))->Next : (_dq)->FrontOfQueue)
+
+PDATA_ENTRY
+NpGetNextRealDataQueueEntry (
+ IN PDATA_QUEUE DataQueue
+ );
+
+//BOOLEAN
+//NpIsDataQueueEmpty (
+// IN PDATA_QUEUE DataQueue
+// );
+#define NpIsDataQueueEmpty(_dq) ((_dq)->QueueState == Empty)
+
+//BOOLEAN
+//NpIsDataQueueReaders (
+// IN PDATA_QUEUE DataQueue
+// );
+#define NpIsDataQueueReaders(_dq) ((_dq)->QueueState == ReadEntries)
+
+//BOOLEAN
+//NpIsDataQueueWriters (
+// IN PDATA_QUEUE DataQueue
+// );
+#define NpIsDataQueueWriters(_dq) ((_dq)->QueueState == WriteEntries)
+
+
+//
+// The following routines are used to manipulate the input buffers and are
+// implemented in DevioSup.c
+//
+
+//PVOID
+//NpMapUserBuffer (
+// IN OUT PIRP Irp
+// );
+#define NpMapUserBuffer(_irp) \
+ (Irp->MdlAddress == NULL ? Irp->UserBuffer : \
+ MmGetSystemAddressForMdl( Irp->MdlAddress ))
+
+
+VOID
+NpLockUserBuffer (
+ IN OUT PIRP Irp,
+ IN LOCK_OPERATION Operation,
+ IN ULONG BufferLength
+ );
+
+
+//
+// The event support routines, implemented in EventSup.c
+//
+
+RTL_GENERIC_COMPARE_RESULTS
+NpEventTableCompareRoutine (
+ IN PRTL_GENERIC_TABLE EventTable,
+ IN PVOID FirstStruct,
+ IN PVOID SecondStruct
+ );
+
+PVOID
+NpEventTableAllocate (
+ IN PRTL_GENERIC_TABLE EventTable,
+ IN CLONG ByteSize
+ );
+
+VOID
+NpEventTableDeallocate (
+ IN PRTL_GENERIC_TABLE EventTable,
+ IN PVOID Buffer
+ );
+
+//
+// VOID
+// NpInitializeEventTable (
+// IN PEVENT_TABLE EventTable
+// );
+//
+
+#define NpInitializeEventTable(_et) { \
+ RtlInitializeGenericTable( &(_et)->Table, \
+ NpEventTableCompareRoutine, \
+ NpEventTableAllocate, \
+ NpEventTableDeallocate, \
+ (PVOID)NonPagedPool ); \
+}
+
+
+//VOID
+//NpUninitializeEventTable (
+// IN PEVENT_TABLE EventTable
+// );
+#define NpUninitializeEventTable(_et) NOTHING
+
+PEVENT_TABLE_ENTRY
+NpAddEventTableEntry (
+ IN PEVENT_TABLE EventTable,
+ IN PCCB Ccb,
+ IN NAMED_PIPE_END NamedPipeEnd,
+ IN HANDLE EventHandle,
+ IN ULONG KeyValue,
+ IN PEPROCESS Process,
+ IN KPROCESSOR_MODE PreviousMode
+ );
+
+VOID
+NpDeleteEventTableEntry (
+ IN PEVENT_TABLE EventTable,
+ IN PEVENT_TABLE_ENTRY Template
+ );
+
+// VOID
+// NpSignalEventTableEntry (
+// IN PEVENT_TABLE_ENTRY EventTableEntry OPTIONAL
+// );
+#define NpSignalEventTableEntry(_ete) \
+ if (ARGUMENT_PRESENT(_ete)) { \
+ KeSetEvent((PKEVENT)(_ete)->Event, 0, FALSE); \
+ }
+
+PEVENT_TABLE_ENTRY
+NpGetNextEventTableEntry (
+ IN PEVENT_TABLE EventTable,
+ IN PVOID *RestartKey
+ );
+
+
+//
+// The following routines are used to manipulate the fscontext fields of
+// a file object, implemented in FilObSup.c
+//
+
+VOID
+NpSetFileObject (
+ IN PFILE_OBJECT FileObject OPTIONAL,
+ IN PVOID FsContext,
+ IN PVOID FsContext2,
+ IN NAMED_PIPE_END NamedPipeEnd
+ );
+
+NODE_TYPE_CODE
+NpDecodeFileObject (
+ IN PFILE_OBJECT FileObject,
+ OUT PFCB *Fcb OPTIONAL,
+ OUT PCCB *Ccb,
+ OUT PNAMED_PIPE_END NamedPipeEnd OPTIONAL
+ );
+
+
+//
+// Largest matching prefix searching routines, implemented in PrefxSup.c
+//
+
+PFCB
+NpFindPrefix (
+ IN PUNICODE_STRING String,
+ IN BOOLEAN CaseInsensitive,
+ OUT PUNICODE_STRING RemainingPart
+ );
+
+PFCB
+NpFindRelativePrefix (
+ IN PDCB Dcb,
+ IN PUNICODE_STRING String,
+ IN BOOLEAN CaseInsensitive,
+ OUT PUNICODE_STRING RemainingPart
+ );
+
+
+//
+// Pipe name aliases, implemented in AliasSup.c
+//
+
+NTSTATUS
+NpInitializeAliases (
+ VOID
+ );
+
+NTSTATUS
+NpTranslateAlias (
+ IN OUT PUNICODE_STRING String
+ );
+
+
+//
+// The follow routine provides common read data queue support
+// for buffered read, unbuffered read, peek, and transceive
+//
+
+IO_STATUS_BLOCK
+NpReadDataQueue ( // implemented in ReadSup.c
+ IN PDATA_QUEUE ReadQueue,
+ IN BOOLEAN PeekOperation,
+ IN BOOLEAN ReadOverflowOperation,
+ IN PUCHAR ReadBuffer,
+ IN ULONG ReadLength,
+ IN READ_MODE ReadMode,
+ IN PCCB Ccb
+ );
+
+
+//
+// The following routines are used for setting and manipulating the
+// security fields in the data entry, and nonpaged ccb, implemented in
+// SecurSup.c
+//
+
+NTSTATUS
+NpInitializeSecurity (
+ IN PCCB Ccb,
+ IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
+ IN PETHREAD UserThread
+ );
+
+VOID
+NpUninitializeSecurity (
+ IN PCCB Ccb
+ );
+
+NTSTATUS
+NpSetDataEntryClientContext (
+ IN NAMED_PIPE_END NamedPipeEnd,
+ IN PCCB Ccb,
+ IN PDATA_ENTRY DataEntry,
+ IN PETHREAD UserThread
+ );
+
+VOID
+NpCopyClientContext (
+ IN PCCB Ccb,
+ IN PDATA_ENTRY DataEntry
+ );
+
+NTSTATUS
+NpImpersonateClientContext (
+ IN PCCB Ccb
+ );
+
+
+//
+// The following routines are used to manipulate the named pipe state
+// implemented in StateSup.c
+//
+
+VOID
+NpInitializePipeState (
+ IN PCCB Ccb,
+ IN PFILE_OBJECT ServerFileObject
+ );
+
+VOID
+NpUninitializePipeState (
+ IN PCCB Ccb
+ );
+
+NTSTATUS
+NpSetListeningPipeState (
+ IN PCCB Ccb,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpSetConnectedPipeState (
+ IN PCCB Ccb,
+ IN PFILE_OBJECT ClientFileObject
+ );
+
+NTSTATUS
+NpSetClosingPipeState (
+ IN PCCB Ccb,
+ IN PIRP Irp,
+ IN NAMED_PIPE_END NamedPipeEnd
+ );
+
+NTSTATUS
+NpSetDisconnectedPipeState (
+ IN PCCB Ccb
+ );
+
+
+//
+// Internal Named Pipe data Structure Routines, implemented in StrucSup.c.
+//
+// These routines maniuplate the in memory data structures.
+//
+
+VOID
+NpInitializeVcb (
+ VOID
+ );
+
+VOID
+NpDeleteVcb (
+ VOID
+ );
+
+VOID
+NpCreateRootDcb (
+ VOID
+ );
+
+VOID
+NpDeleteRootDcb (
+ IN PROOT_DCB Dcb
+ );
+
+PFCB
+NpCreateFcb (
+ IN PDCB ParentDcb,
+ IN PUNICODE_STRING FileName,
+ IN ULONG MaximumInstances,
+ IN LARGE_INTEGER DefaultTimeOut,
+ IN NAMED_PIPE_CONFIGURATION NamedPipeConfiguration,
+ IN NAMED_PIPE_TYPE NamedPipeType
+ );
+
+VOID
+NpDeleteFcb (
+ IN PFCB Fcb
+ );
+
+PCCB
+NpCreateCcb (
+ IN PFCB Fcb,
+ IN PFILE_OBJECT ServerFileObject,
+ IN NAMED_PIPE_STATE NamedPipeState,
+ IN READ_MODE ServerReadMode,
+ IN COMPLETION_MODE ServerCompletionMode,
+ IN PEPROCESS CreatorProcess,
+ IN ULONG InBoundQuota,
+ IN ULONG OutBoundQuota
+ );
+
+PROOT_DCB_CCB
+NpCreateRootDcbCcb (
+ );
+
+VOID
+NpDeleteCcb (
+ IN PCCB Ccb
+ );
+
+
+//
+// Waiting for a named pipe support routines, implemented in WaitSup.c
+//
+
+VOID
+NpInitializeWaitQueue (
+ IN PWAIT_QUEUE WaitQueue
+ );
+
+VOID
+NpUninitializeWaitQueue (
+ IN PWAIT_QUEUE WaitQueue
+ );
+
+VOID
+NpAddWaiter (
+ IN PWAIT_QUEUE WaitQueue,
+ IN LARGE_INTEGER DefaultTimeOut,
+ IN PIRP Irp
+ );
+
+VOID
+NpCancelWaiter (
+ IN PWAIT_QUEUE WaitQueue,
+ IN PUNICODE_STRING NameOfPipe
+ );
+
+
+//
+// The follow routine provides common write data queue support
+// for buffered write, unbuffered write, peek, and transceive
+//
+
+BOOLEAN
+NpWriteDataQueue ( // implemented in WriteSup.c
+ IN PDATA_QUEUE WriteQueue,
+ IN READ_MODE ReadMode,
+ IN PUCHAR WriteBuffer,
+ IN ULONG WriteLength,
+ IN NAMED_PIPE_TYPE PipeType,
+ OUT PULONG WriteRemaining,
+ IN PCCB Ccb,
+ IN NAMED_PIPE_END NamedPipeEnd,
+ IN PETHREAD UserThread
+ );
+
+
+//
+// Miscellaneous support routines
+//
+
+#define BooleanFlagOn(F,SF) ( \
+ (BOOLEAN)(((F) & (SF)) != 0) \
+)
+
+//
+// This macro takes a pointer (or ulong) and returns its rounded up word
+// value
+//
+
+#define WordAlign(Ptr) ( \
+ ((((ULONG)(Ptr)) + 1) & 0xfffffffe) \
+ )
+
+//
+// This macro takes a pointer (or ulong) and returns its rounded up longword
+// value
+//
+
+#define LongAlign(Ptr) ( \
+ ((((ULONG)(Ptr)) + 3) & 0xfffffffc) \
+ )
+
+//
+// This macro takes a pointer (or ulong) and returns its rounded up quadword
+// value
+//
+
+#define QuadAlign(Ptr) ( \
+ ((((ULONG)(Ptr)) + 7) & 0xfffffff8) \
+ )
+
+//
+// The following types and macros are used to help unpack the packed and
+// misaligned fields found in the Bios parameter block
+//
+
+typedef union _UCHAR1 {
+ UCHAR Uchar[1];
+ UCHAR ForceAlignment;
+} UCHAR1, *PUCHAR1;
+
+typedef union _UCHAR2 {
+ UCHAR Uchar[2];
+ USHORT ForceAlignment;
+} UCHAR2, *PUCHAR2;
+
+typedef union _UCHAR4 {
+ UCHAR Uchar[4];
+ ULONG ForceAlignment;
+} UCHAR4, *PUCHAR4;
+
+//
+// This macro copies an unaligned src byte to an aligned dst byte
+//
+
+#define CopyUchar1(Dst,Src) { \
+ *((UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src)); \
+ }
+
+//
+// This macro copies an unaligned src word to an aligned dst word
+//
+
+#define CopyUchar2(Dst,Src) { \
+ *((UCHAR2 *)(Dst)) = *((UNALIGNED UCHAR2 *)(Src)); \
+ }
+
+//
+// This macro copies an unaligned src longword to an aligned dsr longword
+//
+
+#define CopyUchar4(Dst,Src) { \
+ *((UCHAR4 *)(Dst)) = *((UNALIGNED UCHAR4 *)(Src)); \
+ }
+
+
+//
+// VOID
+// NpAcquireExclusiveVcb (
+// );
+//
+// VOID
+// NpAcquireSharedVcb (
+// );
+//
+// VOID
+// NpReleaseVcb (
+// );
+//
+
+#define NpAcquireExclusiveVcb() (VOID)ExAcquireResourceExclusive( &NpVcb->Resource, TRUE )
+
+#define NpAcquireSharedVcb() (VOID)ExAcquireResourceShared( &NpVcb->Resource, TRUE )
+
+#define NpReleaseVcb() ExReleaseResource( &NpVcb->Resource )
+
+#define NpAcquireExclusiveCcb(Ccb) ExAcquireResourceExclusive(&Ccb->NonpagedCcb->Resource,TRUE);
+#define NpReleaseCcb(Ccb) ExReleaseResource(&Ccb->NonpagedCcb->Resource);
+
+
+
+//
+// The FSD Level dispatch routines. These routines are called by the
+// I/O system via the dispatch table in the Driver Object.
+//
+// They each accept as input a pointer to a device object (actually most
+// expect an npfs device object), and a pointer to the IRP.
+//
+
+NTSTATUS
+NpFsdCreate ( // implemented in Create.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdCreateNamedPipe ( // implemented in CreateNp.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdClose ( // implemented in Close.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdRead ( // implemented in Read.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdWrite ( // implemented in Write.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdQueryInformation ( // implemented in FileInfo.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdSetInformation ( // implemented in FileInfo.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdCleanup ( // implemented in Cleanup.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdFlushBuffers ( // implemented in Flush.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdDirectoryControl ( // implemented in Dir.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdFileSystemControl ( // implemented in FsContrl.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdSetSecurityInfo ( // implemented in SeInfo.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdQuerySecurityInfo ( // implemented in SeInfo.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpFsdQueryVolumeInformation ( // implemented in VolInfo.c
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// The following procedures are callbacks used to do fast I/O
+//
+
+BOOLEAN
+NpFastRead (
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN ULONG LockKey,
+ OUT PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus,
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+BOOLEAN
+NpFastWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN ULONG LockKey,
+ IN PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus,
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+
+//
+// Miscellaneous routines.
+//
+
+VOID
+NpCheckForNotify ( // implemented in Dir.c
+ IN PDCB Dcb,
+ IN BOOLEAN CheckAllOutstandingIrps
+ );
+
+//
+// The following macro is used by the FSD routines to complete
+// an IRP.
+//
+
+#define NpCompleteRequest(IRP,STATUS) { \
+ IoSetCancelRoutine( (IRP), NULL ); \
+ FsRtlCompleteRequest( (IRP), (STATUS) ); \
+}
+
+
+//
+// The following two macro are used by the Fsd exception handlers to
+// process an exception. The first macro is the exception filter used in the
+// Fsd to decide if an exception should be handled at this level.
+// The second macro decides if the exception is to be finished off by
+// completing the IRP, and cleaning up the Irp Context, or if we should
+// bugcheck. Exception values such as STATUS_FILE_INVALID (raised by
+// VerfySup.c) cause us to complete the Irp and cleanup, while exceptions
+// such as accvio cause us to bugcheck.
+//
+// The basic structure for fsd exception handling is as follows:
+//
+// NpFsdXxx(...)
+// {
+// try {
+//
+// ...
+//
+// } except(NpExceptionFilter( GetExceptionCode() )) {
+//
+// Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+// }
+//
+// Return Status;
+// }
+//
+
+LONG
+NpExceptionFilter (
+ IN NTSTATUS ExceptionCode
+ );
+
+NTSTATUS
+NpProcessException (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp,
+ IN NTSTATUS ExceptionCode
+ );
+
+
+//
+// The following macros are used to establish the semantics needed
+// to do a return from within a try-finally clause. As a rule every
+// try clause must end with a label call try_exit. For example,
+//
+// try {
+// :
+// :
+//
+// try_exit: NOTHING;
+// } finally {
+//
+// :
+// :
+// }
+//
+// Every return statement executed inside of a try clause should use the
+// try_return macro. If the compiler fully supports the try-finally construct
+// then the macro should be
+//
+// #define try_return(S) { return(S); }
+//
+// If the compiler does not support the try-finally construct then the macro
+// should be
+//
+// #define try_return(S) { S; goto try_exit; }
+//
+
+#define try_return(S) { S; goto try_exit; }
+
+#endif // _NPPROCS_
diff --git a/private/ntos/npfs/npstruc.h b/private/ntos/npfs/npstruc.h
new file mode 100644
index 000000000..566828798
--- /dev/null
+++ b/private/ntos/npfs/npstruc.h
@@ -0,0 +1,810 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ NpStruc.h
+
+Abstract:
+
+ This module defines the data structures that make up the major internal
+ part of the Named Pipe file system.
+
+Author:
+
+ Gary Kimura [GaryKi] 20-Aug-1990
+
+Revision History:
+
+--*/
+
+#ifndef _NPSTRUC_
+#define _NPSTRUC_
+
+
+//
+// The VCB record is the top record in the Named Pipe file system in-memory
+// data structure. This structure must be allocated from non-paged pool
+// and immediately follows (in memory) the Device object for the named
+// pipe. Structurally the layout of the data structure is as follows
+//
+// +------------+
+// |NPDO |
+// | |
+// +------------+
+// |Vcb |
+// | |
+// | EventTable |
+// | WaitQueue |
+// | |
+// +------------+
+// | ^
+// | |
+// | |
+// v |
+// +-------------+
+// |RootDcb |
+// | |<-+
+// +-------------+ |
+// | |
+// v |
+// +-------------+ |
+// |NonPaged | |
+// | | |
+// +-------------+ |
+// : |
+// : |
+// : |
+// v |
+// +----------------+ +-------------------+ +---------+
+// |Fcb | |Ccb | |ServerFO |
+// | |<---| | | |
+// | MaxInstances | | ServerFO |<-------|- 1|
+// | CurrentInst | | ClientFO | | |
+// | DefaultTimeOut |...>| |<-+ +--|- |
+// | | | | | | | |
+// +----------------+ +-------------------+ | | +---------+
+// | | | |
+// v v | |
+// +----------------+ +-------------------+ | | +---------+
+// |NonPagedFcb | |NonPagedCcb |<-|--+ |ClientFO |
+// | |<---| | | | |
+// | PipeConfig | | PipeState | +-----|- 0|
+// | PipeType | | ReadMode[2] | | |
+// | | | CompletionMode[2] |<-------|- |
+// | | | CreatorProcess | | |
+// | | | EventTabEnt[2] | +---------+
+// | | | DataQueue[2] |
+// | | | | (low bit determines
+// +----------------+ +-------------------+ server/client)
+//
+//
+// Where there is only one Vcb for the entire Named Pipe file system, and
+// it contains a single pointer to the root dcb for the file system. Off
+// of the Dcb is a queue of Fcb's. There is one Fcb for every named pipe.
+// There is one Ccb for every instance of a named pipe. There are also
+// two additional ccb types for the vcb and the root dcb, and notify records
+// for the notify change operations.
+//
+// A newly initialized named pipe file system only contains the Vcb and
+// the root dcb. A new Fcb is created when a new named pipe is created
+// and then a ccb must also be created. The file object for the creater
+// (i.e., server end) points to the ccb and indicates that it is the server
+// end. When a user does an open on the named pipe its file object is
+// set to point to the same ccb and is also set to indicate that it is the
+// client end. This is denoted by using the last bit of the FsContext pointer
+// if the bit is 1 it is a server end file object, if the bit is 0 it is
+// the client end.
+//
+// A file object with a null pointer to the FsContext field is a closed or
+// disconnected pipe.
+//
+// The Ccb also contains back pointer to the file objects that have it opened
+//
+
+
+//
+// The following types are used to help during development by keeping the
+// data types distinct. The manifest contants that go in each is declared
+// in the ntioapi.h file
+//
+
+typedef ULONG NAMED_PIPE_TYPE;
+typedef NAMED_PIPE_TYPE *PNAMED_PIPE_TYPE;
+
+typedef ULONG READ_MODE;
+typedef READ_MODE *PREAD_MODE;
+
+typedef ULONG COMPLETION_MODE;
+typedef COMPLETION_MODE *PCOMPLETION_MODE;
+
+typedef ULONG NAMED_PIPE_CONFIGURATION;
+typedef NAMED_PIPE_CONFIGURATION *PNAMED_PIPE_CONFIGURATION;
+
+typedef ULONG NAMED_PIPE_STATE;
+typedef NAMED_PIPE_STATE *PNAMED_PIPE_STATE;
+
+typedef ULONG NAMED_PIPE_END;
+typedef NAMED_PIPE_END *PNAMED_PIPE_END;
+
+
+//
+// The following two types are used by the event table package. The first
+// is the event table itself which is just a generic table. It is protected
+// by the vcb resource, and the second structure is an event table entry.
+//
+
+typedef struct _EVENT_TABLE {
+
+ RTL_GENERIC_TABLE Table;
+
+} EVENT_TABLE;
+typedef EVENT_TABLE *PEVENT_TABLE;
+
+//
+// The event table is a generic table of event table entries. Each Ccb
+// optionally contains a pointer to an event table entry for each direction.
+// The entries are part of the global event table defined off of the Vcb
+//
+
+typedef struct _EVENT_TABLE_ENTRY {
+
+ //
+ // The first two fields are used as keys in the generic table's
+ // comparison routines. The pipe end will either be FILE_PIPE_CLIENT_END
+ // or FILE_PIPE_SERVER_END.
+ //
+
+ struct _CCB *Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ //
+ // The following three fields are used to identify the event entry
+ // to the named pipe user
+ //
+
+ HANDLE EventHandle;
+ PVOID Event;
+ ULONG KeyValue;
+ PEPROCESS Process;
+
+} EVENT_TABLE_ENTRY;
+typedef EVENT_TABLE_ENTRY *PEVENT_TABLE_ENTRY;
+
+
+//
+// Each Ccb has two data queues for holding the outstanding in-bound and
+// out-bound read/write requests. The following type is used to determine
+// if the data queue contains read requests, write requests, or is empty.
+//
+
+typedef enum _QUEUE_STATE {
+
+ ReadEntries,
+ WriteEntries,
+ Empty
+
+} QUEUE_STATE;
+
+//
+// The data queue is a structure that contains the queue state, quota
+// information, and the list head. The quota information is used to
+// maintain pipe quota.
+//
+
+typedef struct _DATA_QUEUE {
+
+ //
+ // The current state of what is contained in this data queue,
+ // how many bytes of read/write data there are, and how many individual
+ // requests there are in the queue that contain data (includes
+ // close or flush requests).
+ //
+
+ QUEUE_STATE QueueState;
+ ULONG BytesInQueue;
+ ULONG EntriesInQueue;
+
+ //
+ // The following two fields denote who much quota was reserved for
+ // this pipe direction and how much we've used up. This is only
+ // the creator quota and not the user quota.
+ //
+
+ ULONG Quota;
+ ULONG QuotaUsed;
+
+ //
+ // This is the head of a queue of data entries (singly linked)
+ //
+
+ struct _DATA_ENTRY *FrontOfQueue;
+ struct _DATA_ENTRY *EndOfQueue;
+
+ //
+ // The following field indicates how far we've already processed
+ // into the first entry in the data queue
+ //
+
+ ULONG NextByteOffset;
+
+} DATA_QUEUE;
+typedef DATA_QUEUE *PDATA_QUEUE;
+
+//
+// Each data entry has a type field that tells us if the operation
+// for the entry is buffered, unbuffered, flush, or a close entry.
+//
+
+typedef enum _DATA_ENTRY_TYPE {
+
+ Buffered,
+ Unbuffered,
+ Flush,
+ Close
+
+} DATA_ENTRY_TYPE;
+
+//
+// The following type is used to denote where we got the memory for the
+// data entry and possibly the data buffer. We either got the memory
+// from the pipe quota, the user quota, or it is part of the next IRP stack
+// location.
+//
+
+typedef enum _FROM {
+
+ PipeQuota,
+ UserQuota,
+ InIrp
+
+} FROM;
+
+//
+// Each entry in the data queue is a data entry. Processing an IRP
+// has the potential of creating and inserting a new data entry. If the
+// memory for the entry is taken from the IRP we use the next stack
+// location.
+//
+
+typedef struct _DATA_ENTRY {
+
+ //
+ // The following field is how we connect into the queue of data entries
+ //
+
+ struct _DATA_ENTRY *Next;
+
+ //
+ // The following two fields describe the type of data entry and where
+ // we got its memory from. If the type is buffered then the From field
+ // also denotes where we got the memory for the data buffer, otherwise
+ // the data buffer has been supplied by the IRP
+ //
+
+ DATA_ENTRY_TYPE DataEntryType : 8;
+ FROM From : 8;
+
+ //
+ // The following field indicates if we still have an IRP associated
+ // with this data entry that need to be completed when the remove
+ // the data entry. Note that if From is InIrp that this IRP field
+ // must not be null.
+ //
+
+ PIRP Irp;
+
+ //
+ // The following two fields describe the size and location of the data
+ // buffer described by this entry. These fields are only used if the
+ // type is buffer, or unbuffered, and are ignored otherwise.
+ //
+
+ ULONG DataSize;
+ PVOID DataPointer;
+
+ //
+ // The following field is used to point to the client context if dynamic
+ // impersonation is being used
+ //
+
+ PSECURITY_CLIENT_CONTEXT SecurityClientContext;
+
+} DATA_ENTRY;
+typedef DATA_ENTRY *PDATA_ENTRY;
+
+
+//
+// The following type is used by the wait queue package
+//
+
+typedef struct _WAIT_QUEUE {
+
+ LIST_ENTRY Queue;
+
+ KSPIN_LOCK SpinLock;
+
+} WAIT_QUEUE;
+typedef WAIT_QUEUE *PWAIT_QUEUE;
+
+
+typedef struct _VCB {
+
+ //
+ // The type and size of this record (must be NPFS_NTC_VCB)
+ //
+
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+
+ //
+ // A pointer to the root DCB for this volume
+ //
+
+ struct _FCB *RootDcb;
+
+ //
+ // A count of the number of file objects that have opened the \NamedPipe
+ // object directly, and also a count of the number of file objects
+ // that have opened a name pipe or the root directory.
+ //
+
+ CLONG OpenCount;
+ CLONG OpenUnderlingCount;
+
+ //
+ // A prefix table that is used for quick, prefix directed, lookup of
+ // FCBs/DCBs that are part of this volume
+ //
+
+ UNICODE_PREFIX_TABLE PrefixTable;
+
+ //
+ // A resource variable to control access to the volume specific data
+ // structures
+ //
+
+ ERESOURCE Resource;
+
+ //
+ // The following table is used to hold the named pipe events
+ //
+
+ EVENT_TABLE EventTable;
+
+ //
+ // The following field is a queue of waiting IRPS of type WaitForNamedPipe
+ //
+
+ WAIT_QUEUE WaitQueue;
+
+ //
+ // The following field is used to check share access people who want
+ // to open the named pipe driver
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+} VCB;
+typedef VCB *PVCB;
+
+
+//
+// The Named Pipe Device Object is an I/O system device object with
+// additional workqueue parameters appended to the end. There is only
+// one of these records created for the entire system during system
+// initialization.
+//
+
+typedef struct _NPFS_DEVICE_OBJECT {
+
+ DEVICE_OBJECT DeviceObject;
+
+ //
+ // This is the file system specific volume control block.
+ //
+
+ VCB Vcb;
+
+} NPFS_DEVICE_OBJECT;
+typedef NPFS_DEVICE_OBJECT *PNPFS_DEVICE_OBJECT;
+
+
+//
+// The Fcb/Dcb record corresponds to every opened named pipe and directory,
+// and to every directory on an opened path.
+//
+// The structure is really divided into two parts. FCB can be allocated
+// from paged pool which the NONPAGED_FCB must be allocated from non-paged
+// pool.
+//
+
+typedef struct _FCB {
+
+ //
+ // Type and size of this record (must be NPFS_NTC_FCB, or
+ // NPFS_NTC_ROOT_DCB)
+ //
+
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+
+ //
+ // The links for the queue of all fcbs for a specific dcb off of
+ // Dcb.ParentDcbQueue. For the root directory this queue is empty
+ //
+
+ LIST_ENTRY ParentDcbLinks;
+
+ //
+ // A pointer to the Dcb that is the parent directory containing
+ // this fcb. If this record itself is the root dcb then this field
+ // is null.
+ //
+
+ struct _FCB *ParentDcb;
+
+ //
+ // A pointer to the Vcb containing this fcb
+ //
+
+ PVCB Vcb;
+
+ //
+ // A count of the number of file objects that have opened
+ // this file/directory. For a pipe this is also the number of instances
+ // created for the pipe.
+ //
+
+ CLONG OpenCount;
+
+ //
+ // A count of the number of server end file objects that have opened
+ // this pipe. ServerOpenCount is incremented when OpenCount is
+ // incremented (when the server end creates an instance), but is
+ // decremented when the server end handle is closed, where OpenCount
+ // isn't decremented until both side's handles are closed. When
+ // ServerOpenCount is 0, a client's attempt to open a named pipe is
+ // met with STATUS_OBJECT_NAME_NOT_FOUND, not STATUS_PIPE_NOT_AVAILABLE,
+ // based on an assumption that since the server doesn't think it has
+ // any instances open, the pipe really doesn't exist anymore. An
+ // example of when this distinction is useful is when the server
+ // process exits, but the client processes haven't closed their
+ // handles yet.
+ //
+
+ CLONG ServerOpenCount;
+
+ //
+ // The following field points to the security descriptor for this named pipe
+ //
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ //
+ // The following union is cased off of the node type code for the fcb.
+ // There is a seperate case for the directory versus file fcbs.
+ //
+
+ union {
+
+ //
+ // A Directory Control Block (Dcb)
+ //
+
+ struct {
+
+ //
+ // A queue of the notify IRPs that will be completed when any
+ // change is made to a file in the directory. Enqueued using
+ // the Tail.Overlay.ListEntry of the Irp.
+ //
+
+ LIST_ENTRY NotifyFullQueue;
+
+ //
+ // A queue of the notify IRPs that will be completed only if a
+ // file is added, deleted, or renamed in the directory. Enqueued
+ // using the Tail.Overlay.ListEntry of the Irp.
+ //
+
+ LIST_ENTRY NotifyPartialQueue;
+
+ //
+ // A queue of all the fcbs/dcbs that are opened under this
+ // Dcb.
+ //
+
+ LIST_ENTRY ParentDcbQueue;
+
+ //
+ // The following field is used to check share access people
+ // who want to open the directory.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ } Dcb;
+
+ //
+ // An File Control Block (Fcb)
+ //
+
+ struct {
+
+ //
+ // This is the maximum number of instances we can have for the
+ // named pipe and the current number of instances is the open
+ // count for the fcb (note that the current number also
+ // correspondsto the number of Ccbs)
+ //
+
+ ULONG MaximumInstances;
+
+ //
+ // The assigned pipe configuration (FILE_PIPE_INBOUND,
+ // FILE_PIPE_OUTBOUND, or FILE_PIPE_FULL_DUPLEX) and pipe
+ // type (FILE_PIPE_MESSAGE_TYPE or
+ // FILE_PIPE_BYTE_STREAM_TYPE).
+ //
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration : 16;
+ NAMED_PIPE_TYPE NamedPipeType : 16;
+
+ //
+ // The following field is the default timeout assigned to the
+ // named pipe
+ //
+
+ LARGE_INTEGER DefaultTimeOut;
+
+ //
+ // The Following field is a queue head for a list of ccbs
+ // that are opened under us
+ //
+
+ LIST_ENTRY CcbQueue;
+
+ } Fcb;
+
+ } Specific;
+
+ //
+ // The following field is the fully qualified file name for this FCB/DCB
+ // starting from the root of the volume, and last file name in the
+ // fully qualified name.
+ //
+
+ UNICODE_STRING FullFileName;
+ UNICODE_STRING LastFileName;
+
+ //
+ // The following field contains a prefix table entry that is used when
+ // searching a volume for a name (or longest matching prefix)
+ //
+
+ UNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry;
+
+ //
+ // A pointer to the specific non-paged data for the Fcb.
+ //
+
+ struct _NONPAGED_FCB *NonpagedFcb;
+
+} FCB, DCB, ROOT_DCB;
+
+typedef FCB *PFCB;
+typedef DCB *PDCB;
+typedef ROOT_DCB *PROOT_DCB;
+
+typedef struct _NONPAGED_FCB {
+
+ //
+ // Type and size of this record (must be NPFS_NTC_NONPAGED_FCB, or
+ // NPFS_NTC_NONPAGED_ROOT_DCB)
+ //
+
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+
+} NONPAGED_FCB, NONPAGED_DCB, NONPAGED_ROOT_DCB;
+
+typedef NONPAGED_FCB *PNONPAGED_FCB;
+typedef NONPAGED_DCB *PNONPAGED_DCB;
+typedef NONPAGED_ROOT_DCB *PNONPAGED_ROOT_DCB;
+
+
+//
+// The Ccb record is allocated for every opened instance of a named pipe.
+// There are two parts to a ccb a paged part and a Nonpaged part. Both
+// parts are pointed at by the FsContext and FsContext2 field of a file
+// object.
+//
+
+typedef struct _CCB {
+
+ //
+ // Type and size of this record (must be NPFS_NTC_CCB).
+ //
+
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+
+ //
+ // The following field is a list entry for the list of ccb that we
+ // are a member of
+ //
+
+ LIST_ENTRY CcbLinks;
+
+ //
+ // A pointer to the paged Fcb, or Vcb that we are tied to
+ //
+
+ PFCB Fcb;
+
+ //
+ // Back pointers to the server and client file objects that have us
+ // opened. This is indexed by either FILE_PIPE_CLIENT_END or
+ // FILE_PIPE_SERVER_END.
+ //
+
+ PFILE_OBJECT FileObject[2];
+
+ //
+ // The internal state of the Ccb. This is the shared access for each
+ // time this pipe/directory is opened.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // The following fields contain the session and process IDs of the
+ // client side of the named pipe instance. They are originally set
+ // to NULL (indicating local session) and the real client process
+ // ID but can be changed via FsCtl calls.
+ //
+
+ PVOID ClientSession;
+ PVOID ClientProcess;
+
+ //
+ // A pointer to the Nonpaged part of the ccb
+ //
+
+ struct _NONPAGED_CCB *NonpagedCcb;
+
+ //
+ // A pointer to the paged Fcb, or Vcb that we are tied to
+ //
+
+ PNONPAGED_FCB NonpagedFcb;
+
+ //
+ // Pipe state indicates the current state of the pipe
+ // (FILE_PIPE_DISCONNECTED_STATE, FILE_PIPE_LISTENING_STATE,
+ // FILE_PIPE_CONNECTED_STATE, or FILE_PIPE_CLOSING_STATE).
+ //
+
+ NAMED_PIPE_STATE NamedPipeState;
+
+ //
+ // read mode (FILE_PIPE_MESSAGE_MODE or FILE_PIPE_BYTE_STREAM_MODE),
+ // and completion mode (FILE_PIPE_QUEUE_OPERATION or
+ // FILE_PIPE_COMPLETE_OPERATION) describe how to handle requests to the
+ // pipe. Both of these fields are indexed by either FILE_PIPE_SERVER_END
+ // or FILE_PIPE_CLIENT_END.
+ //
+
+ READ_MODE ReadMode[2];
+ COMPLETION_MODE CompletionMode[2];
+
+ //
+ // The following field is used to remember the process that created this
+ // instance of the named pipe. It is needed to allocate quota and
+ // return quota
+ //
+
+ PEPROCESS CreatorProcess;
+
+ //
+ // The following data queues are used to contain the buffered information
+ // for each direction in the pipe. They array is indexed by
+ // PIPE_DIRECTION.
+ //
+
+ DATA_QUEUE DataQueue[2];
+
+ //
+ // The following fields are used for security impersonation
+ // Only the server end can impersonate and only for the inbound path
+ // (i.e., client writes then server reads and impersonates).
+ //
+ // If it is static tracking (SecurityQos contains the type of tracking)
+ // then we set the quality of service and the client context in the
+ // nonpaged ccb on open and we never change anything.
+ //
+ // If it is dynamic tracking then we set the quality of service in the
+ // nonpaged ccb and on every write by the client we set the client
+ // context in the data entry and when read by the server we update the
+ // client context field of the nonpaged ccb to value stored in the data
+ // entry.
+ //
+ // On impersonation we use the client context stored in the nonpaged ccb
+ //
+
+ SECURITY_QUALITY_OF_SERVICE SecurityQos;
+ PSECURITY_CLIENT_CONTEXT SecurityClientContext;
+
+} CCB;
+typedef CCB *PCCB;
+
+typedef struct _NONPAGED_CCB {
+
+ //
+ // Type and size of this record (must be NPFS_NTC_NONPAGED_CCB)
+ //
+
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+
+ //
+ // The following pointers denote the events we are to signal for the
+ // server and client ends of the named pipe. The actual entry
+ // is stored in the event table, and referenced here for easy access.
+ // The client end is signaled if ever a read/write occurs to the client
+ // of the pipe, and likewise for the server end. The array is
+ // indexed by either FILE_PIPE_SERVER_END or FILE_PIPE_CLIENT_END.
+ //
+
+ PEVENT_TABLE_ENTRY EventTableEntry[2];
+
+ //
+ // A queue of waiting listening IRPs. They are linked into the
+ // Tail.Overlay.ListEntry field in the Irp.
+ //
+
+ LIST_ENTRY ListeningQueue;
+
+ //
+ // Resource for synchronizing access
+ //
+ ERESOURCE Resource;
+
+} NONPAGED_CCB;
+typedef NONPAGED_CCB *PNONPAGED_CCB;
+
+
+//
+// The Root Dcb Ccb record is allocated for every opened instance of the
+// root dcb. This record is pointed at by FsContext2.
+//
+
+typedef struct _ROOT_DCB_CCB {
+
+ //
+ // Type and size of this record (must be NPFS_NTC_ROOT_DCB_CCB).
+ //
+
+ NODE_TYPE_CODE NodeTypeCode;
+ NODE_BYTE_SIZE NodeByteSize;
+
+ //
+ // The following field is a count of the last index returned
+ // by query directory.
+ //
+
+ ULONG IndexOfLastCcbReturned;
+
+ //
+ // The following string is used as a query template for directory
+ // query operations
+ //
+
+ PUNICODE_STRING QueryTemplate;
+
+} ROOT_DCB_CCB;
+typedef ROOT_DCB_CCB *PROOT_DCB_CCB;
+
+#endif // _NPSTRUC_
diff --git a/private/ntos/npfs/prefxsup.c b/private/ntos/npfs/prefxsup.c
new file mode 100644
index 000000000..4771f305f
--- /dev/null
+++ b/private/ntos/npfs/prefxsup.c
@@ -0,0 +1,255 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ PrefxSup.c
+
+Abstract:
+
+ This module implements the Named Pipe Prefix support routines
+
+Author:
+
+ Gary Kimura [GaryKi] 13-Feb-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (NPFS_BUG_CHECK_PREFXSUP)
+
+//
+// The debug trace level for this module
+//
+
+#define Dbg (DEBUG_TRACE_PREFXSUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpFindPrefix)
+#pragma alloc_text(PAGE, NpFindRelativePrefix)
+#endif
+
+
+PFCB
+NpFindPrefix (
+ IN PUNICODE_STRING String,
+ IN BOOLEAN CaseInsensitive,
+ OUT PUNICODE_STRING RemainingPart
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the FCBs/DCBs of a volume and locates the
+ FCB/DCB with longest matching prefix for the given input string. The
+ search is relative to the root of the volume. So all names must start
+ with a "\".
+
+Arguments:
+
+ String - Supplies the input string to search for
+
+ CaseInsensitive - Specifies if the search is to be done case sensitive
+ (FALSE) or insensitive (TRUE)
+
+ RemainingPart - Returns the string when the prefix no longer matches.
+ For example, if the input string is "\alpha\beta" only matches the
+ root directory then the remaining string is "alpha\beta". If the
+ same string matches a DCB for "\alpha" then the remaining string is
+ "beta".
+
+Return Value:
+
+ PFCB - Returns a pointer to either an FCB or a DCB whichever is the
+ longest matching prefix.
+
+--*/
+
+{
+ PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry;
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFindPrefix, NpVcb = %08lx\n", NpVcb);
+ DebugTrace( 0, Dbg, " String = %Z\n", String);
+
+ //
+ // Find the longest matching prefix
+ //
+
+ PrefixTableEntry = RtlFindUnicodePrefix( &NpVcb->PrefixTable,
+ String,
+ CaseInsensitive );
+
+ //
+ // If we didn't find one then it's an error
+ //
+
+ if (PrefixTableEntry == NULL) {
+
+ DebugDump("Error looking up a prefix", 0, NpVcb);
+ NpBugCheck( 0, 0, 0 );
+ }
+
+ //
+ // Get a pointer to the Fcb containing the prefix table entry
+ //
+
+ Fcb = CONTAINING_RECORD( PrefixTableEntry, FCB, PrefixTableEntry );
+
+ //
+ // Tell the caller how many characters we were able to match. We first
+ // set the remaining part to the original string minus the matched
+ // prefix, then we check if the remaining part starts with a backslash
+ // and if it does then we remove the backslash from the remaining string.
+ //
+
+ RemainingPart->Length = String->Length - Fcb->FullFileName.Length;
+ RemainingPart->MaximumLength = RemainingPart->Length;
+ RemainingPart->Buffer = &String->Buffer[ Fcb->FullFileName.Length/sizeof(WCHAR) ];
+
+ if ((RemainingPart->Length > 0) &&
+ (RemainingPart->Buffer[0] == L'\\')) {
+
+ RemainingPart->Length -= sizeof(WCHAR);
+ RemainingPart->MaximumLength -= sizeof(WCHAR);
+ RemainingPart->Buffer += 1;
+ }
+
+ DebugTrace(0, Dbg, "RemainingPart set to %Z\n", RemainingPart);
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFindPrefix -> %08lx\n", Fcb);
+
+ return Fcb;
+}
+
+
+PFCB
+NpFindRelativePrefix (
+ IN PDCB Dcb,
+ IN PUNICODE_STRING String,
+ IN BOOLEAN CaseInsensitive,
+ OUT PUNICODE_STRING RemainingPart
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the FCBs/DCBs of a volume and locates the
+ FCB/DCB with longest matching prefix for the given input string. The
+ search is relative to a input DCB, and must not start with a leading "\"
+ All searching is done case insensitive.
+
+Arguments:
+
+ Dcb - Supplies the Dcb to start searching from
+
+ String - Supplies the input string to search for
+
+ CaseInsensitive - Specifies if the search is to be done case sensitive
+ (FALSE) or insensitive (TRUE)
+
+ RemainingPart - Returns the index into the string when the prefix no
+ longer matches. For example, if the input string is "beta\gamma"
+ and the input Dcb is for "\alpha" and we only match beta then
+ the remaining string is "gamma".
+
+Return Value:
+
+ PFCB - Returns a pointer to either an FCB or a DCB whichever is the
+ longest matching prefix.
+
+--*/
+
+{
+ ULONG NameLength;
+ PWCH Name;
+
+ UNICODE_STRING FullString;
+ PWCH Temp;
+
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFindRelativePrefix, Dcb = %08lx\n", Dcb);
+ DebugTrace( 0, Dbg, "String = %08lx\n", String);
+
+ //
+ // Initialize the Temp buffer to null so in our termination handler
+ // we'll know to release pool
+ //
+
+ Temp = NULL;
+
+ try {
+
+ //
+ // We first need to build the complete name and then do a relative
+ // search from the root
+ //
+
+ NameLength = String->Length;
+ Name = String->Buffer;
+
+ ASSERT(NodeType(Dcb) == NPFS_NTC_ROOT_DCB);
+
+ Temp = FsRtlAllocatePool( PagedPool, NameLength + 2*sizeof(WCHAR) );
+
+ Temp[0] = L'\\';
+ RtlCopyMemory( &Temp[1], Name, NameLength );
+ Temp[NameLength/sizeof(WCHAR) + 1] = L'\0';
+
+ RtlInitUnicodeString( &FullString, Temp );
+
+ //
+ // Find the prefix relative to the volume
+ //
+
+ Fcb = NpFindPrefix( &FullString,
+ CaseInsensitive,
+ RemainingPart );
+
+ //
+ // Now adjust the remaining part to take care of the relative
+ // volume prefix.
+ //
+
+ RemainingPart->Buffer = &String->Buffer[(String->Length -
+ RemainingPart->Length) / sizeof(WCHAR)];
+
+ DebugTrace(0, Dbg, "RemainingPart set to %Z\n", RemainingPart);
+
+ } finally {
+
+ //
+ // Release the pool if we it was allocated
+ //
+
+ if (Temp != NULL) { ExFreePool( Temp ); }
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFindRelativePrefix -> %08lx\n", Fcb);
+ }
+
+ return Fcb;
+}
+
diff --git a/private/ntos/npfs/read.c b/private/ntos/npfs/read.c
new file mode 100644
index 000000000..19b930ee0
--- /dev/null
+++ b/private/ntos/npfs/read.c
@@ -0,0 +1,529 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Read.c
+
+Abstract:
+
+ This module implements the File Read routine for NPFS called by the
+ dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_READ)
+
+#if DBG
+ULONG NpFastReadTrue = 0;
+ULONG NpFastReadFalse = 0;
+ULONG NpSlowReadCalls = 0;
+#endif
+
+//
+// local procedure prototypes
+//
+
+BOOLEAN
+NpCommonRead (
+ IN PFILE_OBJECT FileObject,
+ OUT PVOID ReadBuffer,
+ IN ULONG ReadLength,
+ OUT PIO_STATUS_BLOCK Iosb,
+ IN PIRP Irp OPTIONAL
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonRead)
+#pragma alloc_text(PAGE, NpFastRead)
+#pragma alloc_text(PAGE, NpFsdRead)
+#endif
+
+
+NTSTATUS
+NpFsdRead (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtReadFile API calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ IO_STATUS_BLOCK Iosb;
+ PIO_STACK_LOCATION IrpSp;
+
+ DebugTrace(+1, Dbg, "NpFsdRead\n", 0);
+ DbgDoit( NpSlowReadCalls += 1 );
+
+ PAGED_CODE();
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireSharedVcb();
+
+ try {
+
+ (VOID) NpCommonRead( IrpSp->FileObject,
+ Irp->UserBuffer,
+ IrpSp->Parameters.Read.Length,
+ &Iosb,
+ Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Iosb.Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdRead -> %08lx\n", Iosb.Status );
+
+ return Iosb.Status;
+}
+
+
+BOOLEAN
+NpFastRead (
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN ULONG LockKey,
+ OUT PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus,
+ IN PDEVICE_OBJECT DeviceObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a fast read bypassing the usual file system
+ entry routine (i.e., without the Irp).
+
+Arguments:
+
+ FileObject - Pointer to the file object being read.
+
+ FileOffset - Byte offset in file for desired data.
+
+ Length - Length of desired data in bytes.
+
+ Wait - FALSE if caller may not block, TRUE otherwise
+
+ LockKey - Supplies the Key used to use if the byte range being read is locked.
+
+ Buffer - Pointer to output buffer to which data should be copied.
+
+ IoStatus - Pointer to standard I/O status block to receive the status
+ for the transfer.
+
+Return Value:
+
+ BOOLEAN - TRUE if the operation completed successfully and FALSE if the
+ caller needs to take the long IRP based route.
+
+--*/
+
+{
+ BOOLEAN Results = FALSE;
+
+ UNREFERENCED_PARAMETER( FileOffset );
+ UNREFERENCED_PARAMETER( Wait );
+ UNREFERENCED_PARAMETER( LockKey );
+ UNREFERENCED_PARAMETER( DeviceObject );
+
+ PAGED_CODE();
+
+#if DBG
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireSharedVcb();
+
+ try {
+
+ if (NpCommonRead( FileObject,
+ Buffer,
+ Length,
+ IoStatus,
+ NULL )) {
+
+ NpFastReadTrue += 1;
+
+ Results = TRUE;
+
+ } else {
+
+ NpFastReadFalse += 1;
+ }
+
+ } except( FsRtlIsNtstatusExpected(GetExceptionCode())
+ ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH ) {
+
+ NOTHING;
+ }
+
+ NpReleaseVcb();
+ FsRtlExitFileSystem();
+ return Results;
+
+#else
+
+ FsRtlEnterFileSystem();
+ NpAcquireSharedVcb();
+
+ try {
+
+ Results = NpCommonRead( FileObject,
+ Buffer,
+ Length,
+ IoStatus,
+ NULL );
+
+ } except( FsRtlIsNtstatusExpected(GetExceptionCode())
+ ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH ) {
+
+ NOTHING;
+ }
+
+ NpReleaseVcb();
+ FsRtlExitFileSystem();
+ return Results;
+
+#endif
+}
+
+
+//
+// Internal support routine
+//
+
+BOOLEAN
+NpCommonRead (
+ IN PFILE_OBJECT FileObject,
+ OUT PVOID ReadBuffer,
+ IN ULONG ReadLength,
+ OUT PIO_STATUS_BLOCK Iosb,
+ IN PIRP Irp OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for reading a named pipe both via the fast
+ path and with an Irp
+
+Arguments:
+
+ FileObject - Supplies the file object used in this operation
+
+ ReadBuffer - Supplies the buffer where data is to be written
+
+ ReadLength - Supplies the length of read buffer in bytes
+
+ Iosb - Receives the final completion status of this operation
+
+ Irp - Optionally supplies an Irp to be used in this operation
+
+Return Value:
+
+ BOOLEAN - TRUE if the operation was successful and FALSE if the caller
+ needs to take the longer Irp based route.
+
+--*/
+
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ ULONG ReadRemaining;
+ READ_MODE ReadMode;
+ COMPLETION_MODE CompletionMode;
+ PDATA_QUEUE ReadQueue;
+ PEVENT_TABLE_ENTRY Event;
+ BOOLEAN Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCommonRead\n", 0);
+ DebugTrace( 0, Dbg, "FileObject = %08lx\n", FileObject);
+ DebugTrace( 0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
+ DebugTrace( 0, Dbg, "ReadLength = %08lx\n", ReadLength);
+ DebugTrace( 0, Dbg, "Iosb = %08lx\n", Iosb);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+
+ Iosb->Information = 0;
+
+ //
+ // Get the Ccb and figure out who we are, and make sure we're not
+ // disconnected
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ Iosb->Status = STATUS_PIPE_DISCONNECTED;
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED ); }
+
+ return TRUE;
+ }
+
+ //
+ // Now we only will allow Read operations on the pipe and not a directory
+ // or the device
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
+
+ Iosb->Status = STATUS_INVALID_PARAMETER;
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); }
+
+ return TRUE;
+ }
+
+ NpAcquireExclusiveCcb(Ccb);
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ try {
+ //
+ // Check if the pipe is not in the connected state.
+ //
+
+ if ((Ccb->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) ||
+ (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE)) {
+
+ DebugTrace(0, Dbg, "Pipe in disconnected or listening state\n", 0);
+
+ if (Ccb->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) {
+
+ Iosb->Status = STATUS_PIPE_DISCONNECTED;
+
+ } else {
+
+ Iosb->Status = STATUS_PIPE_LISTENING;
+ }
+
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, Iosb->Status ); }
+
+ try_return(Status = TRUE);
+ }
+
+ ASSERT((Ccb->NamedPipeState == FILE_PIPE_CONNECTED_STATE) ||
+ (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE));
+
+ //
+ // We only allow a read by the server on a non outbound only pipe
+ // and by the client on a non inbound only pipe
+ //
+
+ NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
+
+ if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
+ (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))
+
+ ||
+
+ ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
+ (NamedPipeConfiguration == FILE_PIPE_INBOUND))) {
+
+ DebugTrace(0, Dbg, "Trying to read to the wrong pipe configuration\n", 0);
+
+ Iosb->Status = STATUS_INVALID_PARAMETER;
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); }
+
+ try_return (Status = TRUE);
+ }
+
+ //
+ // Reference our input parameters to make things easier, and
+ // initialize our main variables that describe the Read command
+ //
+
+ ReadRemaining = ReadLength;
+ ReadMode = Ccb->ReadMode[ NamedPipeEnd ];
+ CompletionMode = Ccb->CompletionMode[ NamedPipeEnd ];
+
+ //
+ // Now the data queue that we read from into and the event that we signal
+ // are based on the named pipe end. The server read from the inbound
+ // queue and signals the client event. The client does just the
+ // opposite.
+ //
+
+ if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+
+ } else {
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
+ }
+
+ DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
+ DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
+ DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode);
+ DebugTrace(0, Dbg, "CompletionMode = %08lx\n", CompletionMode);
+ DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
+ DebugTrace(0, Dbg, "Event = %08lx\n", Event);
+
+ //
+ // if the read queue does not contain any write entries
+ // then we either need to enqueue this operation or
+ // fail immediately
+ //
+
+ if (!NpIsDataQueueWriters( ReadQueue )) {
+
+ //
+ // Check if the other end of the pipe is closing, and if
+ // so then we complete it with end of file.
+ // Otherwise check to see if we should enqueue the irp
+ // or complete the operation and tell the user the pipe is empty.
+ //
+
+ if (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) {
+
+ DebugTrace(0, Dbg, "Complete the irp with eof\n", 0);
+
+ Iosb->Status = STATUS_PIPE_BROKEN;
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, STATUS_PIPE_BROKEN ); }
+
+ } else if (CompletionMode == FILE_PIPE_QUEUE_OPERATION) {
+
+ if (!ARGUMENT_PRESENT(Irp)) {
+
+ DebugTrace(0, Dbg, "Need to supply Irp\n", 0);
+
+ try_return(Status = FALSE);
+ }
+
+ DebugTrace(0, Dbg, "Put the irp into the read queue\n", 0);
+
+ (VOID)NpAddDataQueueEntry( ReadQueue,
+ ReadEntries,
+ Buffered,
+ ReadLength,
+ Irp,
+ NULL );
+
+ IoMarkIrpPending( Irp );
+
+ Iosb->Status = STATUS_PENDING;
+
+ } else {
+
+ DebugTrace(0, Dbg, "Complete the irp with pipe empty\n", 0);
+
+ Iosb->Status = STATUS_PIPE_EMPTY;
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, STATUS_PIPE_EMPTY ); }
+ }
+
+ } else {
+
+ //
+ // otherwise there we have a read irp against a read queue
+ // that contains one or more write entries.
+ //
+
+ *Iosb = NpReadDataQueue( ReadQueue,
+ FALSE,
+ FALSE,
+ ReadBuffer,
+ ReadLength,
+ ReadMode,
+ Ccb );
+
+ //
+ // Finish up the read irp.
+ //
+
+ if (ARGUMENT_PRESENT(Irp)) { Irp->IoStatus = *Iosb; NpCompleteRequest( Irp, Iosb->Status ); }
+ }
+
+ //
+ // Now we need to advance the read queue to the next write irp to
+ // skip over flushes and closes
+ //
+
+ (VOID)NpGetNextRealDataQueueEntry( ReadQueue );
+
+ Status = TRUE;
+ //
+ // And because we've done something we need to signal the
+ // other ends event
+ //
+
+ NpSignalEventTableEntry( Event );
+
+
+ try_exit: NOTHING;
+ } finally {
+ NpReleaseCcb(Ccb);
+ }
+
+
+ DebugTrace(-1, Dbg, "NpCommonRead -> TRUE\n", 0);
+ return Status;
+}
diff --git a/private/ntos/npfs/readsup.c b/private/ntos/npfs/readsup.c
new file mode 100644
index 000000000..0e1367c82
--- /dev/null
+++ b/private/ntos/npfs/readsup.c
@@ -0,0 +1,293 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ReadSup.c
+
+Abstract:
+
+ This module implements the Read support routine. This is a common
+ read function that is called to do read, unbuffered read, peek, and
+ transceive.
+
+Author:
+
+ Gary Kimura [GaryKi] 20-Sep-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_READSUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpReadDataQueue)
+#endif
+
+
+IO_STATUS_BLOCK
+NpReadDataQueue (
+ IN PDATA_QUEUE ReadQueue,
+ IN BOOLEAN PeekOperation,
+ IN BOOLEAN ReadOverflowOperation,
+ IN PUCHAR ReadBuffer,
+ IN ULONG ReadLength,
+ IN READ_MODE ReadMode,
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure reads data from the read queue and fills up the
+ read buffer. It will also dequeue the queue or leave it alone based
+ on an input parameter.
+
+Arguments:
+
+ ReadQueue - Provides the read queue to examine. Its state must
+ already be set to WriteEntries.
+
+ PeekOperation - Indicates if the operation is to dequeue information
+ off of the queue as it is being read or leave the queue alone.
+ TRUE means to leave the queue alone.
+
+ ReadOverflowOperation - Indicates if this is a read overflow operation.
+ With read overflow we will not alter the named pipe if the data
+ will overflow the read buffer.
+
+ ReadBuffer - Supplies a buffer to receive the data
+
+ ReadLength - Supplies the length, in bytes, of ReadBuffer.
+
+ ReadMode - Indicates if the read operation is message mode or
+ byte stream mode.
+
+ NamedPipeEnd - Supplies the end of the named pipe doing the read
+
+ Ccb - Supplies the ccb for the pipe
+
+Return Value:
+
+ IO_STATUS_BLOCK - Indicates the result of the operation.
+
+--*/
+
+{
+ IO_STATUS_BLOCK Iosb;
+
+ PDATA_ENTRY DataEntry;
+
+ ULONG ReadRemaining;
+ ULONG AmountRead;
+
+ PUCHAR WriteBuffer;
+ ULONG WriteLength;
+ ULONG WriteRemaining;
+
+ ULONG AmountToCopy;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpReadDataQueue\n", 0);
+ DebugTrace( 0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
+ DebugTrace( 0, Dbg, "PeekOperation = %08lx\n", PeekOperation);
+ DebugTrace( 0, Dbg, "ReadOverflowOperation = %08lx\n", ReadOverflowOperation);
+ DebugTrace( 0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
+ DebugTrace( 0, Dbg, "ReadLength = %08lx\n", ReadLength);
+ DebugTrace( 0, Dbg, "ReadMode = %08lx\n", ReadMode);
+ DebugTrace( 0, Dbg, "Ccb = %08lx\n", Ccb);
+
+ //
+ // If this is an overflow operation then we will force us to do peeks.
+ // Later when are determine that the opreation succeeded we will complete
+ // the write irp.
+ //
+
+ if (ReadOverflowOperation) {
+
+ PeekOperation = TRUE;
+ }
+
+ //
+ // Now for every real data entry we loop until either we run out
+ // of data entries or until the read buffer is full
+ //
+
+ ReadRemaining = ReadLength;
+ Iosb.Status = STATUS_SUCCESS;
+ AmountRead = 0;
+
+ for (DataEntry = (PeekOperation ? NpGetNextDataQueueEntry( ReadQueue, NULL )
+ : NpGetNextRealDataQueueEntry( ReadQueue ));
+
+ (DataEntry != NULL) && (ReadRemaining > 0);
+
+ DataEntry = (PeekOperation ? NpGetNextDataQueueEntry( ReadQueue, DataEntry )
+ : NpGetNextRealDataQueueEntry( ReadQueue ))) {
+
+ DebugTrace(0, Dbg, "Top of Loop\n", 0);
+ DebugTrace(0, Dbg, "ReadRemaining = %08lx\n", ReadRemaining);
+
+ //
+ // If this is a peek operation then make sure we got a real
+ // data entry and not a close or flush
+ //
+
+ if (!PeekOperation ||
+ (DataEntry->DataEntryType == Buffered) ||
+ (DataEntry->DataEntryType == Unbuffered)) {
+
+ //
+ // Calculate how much data is in this entry. The write
+ // remaining is based on whether this is the first entry
+ // in the queue or a later data entry
+ //
+
+ WriteBuffer = DataEntry->DataPointer;
+ WriteLength = DataEntry->DataSize;
+ WriteRemaining = WriteLength;
+
+ if (DataEntry == NpGetNextDataQueueEntry( ReadQueue, NULL )) {
+
+ WriteRemaining -= ReadQueue->NextByteOffset;
+ }
+
+ DebugTrace(0, Dbg, "WriteBuffer = %08lx\n", WriteBuffer);
+ DebugTrace(0, Dbg, "WriteLength = %08lx\n", WriteLength);
+ DebugTrace(0, Dbg, "WriteRemaining = %08lx\n", WriteRemaining);
+
+ //
+ // copy data from the write buffer at write offset to the
+ // read buffer at read offset by the mininum of write
+ // remaining or read remaining
+ //
+
+ AmountToCopy = (WriteRemaining < ReadRemaining ? WriteRemaining
+ : ReadRemaining);
+
+ try {
+
+ RtlCopyMemory( &ReadBuffer[ ReadLength - ReadRemaining ],
+ &WriteBuffer[ WriteLength - WriteRemaining ],
+ AmountToCopy );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
+ }
+
+ //
+ // Update the Read and Write remaining counts, the total
+ // amount we've read and the next byte offset field in the
+ // read queue
+ //
+
+ ReadRemaining -= AmountToCopy;
+ WriteRemaining -= AmountToCopy;
+ AmountRead += AmountToCopy;
+
+ if (!PeekOperation) {
+
+ ReadQueue->NextByteOffset = WriteLength - WriteRemaining;
+ }
+
+ //
+ // Now update the security fields in the ccb
+ //
+
+ NpCopyClientContext( Ccb, DataEntry );
+
+ //
+ // If the remaining write length is greater than zero
+ // then we've filled up the read buffer so we need to
+ // figure out if its an overflow error
+ //
+
+ if (WriteRemaining > 0 ||
+ (ReadOverflowOperation && (AmountRead == 0))) {
+
+ DebugTrace(0, Dbg, "Write remaining is > 0\n", 0);
+
+ if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
+
+ DebugTrace(0, Dbg, "Overflow message mode read\n", 0);
+
+ //
+ // Set the status field and break out of the for-loop.
+ //
+
+ Iosb.Status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ } else {
+
+ DebugTrace(0, Dbg, "Remaining Write is zero\n", 0);
+
+ //
+ // The write entry is done so remove it from the read
+ // queue, if this is not a peek operation. This might
+ // also have an Irp that needs to be completed
+ //
+
+ if (!PeekOperation || ReadOverflowOperation) {
+
+ PIRP WriteIrp;
+
+ //
+ // For a read overflow operation we need to get the read data
+ // queue entry and remove it.
+ //
+
+ if (ReadOverflowOperation) {
+ PDATA_ENTRY TempDataEntry;
+ TempDataEntry = NpGetNextRealDataQueueEntry( ReadQueue );
+ ASSERT(TempDataEntry == DataEntry);
+ }
+
+ if ((WriteIrp = NpRemoveDataQueueEntry( ReadQueue )) != NULL) {
+
+ NpCompleteRequest( WriteIrp, STATUS_SUCCESS );
+ }
+ }
+
+ //
+ // And if we are doing message mode reads then we'll
+ // work on completing this irp without going back
+ // to the top of the loop
+ //
+
+ if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
+
+ DebugTrace(0, Dbg, "Successful message mode read\n", 0);
+
+ //
+ // Set the status field and break out of the for-loop.
+ //
+
+ Iosb.Status = STATUS_SUCCESS;
+ break;
+ }
+
+ ASSERTMSG("Srv cannot use read overflow on a byte stream pipe ", !ReadOverflowOperation);
+ }
+ }
+ }
+
+ DebugTrace(0, Dbg, "End of loop, AmountRead = %08lx\n", AmountRead);
+
+ Iosb.Information = AmountRead;
+
+ DebugTrace(-1, Dbg, "NpReadDataQueue -> Iosb.Status = %08lx\n", Iosb.Status);
+ return Iosb;
+}
diff --git a/private/ntos/npfs/resrcsup.c b/private/ntos/npfs/resrcsup.c
new file mode 100644
index 000000000..b0c36ac6b
--- /dev/null
+++ b/private/ntos/npfs/resrcsup.c
@@ -0,0 +1,234 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ResrcSup.c
+
+Abstract:
+
+ This module implements the NamedPipe Resource acquisition routines
+
+Author:
+
+ Gary Kimura [GaryKi] 22-Mar-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_RESRCSUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpAcquireExclusiveCcb)
+#pragma alloc_text(PAGE, NpAcquireExclusiveVcb)
+#pragma alloc_text(PAGE, NpAcquireSharedCcb)
+#pragma alloc_text(PAGE, NpAcquireSharedVcb)
+#pragma alloc_text(PAGE, NpReleaseCcb)
+#pragma alloc_text(PAGE, NpReleaseVcb)
+#endif
+
+
+VOID
+NpAcquireExclusiveVcb (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine acquires exclusive access to the Vcb
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpAcquireExclusiveVcb\n", 0);
+
+ ExAcquireResourceExclusive( &(NpVcb->Resource), TRUE );
+
+ DebugTrace(-1, Dbg, "NpAcquireExclusiveVcb -> (VOID)\n", 0);
+
+ return;
+}
+
+
+VOID
+NpAcquireSharedVcb (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine acquires shared access to the Vcb
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpAcquireSharedVcb\n", 0);
+
+ ExAcquireResourceShared( &(NpVcb->Resource), TRUE );
+
+ DebugTrace(-1, Dbg, "NpAcquireSharedVcb -> (VOID)\n", 0);
+
+ return;
+}
+
+
+VOID
+NpAcquireExclusiveCcb (
+ IN PNONPAGED_CCB NonpagedCcb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine acquires exclusive access to the Ccb by first getting
+ shared access to the Fcb.
+
+Arguments:
+
+ NonpagedCcb - Supplies the Ccb to acquire
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpAcquireExclusiveCcb, NonpagedCcb = %08lx\n", NonpagedCcb);
+
+ (VOID)ExAcquireResourceShared( &(NpVcb->Resource), TRUE );
+
+ (VOID)ExAcquireResourceExclusive( &(NonpagedCcb->Resource), TRUE );
+
+ DebugTrace(-1, Dbg, "NpAcquireExclusiveCcb -> (VOID)\n", 0);
+
+ return;
+}
+
+
+VOID
+NpAcquireSharedCcb (
+ IN PNONPAGED_CCB NonpagedCcb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine acquires shared access to the Ccb by first getting
+ shared access to the Fcb.
+
+Arguments:
+
+ NonpagedCcb - Supplies the Ccb to acquire
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpAcquireSharedCcb, NonpagedCcb = %08lx\n", NonpagedCcb);
+
+ (VOID)ExAcquireResourceShared( &(NpVcb->Resource), TRUE );
+
+ (VOID)ExAcquireResourceShared( &(NonpagedCcb->Resource), TRUE );
+
+ DebugTrace(-1, Dbg, "NpAcquireSharedCcb -> (VOID)\n", 0);
+
+ return;
+}
+
+
+VOID
+NpReleaseVcb (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine releases access to the Vcb
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpReleaseVcb\n", 0);
+
+ ExReleaseResource( &(NpVcb->Resource) );
+
+ return;
+}
+
+
+VOID
+NpReleaseCcb (
+ IN PNONPAGED_CCB NonpagedCcb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine releases access to the Ccb
+
+Arguments:
+
+ Ccb - Supplies the Ccb being released
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpReleaseCcb, NonpagedCcb = %08lx\n", NonpagedCcb);
+
+ ExReleaseResource( &(NonpagedCcb->Resource) );
+ ExReleaseResource( &(NpVcb->Resource) );
+
+ return;
+}
diff --git a/private/ntos/npfs/secursup.c b/private/ntos/npfs/secursup.c
new file mode 100644
index 000000000..c6869a55b
--- /dev/null
+++ b/private/ntos/npfs/secursup.c
@@ -0,0 +1,387 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ SecurSup.c
+
+Abstract:
+
+ This module implements the Named Pipe Security support routines
+
+Author:
+
+ Gary Kimura [GaryKi] 06-May-1991
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_SECURSUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCopyClientContext)
+#pragma alloc_text(PAGE, NpImpersonateClientContext)
+#pragma alloc_text(PAGE, NpInitializeSecurity)
+#pragma alloc_text(PAGE, NpSetDataEntryClientContext)
+#pragma alloc_text(PAGE, NpUninitializeSecurity)
+#endif
+
+
+NTSTATUS
+NpInitializeSecurity (
+ IN PCCB Ccb,
+ IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
+ IN PETHREAD UserThread
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the security (impersonation) fields
+ in the ccb. It is called when the client end gets opened.
+
+Arguments:
+
+ Ccb - Supplies the ccb being initialized
+
+ SecurityQos - Supplies the clients quality of service parameter
+
+ UserThread - Supplise the client's user thread
+
+Return Value:
+
+ NTSTATUS - Returns the result of the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpInitializeSecurity, Ccb = %08lx\n", Ccb);
+
+ //
+ // Either copy the security qos parameter, if it is not null or
+ // create a dummy qos
+ //
+
+ if (SecurityQos != NULL) {
+
+ RtlCopyMemory( &Ccb->SecurityQos,
+ SecurityQos,
+ sizeof(SECURITY_QUALITY_OF_SERVICE) );
+
+ } else {
+
+ Ccb->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ Ccb->SecurityQos.ImpersonationLevel = SecurityImpersonation;
+ Ccb->SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ Ccb->SecurityQos.EffectiveOnly = TRUE;
+ }
+
+ //
+ // Because we might be asked to reinitialize the ccb we need
+ // to first check if the security client context is not null and if so then
+ // free its pool
+ //
+
+ if (Ccb->SecurityClientContext != NULL) {
+
+ SeDeleteClientSecurity( Ccb->SecurityClientContext );
+ ExFreePool( Ccb->SecurityClientContext );
+ }
+
+ //
+ // If the tracking mode is static then we need to capture the
+ // client context now otherwise we set the client context field
+ // to null
+ //
+
+ if (Ccb->SecurityQos.ContextTrackingMode == SECURITY_STATIC_TRACKING) {
+
+ //
+ // Allocate a client context record, and then initialize it
+ //
+
+ Ccb->SecurityClientContext = FsRtlAllocatePool( PagedPool,
+ sizeof(SECURITY_CLIENT_CONTEXT) );
+
+ DebugTrace(0, Dbg, "Static tracking, ClientContext = %08lx\n", Ccb->SecurityClientContext);
+
+ if (!NT_SUCCESS(Status = SeCreateClientSecurity( UserThread,
+ &Ccb->SecurityQos,
+ FALSE,
+ Ccb->SecurityClientContext ))) {
+
+ DebugTrace(0, Dbg, "Not successful at creating client security, %08lx\n", Status);
+
+ ExFreePool( Ccb->SecurityClientContext );
+ Ccb->SecurityClientContext = NULL;
+ }
+
+ } else {
+
+ DebugTrace(0, Dbg, "Dynamic tracking\n", 0);
+
+ Ccb->SecurityClientContext = NULL;
+ Status = STATUS_SUCCESS;
+ }
+
+ DebugTrace(-1, Dbg, "NpInitializeSecurity -> %08lx\n", Status);
+
+ return Status;
+}
+
+
+VOID
+NpUninitializeSecurity (
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes the client context referenced by the ccb
+
+Arguments:
+
+ Ccb - Supplies the ccb being uninitialized
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpUninitializeSecurity, Ccb = %08lx\n", Ccb);
+
+ //
+ // We only have work to do if the client context field is not null
+ // and then we need to delete the client context, and free the memory.
+ //
+
+ if (Ccb->SecurityClientContext != NULL) {
+
+ DebugTrace(0, Dbg, "Delete client context, %08lx\n", Ccb->SecurityClientContext);
+
+ SeDeleteClientSecurity( Ccb->SecurityClientContext );
+
+ ExFreePool( Ccb->SecurityClientContext );
+ Ccb->SecurityClientContext = NULL;
+ }
+
+ DebugTrace(-1, Dbg, "NpUninitializeSecurity -> VOID\n", 0);
+
+ return;
+}
+
+
+NTSTATUS
+NpSetDataEntryClientContext (
+ IN NAMED_PIPE_END NamedPipeEnd,
+ IN PCCB Ccb,
+ IN PDATA_ENTRY DataEntry,
+ IN PETHREAD UserThread
+ )
+
+/*++
+
+Routine Description:
+
+ This routine captures a new client context and stores it in the indicated
+ data entry, but only if the tracking mode is dynamic and only for the
+ client end of the named pipe.
+
+Arguments:
+
+ NamedPipeEnd - Indicates the client or server end of the named pipe.
+ Only the client end does anything.
+
+ Ccb - Supplies the ccb for this instance of the named pipe.
+
+ DataEntry - Supplies the data entry to use to store the client context
+
+ UserThread - Supplies the thread of the client
+
+Return Value:
+
+ NTSTATUS - Returns our success code.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpSetDataEntryClientContext, Ccb = %08lx\n", Ccb);
+
+ //
+ // Only do the work if this is the client end and tracking is dynamic
+ //
+
+ if ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
+ (Ccb->SecurityQos.ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)) {
+
+ //
+ // Allocate a client context record, and then initialize it
+ //
+
+ DataEntry->SecurityClientContext = FsRtlAllocatePool( NonPagedPoolMustSucceed,
+ sizeof(SECURITY_CLIENT_CONTEXT) );
+
+ DebugTrace(0, Dbg, "Client End, Dynamic Tracking, ClientContext = %08lx\n", DataEntry->SecurityClientContext);
+
+ if (!NT_SUCCESS(Status = SeCreateClientSecurity( UserThread,
+ &Ccb->SecurityQos,
+ FALSE,
+ DataEntry->SecurityClientContext ))) {
+
+ DebugTrace(0, Dbg, "Not successful at creating client security, %08lx\n", Status);
+
+ ExFreePool( DataEntry->SecurityClientContext );
+ DataEntry->SecurityClientContext = NULL;
+ }
+
+ } else {
+
+ DebugTrace(0, Dbg, "Static Tracking or Not Client End\n", 0);
+
+ DataEntry->SecurityClientContext = NULL;
+ Status = STATUS_SUCCESS;
+ }
+
+ DebugTrace(-1, Dbg, "NpSetDataEntryClientContext -> %08lx\n", Status);
+
+ return Status;
+}
+
+
+VOID
+NpCopyClientContext (
+ IN PCCB Ccb,
+ IN PDATA_ENTRY DataEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the client context stored in the data entry into
+ the ccb, but only for dynamic tracking.
+
+Arguments:
+
+ Ccb - Supplies the ccb to update.
+
+ DataEntry - Supplies the DataEntry to copy from.
+
+Return Value:
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCopyClientContext, Ccb = %08lx\n", Ccb);
+
+ //
+ // Only do the copy if the data entries client context field is not null
+ // which means that we are doing dynamic tracking. Note we will
+ // not be called with a server write data entry that has a non null
+ // client context.
+ //
+
+ if (DataEntry->SecurityClientContext != NULL) {
+
+ DebugTrace(0, Dbg, "have something to copy %08lx\n", DataEntry->SecurityClientContext);
+
+ //
+ // First check if we need to delete and deallocate the client
+ // context in the nonpaged ccb
+ //
+
+ if (Ccb->SecurityClientContext != NULL) {
+
+ DebugTrace(0, Dbg, "Remove current client context %08lx\n", Ccb->SecurityClientContext);
+
+ SeDeleteClientSecurity( Ccb->SecurityClientContext );
+
+ ExFreePool( Ccb->SecurityClientContext );
+ }
+
+ //
+ // Now copy over the reference to the client context, and zero
+ // out the reference in the data entry.
+ //
+
+ Ccb->SecurityClientContext = DataEntry->SecurityClientContext;
+ DataEntry->SecurityClientContext = NULL;
+ }
+
+ DebugTrace(-1, Dbg, "NpCopyClientContext -> VOID\n", 0 );
+
+ return;
+}
+
+
+NTSTATUS
+NpImpersonateClientContext (
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine impersonates the current client context stored in the
+ ccb
+
+Arguments:
+
+ Ccb - Supplies the ccb for the named pipe
+
+Return Value:
+
+ NTSTATUS - returns our status code.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpImpersonateClientContext, Ccb = %08lx\n", Ccb);
+
+ if (Ccb->SecurityClientContext == NULL) {
+
+ DebugTrace(0, Dbg, "Cannot impersonate\n", 0);
+
+ Status = STATUS_CANNOT_IMPERSONATE;
+
+ } else {
+
+ SeImpersonateClient( Ccb->SecurityClientContext, NULL );
+
+ Status = STATUS_SUCCESS;
+ }
+
+ DebugTrace(-1, Dbg, "NpImpersonateClientContext -> %08lx\n", Status);
+
+ return Status;
+}
diff --git a/private/ntos/npfs/seinfo.c b/private/ntos/npfs/seinfo.c
new file mode 100644
index 000000000..3031dd43d
--- /dev/null
+++ b/private/ntos/npfs/seinfo.c
@@ -0,0 +1,416 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ SeInfo.c
+
+Abstract:
+
+ This module implements the Security Info routines for NPFS called by the
+ dispatch driver. There are two entry points NpFsdQueryInformation
+ and NpFsdSetInformation.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_SEINFO)
+
+//
+// local procedure prototypes
+//
+
+NTSTATUS
+NpCommonQuerySecurityInfo (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+
+NTSTATUS
+NpCommonSetSecurityInfo (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonQuerySecurityInfo)
+#pragma alloc_text(PAGE, NpCommonSetSecurityInfo)
+#pragma alloc_text(PAGE, NpFsdQuerySecurityInfo)
+#pragma alloc_text(PAGE, NpFsdSetSecurityInfo)
+#endif
+
+
+NTSTATUS
+NpFsdQuerySecurityInfo (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the Query Security Information API
+ calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdQuerySecurityInfo\n", 0);
+
+ //
+ // Call the common Query Information routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireExclusiveVcb();
+
+ try {
+
+ Status = NpCommonQuerySecurityInfo( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdQuerySecurityInfo -> %08lx\n", Status );
+
+ return Status;
+}
+
+
+NTSTATUS
+NpFsdSetSecurityInfo (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the Set Security Information API
+ calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdSetSecurityInfo\n", 0);
+
+ //
+ // Call the common Set Information routine.
+ //
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireExclusiveVcb();
+
+ try {
+
+ Status = NpCommonSetSecurityInfo( NpfsDeviceObject, Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdSetSecurityInfo -> %08lx\n", Status );
+
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonQuerySecurityInfo (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for querying security information.
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PFCB Fcb;
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonQuerySecurityInfo...\n", 0);
+ DebugTrace( 0, Dbg, " Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, " ->SecurityInformation = %08lx\n", IrpSp->Parameters.QuerySecurity.SecurityInformation);
+ DebugTrace( 0, Dbg, " ->Length = %08lx\n", IrpSp->Parameters.QuerySecurity.Length);
+ DebugTrace( 0, Dbg, " ->UserBuffer = %08lx\n", Irp->UserBuffer);
+
+ //
+ // Get the ccb and figure out who we are, and make sure we're not
+ // disconnected.
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ &Fcb,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ Status = STATUS_PIPE_DISCONNECTED;
+
+ DebugTrace(-1, Dbg, "NpCommonQueryInformation -> %08lx\n", Status );
+ return Status;
+ }
+
+ //
+ // Now we only will allow write operations on the pipe and not a directory
+ // or the device
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ Status = STATUS_INVALID_PARAMETER;
+
+ DebugTrace(-1, Dbg, "NpCommonQueryInformation -> %08lx\n", Status );
+ return Status;
+ }
+
+ //
+ // Call the security routine to do the actual query
+ //
+
+ try {
+
+ Status = SeQuerySecurityDescriptorInfo( &IrpSp->Parameters.QuerySecurity.SecurityInformation,
+ Irp->UserBuffer,
+ &IrpSp->Parameters.QuerySecurity.Length,
+ &Fcb->SecurityDescriptor );
+
+ if ( Status == STATUS_BUFFER_TOO_SMALL ) {
+
+ Irp->IoStatus.Information = IrpSp->Parameters.QuerySecurity.Length;
+
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
+ }
+
+ NpCompleteRequest( Irp, Status );
+
+ DebugTrace(-1, Dbg, "NpCommonQuerySecurityInfo -> %08lx\n", Status );
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonSetSecurityInfo (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for Setting security information.
+
+Arguments:
+
+ Irp - Supplies the Irp to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status;
+
+ NODE_TYPE_CODE NodeTypeCode;
+ PFCB Fcb;
+ PCCB Ccb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ PSECURITY_DESCRIPTOR OldSecurityDescriptor;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NpCommonSetSecurityInfo...\n", 0);
+ DebugTrace( 0, Dbg, " Irp = %08lx\n", Irp);
+ DebugTrace( 0, Dbg, " ->SecurityInformation = %08lx\n", IrpSp->Parameters.SetSecurity.SecurityInformation);
+ DebugTrace( 0, Dbg, " ->SecurityDescriptor = %08lx\n", IrpSp->Parameters.SetSecurity.SecurityDescriptor);
+
+ //
+ // Get the ccb and figure out who we are, and make sure we're not
+ // disconnected.
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
+ &Fcb,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ Status = STATUS_PIPE_DISCONNECTED;
+
+ DebugTrace(-1, Dbg, "NpCommonQueryInformation -> %08lx\n", Status );
+ return Status;
+ }
+
+ //
+ // Now we only will allow write operations on the pipe and not a directory
+ // or the device
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
+ Status = STATUS_INVALID_PARAMETER;
+
+ DebugTrace(-1, Dbg, "NpCommonQueryInformation -> %08lx\n", Status );
+ return Status;
+ }
+
+ //
+ // Call the security routine to do the actual set
+ //
+
+ OldSecurityDescriptor = Fcb->SecurityDescriptor;
+
+ Status = SeSetSecurityDescriptorInfo( NULL,
+ &IrpSp->Parameters.SetSecurity.SecurityInformation,
+ IrpSp->Parameters.SetSecurity.SecurityDescriptor,
+ &Fcb->SecurityDescriptor,
+ PagedPool,
+ IoGetFileObjectGenericMapping() );
+
+ if (NT_SUCCESS(Status)) {
+ ExFreePool( OldSecurityDescriptor );
+ }
+
+ NpCompleteRequest( Irp, Status );
+
+ DebugTrace(-1, Dbg, "NpCommonSetSecurityInfo -> %08lx\n", Status );
+ return Status;
+}
diff --git a/private/ntos/npfs/sources b/private/ntos/npfs/sources
new file mode 100644
index 000000000..063d6f34b
--- /dev/null
+++ b/private/ntos/npfs/sources
@@ -0,0 +1,65 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=npfs
+
+TARGETNAME=npfs
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+INCLUDES=..\inc
+
+NTPROFILEINPUT=yes
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ AliasSup.c \
+ Cleanup.c \
+ Close.c \
+ Create.c \
+ CreateNp.c \
+ DataSup.c \
+ Dir.c \
+ DumpSup.c \
+ EventSup.c \
+ FileInfo.c \
+ FilObSup.c \
+ FlushBuf.c \
+ FsCtrl.c \
+ NpData.c \
+ Npfs.rc \
+ NpInit.c \
+ PrefxSup.c \
+ Read.c \
+ ReadSup.c \
+ SecurSup.c \
+ SeInfo.c \
+ StateSup.c \
+ StrucSup.c \
+ VolInfo.c \
+ WaitSup.c \
+ Write.c \
+ WriteSup.c
diff --git a/private/ntos/npfs/statesup.c b/private/ntos/npfs/statesup.c
new file mode 100644
index 000000000..d7fbb7d2f
--- /dev/null
+++ b/private/ntos/npfs/statesup.c
@@ -0,0 +1,1179 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ StateSup.c
+
+Abstract:
+
+ This module implements the Named Pipe State Support routines
+
+Author:
+
+ Gary Kimura [GaryKi] 30-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (NPFS_BUG_CHECK_STATESUP)
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_STATESUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpInitializePipeState)
+#pragma alloc_text(PAGE, NpUninitializePipeState)
+#endif
+
+VOID
+NpCancelListeningQueueIrp (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+VOID
+NpInitializePipeState (
+ IN PCCB Ccb,
+ IN PFILE_OBJECT ServerFileObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize a named pipe instance to the disconnected state.
+
+Arguments:
+
+ Ccb - Supplies a pointer to the Ccb representing the pipe state
+
+ ServerFileObject - Supplies a pointer to the server file object
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpInitializePipeState, Ccb = %08lx\n", Ccb);
+
+ //
+ // Set the ccb and nonpaged ccb fields
+ //
+
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = ServerFileObject;
+ Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE;
+
+ //
+ // The file object contexts pointers.
+ //
+
+ NpSetFileObject( ServerFileObject,
+ Ccb,
+ Ccb->NonpagedCcb,
+ FILE_PIPE_SERVER_END );
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpInitializePipeState -> VOID\n", 0);
+
+ return;
+}
+
+
+VOID
+NpUninitializePipeState (
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize a named pipe instance to the disconnected state.
+
+Arguments:
+
+ Ccb - Supplies a pointer to the Ccb representing the pipe state
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpUninitializePipeState, Ccb = %08lx\n", Ccb);
+
+ //
+ // The file object contexts pointers for our server to null
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_SERVER_END );
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
+
+
+ //
+ // The file object contexts pointers for our client to null
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_CLIENT_END );
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ //
+ // Set to null both pointers to file object.
+ //
+
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpUninitializePipeState -> VOID\n", 0);
+
+ return;
+}
+
+
+NTSTATUS
+NpSetListeningPipeState (
+ IN PCCB Ccb,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets a named pipe to the listening state. This routine
+ will either complete the IRP right away or put in the listening queue
+ to be completed later.
+
+Arguments:
+
+ Ccb - Supplies a pointer to the Ccb representing the pipe state
+
+ Irp - Supplies the Irp doing the listening operation
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ DebugTrace(+1, Dbg, "NpSetListeningPipeState, Ccb = %08lx\n", Ccb);
+
+ //
+ // Case on the current state of the named pipe
+ //
+
+ switch (Ccb->NamedPipeState) {
+
+ case FILE_PIPE_DISCONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was disconnected\n", 0);
+
+ //
+ // Set the state to listening and check for any wait for named
+ // pipe requests.
+ //
+
+ Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
+
+ NpCancelWaiter( &NpVcb->WaitQueue,
+ &Ccb->Fcb->FullFileName );
+
+ //
+ // If the completion mode is complete operation then we can
+ // complete this irp otherwise we need to enqueue the irp
+ // into the listening queue, and mark it pending.
+ //
+
+ if (Ccb->CompletionMode[ FILE_PIPE_SERVER_END ] == FILE_PIPE_COMPLETE_OPERATION) {
+
+ NpCompleteRequest( Irp, STATUS_PIPE_LISTENING );
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ IoMarkIrpPending( Irp );
+
+ InsertTailList( &Ccb->NonpagedCcb->ListeningQueue, &Irp->Tail.Overlay.ListEntry );
+
+ //
+ // Set the cancel routine and also check if the irp is already cancelled
+ //
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ Irp->IoStatus.Status = (ULONG)Ccb;
+
+ if (Irp->Cancel) {
+
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
+ NpCompleteRequest( Irp, STATUS_CANCELLED );
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ IoSetCancelRoutine( Irp, NpCancelListeningQueueIrp );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ Status = STATUS_PENDING;
+ }
+ }
+
+ break;
+
+ case FILE_PIPE_LISTENING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was listening\n", 0);
+
+ //
+ // If the completion mode is complete operation then we can
+ // complete this irp otherwise we need to enqueue the irp
+ // into the listening queue, and mark it pending.
+ //
+
+ if (Ccb->CompletionMode[ FILE_PIPE_SERVER_END ] == FILE_PIPE_COMPLETE_OPERATION) {
+
+ NpCompleteRequest( Irp, STATUS_PIPE_LISTENING );
+ Status = STATUS_PIPE_LISTENING;
+
+ } else {
+
+ IoMarkIrpPending( Irp );
+
+ InsertTailList( &Ccb->NonpagedCcb->ListeningQueue, &Irp->Tail.Overlay.ListEntry );
+
+ //
+ // Set the cancel routine and also check if the irp is already cancelled
+ //
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ Irp->IoStatus.Status = (ULONG)Ccb;
+
+ if (Irp->Cancel) {
+
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
+ NpCompleteRequest( Irp, STATUS_CANCELLED );
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ IoSetCancelRoutine( Irp, NpCancelListeningQueueIrp );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ Status = STATUS_PENDING;
+ }
+ }
+
+ break;
+
+ case FILE_PIPE_CONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was connected\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_CONNECTED );
+ Status = STATUS_PIPE_CONNECTED;
+
+ break;
+
+ case FILE_PIPE_CLOSING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was closing\n", 0);
+
+ NpCompleteRequest( Irp, STATUS_PIPE_CLOSING );
+ Status = STATUS_PIPE_CLOSING;
+
+ break;
+
+ default:
+
+ NpBugCheck( Ccb->NamedPipeState, 0, 0 );
+ }
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpSetListeningPipeState -> %08lx\n", Status);
+
+ return Status;
+}
+
+
+NTSTATUS
+NpSetConnectedPipeState (
+ IN PCCB Ccb,
+ IN PFILE_OBJECT ClientFileObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the state of a named pipe to connected.
+
+Arguments:
+
+ Ccb - Supplies a pointer to the Ccb representing the pipe state
+
+ ClientFileObject - Supplies the file object for the client that is
+ doing the connect.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ NTSTATUS Status;
+ PNONPAGED_CCB NonpagedCcb;
+ PIRP LocalIrp;
+ KIRQL CancelIrql;
+
+ DebugTrace(+1, Dbg, "NpSetConnectedPipeState, Ccb = %08lx\n", Ccb);
+
+ //
+ // Save a pointer to the nonpaged ccb, we really need to do this now so when we
+ // complete our listening waiters we won't touch paged pool
+ //
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ //
+ // Case on the current state of the named pipe
+ //
+
+ switch (Ccb->NamedPipeState) {
+
+ case FILE_PIPE_DISCONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was disconnected\n", 0);
+
+ NpBugCheck( 0, 0, 0 );
+
+ case FILE_PIPE_LISTENING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was listening\n", 0);
+
+ //
+ // Set the state of the pipe to connected and adjust the
+ // appropriate read mode and completion mode values
+ //
+
+ Ccb->NamedPipeState = FILE_PIPE_CONNECTED_STATE;
+ Ccb->ReadMode[ FILE_PIPE_CLIENT_END ] = FILE_PIPE_BYTE_STREAM_MODE;
+ Ccb->CompletionMode[ FILE_PIPE_CLIENT_END ] = FILE_PIPE_QUEUE_OPERATION;
+
+ //
+ // Set our back pointer to the client file object and set the
+ // client file object context pointers
+ //
+
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = ClientFileObject;
+
+ NpSetFileObject( ClientFileObject,
+ Ccb,
+ NonpagedCcb,
+ FILE_PIPE_CLIENT_END );
+
+ //
+ // And complete any listening waiters
+ //
+
+ IoAcquireCancelSpinLock( &CancelIrql );
+
+ while (!IsListEmpty( &NonpagedCcb->ListeningQueue )) {
+ PLIST_ENTRY Links;
+
+ Links = RemoveHeadList( &NonpagedCcb->ListeningQueue );
+
+ LocalIrp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+
+ //
+ // Disable the cancel routine in the irp before completing the request
+ //
+
+ LocalIrp->CancelIrql = CancelIrql;
+
+ IoSetCancelRoutine( LocalIrp, NULL );
+
+ IoReleaseCancelSpinLock( CancelIrql );
+
+ NpCompleteRequest( LocalIrp, STATUS_SUCCESS );
+
+ IoAcquireCancelSpinLock( &CancelIrql );
+ }
+
+ IoReleaseCancelSpinLock( CancelIrql );
+
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ case FILE_PIPE_CONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was connected\n", 0);
+
+ NpBugCheck( 0, 0, 0 );
+
+ case FILE_PIPE_CLOSING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was closing\n", 0);
+
+ NpBugCheck( 0, 0, 0 );
+
+ default:
+
+ NpBugCheck( Ccb->NamedPipeState, 0, 0 );
+ }
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpSetConnectedPipeState -> %08lx\n", Status);
+
+ return Status;
+}
+
+
+NTSTATUS
+NpSetClosingPipeState (
+ IN PCCB Ccb,
+ IN PIRP Irp,
+ IN NAMED_PIPE_END NamedPipeEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets a pipe state to closing. This routine will
+ either complete the irp right away or put in on the data queue
+ to be completed later.
+
+Arguments:
+
+ Ccb - Supplies a pointer to the Ccb representing the pipe state
+
+ Irp - Supplies the Irp trying to do the close operation
+
+ NamedPipeEnd - Indicates if the server or client is doing the transition
+
+Return Value:
+
+ NTSTATUS -
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PNONPAGED_CCB NonpagedCcb;
+
+ PFCB Fcb;
+ PIRP LocalIrp;
+ KIRQL CancelIrql;
+
+ PDATA_QUEUE ReadQueue;
+ PDATA_QUEUE WriteQueue;
+
+ PEVENT_TABLE_ENTRY Event;
+
+ DebugTrace(+1, Dbg, "NpSetClosingPipeState, Ccb = %08lx\n", Ccb);
+
+ Fcb = Ccb->Fcb;
+
+ //
+ // Save a pointer to the nonpaged ccb, we really need to do this now so when we
+ // complete our listening waiters we won't touch paged pool
+ //
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ //
+ // Case on the current state of the named pipe
+ //
+
+ switch (Ccb->NamedPipeState) {
+
+ case FILE_PIPE_DISCONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was disconnected\n", 0);
+
+ ASSERT( NamedPipeEnd == FILE_PIPE_SERVER_END );
+
+ //
+ // Pipe is disconnected, for safety sake we'll zero out the
+ // file objects context pointers to use
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_SERVER_END );
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_CLIENT_END );
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ //
+ // Close it we delete the instance, and possibly the Fcb if its
+ // open count is now zero.
+ //
+
+ NpDeleteCcb( Ccb );
+ if (Fcb->OpenCount == 0) {
+
+ NpDeleteFcb( Fcb );
+ }
+
+ //
+ // And now complete the irp
+ //
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ case FILE_PIPE_LISTENING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was listening\n", 0);
+
+ ASSERT( NamedPipeEnd == FILE_PIPE_SERVER_END );
+
+ //
+ // Pipe in listening state, so complete all IRPs that are in the
+ // listening queue with a closing status, and then delete the
+ // instance and possibly the Fcb if its open count is now zero
+ //
+
+ IoAcquireCancelSpinLock( &CancelIrql );
+
+ while (!IsListEmpty( &NonpagedCcb->ListeningQueue )) {
+ PLIST_ENTRY Links;
+
+ Links = RemoveHeadList( &NonpagedCcb->ListeningQueue );
+
+ LocalIrp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+
+ //
+ // Disable the cancel routine in the irp before completing the request
+ //
+
+ LocalIrp->CancelIrql = CancelIrql;
+
+ IoSetCancelRoutine( LocalIrp, NULL );
+
+ IoReleaseCancelSpinLock( CancelIrql );
+
+ NpCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN );
+
+ IoAcquireCancelSpinLock( &CancelIrql );
+ }
+
+ IoReleaseCancelSpinLock( CancelIrql );
+
+ //
+ // For safety sake we'll zero out the file objects context
+ // pointers to use
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_SERVER_END );
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_CLIENT_END );
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ //
+ // Remove the ccb and possibly the Fcb
+ //
+
+ NpDeleteCcb( Ccb );
+ if (Fcb->OpenCount == 0) {
+
+ NpDeleteFcb( Fcb );
+ }
+
+ //
+ // And now complete the irp
+ //
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ case FILE_PIPE_CONNECTED_STATE:
+
+ //
+ // The pipe is connected so decide who is trying to do the close
+ // and then fall into common code
+ //
+
+ if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
+
+ DebugTrace(0, Dbg, "Pipe was connected, server doing close\n", 0);
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+
+ //
+ // For safety sake we'll zero out the file objects context
+ // pointers to use
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_SERVER_END );
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
+
+ } else {
+
+ DebugTrace(0, Dbg, "Pipe was connected, client doing close\n", 0);
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
+
+ //
+ // For safety sake we'll zero out the file objects context
+ // pointers to use
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_CLIENT_END );
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+ }
+
+ //
+ // To do a close on a connected pipe we set its state to closing
+ // drain the read queue and drain reads on the write queue.
+ //
+ //
+ // Closing <---ReadQueue---- [ Remove all entries ]
+ // End
+ // ---WriteQueue---> [ Remove only read entries ]
+ //
+
+ Ccb->NamedPipeState = FILE_PIPE_CLOSING_STATE;
+
+ while (!NpIsDataQueueEmpty( ReadQueue )) {
+
+ if ((LocalIrp = NpRemoveDataQueueEntry( ReadQueue )) != NULL) {
+
+ NpCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN );
+ }
+ }
+
+ while (!NpIsDataQueueEmpty( WriteQueue ) &&
+ (WriteQueue->QueueState == ReadEntries)) {
+
+ if ((LocalIrp = NpRemoveDataQueueEntry( WriteQueue )) != NULL) {
+
+ NpCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN );
+ }
+ }
+
+ //
+ // Now if the write queue is empty then we complete this
+ // close request with success otherwise we need to enqueue
+ // the irp to the write queue and set our return status to pending
+ // also the mark the irp pending
+ //
+
+ if ( TRUE || NpIsDataQueueEmpty( WriteQueue ) ) {
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ IoMarkIrpPending( Irp );
+
+ (VOID)NpAddDataQueueEntry( WriteQueue, WriteEntries, Close, 0, Irp, NULL );
+ Status = STATUS_PENDING;
+ }
+
+ //
+ // Now signal the other sides event to show that something has
+ // happened
+ //
+
+ NpSignalEventTableEntry( Event );
+
+ break;
+
+ case FILE_PIPE_CLOSING_STATE:
+
+ //
+ // The pipe is closing so decide who is trying to complete the close
+ // and then fall into common code
+ //
+
+ if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
+
+ DebugTrace(0, Dbg, "Pipe was closing, server doing close\n", 0);
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ //
+ // For safety sake we'll zero out the file objects context
+ // pointers to use
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_SERVER_END );
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_CLIENT_END );
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ } else {
+
+ DebugTrace(0, Dbg, "Pipe was closing, client doing close\n", 0);
+
+ ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ //
+ // For safety sake we'll zero out the file objects context
+ // pointers to use
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_SERVER_END );
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_CLIENT_END );
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+ }
+
+ //
+ // To do a close on a closing pipe we drain the read queue of
+ // all its entries, delete the instance, and possibly delete the
+ // Fcb if its open count is now zero.
+ //
+ //
+ // Previously <-----Closed----- Closing
+ // Closed End
+ // End ----ReadQueue--->
+ //
+
+ while (!NpIsDataQueueEmpty( ReadQueue )) {
+
+ if ((LocalIrp = NpRemoveDataQueueEntry( ReadQueue )) != NULL) {
+
+ NpCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN );
+ }
+ }
+
+ NpDeleteCcb( Ccb );
+ if (Fcb->OpenCount == 0) {
+
+ NpDeleteFcb( Fcb );
+ }
+
+ //
+ // And now complete the irp
+ //
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ NpBugCheck( Ccb->NamedPipeState, 0, 0 );
+ }
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpSetClosingPipeState -> %08lx\n", Status);
+
+ return Status;
+}
+
+
+NTSTATUS
+NpSetDisconnectedPipeState (
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets a pipe state to disconnected, only the server is
+ allowed to do this transition
+
+Arguments:
+
+ Ccb - Supplies a pointer to the Ccb representing the pipe instance
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PNONPAGED_CCB NonpagedCcb;
+
+ PIRP Irp;
+
+ PDATA_QUEUE Inbound;
+ PDATA_QUEUE Outbound;
+ PEVENT_TABLE_ENTRY ClientEvent;
+
+ DebugTrace(+1, Dbg, "NpSetDisconnectedPipeState, Ccb = %08lx\n", Ccb);
+
+
+ //
+ // Save a pointer to the nonpaged ccb, we really need to do this now so when we
+ // complete our listening waiters we won't touch paged pool
+ //
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ //
+ // Case on the current state of the named pipe
+ //
+
+ switch (Ccb->NamedPipeState) {
+
+ case FILE_PIPE_DISCONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe already disconnected\n", 0);
+
+ //
+ // pipe already disconnected so there is no work for us to do
+ //
+
+ Status = STATUS_PIPE_DISCONNECTED;
+
+ break;
+
+ case FILE_PIPE_LISTENING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was listening\n", 0);
+
+ //
+ // Pipe in listening state, so complete all IRPs that are in the
+ // listening queue with a disconnected status
+ //
+
+ while (!IsListEmpty( &NonpagedCcb->ListeningQueue )) {
+ PLIST_ENTRY Links;
+
+ Links = RemoveHeadList( &NonpagedCcb->ListeningQueue );
+
+ Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+
+ //
+ // Disable the cancel routine in the irp before completing the request
+ //
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ IoSetCancelRoutine( Irp, NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ }
+
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ case FILE_PIPE_CONNECTED_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was connected\n", 0);
+
+ Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+ ClientEvent = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+
+ //
+ // Pipe is connected so we need to discard all of the data queues
+ // and complete any of their IRPs with status disconnected.
+ //
+
+ while (!NpIsDataQueueEmpty( Inbound )) {
+
+ if ((Irp = NpRemoveDataQueueEntry( Inbound )) != NULL) {
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ }
+ }
+
+ while (!NpIsDataQueueEmpty( Outbound )) {
+
+ if ((Irp = NpRemoveDataQueueEntry( Outbound )) != NULL) {
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ }
+ }
+
+ //
+ // Signal the client event and then remove it from the pipe
+ //
+
+ NpSignalEventTableEntry( ClientEvent );
+
+ NpDeleteEventTableEntry( &NpVcb->EventTable, ClientEvent );
+ NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ //
+ // Disable the client's file object
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_CLIENT_END );
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ case FILE_PIPE_CLOSING_STATE:
+
+ DebugTrace(0, Dbg, "Pipe was closing\n", 0);
+
+ Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+ Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+ ClientEvent = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+
+ //
+ // Pipe is closing (this had to have been done by the client) we
+ // need to discard all of the data queues (only the inbound can have
+ // entries) and complete any of their IRPs with status disconnected.
+ //
+ //
+ // Server <----Inbound---- Client
+ // End End
+ // ----Closed----->
+ //
+
+ while (!NpIsDataQueueEmpty( Inbound )) {
+
+ if ((Irp = NpRemoveDataQueueEntry( Inbound )) != NULL) {
+
+ NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED );
+ }
+ }
+
+ ASSERT( NpIsDataQueueEmpty( Outbound ) );
+
+ //
+ // The client event should already be gone but for safety sake
+ // we'll make sure its gone.
+ //
+
+ NpDeleteEventTableEntry( &NpVcb->EventTable, ClientEvent );
+ NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ //
+ // Also if it's still connected, disable the client's file object
+ //
+
+ NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
+ NULL,
+ NULL,
+ FILE_PIPE_CLIENT_END );
+ Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
+
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ NpBugCheck( Ccb->NamedPipeState, 0, 0 );
+ }
+
+ //
+ // Set the state to disconnected
+ //
+
+ Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE;
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpSetDisconnectedPipeState -> %08lx\n", Status);
+
+ return Status;
+}
+
+
+//
+// Local support routine
+//
+
+VOID
+NpCancelListeningQueueIrp (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the cancel function for an IRP saved in a listening
+ queue
+
+Arguments:
+
+ DeviceObject - ignored
+
+ Irp - Supplies the Irp being cancelled. A pointer to the ccb
+ structure is stored in the information field of the Irp Iosb
+ field.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCCB Ccb;
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+
+ //
+ // The status field is used to store a pointer to the Ccb
+ // containing this irp
+ //
+
+ Ccb = (PCCB)Irp->IoStatus.Status;
+
+ //
+ // We now need to void the cancel routine and release the io cancel spinlock
+ //
+
+ IoSetCancelRoutine( Irp, NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ //
+ // Get exclusive access to the named pipe vcb so we can now do our work
+ //
+
+ NpAcquireExclusiveVcb();
+
+ try {
+
+ PNONPAGED_CCB NonPagedCcb = Ccb->NonpagedCcb;
+ PLIST_ENTRY Links;
+ BOOLEAN RemoveEntry = FALSE;
+
+ if (NodeType( NonPagedCcb ) == NPFS_NTC_NONPAGED_CCB) {
+
+ //
+ // We need to check that the Irp is still in the listening queue.
+ //
+
+ for (Links = NonPagedCcb->ListeningQueue.Flink;
+ Links != &NonPagedCcb->ListeningQueue;
+ Links = Links->Flink) {
+
+ if (CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry ) == Irp) {
+
+ RemoveEntry = TRUE;
+ break;
+ }
+ }
+
+ if (RemoveEntry) {
+
+ RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
+ NpCompleteRequest( Irp, STATUS_CANCELLED );
+ }
+ }
+
+ //
+ // Catch all exceptions. It's possible that the Ccb has gone away in
+ // the meantime and there is now no Irp to complete.
+ //
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+
+ NOTHING;
+ }
+
+ NpReleaseVcb();
+
+ //
+ // And return to our caller
+ //
+
+ return;
+}
diff --git a/private/ntos/npfs/strucsup.c b/private/ntos/npfs/strucsup.c
new file mode 100644
index 000000000..d3e05d079
--- /dev/null
+++ b/private/ntos/npfs/strucsup.c
@@ -0,0 +1,1022 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ StrucSup.c
+
+Abstract:
+
+ This module implements the Named Pipe in-memory data structure manipulation
+ routines
+
+Author:
+
+ Gary Kimura [GaryKi] 22-Jan-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (NPFS_BUG_CHECK_STRUCSUP)
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_STRUCSUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCreateCcb)
+#pragma alloc_text(PAGE, NpCreateFcb)
+#pragma alloc_text(PAGE, NpCreateRootDcb)
+#pragma alloc_text(PAGE, NpCreateRootDcbCcb)
+#pragma alloc_text(PAGE, NpDeleteCcb)
+#pragma alloc_text(PAGE, NpDeleteFcb)
+#pragma alloc_text(PAGE, NpDeleteRootDcb)
+#pragma alloc_text(PAGE, NpDeleteVcb)
+#pragma alloc_text(PAGE, NpInitializeVcb)
+#endif
+
+
+VOID
+NpInitializeVcb (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes new Vcb record. The Vcb record "hangs" off the
+ end of the Npfs device object and must be allocated by our caller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The following variables are used for abnormal unwinding
+ //
+
+ BOOLEAN UnwindResource = FALSE;
+ BOOLEAN UnwindEventTable = FALSE;
+ BOOLEAN UnwindWaitQueue = FALSE;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpInitializeVcb, Vcb = %08lx\n", NpVcb);
+
+ try {
+
+ //
+ // We start by first zeroing out all of the VCB, this will guarantee
+ // that any stale data is wiped clean
+ //
+
+ RtlZeroMemory( NpVcb, sizeof(VCB) );
+
+ //
+ // Set the proper node type code and node byte size
+ //
+
+ NpVcb->NodeTypeCode = NPFS_NTC_VCB;
+ NpVcb->NodeByteSize = sizeof(VCB);
+
+ //
+ // Initialize the Prefix table
+ //
+
+ RtlInitializeUnicodePrefix( &NpVcb->PrefixTable );
+
+ //
+ // Initialize the resource variable for the Vcb
+ //
+
+ ExInitializeResource( &NpVcb->Resource );
+ UnwindResource = TRUE;
+
+ //
+ // Initialize the event table
+ //
+
+ NpInitializeEventTable( &NpVcb->EventTable );
+ UnwindEventTable = TRUE;
+
+ //
+ // Initialize the wait queue
+ //
+
+ NpInitializeWaitQueue( &NpVcb->WaitQueue );
+ UnwindWaitQueue = TRUE;
+
+ } finally {
+
+ //
+ // If this is an abnormal termination then check if we need
+ // to undo any initialization we've already done.
+ //
+
+ if (AbnormalTermination()) {
+
+ if (UnwindResource) { ExDeleteResource( &NpVcb->Resource ); }
+ if (UnwindEventTable) { NpUninitializeEventTable( &NpVcb->EventTable ); }
+ if (UnwindWaitQueue) { NpUninitializeWaitQueue( &NpVcb->WaitQueue ); }
+ }
+
+ DebugTrace(-1, Dbg, "NpInitializeVcb -> VOID\n", 0);
+ }
+
+ //
+ // return and tell the caller
+ //
+
+ return;
+}
+
+
+VOID
+NpDeleteVcb (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes the Vcb record from our in-memory data
+ structures. It also will remove all associated underlings
+ (i.e., FCB records).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpDeleteVcb, Vcb = %08lx\n", NpVcb);
+
+ //
+ // Make sure the open count is zero, and the open underling count
+ // is also zero.
+ //
+
+ if ((NpVcb->OpenCount != 0) || (NpVcb->OpenUnderlingCount != 0)) {
+
+ DebugDump("Error deleting Vcb\n", 0, NpVcb);
+ NpBugCheck( 0, 0, 0 );
+ }
+
+ //
+ // Remove the Root Dcb
+ //
+
+ if (NpVcb->RootDcb != NULL) {
+
+ NpDeleteFcb( NpVcb->RootDcb );
+ }
+
+ //
+ // Uninitialize the resource variable for the Vcb
+ //
+
+ ExDeleteResource( &NpVcb->Resource );
+
+ //
+ // Uninitialize the event table
+ //
+
+ NpUninitializeEventTable( &NpVcb->EventTable );
+
+ //
+ // Uninitialize the wait queue
+ //
+
+ NpUninitializeWaitQueue( &NpVcb->WaitQueue );
+
+ //
+ // And zero out the Vcb, this will help ensure that any stale data is
+ // wiped clean
+ //
+
+ RtlZeroMemory( NpVcb, sizeof(VCB) );
+
+ //
+ // return and tell the caller
+ //
+
+ DebugTrace(-1, Dbg, "NpDeleteVcb -> VOID\n", 0);
+
+ return;
+}
+
+
+VOID
+NpCreateRootDcb (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates, initializes, and inserts a new root DCB record
+ into the in memory data structure.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The following variables are used for abnormal unwinding
+ //
+
+ PVOID UnwindStorage = NULL;
+ BOOLEAN UnwindPrefix = FALSE;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCreateRootDcb, Vcb = %08lx\n", NpVcb);
+
+ //
+ // Make sure we don't already have a root dcb for this vcb
+ //
+
+ if (NpVcb->RootDcb != NULL) {
+
+ DebugDump("Error trying to create multiple root dcbs\n", 0, NpVcb);
+ NpBugCheck( 0, 0, 0 );
+ }
+
+ try {
+
+ //
+ // Allocate a new DCB and zero it out
+ //
+
+ NpVcb->RootDcb = UnwindStorage = FsRtlAllocatePool( PagedPool, sizeof(DCB) );
+
+ RtlZeroMemory( NpVcb->RootDcb, sizeof(DCB));
+
+ //
+ // Set the proper node type code and node byte size
+ //
+
+ NpVcb->RootDcb->NodeTypeCode = NPFS_NTC_ROOT_DCB;
+ NpVcb->RootDcb->NodeByteSize = sizeof(ROOT_DCB);
+
+ //
+ // The root Dcb has an empty parent dcb links field
+ //
+
+ InitializeListHead( &NpVcb->RootDcb->ParentDcbLinks );
+
+ //
+ // initialize the notify queues, and the parent dcb queue.
+ //
+
+ InitializeListHead( &NpVcb->RootDcb->Specific.Dcb.NotifyFullQueue );
+ InitializeListHead( &NpVcb->RootDcb->Specific.Dcb.NotifyPartialQueue );
+ InitializeListHead( &NpVcb->RootDcb->Specific.Dcb.ParentDcbQueue );
+
+ //
+ // set the full file name
+ //
+ // **** Use good string routines when available ****
+ //
+
+ {
+ static PWCH Name = L"\\\0";
+
+ RtlInitUnicodeString( &NpVcb->RootDcb->FullFileName, Name );
+ RtlInitUnicodeString( &NpVcb->RootDcb->LastFileName, Name );
+ }
+
+ //
+ // Insert this dcb into the prefix table
+ //
+
+ if (!RtlInsertUnicodePrefix( &NpVcb->PrefixTable,
+ &NpVcb->RootDcb->FullFileName,
+ &NpVcb->RootDcb->PrefixTableEntry )) {
+
+ DebugDump("Error trying to insert root dcb into prefix table\n", 0, NpVcb);
+ NpBugCheck( 0, 0, 0 );
+ }
+ UnwindPrefix = TRUE;
+
+ } finally {
+
+ //
+ // If this is an abnormal termination then undo our work
+ //
+
+ if (AbnormalTermination()) {
+
+ if (UnwindPrefix) { RtlRemoveUnicodePrefix( &NpVcb->PrefixTable, &NpVcb->RootDcb->PrefixTableEntry ); }
+
+ if (UnwindStorage != NULL) { ExFreePool( UnwindStorage ); }
+ }
+
+ DebugTrace(-1, Dbg, "NpCreateRootDcb -> %8lx\n", NpVcb->RootDcb);
+ }
+
+ return;
+}
+
+
+VOID
+NpDeleteRootDcb (
+ IN PROOT_DCB RootDcb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates and removes the ROOT DCB record
+ from our in-memory data structures. It also will remove all
+ associated underlings (i.e., Notify queues and child FCB records).
+
+Arguments:
+
+ RootDcb - Supplies the ROOT DCB to be removed
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PLIST_ENTRY Links;
+ PIRP Irp;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpDeleteRootDcb, RootDcb = %08lx\n", RootDcb);
+
+ //
+ // We can only delete this record if the open count is zero.
+ //
+
+ if (RootDcb->OpenCount != 0) {
+
+ DebugDump("Error deleting RootDcb, Still Open\n", 0, RootDcb);
+ NpBugCheck( 0, 0, 0 );
+ }
+
+ //
+ // Remove every Notify Irp from the two notify queues
+ //
+
+ while (!IsListEmpty(&RootDcb->Specific.Dcb.NotifyFullQueue)) {
+
+ Links = RemoveHeadList( &RootDcb->Specific.Dcb.NotifyFullQueue );
+
+ Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+
+ NpCompleteRequest( Irp, STATUS_FILE_FORCED_CLOSED );
+ }
+
+ while (!IsListEmpty(&RootDcb->Specific.Dcb.NotifyPartialQueue)) {
+
+ Links = RemoveHeadList( &RootDcb->Specific.Dcb.NotifyPartialQueue );
+
+ Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+
+ NpCompleteRequest( Irp, STATUS_FILE_FORCED_CLOSED );
+ }
+
+ //
+ // We can only be removed if the no other FCB have us referenced
+ // as a their parent DCB.
+ //
+
+ if (!IsListEmpty(&RootDcb->Specific.Dcb.ParentDcbQueue)) {
+
+ DebugDump("Error deleting RootDcb\n", 0, RootDcb);
+ NpBugCheck( 0, 0, 0 );
+ }
+
+ //
+ // Remove the entry from the prefix table, and then remove the full
+ // file name
+ //
+
+ RtlRemoveUnicodePrefix( &NpVcb->PrefixTable, &RootDcb->PrefixTableEntry );
+ ExFreePool( RootDcb->FullFileName.Buffer );
+
+ //
+ // Finally deallocate the Dcb record
+ //
+
+ ExFreePool( RootDcb );
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpDeleteRootDcb -> VOID\n", 0);
+
+ return;
+}
+
+
+PFCB
+NpCreateFcb (
+ IN PDCB ParentDcb,
+ IN PUNICODE_STRING FileName,
+ IN ULONG MaximumInstances,
+ IN LARGE_INTEGER DefaultTimeOut,
+ IN NAMED_PIPE_CONFIGURATION NamedPipeConfiguration,
+ IN NAMED_PIPE_TYPE NamedPipeType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates, initializes, and inserts a new Fcb record into
+ the in memory data structures.
+
+Arguments:
+
+ ParentDcb - Supplies the parent dcb that the new FCB is under.
+
+ FileName - Supplies the file name of the file relative to the directory
+ it's in (e.g., the file \config.sys is called "CONFIG.SYS" without
+ the preceding backslash).
+
+ MaximumInstances - Supplies the maximum number of pipe instances
+
+ DefaultTimeOut - Supplies the default wait time out value
+
+ NamedPipeConfiguration - Supplies our initial pipe configuration
+
+ NamedPipeType - Supplies our initial pipe type
+
+Return Value:
+
+ PFCB - Returns a pointer to the newly allocated FCB
+
+--*/
+
+{
+ PFCB Fcb;
+
+ //
+ // The following variables are used for abnormal unwinding
+ //
+
+ PVOID UnwindStorage[2] = { NULL, NULL };
+ BOOLEAN UnwindEntryList = FALSE;
+ BOOLEAN UnwindPrefix = FALSE;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCreateFcb\n", 0);
+
+ try {
+
+ //
+ // Allocate a new FCB record and zero it out
+ //
+
+ Fcb = UnwindStorage[0] = FsRtlAllocatePool( PagedPool, sizeof(FCB) );
+
+ RtlZeroMemory( Fcb, sizeof(FCB) );
+
+ //
+ // Set the proper node type code and node byte size
+ //
+
+ Fcb->NodeTypeCode = NPFS_NTC_FCB;
+ Fcb->NodeByteSize = sizeof(FCB);
+
+ //
+ // Insert this fcb into our parent dcb's queue
+ //
+
+ InsertTailList( &ParentDcb->Specific.Dcb.ParentDcbQueue,
+ &Fcb->ParentDcbLinks );
+ UnwindEntryList = TRUE;
+
+ //
+ // Point back to our parent dcb
+ //
+
+ Fcb->ParentDcb = ParentDcb;
+
+ //
+ // Set our maximum instances, default timeout, and initialize our
+ // ccb queue
+ //
+
+ Fcb->Specific.Fcb.MaximumInstances = MaximumInstances;
+ Fcb->Specific.Fcb.DefaultTimeOut = DefaultTimeOut;
+ InitializeListHead( &Fcb->Specific.Fcb.CcbQueue );
+
+ //
+ // set the file name. We need to do this from nonpaged pool because
+ // cancel waiters works while holding a spinlock and uses the fcb name
+ //
+ // **** Use good string routines when available
+ //
+
+ {
+ PWCH Name;
+ ULONG Length;
+
+ Length = FileName->Length;
+
+ Name = UnwindStorage[1] = FsRtlAllocatePool( NonPagedPool, Length + 2 );
+
+ RtlCopyMemory( Name, FileName->Buffer, Length );
+ Name[ Length / sizeof(WCHAR) ] = L'\0';
+
+ Fcb->FullFileName.Length = (USHORT)Length;
+ Fcb->FullFileName.MaximumLength = (USHORT)Length + 2;
+ Fcb->FullFileName.Buffer = &Name[0];
+
+ Fcb->LastFileName.Length = (USHORT)Length - 2;
+ Fcb->LastFileName.MaximumLength = (USHORT)Length + 2 - 2;
+ Fcb->LastFileName.Buffer = &Name[1];
+ }
+
+ //
+ // Insert this Fcb into the prefix table
+ //
+
+ if (!RtlInsertUnicodePrefix( &NpVcb->PrefixTable,
+ &Fcb->FullFileName,
+ &Fcb->PrefixTableEntry )) {
+
+ DebugDump("Error trying to name into prefix table\n", 0, Fcb);
+ NpBugCheck( 0, 0, 0 );
+ }
+ UnwindPrefix = TRUE;
+
+ //
+ // Set the configuration and pipe type
+ //
+
+ Fcb->Specific.Fcb.NamedPipeConfiguration = NamedPipeConfiguration;
+ Fcb->Specific.Fcb.NamedPipeType = NamedPipeType;
+
+ } finally {
+
+ //
+ // If this is an abnormal unwind then undo our work
+ //
+
+ if (AbnormalTermination()) {
+
+ ULONG i;
+
+ if (UnwindPrefix) { RtlRemoveUnicodePrefix( &NpVcb->PrefixTable, &Fcb->PrefixTableEntry ); }
+ if (UnwindEntryList) { RemoveEntryList( &Fcb->ParentDcbLinks ); }
+
+ for (i = 0; i < 2; i += 1) {
+ if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
+ }
+ }
+
+ DebugTrace(-1, Dbg, "NpCreateFcb -> %08lx\n", Fcb);
+ }
+
+ //
+ // return and tell the caller
+ //
+
+ return Fcb;
+}
+
+
+VOID
+NpDeleteFcb (
+ IN PFCB Fcb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates and removes an FCB
+ from our in-memory data structures. It also will remove all
+ associated underlings.
+
+Arguments:
+
+ Fcb - Supplies the FCB to be removed
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDCB ParentDcb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpDeleteFcb, Fcb = %08lx\n", Fcb);
+
+ ParentDcb = Fcb->ParentDcb;
+
+ //
+ // We can only delete this record if the open count is zero.
+ //
+
+ if (Fcb->OpenCount != 0) {
+
+ DebugDump("Error deleting Fcb, Still Open\n", 0, Fcb);
+ NpBugCheck( 0, 0, 0 );
+ }
+
+ //
+ // Remove ourselves from our parents Dcb queue
+ //
+
+ RemoveEntryList( &(Fcb->ParentDcbLinks) );
+
+ //
+ // If there is a security descriptor on the named pipe then deassign it
+ //
+
+ if (Fcb->SecurityDescriptor != NULL) {
+
+ SeDeassignSecurity( &Fcb->SecurityDescriptor );
+ }
+
+ //
+ // Remove the entry from the prefix table, and then remove the full
+ // file name
+ //
+
+ RtlRemoveUnicodePrefix( &NpVcb->PrefixTable, &Fcb->PrefixTableEntry );
+ ExFreePool( Fcb->FullFileName.Buffer );
+
+ //
+ // Finally deallocate the Fcb record
+ //
+
+ ExFreePool( Fcb );
+
+ //
+ // Check for any outstanding notify irps
+ //
+
+ NpCheckForNotify( ParentDcb, TRUE );
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpDeleteFcb -> VOID\n", 0);
+
+ return;
+}
+
+
+PCCB
+NpCreateCcb (
+ IN PFCB Fcb,
+ IN PFILE_OBJECT ServerFileObject,
+ IN NAMED_PIPE_STATE NamedPipeState,
+ IN READ_MODE ServerReadMode,
+ IN COMPLETION_MODE ServerCompletionMode,
+ IN PEPROCESS CreatorProcess,
+ IN ULONG InBoundQuota,
+ IN ULONG OutBoundQuota
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a new CCB record
+
+Arguments:
+
+ Fcb - Supplies a pointer to the fcb we are attached to
+
+ ServerFileObject - Supplies a pointer to the file object for the server
+ end
+
+ NamedPipeState - Supplies the initial pipe state
+
+ ServerReadMode - Supplies our initial read mode
+
+ ServerCompletionMode - Supplies our initial completion mode
+
+ CreatorProcess - Supplies a pointer to our creator process
+
+ InBoundQuota - Supplies the initial inbound quota
+
+ OutBoundQuota - Supplies the initial outbound quota
+
+Return Value:
+
+ PCCB - returns a pointer to the newly allocate CCB
+
+--*/
+
+{
+ PCCB Ccb;
+
+ //
+ // The following variables are used for abnormal unwinding
+ //
+
+ PVOID UnwindStorage[2] = { NULL, NULL };
+ BOOLEAN UnwindEntryList = FALSE;
+ BOOLEAN UnwindDataQueue[2] = { FALSE, FALSE };
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCreateCcb\n", 0);
+
+ try {
+
+ //
+ // Allocate a new CCB record (paged and nonpaged), and zero them out
+ //
+
+ Ccb = UnwindStorage[0] = FsRtlAllocatePool( PagedPool, sizeof(CCB) );
+
+ RtlZeroMemory( Ccb, sizeof(CCB) );
+
+ Ccb->NonpagedCcb = UnwindStorage[1] = FsRtlAllocatePool( NonPagedPool, sizeof(NONPAGED_CCB) );
+
+ RtlZeroMemory( Ccb->NonpagedCcb, sizeof(NONPAGED_CCB) );
+
+ //
+ // Set the proper node type code and node byte size
+ //
+
+ Ccb->NodeTypeCode = NPFS_NTC_CCB;
+ Ccb->NodeByteSize = sizeof(CCB);
+
+ //
+ // Insert ourselves in the list of ccb for the fcb, and increment
+ // the reference count in the fcb.
+ //
+
+ InsertTailList( &Fcb->Specific.Fcb.CcbQueue, &Ccb->CcbLinks );
+ UnwindEntryList = TRUE;
+ Ccb->Fcb = Fcb;
+
+ Fcb->OpenCount += 1;
+ Fcb->ServerOpenCount += 1;
+ NpVcb->OpenUnderlingCount += 1;
+
+ //
+ // Set the server file object
+ //
+
+ Ccb->FileObject[ FILE_PIPE_SERVER_END ] = ServerFileObject;
+
+ //
+ // Initialize the nonpaged ccb
+ //
+ // Set the proper node type code and node byte size
+ //
+
+ Ccb->NonpagedCcb->NodeTypeCode = NPFS_NTC_NONPAGED_CCB;
+ Ccb->NonpagedCcb->NodeByteSize = sizeof(NONPAGED_CCB);
+
+ //
+ // Set the pipe state, read mode, completion mode, and creator process
+ //
+
+ Ccb->NamedPipeState = NamedPipeState;
+ Ccb->ReadMode[ FILE_PIPE_SERVER_END ] = ServerReadMode;
+ Ccb->CompletionMode[ FILE_PIPE_SERVER_END ] = ServerCompletionMode;
+ Ccb->CreatorProcess = CreatorProcess;
+
+ //
+ // Initialize the data queues
+ //
+
+ NpInitializeDataQueue( &Ccb->DataQueue[ FILE_PIPE_INBOUND ],
+ CreatorProcess,
+ InBoundQuota );
+ UnwindDataQueue[ FILE_PIPE_INBOUND ] = TRUE;
+
+ NpInitializeDataQueue( &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ],
+ CreatorProcess,
+ OutBoundQuota );
+ UnwindDataQueue[ FILE_PIPE_OUTBOUND ] = TRUE;
+
+ //
+ // Initialize the listening queue
+ //
+
+ InitializeListHead( &Ccb->NonpagedCcb->ListeningQueue );
+
+ ExInitializeResource(&Ccb->NonpagedCcb->Resource);
+
+ } finally {
+
+ //
+ // If this is an abnormal termination then undo our work
+ //
+
+ if (AbnormalTermination()) {
+
+ ULONG i;
+
+ if (UnwindEntryList) { RemoveEntryList( &Ccb->CcbLinks ); }
+ if (UnwindDataQueue[FILE_PIPE_INBOUND]) { NpUninitializeDataQueue( &Ccb->DataQueue[FILE_PIPE_INBOUND], CreatorProcess ); }
+ if (UnwindDataQueue[FILE_PIPE_OUTBOUND]) { NpUninitializeDataQueue( &Ccb->DataQueue[FILE_PIPE_OUTBOUND], CreatorProcess ); }
+
+ for (i = 0; i < 2; i += 1) {
+ if (UnwindStorage[i] != NULL) { ExFreePool( UnwindStorage[i] ); }
+ }
+ }
+
+ DebugTrace(-1, Dbg, "NpCreateCcb -> %08lx\n", Ccb);
+ }
+
+ //
+ // return and tell the caller
+ //
+
+ return Ccb;
+}
+
+
+PROOT_DCB_CCB
+NpCreateRootDcbCcb (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a new ROOT DCB CCB record
+
+Arguments:
+
+Return Value:
+
+ PROOT_DCB_CCB - returns a pointer to the newly allocate ROOT_DCB_CCB
+
+--*/
+
+{
+ PROOT_DCB_CCB Ccb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCreateRootDcbCcb\n", 0);
+
+ //
+ // Allocate a new ROOT DCB CCB record, and zero it out
+ //
+
+ Ccb = FsRtlAllocatePool( PagedPool, sizeof(ROOT_DCB_CCB) );
+
+ RtlZeroMemory( Ccb, sizeof(ROOT_DCB_CCB) );
+
+ //
+ // Set the proper node type code and node byte size
+ //
+
+ Ccb->NodeTypeCode = NPFS_NTC_ROOT_DCB_CCB;
+ Ccb->NodeByteSize = sizeof(ROOT_DCB_CCB);
+
+ //
+ // return and tell the caller
+ //
+
+ DebugTrace(-1, Dbg, "NpCreateRootDcbCcb -> %08lx\n", Ccb);
+
+ return Ccb;
+}
+
+
+VOID
+NpDeleteCcb (
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates and removes the specified CCB record
+ from the our in memory data structures
+
+Arguments:
+
+ Ccb - Supplies the CCB to remove
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpDeleteCcb, Ccb = %08lx\n", Ccb);
+
+ //
+ // Case on the type of ccb we are deleting
+ //
+
+ switch (Ccb->NodeTypeCode) {
+
+ case NPFS_NTC_CCB:
+
+ RemoveEntryList( &Ccb->CcbLinks );
+ NpVcb->OpenUnderlingCount -= 1;
+ Ccb->Fcb->OpenCount -= 1;
+
+ NpDeleteEventTableEntry( &NpVcb->EventTable,
+ Ccb->NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ] );
+
+ NpDeleteEventTableEntry( &NpVcb->EventTable,
+ Ccb->NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ] );
+
+ NpUninitializeDataQueue( &Ccb->DataQueue[ FILE_PIPE_INBOUND ],
+ Ccb->CreatorProcess );
+
+ NpUninitializeDataQueue( &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ],
+ Ccb->CreatorProcess );
+
+ //
+ // Check for any outstanding notify irps
+ //
+
+ NpCheckForNotify( Ccb->Fcb->ParentDcb, FALSE );
+
+ //
+ // Delete the resource
+ //
+ ExDeleteResource(&Ccb->NonpagedCcb->Resource);
+
+ //
+ // Free up the security fields in the ccb and then free the nonpaged
+ // ccb
+ //
+
+ NpUninitializeSecurity( Ccb );
+ ExFreePool( Ccb->NonpagedCcb );
+
+ break;
+
+ case NPFS_NTC_ROOT_DCB_CCB:
+
+ if (((PROOT_DCB_CCB)Ccb)->QueryTemplate != NULL) {
+
+ ExFreePool( ((PROOT_DCB_CCB)Ccb)->QueryTemplate );
+ }
+ break;
+ }
+
+ // Deallocate the Ccb record
+ //
+
+ ExFreePool( Ccb );
+
+ //
+ // return and tell the caller
+ //
+
+ DebugTrace(-1, Dbg, "NpDeleteCcb -> VOID\n", 0);
+
+ return;
+}
diff --git a/private/ntos/npfs/volinfo.c b/private/ntos/npfs/volinfo.c
new file mode 100644
index 000000000..b3010c1d2
--- /dev/null
+++ b/private/ntos/npfs/volinfo.c
@@ -0,0 +1,360 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ VolInfo.c
+
+Abstract:
+
+ This module implements the volume information routines for NPFS called by
+ the dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 12-Apr-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The local debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_VOLINFO)
+
+//
+// Local procedure prototypes
+//
+
+NTSTATUS
+NpCommonQueryVolumeInformation (
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NpQueryFsDeviceInfo (
+ IN PFILE_FS_DEVICE_INFORMATION Buffer,
+ IN OUT PULONG Length
+ );
+
+NTSTATUS
+NpQueryFsAttributeInfo (
+ IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
+ IN OUT PULONG Length
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonQueryVolumeInformation)
+#pragma alloc_text(PAGE, NpFsdQueryVolumeInformation)
+#pragma alloc_text(PAGE, NpQueryFsAttributeInfo)
+#pragma alloc_text(PAGE, NpQueryFsDeviceInfo)
+#endif
+
+
+NTSTATUS
+NpFsdQueryVolumeInformation (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the Fsd part of the NtQueryVolumeInformation API
+ call.
+
+Arguments:
+
+ VolumeDeviceObject - Supplies the volume device object where the file
+ being queried exists.
+
+ Irp - Supplies the Irp being processed.
+
+Return Value:
+
+ NTSTATUS - The FSD status for the Irp.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdQueryVolumeInformation\n", 0);
+
+ //
+ // Call the common query routine, with blocking allowed if synchronous
+ //
+
+ FsRtlEnterFileSystem();
+
+ try {
+
+ Status = NpCommonQueryVolumeInformation( Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdQueryVolumeInformation -> %08lx\n", Status);
+
+ return Status;
+}
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpCommonQueryVolumeInformation (
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for querying volume information.
+
+Arguments:
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The return status for the operation
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG Length;
+ FS_INFORMATION_CLASS FsInformationClass;
+ PVOID Buffer;
+
+ PAGED_CODE();
+
+ //
+ // Get the current stack location
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NptCommonQueryVolumeInfo...\n", 0);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
+ DebugTrace( 0, Dbg, "Length = %08lx\n", IrpSp->Parameters.QueryVolume.Length);
+ DebugTrace( 0, Dbg, "FsInformationClass = %08lx\n", IrpSp->Parameters.QueryVolume.FsInformationClass);
+ DebugTrace( 0, Dbg, "Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
+
+ //
+ // Reference our input parameters to make things easier
+ //
+
+ Length = IrpSp->Parameters.QueryVolume.Length;
+ FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass;
+ Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+ switch (FsInformationClass) {
+
+ case FileFsDeviceInformation:
+
+ Status = NpQueryFsDeviceInfo( Buffer, &Length );
+ break;
+
+ case FileFsAttributeInformation:
+
+ Status = NpQueryFsAttributeInfo( Buffer, &Length );
+ break;
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ //
+ // Set the information field to the number of bytes actually filled in
+ //
+
+ Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
+
+ //
+ // Complete the request
+
+ NpCompleteRequest( Irp, Status );
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpCommonQueryVolumeInformation -> %08lx\n", Status);
+
+ return Status;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryFsDeviceInfo (
+ IN PFILE_FS_DEVICE_INFORMATION Buffer,
+ IN OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the query volume device call
+
+Arguments:
+
+ Buffer - Supplies a pointer to the output buffer where the information
+ is to be returned
+
+ Length - Supplies the length of the buffer in byte. This variable
+ upon return recieves the remaining bytes free in the buffer
+
+Return Value:
+
+ Status - Returns the status for the query
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpQueryFsDeviceInfo...\n", 0);
+
+ //
+ // Make sure the buffer is large enough
+ //
+
+ if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION)) {
+
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ RtlZeroMemory( Buffer, sizeof(FILE_FS_DEVICE_INFORMATION) );
+
+ //
+ // Set the output buffer
+ //
+
+ Buffer->DeviceType = FILE_DEVICE_NAMED_PIPE;
+
+ //
+ // Adjust the length variable
+ //
+
+ *Length -= sizeof(FILE_FS_DEVICE_INFORMATION);
+
+ //
+ // And return success to our caller
+ //
+
+ return STATUS_SUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+NTSTATUS
+NpQueryFsAttributeInfo (
+ IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
+ IN OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the query volume attribute call
+
+Arguments:
+
+ Buffer - Supplies a pointer to the output buffer where the information
+ is to be returned
+
+ Length - Supplies the length of the buffer in byte. This variable
+ upon return recieves the remaining bytes free in the buffer
+
+Return Value:
+
+ Status - Returns the status for the query
+
+--*/
+
+{
+ ULONG BytesToCopy;
+
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DebugTrace(0, Dbg, "NpQueryFsAttributeInfo...\n", 0);
+
+ //
+ // Determine how much of the file system name will fit.
+ //
+
+ if ( (*Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
+ FileSystemName[0] )) >= 8 ) {
+
+ BytesToCopy = 8;
+ *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
+ FileSystemName[0] ) + 8;
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ BytesToCopy = *Length - FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION,
+ FileSystemName[0]);
+ *Length = 0;
+
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ //
+ // Set the output buffer
+ //
+
+ Buffer->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES;
+ Buffer->MaximumComponentNameLength = MAXULONG;
+ Buffer->FileSystemNameLength = BytesToCopy;
+
+ RtlCopyMemory( &Buffer->FileSystemName[0], L"NPFS", BytesToCopy );
+
+ //
+ // And return success to our caller
+ //
+
+ return Status;
+}
diff --git a/private/ntos/npfs/waitsup.c b/private/ntos/npfs/waitsup.c
new file mode 100644
index 000000000..fa03790e2
--- /dev/null
+++ b/private/ntos/npfs/waitsup.c
@@ -0,0 +1,626 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ WaitSup.c
+
+Abstract:
+
+ This module implements the Wait for Named Pipe support routines.
+
+Author:
+
+ Gary Kimura [GaryKi] 30-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_WAITSUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpInitializeWaitQueue)
+#pragma alloc_text(PAGE, NpUninitializeWaitQueue)
+#endif
+
+
+//
+// Local procedures and structures
+//
+
+typedef struct _WAIT_CONTEXT {
+ KDPC Dpc;
+ KTIMER Timer;
+ PWAIT_QUEUE WaitQueue;
+} WAIT_CONTEXT;
+typedef WAIT_CONTEXT *PWAIT_CONTEXT;
+
+VOID
+NpTimerDispatch(
+ IN PKDPC Dpc,
+ IN PVOID Contxt,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+VOID
+NpCancelWaitQueueIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+VOID
+NpInitializeWaitQueue (
+ IN PWAIT_QUEUE WaitQueue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the wait for named pipe queue.
+
+Arguments:
+
+ WaitQueue - Supplies a pointer to the list head being initialized
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpInitializeWaitQueue, WaitQueue = %08lx\n", WaitQueue);
+
+ //
+ // Initialize the List head
+ //
+
+ InitializeListHead( &WaitQueue->Queue );
+
+ //
+ // Initialize the Wait Queue's spinlock
+ //
+
+ KeInitializeSpinLock( &WaitQueue->SpinLock );
+
+ //
+ // and return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpInitializeWaitQueue -> VOID\n", 0);
+
+ return;
+}
+
+
+VOID
+NpUninitializeWaitQueue (
+ IN PWAIT_QUEUE WaitQueue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine uninitializes the wait for named pipe queue.
+
+Arguments:
+
+ WaitQueue - Supplies a pointer to the list head being uninitialized
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpInitializeWaitQueue, WaitQueue = %08lx\n", WaitQueue);
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpInitializeWaitQueue -> VOID\n", 0);
+
+ return;
+}
+
+
+VOID
+NpAddWaiter (
+ IN PWAIT_QUEUE WaitQueue,
+ IN LARGE_INTEGER DefaultTimeOut,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a new "wait for named pipe" IRP to the wait queue.
+ After calling this function the caller nolonger can access the IRP
+
+Arguments:
+
+ WaitQueue - Supplies the wait queue being used
+
+ DefaultTimeOut - Supplies the default time out to use if one is
+ not supplied in the Irp
+
+ Irp - Supplies a pointer to the wait Irp
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+ PWAIT_CONTEXT Context;
+ PFILE_PIPE_WAIT_FOR_BUFFER WaitForBuffer;
+ LARGE_INTEGER Timeout;
+ ULONG i;
+
+ DebugTrace(+1, Dbg, "NpAddWaiter, WaitQueue = %08lx\n", WaitQueue);
+
+ //
+ // Allocate a dpc and timer structure and initialize them
+ //
+
+ Context = FsRtlAllocatePool( NonPagedPool, sizeof(WAIT_CONTEXT) );
+
+ KeInitializeDpc( &Context->Dpc, NpTimerDispatch, Irp );
+
+ KeInitializeTimer( &Context->Timer );
+
+ Context->WaitQueue = WaitQueue;
+
+ //
+ // Have the information of the irp point to the context buffer
+ //
+
+ Irp->IoStatus.Information = (ULONG)Context;
+
+ //
+ // Figure out our timeout value
+ //
+
+ WaitForBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+
+ if (WaitForBuffer->TimeoutSpecified) {
+
+ Timeout = WaitForBuffer->Timeout;
+
+ } else {
+
+ Timeout = DefaultTimeOut;
+ }
+
+ //
+ // Upcase the name of the pipe we are waiting for
+ //
+
+ for (i = 0; i < WaitForBuffer->NameLength/sizeof(WCHAR); i += 1) {
+
+ WaitForBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitForBuffer->Name[i]);
+ }
+
+ //
+ // Acquire the spinlock
+ //
+
+ KeAcquireSpinLock( &WaitQueue->SpinLock, &OldIrql );
+
+ try {
+
+ //
+ // Now insert this new entry into the Wait Queue
+ //
+
+ InsertTailList( &WaitQueue->Queue, &Irp->Tail.Overlay.ListEntry );
+
+ //
+ // And set the timer to go off
+ //
+
+ (VOID)KeSetTimer( &Context->Timer, Timeout, &Context->Dpc );
+
+ //
+ // Now set the cancel routine for the irp and check if it has been cancelled.
+ //
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ Irp->IoStatus.Status = (ULONG)WaitQueue;
+
+ if (Irp->Cancel) {
+
+ NpCancelWaitQueueIrp( ((PVOID)0x1), Irp );
+
+ } else {
+
+ IoSetCancelRoutine( Irp, NpCancelWaitQueueIrp );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+ }
+
+ } finally {
+
+ //
+ // Release the spinlock
+ //
+
+ KeReleaseSpinLock( &WaitQueue->SpinLock, OldIrql );
+ }
+
+ //
+ // And now return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpAddWaiter -> VOID\n", 0);
+
+ return;
+}
+
+
+VOID
+NpCancelWaiter (
+ IN PWAIT_QUEUE WaitQueue,
+ IN PUNICODE_STRING NameOfPipe
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure cancels all waiters that are waiting for the named
+ pipe to reach the listening state. The corresponding IRPs are completed
+ with STATUS_SUCCESS.
+
+Arguments:
+
+ WaitQueue - Supplies the wait queue being modified
+
+ NameOfPipe - Supplies the name of the named pipe (device relative)
+ that has just reached the listening state.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY Links;
+ PIRP Irp;
+ PFILE_PIPE_WAIT_FOR_BUFFER WaitForBuffer;
+ PWAIT_CONTEXT Context;
+ ULONG i;
+
+ UNICODE_STRING NonPagedNameOfPipe;
+
+ DebugTrace(+1, Dbg, "NpCancelWaiter, WaitQueue = %08lx\n", WaitQueue);
+
+ //
+ // Capture the name of pipe before we grab the spinlock, and upcase it
+ //
+
+ NonPagedNameOfPipe.Buffer = FsRtlAllocatePool( NonPagedPool, NameOfPipe->Length );
+ NonPagedNameOfPipe.Length = 0;
+ NonPagedNameOfPipe.MaximumLength = NameOfPipe->Length;
+
+ (VOID) RtlUpcaseUnicodeString( &NonPagedNameOfPipe, NameOfPipe, FALSE );
+
+ //
+ // Acquire the spinlock
+ //
+
+ KeAcquireSpinLock( &WaitQueue->SpinLock, &OldIrql );
+
+ try {
+
+ //
+ // For each waiting irp check if the name matches
+ //
+
+ for (Links = WaitQueue->Queue.Flink;
+ Links != &WaitQueue->Queue;
+ Links = Links->Flink) {
+
+ Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+ WaitForBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+ Context = (PWAIT_CONTEXT)Irp->IoStatus.Information;
+
+ //
+ // Check if this Irp matches the one we've been waiting for
+ // First check the lengths for equality, and then compare
+ // the strings. They match if we exit the inner loop with
+ // i >= name length.
+ //
+
+ if (((USHORT)(WaitForBuffer->NameLength + sizeof(WCHAR))) == NonPagedNameOfPipe.Length) {
+
+ for (i = 0; i < WaitForBuffer->NameLength/sizeof(WCHAR); i += 1) {
+
+ if (WaitForBuffer->Name[i] != NonPagedNameOfPipe.Buffer[i+1]) {
+
+ break;
+ }
+ }
+
+ if (i >= WaitForBuffer->NameLength/sizeof(WCHAR)) {
+
+ //
+ // We need to complete this irp so we first
+ // stop the timer, dequeue it from the wait queue
+ // (be sure to keep links correct), disable the cancel routine
+ // and then complete the Irp.
+ //
+
+ if (KeCancelTimer( &Context->Timer )) {
+
+ Links = Links->Blink;
+
+ RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
+
+ IoAcquireCancelSpinLock( &Irp->CancelIrql );
+ IoSetCancelRoutine( Irp, NULL );
+ Irp->IoStatus.Information = 0;
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ NpCompleteRequest( Irp, STATUS_SUCCESS );
+
+ ExFreePool( Context );
+ }
+ }
+ }
+ }
+
+ } finally {
+
+ //
+ // Release the spinlock
+ //
+
+ KeReleaseSpinLock( &WaitQueue->SpinLock, OldIrql );
+
+ ExFreePool( NonPagedNameOfPipe.Buffer );
+
+ DebugTrace(-1, Dbg, "NpCancelWaiter -> VOID\n", 0);
+ }
+
+ //
+ // And now return to our caller
+ //
+
+ return;
+}
+
+
+//
+// Local support routine
+//
+
+VOID
+NpTimerDispatch(
+ IN PKDPC Dpc,
+ IN PVOID Contxt,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called whenever a timer on a wait queue Irp goes off
+
+Arguments:
+
+ Dpc - Ignored
+
+ Contxt - Supplies a pointer to the irp whose timer went off
+
+ SystemArgument1 - Ignored
+
+ SystemArgument2 - Ignored
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp = Contxt;
+ KIRQL OldIrql;
+ PLIST_ENTRY Links;
+ PWAIT_CONTEXT Context;
+ PWAIT_QUEUE WaitQueue;
+
+ UNREFERENCED_PARAMETER( Dpc );
+ UNREFERENCED_PARAMETER( SystemArgument1 );
+ UNREFERENCED_PARAMETER( SystemArgument2 );
+
+ Context = (PWAIT_CONTEXT)Irp->IoStatus.Information;
+ WaitQueue = Context->WaitQueue;
+
+ KeAcquireSpinLock( &WaitQueue->SpinLock, &OldIrql );
+
+ try {
+
+ //
+ // Check if the Irp is still in the waiting queue. We need to do
+ // this because we might be in the middle of canceling the entry
+ // when the timer went off.
+ //
+
+ for (Links = WaitQueue->Queue.Flink;
+ Links != &WaitQueue->Queue;
+ Links = Links->Flink) {
+
+ if (Irp == CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry )) {
+
+ //
+ // Remove the IRP, and complete it with a result of timeout
+ //
+
+ RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
+
+ NpCompleteRequest( Irp, STATUS_IO_TIMEOUT );
+
+ //
+ // Deallocate the context
+ //
+
+ ExFreePool( Context );
+
+ //
+ // And exit from the loop because we found our match
+ //
+
+ break;
+ }
+ }
+
+ } finally {
+
+ //
+ // Release the spinlock
+ //
+
+ KeReleaseSpinLock( &WaitQueue->SpinLock, OldIrql );
+ }
+
+ //
+ // And now return to our caller
+ //
+
+ return;
+}
+
+
+//
+// Local Support routine
+//
+
+VOID
+NpCancelWaitQueueIrp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to cancel a wait queue irp
+
+Arguments:
+
+ DeviceObject - Ignored
+
+ Irp - Supplies the Irp being cancelled. The Iosb.Status field in the irp
+ points to the wait queue
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PWAIT_QUEUE WaitQueue;
+ KIRQL OldIrql;
+ PLIST_ENTRY Links;
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+
+ //
+ // The status field is used to store a pointer to the wait queue
+ // containing this irp
+ //
+
+ WaitQueue = (PWAIT_QUEUE)Irp->IoStatus.Status;
+
+ //
+ // We now need to void the cancel routine and release the io cancel spinlock
+ //
+
+ IoSetCancelRoutine( Irp, NULL );
+ IoReleaseCancelSpinLock( Irp->CancelIrql );
+
+ //
+ // Get the spinlock proctecting the wait queue
+ //
+
+ if (DeviceObject != (PVOID)0x1) { KeAcquireSpinLock( &WaitQueue->SpinLock, &OldIrql ); }
+
+ try {
+
+ //
+ // For each waiting irp check if it has been cancelled
+ //
+
+ for (Links = WaitQueue->Queue.Flink;
+ Links != &WaitQueue->Queue;
+ Links = Links->Flink) {
+
+ PIRP LocalIrp;
+ PWAIT_CONTEXT Context;
+
+ LocalIrp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
+ Context = (PWAIT_CONTEXT)LocalIrp->IoStatus.Information;
+
+ if (LocalIrp->Cancel) {
+
+ //
+ // We need to complete this irp so we first
+ // stop the timer, dequeue it from the wait queue
+ // (be sure to keep links correct), and then complete the Irp.
+ //
+
+ if (KeCancelTimer( &Context->Timer )) {
+
+ Links = Links->Blink;
+
+ RemoveEntryList( &LocalIrp->Tail.Overlay.ListEntry );
+
+ LocalIrp->IoStatus.Information = 0;
+
+ NpCompleteRequest( LocalIrp, STATUS_CANCELLED );
+ ExFreePool( Context );
+ }
+ }
+ }
+
+ } finally {
+
+ if (DeviceObject != (PVOID)0x1) { KeReleaseSpinLock( &WaitQueue->SpinLock, OldIrql ); }
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return;
+
+
+
+}
diff --git a/private/ntos/npfs/write.c b/private/ntos/npfs/write.c
new file mode 100644
index 000000000..34356ee02
--- /dev/null
+++ b/private/ntos/npfs/write.c
@@ -0,0 +1,608 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Write.c
+
+Abstract:
+
+ This module implements the File Write routine for NPFS called by the
+ dispatch driver.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Aug-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_WRITE)
+
+#if DBG
+ULONG NpFastWriteTrue = 0;
+ULONG NpFastWriteFalse = 0;
+ULONG NpSlowWriteCalls = 0;
+#endif
+
+//
+// local procedure prototypes
+//
+
+BOOLEAN
+NpCommonWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PVOID WriteBuffer,
+ IN ULONG WriteLength,
+ IN PETHREAD UserThread,
+ OUT PIO_STATUS_BLOCK Iosb,
+ IN PIRP Irp OPTIONAL
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpCommonWrite)
+#pragma alloc_text(PAGE, NpFastWrite)
+#pragma alloc_text(PAGE, NpFsdWrite)
+#endif
+
+
+NTSTATUS
+NpFsdWrite (
+ IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtWriteFile API calls.
+
+Arguments:
+
+ NpfsDeviceObject - Supplies the device object to use.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ IO_STATUS_BLOCK Iosb;
+ PIO_STACK_LOCATION IrpSp;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpFsdWrite\n", 0);
+ DbgDoit( NpSlowWriteCalls += 1 );
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireSharedVcb();
+
+ try {
+
+ (VOID) NpCommonWrite( IrpSp->FileObject,
+ Irp->UserBuffer,
+ IrpSp->Parameters.Write.Length,
+ Irp->Tail.Overlay.Thread,
+ &Iosb,
+ Irp );
+
+ } except(NpExceptionFilter( GetExceptionCode() )) {
+
+ //
+ // We had some trouble trying to perform the requested
+ // operation, so we'll abort the I/O request with
+ // the error status that we get back from the
+ // execption code
+ //
+
+ Iosb.Status = NpProcessException( NpfsDeviceObject, Irp, GetExceptionCode() );
+ }
+
+ NpReleaseVcb();
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NpFsdWrite -> %08lx\n", Iosb.Status );
+
+ return Iosb.Status;
+}
+
+
+BOOLEAN
+NpFastWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN ULONG LockKey,
+ IN PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus,
+ IN PDEVICE_OBJECT DeviceObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a fast write bypassing the usual file system
+ entry routine (i.e., without the Irp).
+
+Arguments:
+
+ FileObject - Pointer to the file object being read.
+
+ FileOffset - Byte offset in file for desired data.
+
+ Length - Length of desired data in bytes.
+
+ Wait - FALSE if caller may not block, TRUE otherwise
+
+ LockKey - Supplies the Key used to use if the byte range being read is locked.
+
+ Buffer - Pointer to output buffer to which data should be copied.
+
+ IoStatus - Pointer to standard I/O status block to receive the status
+ for the transfer.
+
+Return Value:
+
+ BOOLEAN - TRUE if the operation completed successfully and FALSE if the
+ caller needs to take the long IRP based route.
+
+--*/
+
+{
+ BOOLEAN Results = FALSE;
+ UNREFERENCED_PARAMETER( FileOffset );
+ UNREFERENCED_PARAMETER( Wait );
+ UNREFERENCED_PARAMETER( LockKey );
+ UNREFERENCED_PARAMETER( DeviceObject );
+
+ PAGED_CODE();
+
+ FsRtlEnterFileSystem();
+
+ NpAcquireSharedVcb();
+
+ try {
+
+ if (NpCommonWrite( FileObject,
+ Buffer,
+ Length,
+ PsGetCurrentThread(),
+ IoStatus,
+ NULL )) {
+
+ DbgDoit( NpFastWriteTrue += 1 );
+
+ if (IoStatus->Status == STATUS_PENDING) {
+
+ IoStatus->Status = STATUS_SUCCESS;
+ }
+
+ Results = TRUE;
+
+ } else {
+
+ DbgDoit( NpFastWriteFalse += 1 );
+ }
+
+ } except( FsRtlIsNtstatusExpected(GetExceptionCode())
+ ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH ) {
+
+ NOTHING;
+ }
+
+ NpReleaseVcb();
+ FsRtlExitFileSystem();
+ return Results;
+}
+
+
+//
+// Internal support routine
+//
+
+BOOLEAN
+NpCommonWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PVOID WriteBuffer,
+ IN ULONG WriteLength,
+ IN PETHREAD UserThread,
+ OUT PIO_STATUS_BLOCK Iosb,
+ IN PIRP Irp OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for writing data to a named pipe both via the
+ fast path and with an Irp.
+
+Arguments:
+
+ FileObject - Supplies the file object used in this operation
+
+ WriteBuffer - Supplies the buffer where data from which data is to be read
+
+ WriteLength - Supplies the length of the write buffer in bytes
+
+ UserThread - Supplies the thread id of the caller
+
+ Iosb - Receives the final completion status of this operation
+
+ Irp - Optionally supplies an Irp to be used in this operation
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ NODE_TYPE_CODE NodeTypeCode;
+ PCCB Ccb;
+ PNONPAGED_CCB NonpagedCcb;
+ NAMED_PIPE_END NamedPipeEnd;
+
+ NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
+
+ ULONG WriteRemaining;
+ PDATA_QUEUE WriteQueue;
+
+ PEVENT_TABLE_ENTRY Event;
+ READ_MODE ReadMode;
+ BOOLEAN Status;
+
+ PDATA_ENTRY DataEntry;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpCommonWrite\n", 0);
+ DebugTrace( 0, Dbg, "FileObject = %08lx\n", FileObject);
+ DebugTrace( 0, Dbg, "WriteBuffer = %08lx\n", WriteBuffer);
+ DebugTrace( 0, Dbg, "WriteLength = %08lx\n", WriteLength);
+ DebugTrace( 0, Dbg, "UserThread = %08lx\n", UserThread);
+ DebugTrace( 0, Dbg, "Iosb = %08lx\n", Iosb);
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
+
+ Iosb->Information = 0;
+ if (ARGUMENT_PRESENT(Irp)) { Irp->IoStatus.Information = 0; }
+
+ //
+ // Get the Ccb and figure out who we are, and make sure we're not
+ // disconnected
+ //
+
+ if ((NodeTypeCode = NpDecodeFileObject( FileObject,
+ NULL,
+ &Ccb,
+ &NamedPipeEnd )) == NTC_UNDEFINED) {
+
+ DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
+
+ Iosb->Status = STATUS_PIPE_DISCONNECTED;
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED ); }
+
+ return TRUE;
+ }
+
+ //
+ // Now we only will allow write operations on the pipe and not a directory
+ // or the device
+ //
+
+ if (NodeTypeCode != NPFS_NTC_CCB) {
+
+ DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
+
+ Iosb->Status = STATUS_INVALID_PARAMETER;
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); }
+
+ return TRUE;
+ }
+
+ NpAcquireExclusiveCcb(Ccb);
+
+ NonpagedCcb = Ccb->NonpagedCcb;
+
+ try {
+ //
+ // Check if the pipe is not in the connected state.
+ //
+
+ if ((Ccb->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) ||
+ (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) ||
+ (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE)) {
+
+ DebugTrace(0, Dbg, "Pipe in disconnected or listening or closing state\n", 0);
+
+ if (Ccb->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) {
+
+ Iosb->Status = STATUS_PIPE_DISCONNECTED;
+
+ } else if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) {
+
+ Iosb->Status = STATUS_PIPE_LISTENING;
+
+ } else {
+
+ Iosb->Status = STATUS_PIPE_CLOSING;
+ }
+
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, Iosb->Status ); }
+
+ try_return(Status = TRUE);
+ }
+
+ ASSERT(Ccb->NamedPipeState == FILE_PIPE_CONNECTED_STATE);
+
+ //
+ // We only allow a write by the server on a non inbound only pipe
+ // and by the client on a non outbound only pipe
+ //
+
+ NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
+
+ if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
+ (NamedPipeConfiguration == FILE_PIPE_INBOUND))
+
+ ||
+
+ ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
+ (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))) {
+
+ DebugTrace(0, Dbg, "Trying to write to the wrong pipe configuration\n", 0);
+
+ Iosb->Status = STATUS_INVALID_PARAMETER;
+ if (ARGUMENT_PRESENT(Irp)) { NpCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); }
+
+ try_return(Status = TRUE);
+ }
+
+ //
+ // Set up the amount of data we will have written by the time this
+ // operation gets completed and indicate success until we set it otherwise.
+ //
+
+ Iosb->Status = STATUS_SUCCESS;
+ Iosb->Information = WriteLength;
+ if (ARGUMENT_PRESENT(Irp)) { Irp->IoStatus.Information = WriteLength; }
+
+ //
+ // Now the data queue that we write into and the event that we signal
+ // are based on the named pipe end. The server writes to the outbound
+ // queue and signals the client event. The client does just the
+ // opposite. We also need to figure out the read mode for the opposite
+ // end of the pipe.
+ //
+
+ if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
+
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
+ ReadMode = Ccb->ReadMode[ FILE_PIPE_CLIENT_END ];
+
+ } else {
+
+ WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
+
+ Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
+ ReadMode = Ccb->ReadMode[ FILE_PIPE_SERVER_END ];
+ }
+
+ //
+ // The next section checks if we should continue with the write operation.
+ // The reasons why we will not continue are if we recongnize that the
+ // pipe quota will not support this write and it is a message mode type
+ // with complete operations. We will also bail out now if the quota will
+ // not support the write and this is a fast I/O write request.
+ //
+ // If the pipe contains readers and amount to read plus pipe quota is less
+ // than the write length then we need to do some additional checks.
+ // Or if pipe does not contain reads and the amount of quota left is less
+ // than the write length then we need to do some additional checks.
+ //
+
+ if ((NpIsDataQueueReaders( WriteQueue ) &&
+ (WriteQueue->BytesInQueue < WriteLength) &&
+ (WriteQueue->Quota < (WriteLength + sizeof(DATA_ENTRY))))
+
+ ||
+
+ (!NpIsDataQueueReaders( WriteQueue ) &&
+ ((WriteQueue->Quota - WriteQueue->QuotaUsed) < (WriteLength + sizeof(DATA_ENTRY))))) {
+
+ DebugTrace(0, Dbg, "Quota is not sufficient for the request\n", 0);
+
+ //
+ // If this is a message mode pipe with complete operations then we
+ // complete without writing the message
+ //
+
+ if ((Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) &&
+ (Ccb->CompletionMode[NamedPipeEnd] == FILE_PIPE_COMPLETE_OPERATION)) {
+
+ Iosb->Information = 0;
+ if (ARGUMENT_PRESENT(Irp)) { Irp->IoStatus = *Iosb; NpCompleteRequest( Irp, STATUS_SUCCESS ); }
+
+ try_return(Status = TRUE);
+ }
+
+ //
+ // If this is a fast I/O pipe then we tell the call to take the long
+ // Irp based route
+ //
+
+ if (!ARGUMENT_PRESENT(Irp)) {
+
+ DebugTrace(0, Dbg, "Need to supply Irp\n", 0);
+
+ try_return(Status = FALSE);
+ }
+ }
+
+ //
+ // Now we'll call our common write data queue routine to
+ // transfer data out of our write buffer into the data queue.
+ // If the result of the call is FALSE then we still have some
+ // write data to put into the write queue.
+ //
+
+ if (!NpWriteDataQueue( WriteQueue,
+ ReadMode,
+ WriteBuffer,
+ WriteLength,
+ Ccb->Fcb->Specific.Fcb.NamedPipeType,
+ &WriteRemaining,
+ Ccb,
+ NamedPipeEnd,
+ UserThread )) {
+
+ ASSERT( !NpIsDataQueueReaders( WriteQueue ));
+
+ ASSERT((Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_BYTE_STREAM_TYPE) ||
+ (Ccb->CompletionMode[NamedPipeEnd] == FILE_PIPE_QUEUE_OPERATION) ||
+ (WriteRemaining <= (WriteQueue->Quota - WriteQueue->QuotaUsed)));
+
+ //
+ // Check if the operation is not to block and if so then we
+ // will complete the operation now with what we're written, if what is
+ // left will not fit in the quota for the file
+ //
+
+ if ((Ccb->CompletionMode[NamedPipeEnd] == FILE_PIPE_COMPLETE_OPERATION) &&
+ ((WriteQueue->Quota - WriteQueue->QuotaUsed) < (sizeof(DATA_ENTRY) + WriteLength))) {
+
+ DebugTrace(0, Dbg, "Complete the byte stream write immediately\n", 0);
+
+ Iosb->Information = WriteLength - WriteRemaining;
+ if (ARGUMENT_PRESENT(Irp)) { Irp->IoStatus = *Iosb; NpCompleteRequest( Irp, STATUS_SUCCESS ); }
+
+ } else {
+
+ DebugTrace(0, Dbg, "Add write to data queue\n", 0);
+
+ //
+ // Add this write request to the write queue
+ //
+
+ ASSERT( !NpIsDataQueueReaders( WriteQueue ));
+
+ if (ARGUMENT_PRESENT(Irp)) {
+
+ IoMarkIrpPending( Irp );
+
+ try {
+
+ DataEntry = NpAddDataQueueEntry( WriteQueue,
+ WriteEntries,
+ Buffered,
+ WriteLength,
+ Irp,
+ WriteBuffer );
+
+ } finally {
+
+ if (AbnormalTermination()) {
+
+ IoGetCurrentIrpStackLocation((Irp))->Control &= ~SL_PENDING_RETURNED;
+ }
+ }
+
+ } else {
+
+ DataEntry = NpAddDataQueueEntry( WriteQueue,
+ WriteEntries,
+ Buffered,
+ WriteLength,
+ Irp,
+ WriteBuffer );
+ }
+
+ //
+ // And set the security part of the data entry
+ //
+
+ NpSetDataEntryClientContext( NamedPipeEnd,
+ Ccb,
+ DataEntry,
+ UserThread );
+
+ //
+ // Now if the remaining length is not equal to the original
+ // write length then this must have been the first write entry
+ // into the data queue and we need to set the Next Byte
+ // field
+ //
+
+ if (WriteLength > WriteRemaining) {
+
+ WriteQueue->NextByteOffset = WriteLength - WriteRemaining;
+ }
+
+ //
+ // Set our status for the write irp to pending
+ //
+
+ Iosb->Status = STATUS_PENDING;
+ }
+
+ } else {
+
+ DebugTrace(0, Dbg, "Complete the Write Irp\n", 0);
+
+ //
+ // The write irp is finished so we can complete it now
+ //
+
+ if (ARGUMENT_PRESENT(Irp)) { Irp->IoStatus = *Iosb; NpCompleteRequest( Irp, STATUS_SUCCESS ); }
+ }
+
+ //
+ // Now we need to advance the write queue to the next read irp to
+ // skip over flushes and closes
+ //
+
+ //****NpWriteDataQueue does this for us**** (VOID)NpGetNextRealDataQueueEntry( WriteQueue );
+
+ //
+ // And because we've done something we need to signal the
+ // other ends event
+ //
+
+ NpSignalEventTableEntry( Event );
+
+ Status = TRUE;
+
+ try_exit: NOTHING;
+ } finally {
+ NpReleaseCcb(Ccb);
+ }
+
+
+ DebugTrace(-1, Dbg, "NpCommonWrite -> TRUE\n", 0);
+ return Status;
+}
diff --git a/private/ntos/npfs/writesup.c b/private/ntos/npfs/writesup.c
new file mode 100644
index 000000000..5272b53fd
--- /dev/null
+++ b/private/ntos/npfs/writesup.c
@@ -0,0 +1,329 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ WriteSup.c
+
+Abstract:
+
+ This module implements the Write support routine. This is a common
+ write function that is called by write, unbuffered write, and transceive.
+
+Author:
+
+ Gary Kimura [GaryKi] 21-Sep-1990
+
+Revision History:
+
+--*/
+
+#include "NpProcs.h"
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_WRITESUP)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NpWriteDataQueue)
+#endif
+
+
+BOOLEAN
+NpWriteDataQueue (
+ IN PDATA_QUEUE WriteQueue,
+ IN READ_MODE ReadMode,
+ IN PUCHAR WriteBuffer,
+ IN ULONG WriteLength,
+ IN NAMED_PIPE_TYPE PipeType,
+ OUT PULONG WriteRemaining,
+ IN PCCB Ccb,
+ IN NAMED_PIPE_END NamedPipeEnd,
+ IN PETHREAD UserThread
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure writes data from the write buffer into read entries in
+ the write queue. It will also dequeue entries in the queue as necessary.
+
+Arguments:
+
+ WriteQueue - Provides the write queue to process.
+
+ ReadMode - Supplies the read mode of read entries in the write queue.
+
+ WriteBuffer - Provides the buffer from which to read the data.
+
+ WriteLength - Provides the length, in bytes, of WriteBuffer.
+
+ PipeType - Indicates if type of pipe (i.e., message or byte stream).
+
+ WriteRemaining - Receives the number of bytes remaining to be transfered
+ that were not completed by this call. If the operation wrote
+ everything then is value is set to zero.
+
+ Ccb - Supplies the ccb for the operation
+
+ NamedPipeEnd - Supplies the end of the pipe doing the write
+
+ UserThread - Supplies the user thread
+
+Return Value:
+
+ BOOLEAN - TRUE if the operation wrote everything and FALSE otherwise.
+ Note that a zero byte message that hasn't been written will return
+ a function result of FALSE and WriteRemaining of zero.
+
+--*/
+
+{
+ BOOLEAN Result;
+
+ BOOLEAN WriteZeroMessage;
+
+ PDATA_ENTRY DataEntry;
+
+ PUCHAR ReadBuffer;
+ ULONG ReadLength;
+ ULONG ReadRemaining;
+
+ ULONG AmountToCopy;
+
+ PIRP ReadIrp;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "NpWriteDataQueue\n", 0);
+ DebugTrace( 0, Dbg, "WriteQueue = %08lx\n", WriteQueue);
+ DebugTrace( 0, Dbg, "WriteBuffer = %08lx\n", WriteBuffer);
+ DebugTrace( 0, Dbg, "WriteLength = %08lx\n", WriteLength);
+ DebugTrace( 0, Dbg, "PipeType = %08lx\n", PipeType);
+ DebugTrace( 0, Dbg, "Ccb = %08lx\n", Ccb);
+ DebugTrace( 0, Dbg, "NamedPipeEnd = %08lx\n", NamedPipeEnd);
+ DebugTrace( 0, Dbg, "UserThread = %08lx\n", UserThread);
+
+ //
+ // Determine if we are to write a zero byte message, and initialize
+ // WriteRemaining
+ //
+
+ *WriteRemaining = WriteLength;
+
+ if ((PipeType == FILE_PIPE_MESSAGE_TYPE) && (WriteLength == 0)) {
+
+ WriteZeroMessage = TRUE;
+
+ } else {
+
+ WriteZeroMessage = FALSE;
+ }
+
+ //
+ // Now while the write queue has some read entries in it and
+ // there is some remaining write data or this is a write zero message
+ // then we'll do the following main loop
+ //
+
+ for (DataEntry = NpGetNextRealDataQueueEntry( WriteQueue );
+
+ (NpIsDataQueueReaders(WriteQueue) &&
+ ((*WriteRemaining > 0) || WriteZeroMessage));
+
+ DataEntry = NpGetNextRealDataQueueEntry( WriteQueue )) {
+
+ ReadBuffer = DataEntry->DataPointer;
+ ReadLength = DataEntry->DataSize;
+ ReadRemaining = ReadLength - WriteQueue->NextByteOffset;
+
+ DebugTrace(0, Dbg, "Top of main loop...\n", 0);
+ DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
+ DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
+ DebugTrace(0, Dbg, "ReadRemaining = %08lx\n", ReadRemaining);
+ DebugTrace(0, Dbg, "*WriteRemaining = %08lx\n", *WriteRemaining);
+
+ //
+ // Check if this is a ReadOverflow Operation and if so then also check
+ // that the read will succeed otherwise complete this read with
+ // buffer overflow and continue on.
+ //
+
+ {
+ PIO_STACK_LOCATION IrpSp;
+
+ IrpSp = IoGetCurrentIrpStackLocation( DataEntry->Irp );
+
+ if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_PIPE_INTERNAL_READ_OVFLOW) {
+
+ if ((ReadLength < WriteLength) || WriteZeroMessage) {
+
+ ReadIrp = NpRemoveDataQueueEntry( WriteQueue );
+ NpCompleteRequest( ReadIrp, STATUS_BUFFER_OVERFLOW );
+ continue;
+ }
+ }
+ }
+
+ //
+ // copy data from the write buffer at write offset to the
+ // read buffer at read offset by the mininum of write remaining
+ // or read remaining
+ //
+
+ AmountToCopy = (*WriteRemaining < ReadRemaining ? *WriteRemaining
+ : ReadRemaining);
+
+ try {
+
+ RtlCopyMemory( &ReadBuffer[ ReadLength - ReadRemaining ],
+ &WriteBuffer[ WriteLength - *WriteRemaining ],
+ AmountToCopy );
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
+ }
+
+ //
+ // Update the Read and Write remaining counts
+ //
+
+ ReadRemaining -= AmountToCopy;
+ *WriteRemaining -= AmountToCopy;
+
+ //
+ // Now update the security fields in the nonpaged ccb, we'll
+ // just use the two routines supplied in the security support
+ // routines
+ //
+
+ if ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
+ (Ccb->SecurityQos.ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)) {
+
+ NTSTATUS Status;
+
+ if (!NT_SUCCESS( Status = NpSetDataEntryClientContext( NamedPipeEnd,
+ Ccb,
+ DataEntry,
+ UserThread ))) {
+
+ ExRaiseStatus( Status );
+ }
+
+ NpCopyClientContext( Ccb, DataEntry );
+
+ } else {
+
+ DataEntry->SecurityClientContext = NULL;
+ }
+
+ //
+ // Now we've done with the read entry so remove it from the
+ // write queue, get its irp, and fill in the information field
+ // to be the bytes that we've transferred into the read buffer.
+ //
+
+ ReadIrp = NpRemoveDataQueueEntry( WriteQueue );
+
+ ASSERT( ReadIrp != NULL );
+
+ ReadIrp->IoStatus.Information = ReadLength - ReadRemaining;
+
+ //
+ // Now we need to check if this is an internal (unbuffered) read
+ // operation and if so then we need to also update the allocation
+ // size stored in the Irp to be the bytes remaining in the write
+ // queue. We can decide if this is an internal operation by
+ // checking where the data entry would have been kept in the Irp.
+ // RemoveDataQueueEntry makes sure this field is set properly on its
+ // return.
+ //
+
+ {
+ PDATA_ENTRY DataEntry;
+
+ DataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( ReadIrp );
+
+ if (DataEntry->DataEntryType == Unbuffered) {
+
+ ReadIrp->Overlay.AllocationSize.QuadPart = WriteQueue->BytesInQueue;
+ }
+ }
+
+ //
+ // Now if the write remaining is zero then we've completed
+ // both the write and read successfully. We'll complete the
+ // read irp at this time, and set write zero message to false
+ // to guarantee that we'll complete the write irp in the
+ // following if-statement after this main loop.
+ //
+
+ if (*WriteRemaining == 0) {
+
+ DebugTrace(0, Dbg, "Finished up the write remaining\n", 0);
+
+ //**** ASSERT( ReadIrp->IoStatus.Information != 0 );
+
+ NpCompleteRequest( ReadIrp, STATUS_SUCCESS );
+
+ WriteZeroMessage = FALSE;
+
+ } else {
+
+ //
+ // There is still some space in the write buffer to be
+ // written out, but before we can handle that (in the
+ // following if statement) we need to finish the read.
+ // If the read is message mode then we've overflowed the
+ // buffer otherwise we completed successfully
+ //
+
+ if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
+
+ DebugTrace(0, Dbg, "Read buffer Overflow\n", 0);
+
+ NpCompleteRequest( ReadIrp, STATUS_BUFFER_OVERFLOW );
+
+ } else {
+
+ DebugTrace(0, Dbg, "Read buffer byte stream done\n", 0);
+
+ //**** ASSERT( ReadIrp->IoStatus.Information != 0 );
+
+ NpCompleteRequest( ReadIrp, STATUS_SUCCESS );
+ }
+ }
+ }
+
+ DebugTrace(0, Dbg, "Finished loop...\n", 0);
+ DebugTrace(0, Dbg, "*WriteRemaining = %08lx\n", *WriteRemaining);
+ DebugTrace(0, Dbg, "WriteZeroMessage = %08lx\n", WriteZeroMessage);
+
+ //
+ // At this point we've finished off all of the read entries in the
+ // queue and we might still have something left to write. If that
+ // is the case then we'll set our result to FALSE otherwise we're
+ // done so we'll return TRUE.
+ //
+
+ if ((*WriteRemaining > 0) || (WriteZeroMessage)) {
+
+ ASSERT( !NpIsDataQueueReaders( WriteQueue ));
+
+ Result = FALSE;
+
+ } else {
+
+
+ Result = TRUE;
+ }
+
+ DebugTrace(-1, Dbg, "NpWriteDataQueue -> %08lx\n", Result);
+ return Result;
+}
+