/*++

Copyright (c) 1989 - 1999 Microsoft Corporation

Module Name:

    netroot.c

Abstract:

    This module implements the routines for creating the net root.

--*/

#include "precomp.h"
#pragma hdrstop

//
//  The local debug trace level
//

RXDT_DefineCategory(NETROOT);
#define Dbg                 (DEBUG_TRACE_NETROOT)

//
// Forward declarations ...
//

NTSTATUS
NullMiniInitializeNetRootEntry(
    IN PMRX_NET_ROOT pNetRoot
    );

NTSTATUS
NulMRxUpdateNetRootState(
    IN OUT PMRX_NET_ROOT pNetRoot)
/*++

Routine Description:

   This routine updates the mini redirector state associated with a net root.

Arguments:

    pNetRoot - the net root instance.

Return Value:

    NTSTATUS - The return status for the operation

Notes:

    By diffrentiating the mini redirector state from the net root condition it is possible
    to permit a variety of reconnect strategies. It is conceivable that the RDBSS considers
    a net root to be good while the underlying mini redirector might mark it as invalid
    and reconnect on the fly.

--*/
{
    NTSTATUS Status = STATUS_NOT_IMPLEMENTED;

    RxDbgTrace(0, Dbg, ("NulMRxUpdateNetRootState \n"));
    return(Status);
}

NTSTATUS
NulMRxInitializeNetRootEntry(
    IN PMRX_NET_ROOT pNetRoot
    )
/*++

Routine Description:

    This routine initializes a new net root.
    It also validates rootnames. Eg: attempts to create a
    file in a root that has not been created will fail.

Arguments:

    pNetRoot - the net root
    
Return Value:

    NTSTATUS - The return status for the operation

Notes:

--*/
{
    NTSTATUS  Status = STATUS_SUCCESS;
    PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
    UNICODE_STRING RootName;
    PNULMRX_NETROOT_EXTENSION pNetRootExtension = 
        (PNULMRX_NETROOT_EXTENSION)pNetRoot->Context;

    //
    //  A valid new NetRoot is being created
    //
    RxResetNetRootExtension(pNetRootExtension);
    return Status;
}

NTSTATUS
NulMRxCreateVNetRoot(
    IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
    )
/*++

Routine Description:

   This routine patches the RDBSS created net root instance with the information required
   by the mini redirector.

Arguments:

    pVNetRoot - the virtual net root instance.

    pCreateNetRootContext - the net root context for calling back

Return Value:

    NTSTATUS - The return status for the operation

Notes:

--*/
{
    NTSTATUS        Status;
    PRX_CONTEXT     pRxContext = pCreateNetRootContext->RxContext;
    PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot;
    
    PMRX_SRV_CALL   pSrvCall;
    PMRX_NET_ROOT   pNetRoot;

	BOOLEAN Verifyer = FALSE;
    BOOLEAN  fTreeConnectOpen = TRUE; // RxContext->Create.ThisIsATreeConnectOpen;
    BOOLEAN  fInitializeNetRoot;

    RxDbgTrace(0, Dbg, ("NulMRxCreateVNetRoot\n"));
   
    pNetRoot = pVNetRoot->pNetRoot;
    pSrvCall = pNetRoot->pSrvCall;

    // The V_NET_ROOT is associated with a NET_ROOT. The two cases of interest are as
    // follows
    // 1) the V_NET_ROOT and the associated NET_ROOT are being newly created.   
    // 2) a new V_NET_ROOT associated with an existing NET_ROOT is being created.
    //
    // These two cases can be distinguished by checking if the context associated with
    // NET_ROOT is NULL. Since the construction of NET_ROOT's/V_NET_ROOT's are serialized
    // by the wrapper this is a safe check.
    // ( The wrapper cannot have more then one thread tryingto initialize the same
    // NET_ROOT).
    //
    // The above is not really true in our case. Since we have asked the wrapper,
    // to manage our netroot extension, the netroot context will always be non-NULL.
    // We will distinguish the cases by checking our root state in the context...
    //

    if(pNetRoot->Context == NULL) {
        fInitializeNetRoot = TRUE;
    } else {
        {NulMRxGetNetRootExtension(pNetRoot,pNetRootExtension);
         fInitializeNetRoot = TRUE;
        }
    }

    ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
        (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));

    Status = STATUS_SUCCESS;

    // update the net root state to be good.

    if (fInitializeNetRoot) {
		PWCHAR		pRootName;
		ULONG		RootNameLength;

		pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;

		// validate the fixed netroot name

		RootNameLength = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;

		if ( RootNameLength >= 12 )
		{
			pRootName = (PWCHAR) (pNetRoot->pNetRootName->Buffer +
			                      (pSrvCall->pSrvCallName->Length / sizeof(WCHAR)));
		
			Verifyer  = ( pRootName[0] == L'\\' );
			Verifyer &= ( pRootName[1] == L'S' )  || ( pRootName[1] == L's' );
			Verifyer &= ( pRootName[2] == L'H' )  || ( pRootName[2] == L'h' );
			Verifyer &= ( pRootName[3] == L'A' )  || ( pRootName[3] == L'a' );
			Verifyer &= ( pRootName[4] == L'R' )  || ( pRootName[4] == L'r' );
			Verifyer &= ( pRootName[5] == L'E' )  || ( pRootName[5] == L'e' );
			Verifyer &= ( pRootName[6] == L'\\' ) || ( pRootName[6] == L'\0' );
		}
		if ( !Verifyer )
		{
			Status = STATUS_BAD_NETWORK_NAME;
		}

    } else {
        DbgPrint("Creating V_NET_ROOT on existing NET_ROOT\n");
    }

    if( (Status == STATUS_SUCCESS) && fInitializeNetRoot )
    {  
        //
        //  A new NET_ROOT and associated V_NET_ROOT are being created !
        //
        Status = NulMRxInitializeNetRootEntry(pNetRoot);
        RxDbgTrace(0, Dbg, ("NulMRXInitializeNetRootEntry %lx\n",Status));
    }

    if (Status != STATUS_PENDING) {
        pCreateNetRootContext->VirtualNetRootStatus = Status;
        if (fInitializeNetRoot) {
            pCreateNetRootContext->NetRootStatus = Status;
        } else {
            pCreateNetRootContext->NetRootStatus = Status;
        }

        // Callback the RDBSS for resumption.
        pCreateNetRootContext->Callback(pCreateNetRootContext);

        // Map the error code to STATUS_PENDING since this triggers 
        // the synchronization mechanism in the RDBSS.
        Status = STATUS_PENDING;
   }

   return Status;
}

NTSTATUS
NulMRxFinalizeVNetRoot(
    IN PMRX_V_NET_ROOT pVNetRoot,
    IN PBOOLEAN        ForceDisconnect)
/*++

Routine Description:


Arguments:

    pVNetRoot - the virtual net root

    ForceDisconnect - disconnect is forced

Return Value:

    NTSTATUS - The return status for the operation

--*/
{
   RxDbgTrace(0, Dbg, ("NulMRxFinalizeVNetRoot %lx\n",pVNetRoot));
   return STATUS_SUCCESS;
}


NTSTATUS
NulMRxFinalizeNetRoot(
    IN PMRX_NET_ROOT   pNetRoot,
    IN PBOOLEAN        ForceDisconnect)
/*++

Routine Description:


Arguments:

    pVirtualNetRoot - the virtual net root

    ForceDisconnect - disconnect is forced

Return Value:

    NTSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    NulMRxGetNetRootExtension(pNetRoot,pNetRootExtension);

    RxDbgTrace(0, Dbg, ("NulMRxFinalizeNetRoot \n"));

    //
    //  This is called when all outstanding handles on this
    //  root have been cleaned up ! We can now zap the netroot
    //  extension...
    //

    return(Status);
}

VOID
NulMRxExtractNetRootName(
    IN PUNICODE_STRING FilePathName,
    IN PMRX_SRV_CALL   SrvCall,
    OUT PUNICODE_STRING NetRootName,
    OUT PUNICODE_STRING RestOfName OPTIONAL
    )
/*++

Routine Description:

    This routine parses the input name into srv, netroot, and the
    rest.

Arguments:


--*/
{
    UNICODE_STRING xRestOfName;

    ULONG length = FilePathName->Length;
    PWCH w = FilePathName->Buffer;
    PWCH wlimit = (PWCH)(((PCHAR)w)+length);
    PWCH wlow;

    RxDbgTrace(0, Dbg, ("NulMRxExtractNetRootName \n"));
    
    w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR));
    NetRootName->Buffer = wlow = w;
    for (;;) {
        if (w>=wlimit) break;
        if ( (*w == OBJ_NAME_PATH_SEPARATOR) && (w!=wlow) ){
            break;
        }
        w++;
    }
    
    NetRootName->Length = NetRootName->MaximumLength
                = (USHORT)((PCHAR)w - (PCHAR)wlow);
                
    //w = FilePathName->Buffer;
    //NetRootName->Buffer = w++;

    if (!RestOfName) RestOfName = &xRestOfName;
    RestOfName->Buffer = w;
    RestOfName->Length = (USHORT)RestOfName->MaximumLength
                       = (USHORT)((PCHAR)wlimit - (PCHAR)w);

    RxDbgTrace(0, Dbg, ("  NulMRxExtractNetRootName FilePath=%wZ\n",FilePathName));
    RxDbgTrace(0, Dbg, ("         Srv=%wZ,Root=%wZ,Rest=%wZ\n",
                        SrvCall->pSrvCallName,NetRootName,RestOfName));

    return;
}