summaryrefslogtreecommitdiffstats
path: root/private/nw/rdr/create.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/rdr/create.c')
-rw-r--r--private/nw/rdr/create.c3398
1 files changed, 3398 insertions, 0 deletions
diff --git a/private/nw/rdr/create.c b/private/nw/rdr/create.c
new file mode 100644
index 000000000..e50c9ad68
--- /dev/null
+++ b/private/nw/rdr/create.c
@@ -0,0 +1,3398 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ Create.c
+
+Abstract:
+
+ This module implements the File Create routine for the NetWare
+ redirector called by the dispatch driver.
+
+Author:
+
+ Colin Watson [ColinW] 19-Dec-1992
+ Manny Weiser [MannyW] 15-Feb-1993
+
+Revision History:
+
+--*/
+
+#include "Procs.h"
+
+NTSTATUS
+NwCommonCreate (
+ IN PIRP_CONTEXT IrpContext
+ );
+
+IO_STATUS_BLOCK
+OpenRedirector(
+ IN PIRP_CONTEXT IrpContext,
+ ULONG DesiredAccess,
+ ULONG ShareAccess,
+ PFILE_OBJECT FileObject
+ );
+
+IO_STATUS_BLOCK
+CreateRemoteFile(
+ IN PIRP_CONTEXT IrpContext,
+ IN PUNICODE_STRING DriveName
+ );
+
+IO_STATUS_BLOCK
+ChangeDirectory(
+ PIRP_CONTEXT IrpContext,
+ PVCB Vcb,
+ PICB Icb
+ );
+
+IO_STATUS_BLOCK
+CreateDir(
+ PIRP_CONTEXT IrpContext,
+ PVCB Vcb,
+ PICB Icb
+ );
+
+NTSTATUS
+FileOrDirectoryExists(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PICB Icb,
+ PUNICODE_STRING Name,
+ OUT PBOOLEAN IsAFile
+ );
+
+IO_STATUS_BLOCK
+OpenFile(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PICB Icb,
+ IN BYTE SearchFlags,
+ IN BYTE ShareFlags
+ );
+
+IO_STATUS_BLOCK
+CreateNewFile(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PICB Icb,
+ IN BYTE SearchFlags,
+ IN BYTE ShareFlags
+ );
+
+IO_STATUS_BLOCK
+CreateOrOverwriteFile(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PICB Icb,
+ IN BYTE CreateAttributes,
+ IN BYTE OpenFlags,
+ IN BOOLEAN CreateOperation
+ );
+
+IO_STATUS_BLOCK
+OpenRenameTarget(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PDCB Dcb,
+ IN PICB* Icb
+ );
+
+IO_STATUS_BLOCK
+CreatePrintJob(
+ PIRP_CONTEXT IrpContext,
+ PVCB Vcb,
+ PICB Icb,
+ PUNICODE_STRING DriveName
+ );
+
+VOID
+CloseFile(
+ PIRP_CONTEXT pIrpContext,
+ PICB pIcb
+ );
+
+
+// BUGBUG HACK HACK
+
+BOOLEAN
+MmDisableModifiedWriteOfSection (
+ IN PSECTION_OBJECT_POINTERS SectionObjectPointer
+ );
+
+//
+// The debug trace level
+//
+
+#define Dbg (DEBUG_TRACE_CREATE)
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, NwFsdCreate )
+#pragma alloc_text( PAGE, NwCommonCreate )
+#pragma alloc_text( PAGE, ReadAttachEas )
+#pragma alloc_text( PAGE, OpenRedirector )
+#pragma alloc_text( PAGE, CreateRemoteFile )
+#pragma alloc_text( PAGE, ChangeDirectory )
+#pragma alloc_text( PAGE, CreateDir )
+#pragma alloc_text( PAGE, FileOrDirectoryExists )
+#pragma alloc_text( PAGE, OpenFile )
+#pragma alloc_text( PAGE, CreateNewFile )
+#pragma alloc_text( PAGE, CreateOrOverwriteFile )
+#pragma alloc_text( PAGE, OpenRenameTarget )
+#pragma alloc_text( PAGE, CreatePrintJob )
+#pragma alloc_text( PAGE, CloseFile )
+#endif
+
+
+NTSTATUS
+NwFsdCreate (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the FSD part of the NtCreateFile and NtOpenFile
+ API calls.
+
+Arguments:
+
+ DeviceObject - Supplies the device object for the redirector.
+
+ Irp - Supplies the Irp being processed
+
+Return Value:
+
+ NTSTATUS - The Fsd status for the Irp
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIRP_CONTEXT IrpContext = NULL;
+ BOOLEAN TopLevel;
+
+ PAGED_CODE();
+
+ TimerStart(Dbg);
+ DebugTrace(+1, Dbg, "NwFsdCreate\n", 0);
+
+ //
+ // Call the common create routine, with block allowed if the operation
+ // is synchronous.
+ //
+
+ FsRtlEnterFileSystem();
+ TopLevel = NwIsIrpTopLevel( Irp );
+
+ try {
+
+ IrpContext = AllocateIrpContext( Irp );
+ Status = NwCommonCreate( IrpContext );
+
+ } except( NwExceptionFilter( Irp, GetExceptionInformation() )) {
+
+ if ( IrpContext == NULL ) {
+
+ //
+ // If we couldn't allocate an irp context, just complete
+ // irp without any fanfare.
+ //
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
+
+ } else {
+
+ //
+ // 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 = NwProcessException( IrpContext, GetExceptionCode() );
+ }
+ }
+
+ if ( IrpContext ) {
+ NwDequeueIrpContext( IrpContext, FALSE );
+ NwCompleteRequest( IrpContext, Status );
+ }
+
+ if ( TopLevel ) {
+ NwSetTopLevelIrp( NULL );
+ }
+ FsRtlExitFileSystem();
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "NwFsdCreate -> %08lx\n", Status );
+
+ TimerStop(Dbg,"NwFsdCreate");
+
+ return Status;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+}
+
+
+NTSTATUS
+NwCommonCreate (
+ IN PIRP_CONTEXT IrpContext
+ )
+
+/*++
+
+Routine Description:
+
+ This is the common routine for creating/opening a file called by
+ both the fsd and fsp threads.
+
+Arguments:
+
+ IrpContext - Supplies the context information for the IRP to process
+
+Return Value:
+
+ NTSTATUS - the return status for the operation
+
+--*/
+
+{
+ IO_STATUS_BLOCK Iosb;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ PFILE_OBJECT FileObject;
+ ACCESS_MASK DesiredAccess;
+ USHORT ShareAccess;
+ ULONG Options;
+ BOOLEAN CreateTreeConnection;
+ BOOLEAN DeleteOnClose;
+ BOOLEAN DeferredLogon;
+ BOOLEAN DereferenceCodeSection = FALSE;
+ BOOLEAN OpenedTreeHandle = FALSE;
+
+ UNICODE_STRING CreateFileName;
+ UNICODE_STRING Drive;
+ UNICODE_STRING Server;
+ UNICODE_STRING Volume;
+ UNICODE_STRING Path;
+ UNICODE_STRING FileName;
+ UNICODE_STRING UserName, Password;
+ ULONG ShareType;
+ WCHAR DriveLetter;
+ DWORD dwExtendedCreate = FALSE;
+
+ PSCB Scb = NULL;
+ PICB Icb;
+ UNICODE_STRING DefaultServer;
+
+ PAGED_CODE();
+
+ //
+ // Get the current IRP stack location
+ //
+
+ Irp = IrpContext->pOriginalIrp;
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DebugTrace(+1, Dbg, "NwCommonCreate\n", 0 );
+ DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
+ DebugTrace( 0, Dbg, "->Flags = %08lx\n", Irp->Flags );
+ DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject );
+ DebugTrace( 0, Dbg, " ->RelatedFileObject = %08lx\n", IrpSp->FileObject->RelatedFileObject );
+ DebugTrace( 0, Dbg, " ->FileName = \"%wZ\"\n", &IrpSp->FileObject->FileName );
+ DebugTrace( 0, Dbg, "->AllocationSize.LowPart = %08lx\n", Irp->Overlay.AllocationSize.LowPart );
+ DebugTrace( 0, Dbg, "->AllocationSize.HighPart = %08lx\n", Irp->Overlay.AllocationSize.HighPart );
+ DebugTrace( 0, Dbg, "->SystemBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer );
+ DebugTrace( 0, Dbg, "->IrpSp->Flags = %08lx\n", IrpSp->Flags );
+ DebugTrace( 0, Dbg, "->DesiredAccess = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
+ DebugTrace( 0, Dbg, "->Options = %08lx\n", IrpSp->Parameters.Create.Options );
+ DebugTrace( 0, Dbg, "->Disposition = %08lx\n", (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff);
+ DebugTrace( 0, Dbg, "->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes );
+ DebugTrace( 0, Dbg, "->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess );
+ DebugTrace( 0, Dbg, "->EaLength = %08lx\n", IrpSp->Parameters.Create.EaLength );
+
+ CreateFileName = IrpSp->FileObject->FileName;
+ Options = IrpSp->Parameters.Create.Options;
+ DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
+ ShareAccess = IrpSp->Parameters.Create.ShareAccess;
+
+ CreateTreeConnection = BooleanFlagOn( Options, FILE_CREATE_TREE_CONNECTION );
+ DeleteOnClose = BooleanFlagOn( Options, FILE_DELETE_ON_CLOSE );
+
+ DefaultServer.Buffer = NULL;
+
+ //
+ // Make sure the input large integer is valid
+ //
+
+ if (Irp->Overlay.AllocationSize.HighPart != 0) {
+
+ DebugTrace(-1, Dbg, "NwCommonCreate -> STATUS_INVALID_PARAMETER\n", 0);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Fail requests that don't have the proper impersonation level.
+ //
+
+ if ( IrpSp->Parameters.Create.SecurityContext ) {
+
+ if ( IrpSp->Parameters.Create.SecurityContext->SecurityQos ) {
+
+ if ( IrpSp->Parameters.Create.SecurityContext->SecurityQos->ImpersonationLevel <
+ SecurityImpersonation ) {
+
+ DebugTrace(-1, Dbg, "NwCommonCreate -> Insufficient impersation level.\n", 0);
+ return STATUS_ACCESS_DENIED;
+ }
+ }
+ }
+
+ Iosb.Status = STATUS_SUCCESS;
+
+ FileObject = IrpSp->FileObject;
+ IrpContext->pNpScb = NULL;
+ IrpContext->Specific.Create.UserUid =
+ GetUid(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+
+ try {
+
+ if ( IrpSp->FileObject->RelatedFileObject != NULL ) {
+
+ //
+ // If we open a handle then the DereferenceCodeSection flag
+ // will be set to false. The dereference will eventually
+ // happen when the file is closed.
+ //
+
+ NwReferenceUnlockableCodeSection();
+ DereferenceCodeSection = TRUE;
+
+ //
+ // Record the relative file name for this open.
+ //
+
+ IrpContext->Specific.Create.FullPathName = CreateFileName;
+
+ Iosb = CreateRemoteFile( IrpContext, NULL );
+
+ //
+ // If we succeeded, we want to keep the code section
+ // referenced because we have opened a handle.
+ //
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ DereferenceCodeSection = FALSE;
+ }
+
+ try_return( Iosb.Status );
+ }
+
+ Iosb.Status = CrackPath (
+ &CreateFileName,
+ &Drive,
+ &DriveLetter,
+ &Server,
+ &Volume,
+ &Path,
+ &FileName,
+ NULL );
+
+ if ( !NT_SUCCESS(Iosb.Status)) {
+ try_return(Iosb.Status);
+ }
+
+ //
+ // Remember this good info.
+ //
+
+ IrpContext->Specific.Create.VolumeName = Volume;
+ IrpContext->Specific.Create.PathName = Path;
+ IrpContext->Specific.Create.DriveLetter = DriveLetter;
+ IrpContext->Specific.Create.FileName = FileName;
+ IrpContext->Specific.Create.FullPathName = CreateFileName;
+
+ RtlInitUnicodeString( &IrpContext->Specific.Create.UidConnectName, NULL );
+
+ //
+ // For now assume default username and password
+ //
+
+ ShareType = RESOURCETYPE_ANY;
+ RtlInitUnicodeString( &UserName, NULL );
+ RtlInitUnicodeString( &Password, NULL );
+
+ if ( Server.Length == 0) {
+
+ //
+ // Opened the redirector itself
+ //
+
+ Iosb = OpenRedirector(
+ IrpContext,
+ DesiredAccess,
+ ShareAccess,
+ FileObject );
+
+ } else if ( Server.Length == Volume.Length - sizeof( WCHAR ) ) {
+
+ if (IpxHandle == 0 ) {
+
+ //
+ // We're not bound to the transport and the user is not
+ // opening the redirector to tell us to bind so return failed.
+ //
+
+ try_return( Iosb.Status = STATUS_REDIRECTOR_NOT_STARTED );
+ }
+
+ NwReferenceUnlockableCodeSection();
+ DereferenceCodeSection = TRUE;
+
+ //
+ // If the only requested access is FILE_LIST_DIRECTORY,
+ // defer the logon. This will allow all CreateScb to
+ // succeed with when the user or password is invalid, so
+ // that the user can see volumes, or enumerate servers
+ // on the server.
+ //
+
+ if ( (DesiredAccess & ~( FILE_LIST_DIRECTORY | SYNCHRONIZE ) ) == 0 ) {
+ DeferredLogon = TRUE;
+ } else {
+ DeferredLogon = FALSE;
+ }
+
+ //
+ // Server = "Server", Volume = "\Server"
+ //
+
+ if ( Server.Length == sizeof(WCHAR) && Server.Buffer[0] == L'*') {
+
+ //
+ // Attempt to open \\*, open a handle to the preferred
+ // server
+ //
+
+ PLOGON Logon;
+
+ NwAcquireExclusiveRcb( &NwRcb, TRUE );
+
+ Logon = FindUser( &IrpContext->Specific.Create.UserUid, FALSE);
+ ASSERT( Logon != NULL );
+
+ //
+ // Capture the name to avoid holding Rcb or referencing
+ // the logon structure.
+ //
+
+ Iosb.Status = DuplicateUnicodeStringWithString (
+ &DefaultServer,
+ &Logon->ServerName,
+ PagedPool);
+
+ NwReleaseRcb( &NwRcb );
+
+ if (!NT_SUCCESS(Iosb.Status)) {
+ try_return( Iosb.Status );
+ }
+
+ //
+ // If the user specified a preferred server and we managed
+ // to capture the name, try and connect to it.
+ //
+
+ if (DefaultServer.Length != 0) {
+
+ Iosb.Status = CreateScb(
+ &Scb,
+ IrpContext,
+ &DefaultServer,
+ NULL,
+ NULL,
+ NULL,
+ DeferredLogon,
+ FALSE );
+
+ } else {
+
+ //
+ // Record that we could not get to the server specified
+ // in the login structure and that we should attempt to
+ // use the nearest server.
+ //
+
+ Iosb.Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ if ( !NT_SUCCESS(Iosb.Status)) {
+
+ PNONPAGED_SCB NpScb;
+
+ //
+ // First dequeue the IRP context, in case it was left
+ // on an SCB queue.
+ //
+
+ NwDequeueIrpContext( IrpContext, FALSE );
+
+ //
+ // Cannot get to the Preferred server so use any
+ // server we have a connection to.
+ //
+
+
+ NpScb = SelectConnection( NULL );
+
+ if (NpScb != NULL ) {
+
+ Scb = NpScb->pScb;
+
+ Iosb.Status = CreateScb(
+ &Scb,
+ IrpContext,
+ &NpScb->ServerName,
+ NULL,
+ NULL,
+ NULL,
+ DeferredLogon,
+ FALSE );
+
+ //
+ // Release the SCB reference we obtained from
+ // SelectConnection().
+ //
+
+ NwDereferenceScb( NpScb );
+ }
+ }
+
+ if ( !NT_SUCCESS(Iosb.Status)) {
+
+ //
+ // First dequeue the IRP context, in case it was left
+ // on an SCB queue.
+ //
+
+ NwDequeueIrpContext( IrpContext, FALSE );
+
+ //
+ // Let CreateScb try and find a nearest server to talk
+ // to.
+ //
+
+ Iosb.Status = CreateScb(
+ &Scb,
+ IrpContext,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ DeferredLogon,
+ FALSE );
+ }
+
+ if ( !NT_SUCCESS(Iosb.Status)) {
+ try_return( Iosb.Status );
+ }
+
+ } else {
+
+ //
+ // On handle opens to a server or tree we support the concept
+ // of an open with supplemental credentials. In this case, we return
+ // a handle to the server or a dir server using the provided
+ // credentials regardless of whether or not there are existing
+ // connections to the resource. This is primarily for admin
+ // tools like OleDs.
+ //
+
+ ReadAttachEas( Irp, &UserName, &Password, &ShareType, &dwExtendedCreate );
+
+ if ( dwExtendedCreate ) {
+ ASSERT( UserName.Length > 0 );
+ IrpContext->Specific.Create.fExCredentialCreate = TRUE;
+ IrpContext->Specific.Create.puCredentialName = &UserName;
+ }
+
+ //
+ // Attempt to open \\server
+ //
+
+ Iosb.Status = CreateScb(
+ &Scb,
+ IrpContext,
+ &Server,
+ NULL,
+ &UserName,
+ &Password,
+ DeferredLogon,
+ DeleteOnClose );
+
+ if ( ( Iosb.Status == STATUS_REMOTE_NOT_LISTENING ) ||
+ ( Iosb.Status == STATUS_BAD_NETWORK_PATH ) ||
+ ( Iosb.Status == STATUS_UNSUCCESSFUL ) ) {
+
+ //
+ // If we couldn't find the server or something
+ // inexplicable occurred, attempt to open \\tree.
+ //
+
+ Iosb.Status = NdsCreateTreeScb( IrpContext,
+ &Scb, // dest scb
+ &Server, // tree we want
+ &UserName,
+ &Password,
+ DeferredLogon,
+ DeleteOnClose );
+
+ if ( !NT_SUCCESS( Iosb.Status ) ) {
+ try_return( Iosb.Status );
+ }
+
+ OpenedTreeHandle = TRUE;
+
+ } else if ( !NT_SUCCESS( Iosb.Status ) ) {
+
+ //
+ // If we failed to get the bindery server for
+ // some legitimate reason, bail out now.
+ //
+ try_return( Iosb.Status );
+ }
+
+ //
+ // We must have a connection at this point. We don't tree
+ // connect the dir server since it's virtual.
+ //
+
+ if ( !OpenedTreeHandle && CreateTreeConnection && !DeleteOnClose ) {
+ TreeConnectScb( Scb );
+ }
+
+ }
+
+ //
+ // Now create the ICB.
+ //
+
+ ASSERT( Iosb.Status == STATUS_SUCCESS );
+ ASSERT( Scb != NULL );
+
+ Icb = NwCreateIcb( NW_NTC_ICB_SCB, Scb );
+ Icb->FileObject = FileObject;
+ NwSetFileObject( FileObject, NULL, Icb );
+
+ //
+ // Indicate that the SCB was opened.
+ //
+
+ Icb->State = ICB_STATE_OPENED;
+
+ //
+ // Is this a tree handle?
+ //
+
+ Icb->IsTreeHandle = OpenedTreeHandle;
+
+ } else {
+
+ NwReferenceUnlockableCodeSection();
+ DereferenceCodeSection = TRUE;
+
+ DeferredLogon = FALSE;
+
+ if ( CreateTreeConnection ) {
+
+ //
+ // We ignore the extended create attribute here because
+ // we DO NOT support extended credential creates to random
+ // files and directories!
+ //
+
+ ReadAttachEas( Irp, &UserName, &Password, &ShareType, NULL );
+
+ if ( DeleteOnClose ) {
+
+ //
+ // Opening a directory to delete a volume. Do not
+ // force logon.
+ //
+
+ DeferredLogon = TRUE;
+ }
+ }
+
+ IrpContext->Specific.Create.ShareType = ShareType;
+ IrpContext->Specific.Create.NdsCreate = FALSE;
+
+ Iosb.Status = CreateScb(
+ &Scb,
+ IrpContext,
+ &Server,
+ NULL,
+ &UserName,
+ &Password,
+ DeferredLogon,
+ DeleteOnClose );
+
+ if ( Iosb.Status == STATUS_REMOTE_NOT_LISTENING ||
+ Iosb.Status == STATUS_BAD_NETWORK_PATH ||
+ Iosb.Status == STATUS_UNSUCCESSFUL ) {
+
+ //
+ // If we couldn't find the server or something
+ // inexplicable occurred, attempt to open \\tree.
+ //
+
+ IrpContext->Specific.Create.NdsCreate = TRUE;
+ IrpContext->Specific.Create.NeedNdsData = TRUE;
+
+ Iosb.Status = NdsCreateTreeScb( IrpContext,
+ &Scb,
+ &Server,
+ &UserName,
+ &Password,
+ DeferredLogon,
+ DeleteOnClose );
+ }
+
+ //
+ // If we have success, then there's a volume to connect.
+ //
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+
+ NTSTATUS CreateScbStatus;
+
+ ASSERT( Scb != NULL );
+
+ //
+ // Remember the status from create SCB, since it might
+ // be an interesting warning.
+ //
+
+ CreateScbStatus = Iosb.Status;
+
+ //
+ // We catch this exception in case we have to retry the
+ // create on the NDS path. This sucks, as does the
+ // exception structure in this code right now, but it's
+ // legacy and now is not the time to change it.
+ //
+
+ try {
+
+ Iosb = CreateRemoteFile(
+ IrpContext,
+ &Drive );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ Iosb.Status = GetExceptionCode();
+ }
+
+ //
+ // If this is a server whose name is the same as the tree
+ // that it is a member of, and the create was marked as
+ // non-nds and it failed, retry an nds create.
+ //
+
+ if ( ( !NT_SUCCESS( Iosb.Status) ) &&
+ ( !(IrpContext->Specific.Create.NdsCreate) ) &&
+ ( RtlEqualUnicodeString( &(Scb->pNpScb->ServerName),
+ &(Scb->NdsTreeName),
+ TRUE ) ) ) {
+
+ IrpContext->Specific.Create.NdsCreate = TRUE;
+ IrpContext->Specific.Create.NeedNdsData = TRUE;
+
+ Iosb = CreateRemoteFile(
+ IrpContext,
+ &Drive );
+
+ //
+ // If this fails, it will raise status before setting IOSB
+ // and we'll return the status from the original create,
+ // which is the more interesting one.
+ //
+
+ }
+
+ //
+ // If we successfully open the remote file, return the
+ // CreateScb status instead.
+ //
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = CreateScbStatus;
+ }
+
+ }
+ }
+
+ //
+ // If we succeeded, we want to keep the code section
+ // referenced because we have opened a handle.
+ //
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ DereferenceCodeSection = FALSE;
+ }
+
+ try_exit: NOTHING;
+ } finally {
+
+
+ //
+ // Track the Scb in the IrpContext, not in the local Scb
+ // variable since we may have been routed to another server
+ // in process.
+ //
+
+ if ( Scb != NULL ) {
+ ASSERT( IrpContext->pNpScb );
+ NwDereferenceScb( IrpContext->pNpScb );
+ }
+
+ if ( DefaultServer.Buffer != NULL ) {
+ FREE_POOL( DefaultServer.Buffer );
+ }
+
+ DebugTrace(-1, Dbg, "NwCommonCreate -> %08lx\n", Iosb.Status);
+
+ if ( DereferenceCodeSection ) {
+ NwDereferenceUnlockableCodeSection ();
+ }
+
+ }
+
+ //
+ // Map a timeout error to server not found, so that MPR will
+ // try to connect on the next network provider instead of giving up,
+ // which is wrong wrong wrong.
+ //
+
+ if ( Iosb.Status == STATUS_REMOTE_NOT_LISTENING ) {
+ Iosb.Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ //
+ // Map an unbound transport error to server not found, so that MPR
+ // will try to connect on the next provider.
+ //
+
+ if ( Iosb.Status == STATUS_NETWORK_UNREACHABLE ) {
+ Iosb.Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ return Iosb.Status;
+}
+
+
+NTSTATUS
+ReadAttachEas(
+ IN PIRP Irp,
+ OUT PUNICODE_STRING UserName,
+ OUT PUNICODE_STRING Password,
+ OUT PULONG ShareType,
+ OUT PDWORD CredentialExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes the EAs provided when the caller attempts
+ to attach to a remote server.
+
+ Note: This routine does not create additional storage for the names.
+ It is the callers responsibility to save them if required.
+
+Arguments:
+
+ Irp - Supplies all the information
+
+ UserName - Returns the value of the User name EA
+
+ Password - Returns the value of the password EA
+
+ ShareType - Returns the value of the share type EA
+
+ CredentialExtension - Returns whether or not this create
+ should use the provided credentials for an credential
+ extended connection. This is primarily for OleDs
+ accessing the ds in multiple security contexts.
+
+Return Value:
+
+ NTSTATUS - Status of operation
+
+--*/
+{
+
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ PAGED_CODE();
+
+ RtlInitUnicodeString( UserName, NULL );
+ RtlInitUnicodeString( Password, NULL );
+ *ShareType = RESOURCETYPE_ANY;
+ if ( CredentialExtension ) {
+ *CredentialExtension = FALSE;
+ }
+
+ DebugTrace(+1, Dbg, "ReadAttachEas....\n", 0);
+
+ if ( EaBuffer != NULL) {
+
+ while (TRUE) {
+ ULONG EaNameLength = EaBuffer->EaNameLength;
+
+ if (strcmp(EaBuffer->EaName, EA_NAME_USERNAME) == 0) {
+
+ UserName->Length = EaBuffer->EaValueLength;
+ UserName->MaximumLength = EaBuffer->EaValueLength;
+ UserName->Buffer = (PWSTR)(EaBuffer->EaName+EaNameLength+1);
+
+ } else if (strcmp(EaBuffer->EaName, EA_NAME_PASSWORD) == 0) {
+
+ Password->Length = EaBuffer->EaValueLength;
+ Password->MaximumLength = EaBuffer->EaValueLength;
+ Password->Buffer = (PWSTR)(EaBuffer->EaName+EaNameLength+1);
+
+ } else if (strcmp(EaBuffer->EaName, EA_NAME_TYPE) == 0) {
+
+ *ShareType = *(ULONG UNALIGNED *)(EaBuffer->EaName+EaNameLength+1);
+
+ } else if (strcmp(EaBuffer->EaName, EA_NAME_CREDENTIAL_EX) == 0) {
+
+ if ( CredentialExtension ) {
+ *CredentialExtension = TRUE;
+ DebugTrace(0, Dbg, "ReadAttachEas signals a credential extension.\n", 0 );
+ }
+
+ } else {
+ DebugTrace(0, Dbg, "ReadAttachEas Unknown EA -> %s\n", EaBuffer->EaName);
+ }
+
+ if (EaBuffer->NextEntryOffset == 0) {
+ break;
+ } else {
+ EaBuffer = (PFILE_FULL_EA_INFORMATION) ((PCHAR) EaBuffer+EaBuffer->NextEntryOffset);
+ }
+ }
+ }
+
+ DebugTrace(-1, Dbg, "ReadAttachEas -> %08lx\n", STATUS_SUCCESS);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+IO_STATUS_BLOCK
+OpenRedirector(
+ IN PIRP_CONTEXT IrpContext,
+ ULONG DesiredAccess,
+ ULONG ShareAccess,
+ PFILE_OBJECT FileObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routines opens a handle to the redirector device.
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ DesiredAccess - The requested access to the redirector.
+
+ ShareAccess - The requested share access to the redirector.
+
+ FileObject - A pointer to the caller file object.
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+
+{
+ IO_STATUS_BLOCK iosb;
+
+ PAGED_CODE();
+
+ //
+ // Note that the object manager will only allow an administrator
+ // to open the redir itself. This is good.
+ //
+
+ DebugTrace(+1, Dbg, "NwOpenRedirector\n", 0);
+
+ NwAcquireExclusiveRcb( &NwRcb, TRUE );
+
+ try {
+
+ //
+ // Set the new share access
+ //
+
+ if (!NT_SUCCESS(iosb.Status = IoCheckShareAccess( DesiredAccess,
+ ShareAccess,
+ FileObject,
+ &NwRcb.ShareAccess,
+ TRUE ))) {
+
+ DebugTrace(0, Dbg, "bad share access\n", 0);
+
+ try_return( NOTHING );
+ }
+
+ NwSetFileObject( FileObject, NULL, &NwRcb );
+ ++NwRcb.OpenCount;
+
+ //
+ // Set the return status.
+ //
+
+ iosb.Status = STATUS_SUCCESS;
+ iosb.Information = FILE_OPENED;
+
+ try_exit: NOTHING;
+ } finally {
+
+ NwReleaseRcb( &NwRcb );
+ DebugTrace(-1, Dbg, "NwOpenRedirector -> Iosb.Status = %08lx\n", iosb.Status);
+
+ }
+
+ //
+ // Return to the caller.
+ //
+
+ return iosb;
+}
+
+
+IO_STATUS_BLOCK
+CreateRemoteFile(
+ IN PIRP_CONTEXT IrpContext,
+ IN PUNICODE_STRING DriveName
+ )
+/*++
+
+Routine Description:
+
+ This routines opens a remote file or directory.
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ DriveName - The drive name. One of three forms X:, LPTx, or NULL.
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+{
+ IO_STATUS_BLOCK Iosb;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ ULONG DesiredAccess;
+ ULONG ShareAccess;
+ PFILE_OBJECT FileObject;
+
+ UNICODE_STRING FileName;
+ PFILE_OBJECT RelatedFileObject;
+ ULONG Options;
+ ULONG FileAttributes;
+
+ BOOLEAN CreateDirectory;
+ BOOLEAN OpenDirectory;
+ BOOLEAN DirectoryFile;
+ BOOLEAN NonDirectoryFile;
+ BOOLEAN DeleteOnClose;
+ BOOLEAN OpenTargetDirectory;
+ ULONG AllocationSize;
+
+ // Unhandled open features.
+
+ // PFILE_FULL_EA_INFORMATION EaBuffer;
+ // ULONG EaLength;
+ // BOOLEAN SequentialOnly;
+ // BOOLEAN NoIntermediateBuffering;
+ // BOOLEAN IsPagingFile;
+ // BOOLEAN NoEaKnowledge;
+
+ ULONG CreateDisposition;
+
+ PFCB Fcb = NULL;
+ PICB Icb = NULL;
+ PDCB Dcb;
+ PVCB Vcb = NULL;
+ PSCB Scb;
+
+ BOOLEAN IsAFile;
+ BOOLEAN MayBeADirectory = FALSE;
+ BOOLEAN OwnOpenLock = FALSE;
+ BOOLEAN SetShareAccess = FALSE;
+
+ BYTE SearchFlags;
+ BYTE ShareFlags;
+
+ BOOLEAN CreateTreeConnection;
+ PUNICODE_STRING VolumeName;
+
+ NTSTATUS Status;
+ UNICODE_STRING NdsConnectName;
+ WCHAR ConnectBuffer[MAX_NDS_NAME_CHARS];
+ BOOLEAN MadeUidNdsName = FALSE;
+
+ PAGED_CODE();
+
+ Irp = IrpContext->pOriginalIrp;
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+ DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
+ ShareAccess = IrpSp->Parameters.Create.ShareAccess;
+ FileObject = IrpSp->FileObject;
+ OpenTargetDirectory = BooleanFlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY );
+
+ //
+ // It is ok to attempt a reconnect if this request fails with a
+ // connection error.
+ //
+
+ SetFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
+
+
+ try {
+
+ //
+ // Reference our input parameters to make things easier
+ //
+
+ RelatedFileObject = FileObject->RelatedFileObject;
+
+ //
+ // We actually want the parsed file name.
+ // FileName = FileObject->FileName;
+ //
+ FileName = IrpContext->Specific.Create.FullPathName;
+ Options = IrpSp->Parameters.Create.Options;
+ FileAttributes = IrpSp->Parameters.Create.FileAttributes;
+ AllocationSize = Irp->Overlay.AllocationSize.LowPart;
+
+ //
+ // Short circuit an attempt to open a wildcard name.
+ //
+
+ if ( FsRtlDoesNameContainWildCards( &FileName ) ) {
+ try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
+ }
+
+ // Decipher Option flags and values
+ //
+
+ DirectoryFile = BooleanFlagOn( Options, FILE_DIRECTORY_FILE );
+ NonDirectoryFile = BooleanFlagOn( Options, FILE_NON_DIRECTORY_FILE );
+ DeleteOnClose = BooleanFlagOn( Options, FILE_DELETE_ON_CLOSE );
+
+ //
+ // Things we currently ignore, because netware servers don't support it.
+ //
+
+ // SequentialOnly = BooleanFlagOn( Options, FILE_SEQUENTIAL_ONLY );
+ // NoIntermediateBuffering = BooleanFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING );
+ // NoEaKnowledge = BooleanFlagOn( Options, FILE_NO_EA_KNOWLEDGE );
+ // EaBuffer = Irp->AssociatedIrp.SystemBuffer;
+ // EaLength = IrpSp->Parameters.Create.EaLength;
+ // IsPagingFile = BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE );
+
+ if ( BooleanFlagOn( Options, FILE_CREATE_TREE_CONNECTION ) ) {
+ CreateDisposition = FILE_OPEN;
+ } else {
+ CreateDisposition = (Options >> 24) & 0x000000ff;
+ }
+
+ CreateDirectory = (BOOLEAN)(DirectoryFile &&
+ ((CreateDisposition == FILE_CREATE) ||
+ (CreateDisposition == FILE_OPEN_IF)));
+
+ OpenDirectory = (BOOLEAN)(DirectoryFile &&
+ ((CreateDisposition == FILE_OPEN) ||
+ (CreateDisposition == FILE_OPEN_IF)));
+
+ Dcb = NULL;
+ if ( RelatedFileObject != NULL ) {
+
+ PNONPAGED_DCB NonPagedDcb;
+
+ NonPagedDcb = RelatedFileObject->FsContext;
+ Dcb = NonPagedDcb->Fcb;
+
+ //
+ // If there is a related file object then this is a relative open
+ // and it better be a DCB.
+ //
+
+ if ( NodeType( Dcb ) != NW_NTC_DCB ) {
+
+ DebugTrace(0, Dbg, "Bad file name\n", 0);
+ Iosb.Status = STATUS_OBJECT_NAME_INVALID;
+ try_return( Iosb );
+ }
+
+
+ //
+ // Obtain SCB pointers.
+ //
+
+ IrpContext->pScb = Dcb->Scb;
+ IrpContext->pNpScb = Dcb->Scb->pNpScb;
+ }
+
+ //
+ // We are about ready to send a packet. Append this IRP context
+ // the SCB workqueue, and wait until it gets to the front.
+ //
+
+ NwAppendToQueueAndWait( IrpContext );
+ ASSERT( IrpContext->pNpScb->Requests.Flink == &IrpContext->NextRequest );
+
+ //
+ // Acquire the Global FCB resource to ensure that one thread
+ // can't access the half created FCB of another thread.
+ //
+
+ NwAcquireOpenLock( );
+ OwnOpenLock = TRUE;
+
+ //
+ // Find the volume for this file.
+ //
+
+ CreateTreeConnection = BooleanFlagOn( Options, FILE_CREATE_TREE_CONNECTION );
+
+ if ( CreateTreeConnection ) {
+ VolumeName = &IrpContext->Specific.Create.FullPathName;
+ } else {
+ VolumeName = &IrpContext->Specific.Create.VolumeName;
+ }
+
+ if ( Dcb == NULL ) {
+
+RetryFindVcb:
+
+ Vcb = NwFindVcb(
+ IrpContext,
+ VolumeName,
+ IrpContext->Specific.Create.ShareType,
+ IrpContext->Specific.Create.DriveLetter,
+ CreateTreeConnection,
+ ( BOOLEAN )( CreateTreeConnection && DeleteOnClose ) );
+
+ if ( Vcb == NULL ) {
+
+ //
+ // If this create failed because we need nds data, get
+ // the data from the ds and resubmit the request.
+ //
+
+ if ( IrpContext->Specific.Create.NdsCreate &&
+ IrpContext->Specific.Create.NeedNdsData ) {
+
+ //
+ // Release the open resource so we can move around.
+ //
+
+ NwReleaseOpenLock( );
+ OwnOpenLock = FALSE;
+
+ //
+ // Take the volume name and build the server/share
+ // connect name.
+ //
+
+ NdsConnectName.Buffer = ConnectBuffer;
+ NdsConnectName.MaximumLength = sizeof( ConnectBuffer );
+ NdsConnectName.Length = 0;
+
+ //
+ // Get the ds information. We may jump servers here.
+ //
+
+ Status = NdsMapObjectToServerShare( IrpContext,
+ &Scb,
+ &NdsConnectName,
+ CreateTreeConnection,
+ &(IrpContext->Specific.Create.dwNdsOid) );
+
+ if( !NT_SUCCESS( Status ) ) {
+ ExRaiseStatus( Status );
+ }
+
+ //
+ // Make sure we are on the scb queue after all the
+ // possible server jumping.
+ //
+
+ NwAppendToQueueAndWait( IrpContext );
+
+ NwAcquireOpenLock( );
+ OwnOpenLock = TRUE;
+
+ //
+ // Prepend the Uid to the server/share name.
+ //
+
+ MergeStrings( &IrpContext->Specific.Create.UidConnectName,
+ &Scb->UnicodeUid,
+ &NdsConnectName,
+ PagedPool );
+
+ MadeUidNdsName = TRUE;
+
+ //
+ // We have the data, so re-do the connect.
+ //
+
+ IrpContext->Specific.Create.NeedNdsData = FALSE;
+ goto RetryFindVcb;
+
+ } else {
+
+ //
+ // If this was an open to delete a tree connect, and we failed
+ // to find the VCB, simply return the error.
+ //
+
+ Iosb.Status = STATUS_BAD_NETWORK_PATH;
+ try_return ( Iosb );
+
+ }
+
+ }
+
+ } else {
+
+ Vcb = Dcb->Vcb;
+ NwReferenceVcb( Vcb );
+
+ }
+
+ ASSERT( Vcb->Scb == IrpContext->pScb );
+
+ //
+ // If this is the target name for a rename then we want to find the
+ // DCB for the parent directory.
+ //
+
+ if (OpenTargetDirectory) {
+
+ Iosb = OpenRenameTarget(IrpContext, Vcb, Dcb, &Icb );
+ if (Icb != NULL) {
+ Fcb = Icb->SuperType.Fcb;
+ }
+ try_return ( Iosb );
+
+ }
+
+ //
+ // Find the FCB for this file. If the FCB exists, we get a
+ // referenced pointer. Otherwise a new FCB is created.
+ //
+
+ Fcb = NwFindFcb( IrpContext->pScb, Vcb, &FileName, Dcb );
+
+ //
+ // Check the share access for this file. The share access
+ // is updated if access is granted.
+ //
+
+ if ( Fcb->IcbCount > 0 ) {
+
+ Iosb.Status = IoCheckShareAccess(
+ DesiredAccess,
+ ShareAccess,
+ FileObject,
+ &Fcb->ShareAccess,
+ TRUE );
+
+ if ( !NT_SUCCESS( Iosb.Status ) ) {
+ try_return( Iosb );
+ }
+
+ } else {
+
+ IoSetShareAccess(
+ DesiredAccess,
+ ShareAccess,
+ FileObject,
+ &Fcb->ShareAccess );
+ }
+
+ SetShareAccess = TRUE;
+
+ //
+ // Now create the ICB.
+ //
+
+ Icb = NwCreateIcb( NW_NTC_ICB, Fcb );
+ Icb->FileObject = FileObject;
+ NwSetFileObject( FileObject, Fcb->NonPagedFcb, Icb );
+
+#ifndef QFE_BUILD
+
+ //
+ // Supply a resource for the modified page write to grab when
+ // writing mem mapped files. We do this because it is imposed
+ // on us by the system, we do not require the resource for any
+ // real serialization.
+ //
+
+ Fcb->NonPagedFcb->Header.Flags = 0;
+ Fcb->NonPagedFcb->Header.Resource = NULL;
+
+#endif
+
+#ifdef NWFASTIO
+ //
+ // Initialize private cache map so that the i/o system will call
+ // our fast path.
+ //
+
+ FileObject->PrivateCacheMap = (PVOID)1;
+#endif
+
+ IrpContext->Icb = Icb;
+
+ //
+ // Allocate an 8 bit PID for this ICB. Use different thread so
+ // each Wow program gets its own id. This is because if the same id
+ // has locks using two handles and closes just one of them the locks
+ // on that handle are not discarded.
+ //
+
+ Iosb.Status = NwMapPid( (ULONG)PsGetCurrentThread(), &Icb->Pid );
+
+ if ( !NT_SUCCESS( Iosb.Status ) ) {
+ try_return( Iosb.Status );
+ }
+
+ //
+ // Try to figure out what it is we're expected to open.
+ //
+
+ Iosb.Status = STATUS_SUCCESS;
+
+ if ( FlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
+
+ //
+ // Opening a print queue job.
+ //
+
+ Iosb = CreatePrintJob( IrpContext, Vcb, Icb, DriveName );
+
+ } else if ( DirectoryFile ||
+ ( Fcb->State == FCB_STATE_OPENED &&
+ Fcb->NodeTypeCode == NW_NTC_DCB ) ) {
+
+ //
+ // Opening a directory.
+ //
+
+ MayBeADirectory = TRUE;
+
+ switch ( CreateDisposition ) {
+
+ case FILE_OPEN:
+ Iosb = ChangeDirectory( IrpContext, Vcb, Icb );
+ break;
+
+ case FILE_CREATE:
+ Iosb = CreateDir( IrpContext, Vcb, Icb );
+ break;
+
+ case FILE_OPEN_IF:
+ Iosb.Status = FileOrDirectoryExists( IrpContext,
+ Vcb,
+ Icb,
+ &Icb->SuperType.Fcb->RelativeFileName,
+ &IsAFile );
+
+ //
+ // If the opener specified a directory, fail this request
+ // if the object is a file.
+ //
+
+ if ( NT_SUCCESS( Iosb.Status ) && IsAFile ) {
+ Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND;
+ } else if ( !NT_SUCCESS( Iosb.Status )) {
+ Iosb = CreateDir( IrpContext, Vcb, Icb );
+ }
+ break;
+
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE:
+ case FILE_OVERWRITE_IF:
+ Iosb.Status = STATUS_INVALID_PARAMETER;
+ break;
+
+ default:
+ KeBugCheck( RDR_FILE_SYSTEM );
+
+ }
+
+ } else {
+
+ SearchFlags = NtAttributesToNwAttributes( FileAttributes );
+ ShareFlags = NtToNwShareFlags( DesiredAccess, ShareAccess );
+
+ IsAFile = NonDirectoryFile ||
+ (Fcb->State == FCB_STATE_OPENED &&
+ Fcb->NodeTypeCode == NW_NTC_FCB );
+ //
+ // Assume we are opening a file. If that fails, and it makes
+ // sense try to open a directory.
+ //
+
+ switch ( CreateDisposition ) {
+
+ case FILE_OPEN:
+
+ //
+ // If the disposition is FILE_OPEN try to avoid an unneeded
+ // open, for some desired access types.
+ //
+
+ switch ( DesiredAccess & ~SYNCHRONIZE ) {
+
+ case FILE_WRITE_ATTRIBUTES:
+ case FILE_READ_ATTRIBUTES:
+ case DELETE:
+
+ Iosb.Status = FileOrDirectoryExists(
+ IrpContext,
+ Vcb,
+ Icb,
+ &Icb->SuperType.Fcb->RelativeFileName,
+ &IsAFile );
+
+ if ( !IsAFile) {
+ MayBeADirectory = TRUE;
+ }
+
+ //
+ // Fail open of read only file for delete access,
+ // since the netware server won't fail the delete.
+ //
+
+ if ( NT_SUCCESS( Iosb.Status ) &&
+ CreateDisposition == DELETE &&
+ FlagOn( Icb->NpFcb->Attributes, NW_ATTRIBUTE_READ_ONLY ) ) {
+
+ Iosb.Status = STATUS_ACCESS_DENIED;
+ }
+
+ if ( ( Iosb.Status == STATUS_OBJECT_NAME_NOT_FOUND ) &&
+ ( (DesiredAccess & ~SYNCHRONIZE) == DELETE ) ) {
+ //
+ // we may not have scan rights. fake the return as OK.
+ // NW allows the delete without scan rights.
+ //
+ Iosb.Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ default:
+
+ Iosb = OpenFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
+
+ if ( ( Iosb.Status == STATUS_OBJECT_NAME_NOT_FOUND ||
+ Iosb.Status == STATUS_FILE_IS_A_DIRECTORY )
+ && !IsAFile) {
+
+ //
+ // Opener didn't specify file or directory, and open
+ // file failed. So try open directory.
+ //
+
+ Iosb = ChangeDirectory( IrpContext, Vcb, Icb );
+ MayBeADirectory = TRUE;
+
+ } else if ( (Iosb.Status == STATUS_SHARING_VIOLATION) &&
+ ((ShareFlags == (NW_OPEN_FOR_READ | NW_DENY_WRITE)) ||
+ (ShareFlags == (NW_OPEN_FOR_READ)))) {
+
+ //
+ // if the file was already open exclusive (eg. GENERIC_EXECUTE)
+ // then a debugger opening it again for read will fail with
+ // sharing violation. In this case, we will try open exclusive
+ // again to see if that passes.
+ //
+
+ ShareFlags |= NW_OPEN_EXCLUSIVE ;
+ ShareFlags &= ~(NW_DENY_WRITE | NW_DENY_READ);
+ Iosb = OpenFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
+ }
+
+ break;
+
+ }
+
+ break;
+
+ case FILE_CREATE:
+ Iosb = CreateNewFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
+ break;
+
+ case FILE_OPEN_IF:
+ Iosb.Status = FileOrDirectoryExists( IrpContext,
+ Vcb,
+ Icb,
+ &Icb->SuperType.Fcb->RelativeFileName,
+ &IsAFile );
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb = OpenFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
+ } else {
+ Iosb = CreateNewFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
+ }
+
+ if ( !NT_SUCCESS( Iosb.Status ) && !IsAFile) {
+
+ //
+ // Opener didn't specify file or directory, and open
+ // file and create new file both failed. So try open
+ // or create directory.
+ //
+
+ MayBeADirectory = TRUE;
+ Iosb.Status = FileOrDirectoryExists(
+ IrpContext,
+ Vcb,
+ Icb,
+ &Icb->SuperType.Fcb->RelativeFileName,
+ &IsAFile);
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Information = FILE_OPENED;
+ } else {
+ Iosb = CreateDir( IrpContext, Vcb, Icb );
+ }
+ }
+
+ break;
+
+ //
+ // None of the below make sense for directories so if the
+ // file operation fails, just return the failure status
+ // to the user.
+ //
+
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE_IF:
+
+ //
+ // Actually, if Overwrite is chosen, we are supposed to
+ // get the attributes for a file and OR them with the
+ // new attributes.
+ //
+
+ Iosb = CreateOrOverwriteFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags, FALSE );
+ break;
+
+ case FILE_OVERWRITE:
+ Iosb.Status = FileOrDirectoryExists(
+ IrpContext,
+ Vcb,
+ Icb,
+ &Icb->SuperType.Fcb->RelativeFileName,
+ &IsAFile );
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb = CreateOrOverwriteFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags, FALSE );
+ }
+
+ break;
+
+ default:
+ KeBugCheck( RDR_FILE_SYSTEM );
+ }
+
+
+ }
+
+try_exit: NOTHING;
+
+ } finally {
+
+ if ( Vcb != NULL ) {
+ NwDereferenceVcb( Vcb, IrpContext, FALSE );
+ }
+
+ if ( MadeUidNdsName ) {
+ FREE_POOL( IrpContext->Specific.Create.UidConnectName.Buffer );
+ }
+
+ if ( AbnormalTermination() || !NT_SUCCESS( Iosb.Status ) ) {
+
+ //
+ // Remove the share access if necessary
+ //
+
+ if ( SetShareAccess ) {
+ IoRemoveShareAccess( FileObject, &Fcb->ShareAccess );
+ }
+
+ //
+ // Failed to create
+ //
+
+ if ( Icb != NULL ) {
+
+ if ( Icb->Pid != 0 ) {
+ NwUnmapPid( Icb->Pid, NULL );
+ }
+
+ NwDeleteIcb( NULL, Icb );
+ }
+
+ //
+ // If this was a tree connect, derefence the extra
+ // reference on the VCB.
+ //
+
+ if ( CreateTreeConnection && !DeleteOnClose ) {
+ if ( Vcb != NULL ) {
+ NwDereferenceVcb( Vcb, IrpContext, FALSE );
+ }
+ }
+
+ NwDequeueIrpContext( IrpContext, FALSE );
+
+ } else {
+
+ Icb->State = ICB_STATE_OPENED;
+ if ( Fcb->State == FCB_STATE_OPEN_PENDING ) {
+ Fcb->State = FCB_STATE_OPENED;
+ }
+
+ if ( DeleteOnClose && !CreateTreeConnection ) {
+ SetFlag( Fcb->Flags, FCB_FLAGS_DELETE_ON_CLOSE );
+ }
+
+ FileObject->SectionObjectPointer = &Fcb->NonPagedFcb->SegmentObject;
+
+ if ( MayBeADirectory ) {
+
+ //
+ // We successfully opened the file as a directory.
+ // If the DCB is newly created, it will be marked
+ // type FCB, update it.
+ //
+
+ Fcb->NodeTypeCode = NW_NTC_DCB;
+ }
+
+ NwDequeueIrpContext( IrpContext, FALSE );
+
+ }
+
+ if ( OwnOpenLock ) {
+ NwReleaseOpenLock( );
+ }
+
+ }
+
+ return( Iosb );
+}
+
+
+IO_STATUS_BLOCK
+ChangeDirectory(
+ PIRP_CONTEXT IrpContext,
+ PVCB Vcb,
+ PICB Icb
+ )
+/*++
+
+Routine Description:
+
+ This routines sets the directory for a remote drive.
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ Vcb - A pointer to the VCB for the remote drive.
+
+ Icb - A pointer to the file we are opening.
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+{
+ IO_STATUS_BLOCK Iosb;
+ PFCB Fcb;
+ BYTE Attributes;
+ BOOLEAN FirstTime = TRUE;
+
+ PAGED_CODE();
+
+ //
+ // No need to send a packet if we are opening the root of the volume.
+ //
+
+ if ( Icb->SuperType.Fcb->RelativeFileName.Length == 0 ) {
+
+ Iosb.Status = STATUS_SUCCESS;
+ Iosb.Information = FILE_OPENED;
+
+ return( Iosb );
+ }
+
+Retry:
+
+ if ( !BooleanFlagOn( Icb->SuperType.Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "FwbbJ",
+ NCP_SEARCH_FILE,
+ -1,
+ Vcb->Specific.Disk.Handle,
+ SEARCH_ALL_DIRECTORIES,
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "N==_b",
+ 14,
+ &Attributes );
+ }
+
+
+ } else {
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "LbbWDbDbC",
+ NCP_LFN_GET_INFO,
+ Vcb->Specific.Disk.LongNameSpace,
+ Vcb->Specific.Disk.LongNameSpace,
+ SEARCH_ALL_DIRECTORIES,
+ LFN_FLAG_INFO_ATTRIBUTES |
+ LFN_FLAG_INFO_MODIFY_TIME,
+ Vcb->Specific.Disk.VolumeNumber,
+ Vcb->Specific.Disk.Handle,
+ 0,
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "N_b",
+ 4,
+ &Attributes );
+ }
+
+ //
+ // Unfortunately, this succeeds even if the file in question
+ // is not a directory.
+ //
+
+ if ( NT_SUCCESS( Iosb.Status ) &&
+ ( !FlagOn( Attributes, NW_ATTRIBUTE_DIRECTORY ) ) ) {
+
+ Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+ }
+
+ if ((Iosb.Status == STATUS_INVALID_HANDLE) &&
+ (FirstTime)) {
+
+ //
+ // Check to see if Volume handle is invalid. Caused when volume
+ // is unmounted and then remounted.
+ //
+
+ FirstTime = FALSE;
+
+ NwReopenVcbHandle( IrpContext, Vcb );
+
+ goto Retry;
+ }
+
+ Fcb = Icb->SuperType.Fcb;
+
+ Fcb->NonPagedFcb->Attributes = (UCHAR)Attributes;
+ SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
+
+ //
+ // Set information field assuming success. It will be ignored
+ // if the NCP failed.
+ //
+
+ Iosb.Information = FILE_OPENED;
+
+ if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
+ Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ return( Iosb );
+}
+
+
+IO_STATUS_BLOCK
+CreateDir(
+ PIRP_CONTEXT IrpContext,
+ PVCB Vcb,
+ PICB Icb
+ )
+/*++
+
+Routine Description:
+
+ This routines create a new directory.
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ Vcb - A pointer to the VCB for the remote drive.
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+{
+ IO_STATUS_BLOCK Iosb;
+
+ PAGED_CODE();
+
+ if ( Icb->SuperType.Fcb->RelativeFileName.Length == 0 ) {
+ Iosb.Status = STATUS_ACCESS_DENIED;
+ return( Iosb );
+ }
+
+ if ( !BooleanFlagOn( Icb->SuperType.Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
+
+ if (!IsFatNameValid(&Icb->SuperType.Fcb->RelativeFileName)) {
+
+ Iosb.Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
+
+ return( Iosb );
+
+ }
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "SbbJ",
+ NCP_DIR_FUNCTION, NCP_CREATE_DIRECTORY,
+ Vcb->Specific.Disk.Handle,
+ 0xFF,
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ } else {
+
+ Iosb.Status = ExchangeWithWait(
+ IrpContext,
+ SynchronousResponseCallback,
+ "LbbWDDWbDbC",
+ NCP_LFN_OPEN_CREATE,
+ Vcb->Specific.Disk.LongNameSpace,
+ LFN_FLAG_OM_CREATE,
+ 0, // Search Flags,
+ 0, // Return Info Mask
+ NW_ATTRIBUTE_DIRECTORY,
+ 0x00ff, // Desired access
+ Vcb->Specific.Disk.VolumeNumber,
+ Vcb->Specific.Disk.Handle,
+ 0, // Short directory flag
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ }
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "N" );
+ }
+
+ //
+ // Set information field assuming success. It will be ignored
+ // if the NCP failed.
+ //
+
+ Iosb.Information = FILE_CREATED;
+
+ if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
+ Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ return( Iosb );
+}
+
+
+NTSTATUS
+FileOrDirectoryExists(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PICB Icb OPTIONAL,
+ PUNICODE_STRING Name,
+ OUT PBOOLEAN IsAFile
+ )
+/*++
+
+Routine Description:
+
+ This routines looks to see if a file or directory exists.
+
+Arguments:
+
+ IrpContext - Supplies allx the information
+
+ Vcb - A pointer to the VCB for the remote drive.
+
+ Icb - A pointer to the ICB for the file we are looking for.
+
+ Name - Fully qualified name.
+
+ IsAFile - Returns TRUE is the found file is a file, FALSE if it is
+ a directory. Return nothing if the function returns FALSE.
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+{
+ ULONG Attributes;
+ ULONG FileSize;
+ USHORT LastModifiedDate;
+ USHORT LastModifiedTime;
+ USHORT CreationDate;
+ USHORT CreationTime = DEFAULT_TIME;
+ USHORT LastAccessDate;
+ NTSTATUS Status;
+ PFCB Fcb;
+ BOOLEAN FirstTime = TRUE;
+
+ PAGED_CODE();
+
+ //
+ // No need to send a packet if we are searching for the root of the volume.
+ //
+
+ if ( Name->Length == 0 ) {
+ *IsAFile = FALSE;
+
+ return( STATUS_SUCCESS );
+ }
+
+ //
+ // Decide how to handle this request. If we have an ICB, use the FCB
+ // to determine the file name type, otherwise we have to make the
+ // decision here.
+ //
+
+ if ( Icb != NULL &&
+ !BooleanFlagOn( Icb->SuperType.Fcb->Flags, FCB_FLAGS_LONG_NAME ) ||
+
+ Vcb->Specific.Disk.LongNameSpace == LFN_NO_OS2_NAME_SPACE ||
+
+ IsFatNameValid( Name ) ) {
+Retry:
+ //
+ // First try a file
+ //
+
+ IrpContext->ResponseLength = 0;
+
+ Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "FwbbJ",
+ NCP_SEARCH_FILE,
+ -1,
+ Vcb->Specific.Disk.Handle,
+ SEARCH_ALL_FILES,
+ Name );
+
+ if ( NT_SUCCESS( Status ) ) {
+ Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "N==_b-dwwww",
+ 14,
+ &Attributes,
+ &FileSize,
+ &CreationDate,
+ &LastAccessDate,
+ &LastModifiedDate,
+ &LastModifiedTime );
+ }
+
+ if ((Status == STATUS_INVALID_HANDLE) &&
+ (FirstTime)) {
+
+ //
+ // Check to see if Volume handle is invalid. Caused when volume
+ // is unmounted and then remounted.
+ //
+
+ FirstTime = FALSE;
+
+ NwReopenVcbHandle( IrpContext, Vcb );
+
+ goto Retry;
+ }
+
+ if ( Status == STATUS_UNSUCCESSFUL ) {
+
+ //
+ // Not a file, Is it a directory?
+ //
+
+ Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "FwbbJ",
+ NCP_SEARCH_FILE,
+ -1,
+ Vcb->Specific.Disk.Handle,
+ SEARCH_ALL_DIRECTORIES,
+ Name );
+
+ if ( NT_SUCCESS( Status ) ) {
+ Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "N==_b",
+ 14,
+ &Attributes );
+ }
+
+ //
+ // If the exchange or ParseResponse fails then exit with not found
+ //
+
+ if ( !NT_SUCCESS( Status ) ) {
+ return( STATUS_OBJECT_NAME_NOT_FOUND );
+ }
+
+ *IsAFile = FALSE;
+ ASSERT( (Attributes & NW_ATTRIBUTE_DIRECTORY) != 0 );
+
+ } else {
+
+ if ( Status == STATUS_UNEXPECTED_NETWORK_ERROR &&
+ IrpContext->ResponseLength >= sizeof( NCP_RESPONSE ) ) {
+
+ //
+ // Work-around for netware bug. If netware returns short
+ // packet, just return success. We exit prematurely
+ // because we have no attributes to record.
+ //
+
+ Icb = NULL;
+ *IsAFile = TRUE;
+ return ( STATUS_SUCCESS );
+ }
+
+ if ( !NT_SUCCESS( Status ) ) {
+ return( Status );
+ }
+
+ *IsAFile = TRUE;
+ ASSERT( ( Attributes & NW_ATTRIBUTE_DIRECTORY ) == 0 );
+
+ }
+
+ } else {
+
+ Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "LbbWDbDbC",
+ NCP_LFN_GET_INFO,
+ Vcb->Specific.Disk.LongNameSpace,
+ Vcb->Specific.Disk.LongNameSpace,
+ SEARCH_ALL_DIRECTORIES,
+ LFN_FLAG_INFO_ATTRIBUTES |
+ LFN_FLAG_INFO_FILE_SIZE |
+ LFN_FLAG_INFO_MODIFY_TIME |
+ LFN_FLAG_INFO_CREATION_TIME,
+ Vcb->Specific.Disk.VolumeNumber,
+ Vcb->Specific.Disk.Handle,
+ 0,
+ Name );
+
+ if ( NT_SUCCESS( Status ) ) {
+ Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "N_e=e_xx_xx_x",
+ 4,
+ &Attributes,
+ &FileSize,
+ 6,
+ &CreationTime,
+ &CreationDate,
+ 4,
+ &LastModifiedTime,
+ &LastModifiedDate,
+ 4,
+ &LastAccessDate );
+ }
+
+ //
+ // If the exchange or ParseResponse fails then exit with not found
+ //
+
+ if ( !NT_SUCCESS( Status ) ) {
+ return( STATUS_OBJECT_NAME_NOT_FOUND );
+ }
+
+ if ( Attributes & NW_ATTRIBUTE_DIRECTORY) {
+ *IsAFile = FALSE;
+ } else {
+ *IsAFile = TRUE;
+ }
+ }
+
+ //
+ // If the caller supplied an ICB, update the FCB attributes.
+ // We'll use this info if the caller does a query attributes
+ // on the ICB.
+ //
+
+ if ( Icb != NULL && *IsAFile ) {
+
+ Fcb = Icb->SuperType.Fcb;
+ ASSERT( Fcb->NodeTypeCode == NW_NTC_FCB );
+
+ Fcb->NonPagedFcb->Attributes = (UCHAR)Attributes;
+ Fcb->NonPagedFcb->Header.FileSize.QuadPart = FileSize;
+ Fcb->LastModifiedDate = LastModifiedDate;
+ Fcb->LastModifiedTime = LastModifiedTime;
+ Fcb->CreationTime = CreationTime;
+ Fcb->CreationDate = CreationDate;
+ Fcb->LastAccessDate = LastAccessDate;
+
+ DebugTrace( 0, Dbg, "Attributes -> %08lx\n", Fcb->NonPagedFcb->Attributes );
+ DebugTrace( 0, Dbg, "FileSize.Low-> %08lx\n", Fcb->NonPagedFcb->Header.FileSize.LowPart );
+ DebugTrace( 0, Dbg, "ModifiedDate-> %08lx\n", Fcb->LastModifiedDate );
+ DebugTrace( 0, Dbg, "ModifiedTime-> %08lx\n", Fcb->LastModifiedTime );
+ DebugTrace( 0, Dbg, "CreationTime-> %08lx\n", Fcb->CreationTime );
+ DebugTrace( 0, Dbg, "CreationDate-> %08lx\n", Fcb->CreationDate );
+ DebugTrace( 0, Dbg, "LastAccDate -> %08lx\n", Fcb->LastAccessDate );
+
+ SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
+ }
+
+ return( STATUS_SUCCESS );
+}
+
+
+IO_STATUS_BLOCK
+OpenFile(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PICB Icb,
+ IN BYTE Attributes,
+ IN BYTE OpenFlags
+ )
+/*++
+
+Routine Description:
+
+ This routines sets opens a file on a netware server. It fails if
+ the file does not exist.
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ Vcb - A pointer to the VCB for the remote drive.
+
+ Icb - A pointer to the ICB we are opening.
+
+ Attributes - Open attributes.
+
+ OpenFlags - Open mode and sharing mode flags.
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+{
+ IO_STATUS_BLOCK Iosb;
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ //
+ // No need to send a packet if we are trying to open the root of
+ // the volume as a file.
+ //
+
+ if ( Icb->SuperType.Fcb->RelativeFileName.Length == 0 ) {
+ Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
+ return( Iosb );
+ }
+
+ Fcb = Icb->SuperType.Fcb;
+ ASSERT( NodeType( Fcb ) == NW_NTC_FCB );
+
+ //
+ // Send the open request and wait for the response.
+ //
+
+ if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "FbbbJ",
+ NCP_OPEN_FILE,
+ Vcb->Specific.Disk.Handle,
+ SEARCH_ALL_FILES,
+ OpenFlags,
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ if ( ( ReadExecOnlyFiles ) &&
+ ( !NT_SUCCESS( Iosb.Status ) ) ) {
+
+ //
+ // Retry the open with the appropriate flags for
+ // execute only files.
+ //
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "FbbbJ",
+ NCP_OPEN_FILE,
+ Vcb->Specific.Disk.Handle,
+ SEARCH_EXEC_ONLY_FILES,
+ OpenFlags,
+ &Icb->SuperType.Fcb->RelativeFileName );
+ }
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "Nr=_b-dwwww",
+ Icb->Handle,
+ sizeof( Icb->Handle ),
+ 14,
+ &Fcb->NonPagedFcb->Attributes,
+ &Fcb->NonPagedFcb->Header.FileSize,
+ &Fcb->CreationDate,
+ &Fcb->LastAccessDate,
+ &Fcb->LastModifiedDate,
+ &Fcb->LastModifiedTime );
+
+ Fcb->CreationTime = DEFAULT_TIME;
+
+ }
+
+ } else {
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "LbbWDDWbDbC",
+ NCP_LFN_OPEN_CREATE,
+ Vcb->Specific.Disk.LongNameSpace,
+ LFN_FLAG_OM_OPEN,
+ NW_ATTRIBUTE_HIDDEN | NW_ATTRIBUTE_SYSTEM, // Search Flags,
+ LFN_FLAG_INFO_ATTRIBUTES |
+ LFN_FLAG_INFO_FILE_SIZE |
+ LFN_FLAG_INFO_MODIFY_TIME |
+ LFN_FLAG_INFO_CREATION_TIME,
+ 0, // Create attributes
+ OpenFlags, // Desired access
+ Vcb->Specific.Disk.VolumeNumber,
+ Vcb->Specific.Disk.Handle,
+ 0, // Short directory flag
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ if ( ( ReadExecOnlyFiles ) &&
+ ( !NT_SUCCESS( Iosb.Status ) ) ) {
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "LbbWDDWbDbC",
+ NCP_LFN_OPEN_CREATE,
+ Vcb->Specific.Disk.LongNameSpace,
+ LFN_FLAG_OM_OPEN,
+ NW_ATTRIBUTE_EXEC_ONLY,
+ LFN_FLAG_INFO_ATTRIBUTES |
+ LFN_FLAG_INFO_FILE_SIZE |
+ LFN_FLAG_INFO_MODIFY_TIME |
+ LFN_FLAG_INFO_CREATION_TIME,
+ 0, // Create attributes
+ OpenFlags, // Desired access
+ Vcb->Specific.Disk.VolumeNumber,
+ Vcb->Specific.Disk.Handle,
+ 0, // Short directory flag
+ &Icb->SuperType.Fcb->RelativeFileName );
+ }
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "Ne_e=e_xx_xx_x",
+ &Icb->Handle[2],
+ 6,
+ &Fcb->NonPagedFcb->Attributes,
+ &Fcb->NonPagedFcb->Header.FileSize,
+ 6,
+ &Fcb->CreationTime,
+ &Fcb->CreationDate,
+ 4,
+ &Fcb->LastModifiedTime,
+ &Fcb->LastModifiedDate,
+ 4,
+ &Fcb->LastAccessDate );
+ }
+ }
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+
+ //
+ // NT does not allow you to open a read only file for write access.
+ // Netware does. To fake NT semantics, check to see if we should
+ // fail the open that the netware server just succeeded.
+ //
+
+ if ( ( Fcb->NonPagedFcb->Attributes & NW_ATTRIBUTE_READ_ONLY ) &&
+ ( OpenFlags & NW_OPEN_FOR_WRITE ) ) {
+
+ CloseFile( IrpContext, Icb );
+ Iosb.Status = STATUS_ACCESS_DENIED;
+ }
+
+ SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
+ Icb->HasRemoteHandle = TRUE;
+
+
+ DebugTrace( 0, Dbg, "Attributes -> %08lx\n", Fcb->NonPagedFcb->Attributes );
+ DebugTrace( 0, Dbg, "FileSize.Low-> %08lx\n", Fcb->NonPagedFcb->Header.FileSize.LowPart );
+ DebugTrace( 0, Dbg, "ModifiedDate-> %08lx\n", Fcb->LastModifiedDate );
+ DebugTrace( 0, Dbg, "ModifiedTime-> %08lx\n", Fcb->LastModifiedTime );
+ DebugTrace( 0, Dbg, "CreationDate-> %08lx\n", Fcb->CreationDate );
+ DebugTrace( 0, Dbg, "CreationTime-> %08lx\n", Fcb->CreationTime );
+ DebugTrace( 0, Dbg, "LastAccDate -> %08lx\n", Fcb->LastAccessDate );
+
+ }
+
+ //
+ // Set information field assuming success. It will be ignored
+ // if the NCP failed.
+ //
+
+ Iosb.Information = FILE_OPENED;
+
+ if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
+ Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ return( Iosb );
+}
+
+
+IO_STATUS_BLOCK
+CreateNewFile(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PICB Icb,
+ IN BYTE CreateAttributes,
+ IN BYTE OpenFlags
+ )
+/*++
+
+Routine Description:
+
+ This routines creates a new file on a netware server. It fails
+ if the file exists.
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ Vcb - A pointer to the VCB for the remote drive.
+
+ Icb - A pointer to the ICB we are opening.
+
+ CreateAttributes - Create attributes.
+
+ OpenFlags - Open mode and sharing mode flags.
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+{
+ IO_STATUS_BLOCK Iosb;
+ PFCB Fcb;
+ UCHAR DelayedAttributes;
+ BOOLEAN CloseAndReopen;
+
+ PAGED_CODE();
+
+ //
+ // If the user opens the file for shared access, then we will need to
+ // create the file close, then reopen it (since we have no NCP to say
+ // create with shared access). If the file is being created read-only,
+ // and the creator requests write access then we pull the additional
+ // trick of creating the file without the read-only, and set it later,
+ // so that the second open can succeed.
+ //
+
+ CloseAndReopen = FALSE;
+ DelayedAttributes = 0;
+
+ if ( OpenFlags != NW_OPEN_EXCLUSIVE ) {
+ CloseAndReopen = TRUE;
+
+ if ( ( CreateAttributes & NW_ATTRIBUTE_READ_ONLY ) &&
+ ( OpenFlags & NW_OPEN_FOR_WRITE ) ) {
+
+ DelayedAttributes = CreateAttributes;
+ CreateAttributes = 0;
+ }
+ }
+
+ //
+ // Send the create request and wait for the response.
+ //
+
+ Fcb = Icb->SuperType.Fcb;
+
+ if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
+
+ if (!IsFatNameValid(&Icb->SuperType.Fcb->RelativeFileName)) {
+
+ Iosb.Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
+
+ return( Iosb );
+
+ }
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "FbbJ", // NCP Create New File
+ NCP_CREATE_NEW_FILE,
+ Vcb->Specific.Disk.Handle,
+ CreateAttributes,
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "Nr=_b-dwwww",
+ Icb->Handle, sizeof( Icb->Handle ),
+ 14,
+ &Fcb->NonPagedFcb->Attributes,
+ &Fcb->NonPagedFcb->Header.FileSize,
+ &Fcb->CreationDate,
+ &Fcb->LastAccessDate,
+ &Fcb->LastModifiedDate,
+ &Fcb->LastModifiedTime );
+
+ Fcb->CreationTime = DEFAULT_TIME;
+
+ }
+
+ } else {
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "LbbWDDWbDbC",
+ NCP_LFN_OPEN_CREATE,
+ Vcb->Specific.Disk.LongNameSpace,
+ LFN_FLAG_OM_CREATE,
+ 0, // Search Flags
+ LFN_FLAG_INFO_ATTRIBUTES |
+ LFN_FLAG_INFO_FILE_SIZE |
+ LFN_FLAG_INFO_MODIFY_TIME |
+ LFN_FLAG_INFO_CREATION_TIME,
+ CreateAttributes,
+ 0, // Desired access
+ Vcb->Specific.Disk.VolumeNumber,
+ Vcb->Specific.Disk.Handle,
+ 0, // Short directory flag
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "Ne_e=e_xx_xx_x",
+ &Icb->Handle[2],
+ 6,
+ &Fcb->NonPagedFcb->Attributes,
+ &Fcb->NonPagedFcb->Header.FileSize,
+ 6,
+ &Fcb->CreationTime,
+ &Fcb->CreationDate,
+ 4,
+ &Fcb->LastModifiedTime,
+ &Fcb->LastModifiedDate,
+ 4,
+ &Fcb->LastAccessDate );
+ }
+ }
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
+ Icb->HasRemoteHandle = TRUE;
+ DebugTrace( 0, Dbg, "Attributes -> %08lx\n", Fcb->NonPagedFcb->Attributes );
+ DebugTrace( 0, Dbg, "FileSize.Low-> %08lx\n", Fcb->NonPagedFcb->Header.FileSize.LowPart );
+ DebugTrace( 0, Dbg, "ModifiedDate-> %08lx\n", Fcb->LastModifiedDate );
+ DebugTrace( 0, Dbg, "ModifiedTime-> %08lx\n", Fcb->LastModifiedTime );
+ DebugTrace( 0, Dbg, "CreationDate-> %08lx\n", Fcb->CreationDate );
+ DebugTrace( 0, Dbg, "CreationTime-> %08lx\n", Fcb->CreationTime );
+ DebugTrace( 0, Dbg, "LastAcceDate-> %08lx\n", Fcb->LastAccessDate );
+ }
+
+ if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
+ Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if ( !NT_SUCCESS( Iosb.Status ) ) {
+ return( Iosb );
+ }
+
+
+ //
+ // We've created the file, and the users wants shared access to the
+ // file. Close the file and reopen in sharing mode.
+ //
+
+ if ( CloseAndReopen ) {
+ CloseFile( IrpContext, Icb );
+ Iosb = OpenFile( IrpContext, Vcb, Icb, CreateAttributes, OpenFlags );
+ }
+
+ //
+ // If we need to set attributes, do it now. Ignore errors, if any.
+ //
+
+ if ( DelayedAttributes != 0 ) {
+
+ ExchangeWithWait(
+ IrpContext,
+ SynchronousResponseCallback,
+ "FbbbU",
+ NCP_SET_FILE_ATTRIBUTES,
+ DelayedAttributes,
+ Fcb->Vcb->Specific.Disk.Handle,
+ SEARCH_ALL_FILES,
+ &Fcb->RelativeFileName );
+
+ }
+
+ //
+ // Set information field assuming success. It will be ignored
+ // if the NCP failed.
+ //
+
+ Iosb.Information = FILE_CREATED;
+ return( Iosb );
+}
+
+
+IO_STATUS_BLOCK
+CreateOrOverwriteFile(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PICB Icb,
+ IN BYTE CreateAttributes,
+ IN BYTE OpenFlags,
+ IN BOOLEAN CreateOperation
+ )
+/*++
+
+Routine Description:
+
+ This routines creates a file on a netware server. If the file
+ exists it is overwritten.
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ Vcb - A pointer to the VCB for the remote drive.
+
+ Icb - A pointer to the ICB we are opening.
+
+ Attributes - Open attributes.
+
+ OpenFlags - Open mode and sharing mode flags.
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+{
+ IO_STATUS_BLOCK Iosb;
+ PFCB Fcb;
+ UCHAR DelayedAttributes;
+ BOOLEAN CloseAndReopen;
+
+ PAGED_CODE();
+
+ Fcb = Icb->SuperType.Fcb;
+
+ //
+ // Send the request and wait for the response.
+ //
+
+ if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
+
+ if (!IsFatNameValid(&Icb->SuperType.Fcb->RelativeFileName)) {
+
+ Iosb.Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
+
+ return( Iosb );
+
+ }
+
+ //
+ // If the user opens the file for shared access, then we will need to
+ // create the file close, then reopen it (since we have no NCP to say
+ // create with shared access). If the file is being created read-only,
+ // and the creator requests write access then we pull the additional
+ // trick of creating the file without the read-only, and set it later,
+ // so that the second open can succeed.
+ //
+
+ if ( ( CreateAttributes & NW_ATTRIBUTE_READ_ONLY ) &&
+ ( OpenFlags & NW_OPEN_FOR_WRITE ) ) {
+
+ DelayedAttributes = CreateAttributes;
+ CreateAttributes = 0;
+ } else {
+ DelayedAttributes = 0;
+ }
+
+ //
+ // Dos namespace create always returns the file exclusive.
+ //
+
+ if (!FlagOn(OpenFlags, NW_OPEN_EXCLUSIVE)) {
+ CloseAndReopen = TRUE;
+ } else {
+ CloseAndReopen = FALSE;
+ }
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "FbbJ",
+ NCP_CREATE_FILE,
+ Vcb->Specific.Disk.Handle,
+ CreateAttributes,
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "Nr=_b-dwwww",
+ Icb->Handle,
+ sizeof( Icb->Handle ),
+ 14,
+ &Fcb->NonPagedFcb->Attributes,
+ &Fcb->NonPagedFcb->Header.FileSize,
+ &Fcb->CreationDate,
+ &Fcb->LastAccessDate,
+ &Fcb->LastModifiedDate,
+ &Fcb->LastModifiedTime );
+
+ Fcb->CreationTime = DEFAULT_TIME;
+
+ }
+
+ //
+ // We've created the file, and the users wants shared access to the
+ // file. Close the file and reopen in sharing mode.
+ //
+
+ if (( NT_SUCCESS( Iosb.Status ) ) &&
+ ( CloseAndReopen )) {
+
+ CloseFile( IrpContext, Icb );
+ Iosb = OpenFile( IrpContext, Vcb, Icb, CreateAttributes, OpenFlags );
+ }
+
+ if ( DelayedAttributes != 0 ) {
+ ExchangeWithWait(
+ IrpContext,
+ SynchronousResponseCallback,
+ "FbbbU",
+ NCP_SET_FILE_ATTRIBUTES,
+ DelayedAttributes,
+ Fcb->Vcb->Specific.Disk.Handle,
+ SEARCH_ALL_FILES,
+ &Fcb->RelativeFileName );
+ }
+
+ } else {
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "LbbWDDWbDbC",
+ NCP_LFN_OPEN_CREATE,
+ Vcb->Specific.Disk.LongNameSpace,
+ LFN_FLAG_OM_OVERWRITE,
+ 0, // Search Flags
+ LFN_FLAG_INFO_ATTRIBUTES |
+ LFN_FLAG_INFO_FILE_SIZE |
+ LFN_FLAG_INFO_MODIFY_TIME |
+ LFN_FLAG_INFO_CREATION_TIME,
+ CreateAttributes,
+ OpenFlags, // DesiredAccess
+ Vcb->Specific.Disk.VolumeNumber,
+ Vcb->Specific.Disk.Handle,
+ 0, // Short directory flag
+ &Icb->SuperType.Fcb->RelativeFileName );
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "Ne_e=e_xx_xx_x",
+ &Icb->Handle[2],
+ 6,
+ &Fcb->NonPagedFcb->Attributes,
+ &Fcb->NonPagedFcb->Header.FileSize,
+ 6,
+ &Fcb->CreationTime,
+ &Fcb->CreationDate,
+ 4,
+ &Fcb->LastModifiedTime,
+ &Fcb->LastModifiedDate,
+ 4,
+ &Fcb->LastAccessDate );
+ }
+ }
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
+ Icb->HasRemoteHandle = TRUE;
+ DebugTrace( 0, Dbg, "Attributes -> %08lx\n", Fcb->NonPagedFcb->Attributes );
+ DebugTrace( 0, Dbg, "FileSize.Low-> %08lx\n", Fcb->NonPagedFcb->Header.FileSize.LowPart );
+ DebugTrace( 0, Dbg, "ModifiedDate-> %08lx\n", Fcb->LastModifiedDate );
+ DebugTrace( 0, Dbg, "ModifiedTime-> %08lx\n", Fcb->LastModifiedTime );
+ DebugTrace( 0, Dbg, "CreationDate-> %08lx\n", Fcb->CreationDate );
+ DebugTrace( 0, Dbg, "CreationTime-> %08lx\n", Fcb->CreationTime );
+ DebugTrace( 0, Dbg, "LastAccDate -> %08lx\n", Fcb->LastAccessDate );
+ } else {
+ return( Iosb );
+ }
+
+ //
+ // Set information field assuming success. It will be ignored
+ // if the NCP failed.
+ //
+
+ if ( CreateOperation) {
+ Iosb.Information = FILE_CREATED;
+ } else {
+ Iosb.Information = FILE_OVERWRITTEN;
+ }
+
+ return( Iosb );
+}
+
+
+IO_STATUS_BLOCK
+OpenRenameTarget(
+ IN PIRP_CONTEXT IrpContext,
+ IN PVCB Vcb,
+ IN PDCB Dcb,
+ IN PICB* Icb
+ )
+/*++
+
+Routine Description:
+
+ This routine opens a directory. If the filename provided specifies
+ a directory then the file/directory to be renamed will be put in this
+ directory.
+
+ If the target foo\bar does not exist or is a file then the source of
+ the rename must be a file and will end up in the directory foo with
+ the name bar
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ Vcb - A pointer to the VCB for the remote drive.
+
+ Dcb - A pointer to the DCB for relative opens. If NULL the FileName
+ is an full path name. If non NUL the FileName is relative to
+ this directory.
+
+ Icb - A pointer to where the address of the Icb is to be stored.
+
+Return Value:
+
+ NT_STATUS - Status of operation
+
+--*/
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ IO_STATUS_BLOCK Iosb;
+ PFCB Fcb;
+ BOOLEAN FullNameIsAFile;
+ BOOLEAN FullNameExists;
+ BOOLEAN PathIsAFile;
+
+#if 0
+ UNICODE_STRING Drive;
+ WCHAR DriveLetter;
+ UNICODE_STRING Server;
+ UNICODE_STRING Volume;
+ UNICODE_STRING FileName;
+#endif
+ UNICODE_STRING Path;
+ UNICODE_STRING FullName;
+ UNICODE_STRING CompleteName;
+ UNICODE_STRING VcbName;
+ PWCH pTrailingSlash;
+
+ USHORT i;
+ USHORT DcbNameLength;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "OpenRenameTarget\n", 0);
+
+ //
+ // Get the current IRP stack location
+ //
+
+ Irp = IrpContext->pOriginalIrp;
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Build a complete filename of the form \g:\server\volume\dir1\file
+ //
+
+ if ( Dcb != NULL ) {
+
+ //
+ // Strip to UID portion of the DCB name.
+ //
+
+ for ( i = 0 ; i < Dcb->FullFileName.Length / sizeof(WCHAR) ; i++ ) {
+ if ( Dcb->FullFileName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ break;
+ }
+ }
+
+ ASSERT( Dcb->FullFileName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR );
+
+ //
+ // Now build the full name by appending the file name to the DCB name.
+ //
+
+ DcbNameLength = Dcb->FullFileName.Length - ( i * sizeof(WCHAR) );
+ CompleteName.Length = DcbNameLength + IrpSp->FileObject->FileName.Length + sizeof( WCHAR);
+ CompleteName.MaximumLength = CompleteName.Length;
+ CompleteName.Buffer = ALLOCATE_POOL_EX( PagedPool, CompleteName.Length );
+
+ RtlCopyMemory(
+ CompleteName.Buffer,
+ Dcb->FullFileName.Buffer + i,
+ DcbNameLength );
+
+ CompleteName.Buffer[ DcbNameLength / sizeof(WCHAR) ] = L'\\';
+
+ RtlCopyMemory(
+ CompleteName.Buffer + DcbNameLength / sizeof(WCHAR ) + 1,
+ IrpSp->FileObject->FileName.Buffer,
+ IrpSp->FileObject->FileName.Length );
+
+ Dcb = NULL;
+
+ } else {
+
+ CompleteName = IrpSp->FileObject->FileName;
+
+ }
+
+ //
+ // Calculate the VCB name, without the UID prefix.
+ //
+
+ VcbName.Buffer = wcschr( Vcb->Name.Buffer, L'\\' );
+ VcbName.Length = Vcb->Name.Length -
+ ( (PCHAR)VcbName.Buffer - (PCHAR)Vcb->Name.Buffer );
+
+ //
+ // Calculate the target relative name. This is simply the complete
+ // name minus the VcbName and the leading backslash.
+ //
+
+ FullName.Buffer = CompleteName.Buffer + ( VcbName.Length / sizeof(WCHAR) ) + 1;
+ FullName.Length = CompleteName.Length -
+ ( (PCHAR)FullName.Buffer - (PCHAR)CompleteName.Buffer );
+
+ //
+ // Calculate the target directory relative name. This the the target
+ // full name, minus the last component of the name.
+ //
+
+ pTrailingSlash = FullName.Buffer + FullName.Length / sizeof(WCHAR) - 1;
+ for ( i = 0; i < FullName.Length ; i += sizeof(WCHAR) ) {
+ if ( *pTrailingSlash == L'\\' ) {
+ break;
+ }
+ --pTrailingSlash;
+ }
+
+
+ Path.Buffer = FullName.Buffer;
+
+ if ( i == FullName.Length ) {
+
+ //
+ // If no trailing slash was found, the the target path is the
+ // root directory.
+ //
+
+ Path.Length = 0;
+
+ } else {
+
+ Path.Length = (PCHAR)pTrailingSlash - (PCHAR)FullName.Buffer;
+
+ }
+
+#if 0
+ Iosb.Status = CrackPath(
+ &CompleteName,
+ &Drive,
+ &DriveLetter,
+ &Server,
+ &Volume,
+ &Path,
+ &FileName,
+ &FullName );
+#endif
+
+ Iosb.Status = FileOrDirectoryExists( IrpContext,
+ Vcb,
+ NULL,
+ &Path,
+ &PathIsAFile );
+
+ if ( !NT_SUCCESS( Iosb.Status) ) {
+
+ // The directory containing the file does not exist
+
+ return(Iosb);
+ }
+
+ Iosb.Status = FileOrDirectoryExists( IrpContext,
+ Vcb,
+ NULL,
+ &FullName,
+ &FullNameIsAFile );
+
+ if ( !NT_SUCCESS( Iosb.Status ) ) {
+ FullNameExists = FALSE;
+ Iosb.Information = FILE_DOES_NOT_EXIST;
+ } else {
+ FullNameExists = TRUE;
+ Iosb.Information = 0;
+ }
+
+ DebugTrace( 0, Dbg, "FullNameExists = %08lx\n", FullNameExists);
+ DebugTrace( 0, Dbg, "FullNameIsAFile = %08lx\n", FullNameIsAFile);
+
+ try {
+ UNICODE_STRING TargetPath;
+
+ //
+ // Find the FCB for this file. If the FCB exists, we get a
+ // referenced pointer. Otherwise a new FCB is created.
+ // The file is the complete path minus the target filename.
+ //
+
+ TargetPath = CompleteName;
+
+ Fcb = NwFindFcb( IrpContext->pScb, Vcb, &TargetPath, Dcb );
+
+ //
+ // Now create the ICB.
+ //
+
+ *Icb = NwCreateIcb( NW_NTC_ICB, Fcb );
+
+ (*Icb)->FileObject = IrpSp->FileObject;
+ NwSetFileObject( IrpSp->FileObject, Fcb->NonPagedFcb, *Icb );
+ (*Icb)->Exists = FullNameExists;
+ (*Icb)->IsAFile = FullNameIsAFile;
+
+ try_return(Iosb.Status = STATUS_SUCCESS);
+
+try_exit: NOTHING;
+
+ } finally {
+
+
+ if ( AbnormalTermination() || !NT_SUCCESS( Iosb.Status ) ) {
+
+ //
+ // Failed to create
+ //
+
+ if ( *Icb != NULL ) {
+ NwDeleteIcb( NULL, *Icb );
+ *Icb = NULL;
+ }
+ }
+ }
+
+ DebugTrace(-1, Dbg, "OpenRenameTarget\n", Iosb.Status);
+
+ return( Iosb );
+}
+
+
+IO_STATUS_BLOCK
+CreatePrintJob(
+ PIRP_CONTEXT IrpContext,
+ PVCB Vcb,
+ PICB Icb,
+ PUNICODE_STRING DriveName
+ )
+/*++
+
+Routine Description:
+
+ This routines create a new directory.
+
+Arguments:
+
+ IrpContext - Supplies all the information
+
+ Vcb - A pointer to the VCB for the remote print queue.
+
+ Icb - A pointer to the newly created ICB.
+
+ DriveName - LPTx
+
+Return Value:
+
+ IO_STATUS_BLOCK - Status of operation
+
+--*/
+{
+ IO_STATUS_BLOCK Iosb;
+ PFCB Fcb;
+ ANSI_STRING ODriveName;
+ static CHAR LptName[] = "LPT" ;
+
+ PAGED_CODE();
+
+ //
+ // Make sure the print queue name is correct.
+ //
+
+ if ( Icb->SuperType.Fcb->RelativeFileName.Length != 0 ) {
+ Iosb.Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
+ return( Iosb );
+ }
+
+ //
+ // Send a create queue job packet, and wait the response.
+ //
+
+ if ((DriveName->Length == 0 ) ||
+ (!NT_SUCCESS(RtlUnicodeStringToOemString( &ODriveName, DriveName, TRUE )))) {
+ //
+ // if we dont have a name, use the string "LPT". we do this because
+ // some printers insist on a name.
+ //
+
+ RtlInitString(&ODriveName, LptName);
+ }
+
+ Iosb.Status = ExchangeWithWait (
+ IrpContext,
+ SynchronousResponseCallback,
+ "Sd_ddw_b_r_bbwwww_x-x_", // Format string
+ NCP_ADMIN_FUNCTION, NCP_CREATE_QUEUE_JOB,
+ Vcb->Specific.Print.QueueId,// Queue ID
+ 6, // Skip bytes
+ 0xffffffff, // Target Server ID number
+ 0xffffffff, 0xffff, // Target Execution time
+ 11, // Skip bytes
+ 0x00, // Job Control Flags
+ 26, // Skip bytes
+ ODriveName.Buffer, ODriveName.Length, // Description
+ 50 - ODriveName.Length , // Description pad
+ 0, // Version number
+ 8, // Tab Size
+ 1, // Number of copies
+ NwPrintOptions, // Control Flags
+ 0x3C, // Maximum lines BUGBUG
+ 0x84, // Maximum characters BUGBUG
+ 22, // Skip bytes
+ &IrpContext->pScb->UserName, 12, // Banner Name
+ &Vcb->ShareName, 12, // Header Name
+ 1+14+80 // null last string & skip rest of client area
+ );
+
+ //
+ // free the string if it was allocated
+ //
+ if (ODriveName.Buffer != LptName)
+ RtlFreeAnsiString(&ODriveName);
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+ Iosb.Status = ParseResponse(
+ IrpContext,
+ IrpContext->rsp,
+ IrpContext->ResponseLength,
+ "N_w_r",
+ 22,
+ &Icb->JobId,
+ 18,
+ Icb->Handle, sizeof(Icb->Handle) );
+ }
+
+ if ( NT_SUCCESS( Iosb.Status ) ) {
+
+ Fcb = Icb->SuperType.Fcb;
+
+ Fcb->NonPagedFcb->Attributes = 0;
+ Fcb->CreationDate = 0;
+ Fcb->LastAccessDate = 0;
+ Fcb->LastModifiedDate = 0;
+ Fcb->LastModifiedTime = 0;
+
+ Icb->HasRemoteHandle = TRUE;
+ Icb->IsPrintJob = TRUE;
+ Icb->ActuallyPrinted = FALSE;
+
+ SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
+
+ }
+
+ //
+ // Set information field assuming success. It will be ignored
+ // if the NCP failed.
+ //
+
+ Iosb.Information = FILE_CREATED;
+
+ if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
+ Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
+ }
+
+
+ return( Iosb );
+}
+
+VOID
+CloseFile(
+ PIRP_CONTEXT pIrpContext,
+ PICB pIcb
+ )
+/*++
+
+Routine Description:
+
+ This routines closes an opened file.
+
+Arguments:
+
+ pIrpContext - Supplies all the information
+
+ pIcb - A pointer to the newly created ICB.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PAGED_CODE();
+
+ ExchangeWithWait(
+ pIrpContext,
+ SynchronousResponseCallback,
+ "F-r",
+ NCP_CLOSE,
+ pIcb->Handle, 6 );
+}
+