示例#1
0
VOID
NtfsUpdateScbFromFileObject (
    IN PIRP_CONTEXT IrpContext,
    IN PFILE_OBJECT FileObject,
    IN PSCB Scb,
    IN BOOLEAN CheckTimeStamps
    )

/*++

Routine Description:

    This routine is called to update the Scb/Fcb to reflect the changes to
    a file through the fast io path.  It only called with a file object which
    represents a user's handle.

Arguments:

    FileObject - This is the file object used in the fast io path.

    Scb - This is the Scb for this stream.

    CheckTimeStamps - Indicates whether we want to update the time stamps from the
        fast io flags as well.  This will be TRUE if our caller will update the standard information,
        attribute header and duplicate info.  FALSE if only the attribute header and duplicate info.
        The latter case is the valid data length callback from the cache manager.

Return Value:

    None.

--*/

{

    PFCB Fcb = Scb->Fcb;
    ULONG CcbFlags;
    ULONG ScbFlags = 0;
    LONGLONG CurrentTime;

    PAGED_CODE();

    //
    //  If the size of the main data stream is not part of the Fcb then update it
    //  now and set the correct Fcb flag.
    //

    if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {

        if (Fcb->Info.FileSize != Scb->Header.FileSize.QuadPart) {

            Fcb->Info.FileSize = Scb->Header.FileSize.QuadPart;
            SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_SIZE );
        }

        if (Fcb->Info.AllocatedLength != Scb->TotalAllocated) {

            Fcb->Info.AllocatedLength = Scb->TotalAllocated;
            SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE );
        }

        if (FlagOn( FileObject->Flags, FO_FILE_SIZE_CHANGED )) {

            SetFlag( ScbFlags, SCB_STATE_CHECK_ATTRIBUTE_SIZE );
        }

    //
    //  Remember to update the size in the attribute header for named streams as well.
    //

    } else if (FlagOn( FileObject->Flags, FO_FILE_SIZE_CHANGED )) {

        SetFlag( ScbFlags, SCB_STATE_NOTIFY_RESIZE_STREAM | SCB_STATE_CHECK_ATTRIBUTE_SIZE );
    }

    ClearFlag( FileObject->Flags, FO_FILE_SIZE_CHANGED );

    //
    //  Check whether to update the time stamps if our caller requested it.
    //

    if (CheckTimeStamps && !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {

        BOOLEAN UpdateLastAccess = FALSE;
        BOOLEAN UpdateLastChange = FALSE;
        BOOLEAN UpdateLastModify = FALSE;
        BOOLEAN SetArchive = TRUE;

        //
        //  Copy the Ccb flags to a local variable.  Then we won't have to test
        //  for the existence of the Ccb each time.
        //

        CcbFlags = 0;

        //
        //  Capture the real flags if present and clear them since we will update the Scb/Fcb.
        //

        if (FileObject->FsContext2 != NULL) {

            CcbFlags = ((PCCB) FileObject->FsContext2)->Flags;
            ClearFlag( ((PCCB) FileObject->FsContext2)->Flags,
                       (CCB_FLAG_UPDATE_LAST_MODIFY |
                        CCB_FLAG_UPDATE_LAST_CHANGE |
                        CCB_FLAG_SET_ARCHIVE) );
        }

        NtfsGetCurrentTime( IrpContext, CurrentTime );

        //
        //  If there was a write to the file then update the last change, last access
        //  and last write and the archive bit.
        //

        if (FlagOn( FileObject->Flags, FO_FILE_MODIFIED )) {

            UpdateLastModify =
            UpdateLastAccess =
            UpdateLastChange = TRUE;

        //
        //  Otherwise test each of the individual bits in the file object and
        //  Ccb.
        //

        } else {

            if (FlagOn( FileObject->Flags, FO_FILE_FAST_IO_READ )) {

                UpdateLastAccess = TRUE;
            }

            if (FlagOn( CcbFlags, CCB_FLAG_UPDATE_LAST_CHANGE )) {

                UpdateLastChange = TRUE;

                if (FlagOn( CcbFlags, CCB_FLAG_UPDATE_LAST_MODIFY )) {

                    UpdateLastModify = TRUE;
                }

                if (!FlagOn( CcbFlags, CCB_FLAG_SET_ARCHIVE )) {

                    SetArchive = FALSE;
                }
            }
        }

        //
        //  Now set the correct Fcb bits.
        //

        if (UpdateLastChange) {

            if (SetArchive) {

                SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ARCHIVE );
                SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR );
                SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
            }

            if (!FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_CHANGE_TIME )) {

                Fcb->Info.LastChangeTime = CurrentTime;
                SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_LAST_CHANGE );
                SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
            }

            if (UpdateLastModify) {

                //
                //  Remember a change to a named data stream.
                //

                if (!FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA ) &&
                    (Scb->AttributeTypeCode == $DATA)) {

                    SetFlag( ScbFlags, SCB_STATE_NOTIFY_MODIFY_STREAM );
                }

                if (!FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_MOD_TIME )) {

                    Fcb->Info.LastModificationTime = CurrentTime;
                    SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_LAST_MOD );
                    SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO );
                }
            }
        }

        if (UpdateLastAccess &&
            !FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_ACCESS_TIME ) &&
            !FlagOn( NtfsData.Flags, NTFS_FLAGS_DISABLE_LAST_ACCESS )) {

            Fcb->CurrentLastAccess = CurrentTime;
        }

        //
        //  Clear all of the fast io flags in the file object.
        //

        ClearFlag( FileObject->Flags, FO_FILE_MODIFIED | FO_FILE_FAST_IO_READ );
    }

    //
    //  Now store the Scb flags into the Scb.
    //

    if (ScbFlags) {

        NtfsAcquireFsrtlHeader( Scb );
        SetFlag( Scb->ScbState, ScbFlags );
        NtfsReleaseFsrtlHeader( Scb );
    }

    return;
}
示例#2
0
NTSTATUS
NtfsCommonLockControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for Lock Control called by both the fsd and fsp
    threads.

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;

    TYPE_OF_OPEN TypeOfOpen;
    PVCB Vcb;
    PFCB Fcb;
    PSCB Scb;
    PCCB Ccb;
    BOOLEAN FcbAcquired = FALSE;

    BOOLEAN OplockPostIrp;

    ASSERT_IRP_CONTEXT( IrpContext );
    ASSERT_IRP( Irp );

    PAGED_CODE();

    //
    //  Get a pointer to the current Irp stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace( +1, Dbg, ("NtfsCommonLockControl\n") );
    DebugTrace( 0, Dbg, ("IrpContext    = %08lx\n", IrpContext) );
    DebugTrace( 0, Dbg, ("Irp           = %08lx\n", Irp) );
    DebugTrace( 0, Dbg, ("MinorFunction = %08lx\n", IrpSp->MinorFunction) );

    //
    //  Extract and decode the type of file object we're being asked to process
    //

    FileObject = IrpSp->FileObject;
    TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );

    //
    //  If the file is not a user file open then we reject the request
    //  as an invalid parameter
    //

    if (TypeOfOpen != UserFileOpen) {

        NtfsCompleteRequest( &IrpContext, &Irp, STATUS_INVALID_PARAMETER );

        DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> STATUS_INVALID_PARAMETER\n") );
        return STATUS_INVALID_PARAMETER;
    }

    //
    //  Acquire exclusive access to the Fcb
    //

    if (Scb->ScbType.Data.FileLock == NULL) {

        NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, FALSE, FALSE );
        FcbAcquired = TRUE;

    } else {

        //NtfsAcquireSharedFcb( IrpContext, Fcb, Scb );
    }

    OplockPostIrp = FALSE;

    try {

        //
        //  We check whether we can proceed based on the state of the file oplocks.
        //  This call might post the irp for us.
        //

        Status = FsRtlCheckOplock( &Scb->ScbType.Data.Oplock,
                                   Irp,
                                   IrpContext,
                                   NtfsOplockComplete,
                                   NULL );

        if (Status != STATUS_SUCCESS) {

            OplockPostIrp = TRUE;
            try_return( NOTHING );
        }

        //
        //  If we don't have a file lock, then get one now.
        //

        if (Scb->ScbType.Data.FileLock == NULL) {

            NtfsCreateFileLock( Scb, TRUE );
        }

        //
        //  Now call the FsRtl routine to do the actual processing of the
        //  Lock request
        //

        Status = FsRtlProcessFileLock( Scb->ScbType.Data.FileLock, Irp, NULL );

        //
        //  Set the flag indicating if Fast I/O is possible
        //

        NtfsAcquireFsrtlHeader( Scb );
        Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
        NtfsReleaseFsrtlHeader( Scb );

    try_exit: NOTHING;
    } finally {

        DebugUnwind( NtfsCommonLockControl );

        //
        //  Release the Fcb, and return to our caller
        //

        if (FcbAcquired) {
            NtfsReleaseFcb( IrpContext, Fcb );
        }

        //
        //  Only if this is not an abnormal termination and we did not post the irp
        //  do we delete the irp context
        //

        if (!AbnormalTermination() && !OplockPostIrp) {

            NtfsCompleteRequest( &IrpContext, NULL, 0 );
        }

        DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> %08lx\n", Status) );
    }

    return Status;
}
示例#3
0
BOOLEAN
NtfsFastUnlockAllByKey (
    IN PFILE_OBJECT FileObject,
    PVOID ProcessId,
    ULONG Key,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This is a call back routine for doing the fast unlock all by key call.

Arguments:

    FileObject - Supplies the file object used in this operation

    ProcessId - Supplies the process ID used in this operation

    Key - Supplies the key used in this operation

    Status - Receives the Status if this operation is successful

Return Value:

    BOOLEAN - TRUE if this operation completed and FALSE if caller
        needs to take the long route.

--*/

{
    BOOLEAN Results;
    IRP_CONTEXT IrpContext;
    TYPE_OF_OPEN TypeOfOpen;
    PVCB Vcb;
    PFCB Fcb;
    PSCB Scb;
    PCCB Ccb;

    UNREFERENCED_PARAMETER( DeviceObject );

    PAGED_CODE();

    DebugTrace( +1, Dbg, ("NtfsFastUnlockAllByKey\n") );

    IoStatus->Information = 0;

    //
    //  Decode the type of file object we're being asked to process and
    //  make sure that is is only a user file open.
    //

    TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE );

    if (TypeOfOpen != UserFileOpen) {

        IoStatus->Status = STATUS_INVALID_PARAMETER;
        IoStatus->Information = 0;

        DebugTrace( -1, Dbg, ("NtfsFastUnlockAllByKey -> TRUE (STATUS_INVALID_PARAMETER)\n") );
        return TRUE;
    }

    //
    //  Acquire exclusive access to the Fcb this operation can always wait
    //

    FsRtlEnterFileSystem();

    if (Scb->ScbType.Data.FileLock == NULL) {

        (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE );

    } else {

        (VOID) ExAcquireResourceShared( Fcb->Resource, TRUE );
    }

    try {

        //
        //  We check whether we can proceed based on the state of the file oplocks.
        //

        if (!FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) {

            try_return( Results = FALSE );
        }

        //
        //  If we don't have a file lock, then get one now.
        //

        if (Scb->ScbType.Data.FileLock == NULL
            && !NtfsCreateFileLock( Scb, FALSE )) {

            try_return( Results = FALSE );
        }

        //
        //  Now call the FsRtl routine to do the actual processing of the
        //  Lock request.  The call will always succeed.
        //

        Results = TRUE;
        IoStatus->Status = FsRtlFastUnlockAllByKey( Scb->ScbType.Data.FileLock,
                                                    FileObject,
                                                    ProcessId,
                                                    Key,
                                                    NULL );

        //
        //  Set the flag indicating if Fast I/O is possible
        //

        NtfsAcquireFsrtlHeader( Scb );
        Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
        NtfsReleaseFsrtlHeader( Scb );

    try_exit:  NOTHING;
    } finally {

        DebugUnwind( NtfsFastUnlockAllByKey );

        //
        //  Release the Fcb, and return to our caller
        //

        ExReleaseResource( Fcb->Resource );

        FsRtlExitFileSystem();

        DebugTrace( -1, Dbg, ("NtfsFastUnlockAllByKey -> %08lx\n", Results) );
    }

    return Results;
}
示例#4
0
BOOLEAN
NtfsFastUnlockSingle (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN PLARGE_INTEGER Length,
    PEPROCESS ProcessId,
    ULONG Key,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This is a call back routine for doing the fast unlock single call.

Arguments:

    FileObject - Supplies the file object used in this operation

    FileOffset - Supplies the file offset used in this operation

    Length - Supplies the length used in this operation

    ProcessId - Supplies the process ID used in this operation

    Key - Supplies the key used in this operation

    Status - Receives the Status if this operation is successful

Return Value:

    BOOLEAN - TRUE if this operation completed and FALSE if caller
        needs to take the long route.

--*/

{
    BOOLEAN Results;
    PFCB Fcb;
    PSCB Scb;
    BOOLEAN ResourceAcquired = FALSE;

    UNREFERENCED_PARAMETER( DeviceObject );

    PAGED_CODE();

    DebugTrace( +1, Dbg, ("NtfsFastUnlockSingle\n") );

    IoStatus->Information = 0;

    //
    //  Decode the type of file object we're being asked to process and
    //  make sure that is is only a user file open.
    //

    if ((Scb = NtfsFastDecodeUserFileOpen( FileObject )) == NULL) {

        IoStatus->Status = STATUS_INVALID_PARAMETER;

        DebugTrace( -1, Dbg, ("NtfsFastUnlockSingle -> TRUE (STATUS_INVALID_PARAMETER)\n") );
        return TRUE;
    }

    Fcb = Scb->Fcb;

    //
    //  Acquire exclusive access to the Fcb this operation can always wait
    //

    FsRtlEnterFileSystem();

    if (Scb->ScbType.Data.FileLock == NULL) {

        (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE );
        ResourceAcquired = TRUE;

    } else {

        //(VOID) ExAcquireResourceShared( Fcb->Resource, TRUE );
    }

    try {

        //
        //  We check whether we can proceed based on the state of the file oplocks.
        //

        if ((Scb->ScbType.Data.Oplock != NULL) &&
            !FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) {

            try_return( Results = FALSE );
        }

        //
        //  If we don't have a file lock, then get one now.
        //

        if (Scb->ScbType.Data.FileLock == NULL
            && !NtfsCreateFileLock( Scb, FALSE )) {

            try_return( Results = FALSE );
        }

        //
        //  Now call the FsRtl routine to do the actual processing of the
        //  Lock request.  The call will always succeed.
        //

        Results = TRUE;
        IoStatus->Status = FsRtlFastUnlockSingle( Scb->ScbType.Data.FileLock,
                                                  FileObject,
                                                  FileOffset,
                                                  Length,
                                                  ProcessId,
                                                  Key,
                                                  NULL,
                                                  FALSE );

        //
        //  Set the flag indicating if Fast I/O is possible.  We are
        //  only concerned if there are no longer any filelocks on this
        //  file.
        //

        if (!FsRtlAreThereCurrentFileLocks( Scb->ScbType.Data.FileLock ) &&
            (Scb->Header.IsFastIoPossible != FastIoIsPossible)) {

            NtfsAcquireFsrtlHeader( Scb );
            Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
            NtfsReleaseFsrtlHeader( Scb );
        }

    try_exit:  NOTHING;
    } finally {

        DebugUnwind( NtfsFastUnlockSingle );

        //
        //  Release the Fcb, and return to our caller
        //

        if (ResourceAcquired) {
            ExReleaseResource( Fcb->Resource );
        }

        FsRtlExitFileSystem();

        DebugTrace( -1, Dbg, ("NtfsFastUnlockSingle -> %08lx\n", Results) );
    }

    return Results;
}
示例#5
0
NTSTATUS
NtfsCompleteMdl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine performs the function of completing Mdl read and write
    requests.  It should be called only from NtfsFsdRead and NtfsFsdWrite.

Arguments:

    Irp - Supplies the originating Irp.

Return Value:

    NTSTATUS - Will always be STATUS_PENDING or STATUS_SUCCESS.

--*/

{
    PFILE_OBJECT FileObject;
    PIO_STACK_LOCATION IrpSp;
    PNTFS_ADVANCED_FCB_HEADER Header;

    ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
    PAGED_CODE();

    DebugTrace( +1, Dbg, ("NtfsCompleteMdl\n") );
    DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
    DebugTrace( 0, Dbg, ("Irp        = %08lx\n", Irp) );

    //
    // Do completion processing.
    //

    FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;

    switch( IrpContext->MajorFunction ) {

    case IRP_MJ_READ:

        CcMdlReadComplete( FileObject, Irp->MdlAddress );
        break;

    case IRP_MJ_WRITE:

        try {

            PSCB Scb;
            VBO StartingVbo;
            LONGLONG ByteCount;
            LONGLONG ByteRange;
            BOOLEAN DoingIoAtEof = FALSE;

            ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT ));

            IrpSp = IoGetCurrentIrpStackLocation( Irp );
            Scb = (PSCB)(IrpSp->FileObject->FsContext);
            Header = &(Scb->Header);

            //
            //  Now synchronize with the FsRtl Header and Scb.
            //

            if (Header->PagingIoResource != NULL) {

                StartingVbo = IrpSp->Parameters.Write.ByteOffset.QuadPart;
                ByteCount = (LONGLONG) IrpSp->Parameters.Write.Length;
                ByteRange = StartingVbo + ByteCount + PAGE_SIZE - 1;
                ClearFlag( ((ULONG) ByteRange), PAGE_SIZE - 1 );

                ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
                NtfsAcquireFsrtlHeader( Scb );

                //
                //  Now see if this is at EOF.
                //  Recursive flush will generate IO which ends on page boundary
                //  which is why we rounded the range
                //

                if (ByteRange > Header->ValidDataLength.QuadPart) {

                    //
                    //  Mark that we are writing to EOF.  If someone else is currently
                    //  writing to EOF, wait for them.
                    //

                    ASSERT( ByteRange - StartingVbo < MAXULONG );

                    DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) ||
                                   NtfsWaitForIoAtEof( Header, (PLARGE_INTEGER)&StartingVbo, (ULONG)(ByteRange - StartingVbo) );

                    if (DoingIoAtEof) {

                        SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE );

#if (DBG || defined( NTFS_FREE_ASSERTS ))
                        ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread();
#endif
                        //
                        //  Store this in the IrpContext until commit or post.
                        //

                        IrpContext->CleanupStructure = Scb;
                    }
                }

                NtfsReleaseFsrtlHeader( Scb );
            }

            CcMdlWriteComplete( FileObject, &IrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress );

        } finally {

            if (Header->PagingIoResource != NULL) {

                ExReleaseResourceLite( Header->PagingIoResource );
            }
        }

        break;

    default:

        DebugTrace( DEBUG_TRACE_ERROR, 0, ("Illegal Mdl Complete.\n") );

        ASSERTMSG("Illegal Mdl Complete, About to bugcheck ", FALSE);
        NtfsBugCheck( IrpContext->MajorFunction, 0, 0 );
    }

    //
    // Mdl is now deallocated.
    //

    Irp->MdlAddress = NULL;

    //
    //  Ignore errors.  CC has already cleaned up his structures.
    //

    IrpContext->ExceptionStatus = STATUS_SUCCESS;
    NtfsMinimumExceptionProcessing( IrpContext );

    //
    // Complete the request and exit right away.
    //

    NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );

    DebugTrace( -1, Dbg, ("NtfsCompleteMdl -> STATUS_SUCCESS\n") );

    return STATUS_SUCCESS;
}
示例#6
0
VOID
NtfsCreateInternalStreamCommon (
    IN PIRP_CONTEXT IrpContext,
    IN PSCB Scb,
    IN BOOLEAN UpdateScb,
    IN BOOLEAN CompressedStream,
    IN UNICODE_STRING const *StreamName
    )

/*++

Routine Description:

    This routine is called to prepare a stream file associated with a
    particular attribute of a file.  On return, the Scb for the attribute
    will have an associated stream file object.  On return, this
    stream file will have been initialized through the cache manager.

    TEMPCODE  The following assumptions have been made or if open issue,
    still unresolved.

        - Assume.  The call to create Scb will initialize the Mcb for
          the non-resident case.

        - Assume.  When this file is created I increment the open count
          but not the unclean count for this Scb.  When we are done with
          the stream file, we should uninitialize it and dereference it.
          We also set the file object pointer to NULL.  Close will then
          do the correct thing.

        - Assume.  Since this call is likely to be followed shortly by
          either a read or write, the cache map is initialized here.

Arguments:

    Scb - Supplies the address to store the Scb for this attribute and
          stream file.  This will exist on return from this function.

    UpdateScb - Indicates if the caller wants to update the Scb from the
                attribute.

    CompressedStream - Supplies TRUE if caller wishes to create the
                       compressed stream.

    StreamName - Internal stream name or NULL is there isn't one available.
                 This is a constant value so we don't have to allocate any pool.

Return Value:

    None.

--*/

{
    PVCB Vcb = Scb->Vcb;

    CC_FILE_SIZES CcFileSizes;
    PFILE_OBJECT CallersFileObject;
    PFILE_OBJECT *FileObjectPtr = &Scb->FileObject;
    PFILE_OBJECT UnwindStreamFile = NULL;

    BOOLEAN UnwindInitializeCacheMap = FALSE;
    BOOLEAN DecrementScbCleanup = FALSE;

    BOOLEAN AcquiredMutex = FALSE;

    ASSERT_IRP_CONTEXT( IrpContext );

    PAGED_CODE();

    DebugTrace( +1, Dbg2, ("NtfsCreateInternalAttributeStream\n") );
    DebugTrace( 0, Dbg2, ("Scb        -> %08lx\n", Scb) );

    //
    //  Change FileObjectPtr if he wants the compressed stream
    //
#if (__NDAS_NTFS_DBG__ && __NDAS_NTFS_SECONDARY__) 
	if (FlagOn(Scb->Fcb->NdasNtfsFlags, NDAS_NTFS_FCB_FLAG_SECONDARY))
		ASSERT( FALSE );
#endif

#ifdef  COMPRESS_ON_WIRE
    if (CompressedStream) {
        FileObjectPtr = &Scb->Header.FileObjectC;
    }
#endif

    //
    //  If there is no file object, we create one and initialize
    //  it.
    //

    if (*FileObjectPtr == NULL) {

        //
        //  Only acquire the mutex if we don't have the file exclusive.
        //

        if (!NtfsIsExclusiveScb( Scb )) {

            KeWaitForSingleObject( &StreamFileCreationMutex, Executive, KernelMode, FALSE, NULL );
            AcquiredMutex = TRUE;
        }

        try {

            //
            //  Someone could have gotten there first.
            //

            if (*FileObjectPtr == NULL) {

                UnwindStreamFile = IoCreateStreamFileObjectLite( NULL, Scb->Vcb->Vpb->RealDevice);

                if (ARGUMENT_PRESENT( StreamName )) {
                    UnwindStreamFile->FileName.MaximumLength = StreamName->MaximumLength;
                    UnwindStreamFile->FileName.Length = StreamName->Length;
                    UnwindStreamFile->FileName.Buffer = StreamName->Buffer;
                }

                //
                //  Propagate any flags from the caller's FileObject to our
                //  stream file that the Cache Manager may look at, so we do not
                //  miss hints like sequential only or temporary.
                //

                if (!FlagOn(Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE) &&
                    (IrpContext->OriginatingIrp != NULL) &&
                    (CallersFileObject = IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->FileObject)) {

                    SetFlag( UnwindStreamFile->Flags,
                             CallersFileObject->Flags & NTFS_FO_PROPAGATE_TO_STREAM );
                }

                UnwindStreamFile->SectionObjectPointer = &Scb->NonpagedScb->SegmentObject;

                //
                //  For a compressed stream, we have to use separate section
                //  object pointers.
                //

#ifdef  COMPRESS_ON_WIRE
                if (CompressedStream) {
                    UnwindStreamFile->SectionObjectPointer = &Scb->NonpagedScb->SegmentObjectC;

                }
#endif

                //
                //  If we have created the stream file, we set it to type
                //  'StreamFileOpen'
                //

                NtfsSetFileObject( UnwindStreamFile,
                                   StreamFileOpen,
                                   Scb,
                                   NULL );

                if (FlagOn( Scb->ScbState, SCB_STATE_TEMPORARY )) {

                    SetFlag( UnwindStreamFile->Flags, FO_TEMPORARY_FILE );
                }

                //
                //  Initialize the fields of the file object.
                //

                UnwindStreamFile->ReadAccess = TRUE;
                UnwindStreamFile->WriteAccess = TRUE;
                UnwindStreamFile->DeleteAccess = TRUE;

                //
                //  Increment the open count and set the section
                //  object pointers.  We don't set the unclean count as the
                //  cleanup call has already occurred.
                //

                NtfsIncrementCloseCounts( Scb, TRUE, FALSE );

                //
                //  Increment the cleanup count in this Scb to prevent the
                //  Scb from going away if the cache call fails.
                //

                InterlockedIncrement( &Scb->CleanupCount );
                DecrementScbCleanup = TRUE;

                //
                //  If the Scb header has not been initialized, we will do so now.
                //

                if (UpdateScb
                    && !FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {

                    NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
                }

                //
                //  If this is a compressed stream and the file is not already
                //  marked as MODIFIED_NO_WRITE then do it now.  Use the
                //  Extended flag field in the Fsrtl header for this.  Since this
                //  is the only place we make this call with FsContext2 == NULL,
                //  it does not matter how we leave the FsRtl header flag.!
                //

                NtfsAcquireFsrtlHeader( Scb );
                ClearFlag(Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE);
                if (!FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE ) &&
                    !FlagOn( Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE ) &&
                    !CompressedStream) {

                    SetFlag(Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE);
                }
                NtfsReleaseFsrtlHeader( Scb );

                //
                //  Check if we need to initialize the cache map for the stream file.
                //  The size of the section to map will be the current allocation
                //  for the stream file.
                //

                if (UnwindStreamFile->PrivateCacheMap == NULL) {

                    BOOLEAN PinAccess;

                    CcFileSizes = *(PCC_FILE_SIZES)&Scb->Header.AllocationSize;

                    //
                    //  If this is a stream with Usa protection, we want to tell
                    //  the Cache Manager we do not need to get any valid data
                    //  callbacks.  We do this by having xxMax sitting in
                    //  ValidDataLength for the call, but we have to restore the
                    //  correct value afterwards.
                    //
                    //  We also do this for all of the stream files created during
                    //  restart.  This has the effect of telling Mm to always
                    //  fault the page in from disk.  Don't generate a zero page if
                    //  push up the file size during restart.
                    //

                    if (FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE )) {

                        CcFileSizes.ValidDataLength.QuadPart = MAXLONGLONG;
                    }

                    PinAccess =
                        (BOOLEAN) (Scb->AttributeTypeCode != $DATA ||
                                   FlagOn(Scb->Fcb->FcbState, FCB_STATE_PAGING_FILE | FCB_STATE_SYSTEM_FILE) ||
                                   FlagOn( Scb->Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS ) ||
                                   CompressedStream);

                    //
                    //  Bias this for the Usn journal.
                    //

                    if (FlagOn( Scb->ScbPersist, SCB_PERSIST_USN_JOURNAL )) {

                        CcFileSizes.AllocationSize.QuadPart -= Vcb->UsnCacheBias;
                        CcFileSizes.FileSize.QuadPart -= Vcb->UsnCacheBias;
                    }

                    CcInitializeCacheMap( UnwindStreamFile,
                                          &CcFileSizes,
                                          PinAccess,
                                          &NtfsData.CacheManagerCallbacks,
                                          (PCHAR)Scb + CompressedStream );

                    UnwindInitializeCacheMap = TRUE;
                }

                //
                //  Now call Cc to set the log handle for the file.
                //

                if (FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE ) &&
                    (Scb != Vcb->LogFileScb)) {

                    CcSetLogHandleForFile( UnwindStreamFile,
                                           Vcb->LogHandle,
                                           &LfsFlushToLsn );
                }

                //
                //  It is now safe to store the stream file in the Scb.  We wait
                //  until now because we don't want an unsafe tester to use the
                //  file object until the cache is initialized.
                //

                *FileObjectPtr = UnwindStreamFile;
            }

        } finally {

            DebugUnwind( NtfsCreateInternalAttributeStream );

            //
            //  Undo our work if an error occurred.
            //

            if (AbnormalTermination()) {

                //
                //  Uninitialize the cache file if we initialized it.
                //

                if (UnwindInitializeCacheMap) {

                    CcUninitializeCacheMap( UnwindStreamFile, NULL, NULL );
                }

                //
                //  Dereference the stream file if we created it.
                //

                if (UnwindStreamFile != NULL) {

                    //
                    //  Clear the internal file name constant
                    //

                    NtfsClearInternalFilename( UnwindStreamFile );

                    ObDereferenceObject( UnwindStreamFile );
                }
            }

            //
            //  Restore the Scb cleanup count.
            //

            if (DecrementScbCleanup) {

                InterlockedDecrement( &Scb->CleanupCount );
            }

            if (AcquiredMutex) {

                KeReleaseMutant( &StreamFileCreationMutex, IO_NO_INCREMENT, FALSE, FALSE );
            }

            DebugTrace( -1, Dbg2, ("NtfsCreateInternalAttributeStream -> VOID\n") );
        }
    }

    return;
}