示例#1
0
NTSTATUS _InitializePrefixTableEntryAllocation(PDFS_PREFIX_TABLE pTable)
{
    NTSTATUS status = STATUS_SUCCESS;

#ifdef KERNEL_MODE
    PVOID    pSegment = NULL;

    pSegment = ExAllocatePool(PagedPool,PREFIX_TABLE_ENTRY_SEGMENT_SIZE);
    if (pSegment != NULL)
    {
        status = ExInitializeZone(&pTable->PrefixTableEntryZone,
                                  QuadAlign(sizeof(DFS_PREFIX_TABLE_ENTRY)),
                                  pSegment,
                                  PREFIX_TABLE_ENTRY_SEGMENT_SIZE);
    }
    else
        status = STATUS_NO_MEMORY;
#endif

    return  status;
}
示例#2
0
文件: fileinfo.c 项目: Driim/dokany
NTSTATUS
DokanFindStreams(PFILE_STREAM_INFORMATION StreamInfo, PDOKAN_FILE_INFO FileInfo,
                 PEVENT_CONTEXT EventContext, PDOKAN_INSTANCE DokanInstance,
                 PULONG RemainingLength) {
  PDOKAN_OPEN_INFO openInfo =
      (PDOKAN_OPEN_INFO)(UINT_PTR)FileInfo->DokanContext;
  NTSTATUS status = STATUS_SUCCESS;

  if (!DokanInstance->DokanOperations->FindStreams) {
    return STATUS_NOT_IMPLEMENTED;
  }

  if (openInfo->StreamListHead == NULL) {
    openInfo->StreamListHead = malloc(sizeof(LIST_ENTRY));
    if (openInfo->StreamListHead != NULL) {
      InitializeListHead(openInfo->StreamListHead);
    } else {
      status = STATUS_NO_MEMORY;
    }
  }

  if (status == STATUS_SUCCESS && IsListEmpty(openInfo->StreamListHead)) {
    status = DokanInstance->DokanOperations->FindStreams(
        EventContext->Operation.File.FileName, DokanFillFindStreamData,
        FileInfo);
  }

  if (status == STATUS_SUCCESS) {
    PLIST_ENTRY listHead, entry;
    ULONG entrySize;

    listHead = openInfo->StreamListHead;
    entrySize = 0;

    for (entry = listHead->Flink; entry != listHead; entry = entry->Flink) {
      PDOKAN_FIND_STREAM_DATA find =
          CONTAINING_RECORD(entry, DOKAN_FIND_STREAM_DATA, ListEntry);

      ULONG nextEntryOffset = entrySize;

      ULONG streamNameLength =
          (ULONG)wcslen(find->FindStreamData.cStreamName) * sizeof(WCHAR);
      entrySize = sizeof(FILE_STREAM_INFORMATION) + streamNameLength;
      // Must be align on a 8-byte boundary.
      entrySize = QuadAlign(entrySize);
      if (*RemainingLength < entrySize) {
        status = STATUS_BUFFER_OVERFLOW;
        break;
      }

      // Not the first entry, set the offset before filling the new entry
      if (nextEntryOffset > 0) {
        StreamInfo->NextEntryOffset = nextEntryOffset;
        StreamInfo = (PFILE_STREAM_INFORMATION)((LPBYTE)StreamInfo +
                                                StreamInfo->NextEntryOffset);
      }

      // Fill the new entry
      StreamInfo->StreamNameLength = streamNameLength;
      memcpy(StreamInfo->StreamName, find->FindStreamData.cStreamName,
             streamNameLength);
      StreamInfo->StreamSize = find->FindStreamData.StreamSize;
      StreamInfo->StreamAllocationSize = find->FindStreamData.StreamSize;
      StreamInfo->NextEntryOffset = 0;
      ALIGN_ALLOCATION_SIZE(&StreamInfo->StreamAllocationSize);

      *RemainingLength -= entrySize;
    }

    if (status != STATUS_BUFFER_OVERFLOW) {
      ClearFindStreamData(openInfo->StreamListHead);
    }

  } else {
    ClearFindStreamData(openInfo->StreamListHead);
  }

  return status;
}
示例#3
0
NTSTATUS
NdasFatSecondaryQueryDirectory (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine performs the query directory operation.  It is responsible
    for either completing of enqueuing the input Irp.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;

    PVCB Vcb;
    PDCB Dcb;
    PCCB Ccb;
    PBCB Bcb;

    ULONG i;
    PUCHAR Buffer;
    CLONG UserBufferLength;

    PUNICODE_STRING UniArgFileName;
    WCHAR LongFileNameBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE];
    UNICODE_STRING LongFileName;
    FILE_INFORMATION_CLASS FileInformationClass;
    ULONG FileIndex;
    BOOLEAN RestartScan;
    BOOLEAN ReturnSingleEntry;
    BOOLEAN IndexSpecified;

    BOOLEAN InitialQuery;
    VBO CurrentVbo;
    BOOLEAN UpdateCcb;
    PDIRENT Dirent;
    UCHAR Fat8Dot3Buffer[12];
    OEM_STRING Fat8Dot3String;
    ULONG DiskAllocSize;

    ULONG NextEntry;
    ULONG LastEntry;

    PFILE_DIRECTORY_INFORMATION DirInfo;
    PFILE_FULL_DIR_INFORMATION FullDirInfo;
    PFILE_BOTH_DIR_INFORMATION BothDirInfo;
    PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo;
    PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo;
    PFILE_NAMES_INFORMATION NamesInfo;

#if 1

	PVOLUME_DEVICE_OBJECT		volDo;
	BOOLEAN						secondarySessionResourceAcquired = FALSE;

	PSECONDARY_REQUEST			secondaryRequest = NULL;

	PNDFS_REQUEST_HEADER		ndfsRequestHeader;
	PNDFS_WINXP_REQUEST_HEADER	ndfsWinxpRequestHeader;
	PNDFS_WINXP_REPLY_HEADER	ndfsWinxpReplytHeader;
	_U8							*ndfsWinxpRequestData;

	LARGE_INTEGER				timeOut;

	struct QueryDirectory		queryDirectory;
	PVOID						inputBuffer;
	ULONG						inputBufferLength;

	ULONG						returnedDataSize;

#endif

    PAGED_CODE();

    //
    //  Get the current Stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    //
    //  Display the input values.
    //
    DebugTrace(+1, Dbg, "FatQueryDirectory...\n", 0);
    DebugTrace( 0, Dbg, " Wait                   = %08lx\n", FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
    DebugTrace( 0, Dbg, " Irp                    = %08lx\n", Irp);
    DebugTrace( 0, Dbg, " ->Length               = %08lx\n", IrpSp->Parameters.QueryDirectory.Length);
    DebugTrace( 0, Dbg, " ->FileName             = %08lx\n", IrpSp->Parameters.QueryDirectory.FileName);
    DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
    DebugTrace( 0, Dbg, " ->FileIndex            = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex);
    DebugTrace( 0, Dbg, " ->UserBuffer           = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
    DebugTrace( 0, Dbg, " ->RestartScan          = %08lx\n", FlagOn( IrpSp->Flags, SL_RESTART_SCAN ));
    DebugTrace( 0, Dbg, " ->ReturnSingleEntry    = %08lx\n", FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY ));
    DebugTrace( 0, Dbg, " ->IndexSpecified       = %08lx\n", FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED ));

    //
    //  Reference our input parameters to make things easier
    //

    UserBufferLength = IrpSp->Parameters.QueryDirectory.Length;

    FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
    FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;

    UniArgFileName = (PUNICODE_STRING) IrpSp->Parameters.QueryDirectory.FileName;

    RestartScan       = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
    ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
    IndexSpecified    = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);

    //
    //  Check on the type of open.  We return invalid parameter for all
    //  but UserDirectoryOpens.  Also check that the filename is a valid
    //  UNICODE string.
    //
    
    if (FatDecodeFileObject( IrpSp->FileObject,
                             &Vcb,
                             &Dcb,
                             &Ccb) != UserDirectoryOpen ||
        (UniArgFileName &&
         UniArgFileName->Length % sizeof(WCHAR))) {

        FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
        DebugTrace(-1, Dbg, "FatQueryDirectory -> STATUS_INVALID_PARAMETER\n", 0);

        return STATUS_INVALID_PARAMETER;
    }

#if 1

	 if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) {

		 ASSERT( FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) );

		 FatCompleteRequest( IrpContext, Irp, STATUS_FILE_CORRUPT_ERROR );

		 DebugTrace2( -1, Dbg, ("NtfsCommonDirectoryControl -> STATUS_FILE_CORRUPT_ERROR\n") );
		 return STATUS_FILE_CORRUPT_ERROR;
	 }

#endif


    //
    //  Initialize the local variables.
    //

    Bcb = NULL;
    UpdateCcb = TRUE;
    Dirent = NULL;

    Fat8Dot3String.MaximumLength = 12;
    Fat8Dot3String.Buffer = Fat8Dot3Buffer;

    LongFileName.Length = 0;
    LongFileName.MaximumLength = sizeof( LongFileNameBuffer);
    LongFileName.Buffer = LongFileNameBuffer;

    InitialQuery = (BOOLEAN)((Ccb->UnicodeQueryTemplate.Buffer == NULL) &&
                             !FlagOn(Ccb->Flags, CCB_FLAG_MATCH_ALL));
    Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;

    DiskAllocSize = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;

    //
    //  If this is the initial query, then grab exclusive access in
    //  order to update the search string in the Ccb.  We may
    //  discover that we are not the initial query once we grab the Fcb
    //  and downgrade our status.
    //

    if (InitialQuery) {

        if (!FatAcquireExclusiveFcb( IrpContext, Dcb )) {

            DebugTrace(0, Dbg, "FatQueryDirectory -> Enqueue to Fsp\n", 0);
            Status = FatFsdPostRequest( IrpContext, Irp );
            DebugTrace(-1, Dbg, "FatQueryDirectory -> %08lx\n", Status);

            return Status;
        }

        if (Ccb->UnicodeQueryTemplate.Buffer != NULL) {

            InitialQuery = FALSE;

            FatConvertToSharedFcb( IrpContext, Dcb );
        }

    } else {

        if (!FatAcquireSharedFcb( IrpContext, Dcb )) {

            DebugTrace(0, Dbg, "FatQueryDirectory -> Enqueue to Fsp\n", 0);
            Status = FatFsdPostRequest( IrpContext, Irp );
            DebugTrace(-1, Dbg, "FatQueryDirectory -> %08lx\n", Status);

            return Status;

        }
    }

    try {

        ULONG BaseLength;
        ULONG BytesConverted;

        //
        // If we are in the Fsp now because we had to wait earlier,
        // we must map the user buffer, otherwise we can use the
        // user's buffer directly.
        //

        Buffer = FatMapUserBuffer( IrpContext, Irp );

#if 1

		volDo = CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb );

		secondarySessionResourceAcquired 
			= SecondaryAcquireResourceExclusiveLite( IrpContext, 
													 &volDo->SessionResource, 
													 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );

		
		if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) {

			NDASFAT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
			SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST );
			FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
		}

		queryDirectory.FileIndex			= IrpSp->Parameters.QueryDirectory.FileIndex;
		queryDirectory.FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
		queryDirectory.FileName				= IrpSp->Parameters.QueryDirectory.FileName;
		queryDirectory.Length				= IrpSp->Parameters.QueryDirectory.Length;

		inputBuffer			= (queryDirectory.FileName) ? (queryDirectory.FileName->Buffer) : NULL;
		inputBufferLength	= (queryDirectory.FileName) ? (queryDirectory.FileName->Length) : 0;

		if (queryDirectory.FileName) {

			DebugTrace2( 0, Dbg, ("NdNtfsSecondaryQueryDirectory: queryFileName = %wZ\n", queryDirectory.FileName) );
		}

		ASSERT( inputBufferLength <= volDo->Secondary->Thread.SessionContext.PrimaryMaxDataSize );
		ASSERT( UserBufferLength <= volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize );

		secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, 
														  IRP_MJ_DIRECTORY_CONTROL,
														  ((inputBufferLength > UserBufferLength) ? inputBufferLength : UserBufferLength) );

		if (secondaryRequest == NULL) {

			try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
		}

		ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader;
		INITIALIZE_NDFS_REQUEST_HEADER(	ndfsRequestHeader, 
										NDFS_COMMAND_EXECUTE, 
										volDo->Secondary, 
										IRP_MJ_DIRECTORY_CONTROL, 
										inputBufferLength );

		ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1);
		ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData );
		INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, Irp, IrpSp, Ccb->PrimaryFileHandle );

		ndfsWinxpRequestHeader->QueryDirectory.Length				= UserBufferLength;
		ndfsWinxpRequestHeader->QueryDirectory.FileInformationClass	= queryDirectory.FileInformationClass;
		ndfsWinxpRequestHeader->QueryDirectory.FileIndex			= queryDirectory.FileIndex;

		ndfsWinxpRequestData = (_U8 *)(ndfsWinxpRequestHeader+1);
		if (inputBufferLength)
			RtlCopyMemory( ndfsWinxpRequestData, inputBuffer, inputBufferLength );

		secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE;
		QueueingSecondaryRequest( volDo->Secondary, secondaryRequest );

		timeOut.QuadPart = -NDASFAT_TIME_OUT;		
		Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut );
		
		KeClearEvent( &secondaryRequest->CompleteEvent );

		if (Status != STATUS_SUCCESS) {

			secondaryRequest = NULL;
			try_return( Status = STATUS_IO_DEVICE_ERROR );
		}

		SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource );		
		secondarySessionResourceAcquired = FALSE;

		if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) {

			if (IrpContext->OriginatingIrp)
				PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp );
			DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) );

			NDASFAT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
			SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST );
			FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
		}

		ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData;
		Status = Irp->IoStatus.Status = ndfsWinxpReplytHeader->Status;
		Irp->IoStatus.Information = ndfsWinxpReplytHeader->Information;
		
		returnedDataSize = secondaryRequest->NdfsReplyHeader.MessageSize - sizeof(NDFS_REPLY_HEADER) - sizeof(NDFS_WINXP_REPLY_HEADER);

		if (returnedDataSize) {

			ASSERT( ndfsWinxpReplytHeader->Information != 0 );
			ASSERT(returnedDataSize <= ADD_ALIGN8(queryDirectory.Length));
			ASSERT( Buffer );

			RtlCopyMemory( Buffer,
						   (_U8 *)(ndfsWinxpReplytHeader+1),
						   (returnedDataSize < queryDirectory.Length) ? returnedDataSize : queryDirectory.Length );
		}

#endif

#if 0

        //
        //  Make sure the Dcb is still good.
        //

        FatVerifyFcb( IrpContext, Dcb );

        //
        //  Determine where to start the scan.  Highest priority is given
        //  to the file index.  Lower priority is the restart flag.  If
        //  neither of these is specified, then the Vbo offset field in the
        //  Ccb is used.
        //

        if (IndexSpecified) {

            CurrentVbo = FileIndex + sizeof( DIRENT );

        } else if (RestartScan) {

            CurrentVbo = 0;

        } else {

            CurrentVbo = Ccb->OffsetToStartSearchFrom;

        }

        //
        //  If this is the first try then allocate a buffer for the file
        //  name.
        //

        if (InitialQuery) {

            //
            //  If either:
            //
            //  - No name was specified
            //  - An empty name was specified
            //  - We received a '*'
            //  - The user specified the DOS equivolent of ????????.???
            //
            //  then match all names.
            //

            if ((UniArgFileName == NULL) ||
                (UniArgFileName->Length == 0) ||
                (UniArgFileName->Buffer == NULL) ||
                ((UniArgFileName->Length == sizeof(WCHAR)) &&
                 (UniArgFileName->Buffer[0] == L'*')) ||
                ((UniArgFileName->Length == 12*sizeof(WCHAR)) &&
                 (RtlEqualMemory( UniArgFileName->Buffer,
                                  Fat8QMdot3QM,
                                  12*sizeof(WCHAR) )))) {

                Ccb->ContainsWildCards = TRUE;

                SetFlag( Ccb->Flags, CCB_FLAG_MATCH_ALL );

            } else {

                BOOLEAN ExtendedName = FALSE;
                OEM_STRING LocalBestFit;

                //
                //  First and formost, see if the name has wild cards.
                //

                Ccb->ContainsWildCards =
                    FsRtlDoesNameContainWildCards( UniArgFileName );

                //
                //  Now check to see if the name contains any extended
                //  characters
                //

                for (i=0; i < UniArgFileName->Length / sizeof(WCHAR); i++) {

                    if (UniArgFileName->Buffer[i] >= 0x80) {

                        ExtendedName = TRUE;
                        break;
                    }
                }

                //
                //  OK, now do the conversions we need.
                //

                if (ExtendedName) {

                    Status = RtlUpcaseUnicodeString( &Ccb->UnicodeQueryTemplate,
                                                     UniArgFileName,
                                                     TRUE );

                    if (!NT_SUCCESS(Status)) {

                        try_return( Status );
                    }

                    SetFlag( Ccb->Flags, CCB_FLAG_FREE_UNICODE );

                    //
                    //  Upcase the name and convert it to the Oem code page.
                    //

                    Status = RtlUpcaseUnicodeStringToCountedOemString( &LocalBestFit,
                                                                       UniArgFileName,
                                                                       TRUE );

                    //
                    //  If this conversion failed for any reason other than
                    //  an unmappable character fail the request.
                    //

                    if (!NT_SUCCESS(Status)) {

                        if (Status == STATUS_UNMAPPABLE_CHARACTER) {

                            SetFlag( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE );

                        } else {

                            try_return( Status );
                        }

                    } else {

                        SetFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT );
                    }

                } else {

                    PVOID Buffers;

                    //
                    //  This case is optimized because I know I only have to
                    //  worry about a-z.
                    //

                    Buffers = FsRtlAllocatePoolWithTag( PagedPool,
                                                        UniArgFileName->Length +
                                                        UniArgFileName->Length / sizeof(WCHAR),
                                                        TAG_FILENAME_BUFFER );

                    Ccb->UnicodeQueryTemplate.Buffer = Buffers;
                    Ccb->UnicodeQueryTemplate.Length = UniArgFileName->Length;
                    Ccb->UnicodeQueryTemplate.MaximumLength = UniArgFileName->Length;

                    LocalBestFit.Buffer = (PUCHAR)Buffers + UniArgFileName->Length;
                    LocalBestFit.Length = UniArgFileName->Length / sizeof(WCHAR);
                    LocalBestFit.MaximumLength = LocalBestFit.Length;

                    SetFlag( Ccb->Flags, CCB_FLAG_FREE_UNICODE );

                    for (i=0; i < UniArgFileName->Length / sizeof(WCHAR); i++) {

                        WCHAR c = UniArgFileName->Buffer[i];

                        LocalBestFit.Buffer[i] = (UCHAR)
                        (Ccb->UnicodeQueryTemplate.Buffer[i] =
                             (c < 'a' ? c : c <= 'z' ? c - ('a' - 'A') : c));
                    }
                }

                //
                //  At this point we now have the upcased unicode name,
                //  and the two Oem names if they could be represented in
                //  this code page.
                //
                //  Now determine if the Oem names are legal for what we
                //  going to try and do.  Mark them as not usable is they
                //  are not legal.  Note that we can optimize extended names
                //  since they are actually both the same string.
                //

                if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE ) &&
                    !FatIsNameShortOemValid( IrpContext,
                                             LocalBestFit,
                                             Ccb->ContainsWildCards,
                                             FALSE,
                                             FALSE )) {

                    if (ExtendedName) {

                        RtlFreeOemString( &LocalBestFit );
                        ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT );
                    }

                    SetFlag( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE );
                }

                //
                //  OK, now both locals oem strings correctly reflect their
                //  usability.  Now we want to load up the Ccb structure.
                //
                //  Now we will branch on two paths of wheather the name
                //  is wild or not.
                //

                if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE )) {

                    if (Ccb->ContainsWildCards) {

                        Ccb->OemQueryTemplate.Wild = LocalBestFit;

                    } else {

                        FatStringTo8dot3( IrpContext,
                                          LocalBestFit,
                                          &Ccb->OemQueryTemplate.Constant );

                        if (FlagOn(Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT)) {

                            RtlFreeOemString( &LocalBestFit );
                            ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT );
                        }
                    }
                }
            }

            //
            //  We convert to shared access.
            //

            FatConvertToSharedFcb( IrpContext, Dcb );
        }

        LastEntry = 0;
        NextEntry = 0;

        switch (FileInformationClass) {

        case FileDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
                                       FileName[0] );
            break;

        case FileFullDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
                                       FileName[0] );
            break;

        case FileIdFullDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
                                       FileName[0] );
            break;

        case FileNamesInformation:

            BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
                                       FileName[0] );
            break;

        case FileBothDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
                                       FileName[0] );
            break;

        case FileIdBothDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
                                       FileName[0] );
            break;

        default:

            try_return( Status = STATUS_INVALID_INFO_CLASS );
        }

        //
        //  At this point we are about to enter our query loop.  We have
        //  determined the index into the directory file to begin the
        //  search.  LastEntry and NextEntry are used to index into the user
        //  buffer.  LastEntry is the last entry we've added, NextEntry is
        //  current one we're working on.  If NextEntry is non-zero, then
        //  at least one entry was added.
        //

        while ( TRUE ) {

            VBO NextVbo;
            ULONG FileNameLength;
            ULONG BytesRemainingInBuffer;


            DebugTrace(0, Dbg, "FatQueryDirectory -> Top of loop\n", 0);

            //
            //  If the user had requested only a single match and we have
            //  returned that, then we stop at this point.
            //

            if (ReturnSingleEntry && NextEntry != 0) {

                try_return( Status );
            }

            //
            //  We call FatLocateDirent to lock down the next matching dirent.
            //

            FatLocateDirent( IrpContext,
                             Dcb,
                             Ccb,
                             CurrentVbo,
                             &Dirent,
                             &Bcb,
                             &NextVbo,
                             NULL,
                             &LongFileName);

            //
            //  If we didn't receive a dirent, then we are at the end of the
            //  directory.  If we have returned any files, we exit with
            //  success, otherwise we return STATUS_NO_MORE_FILES.
            //

            if (!Dirent) {

                DebugTrace(0, Dbg, "FatQueryDirectory -> No dirent\n", 0);

                if (NextEntry == 0) {

                    UpdateCcb = FALSE;

                    if (InitialQuery) {

                        Status = STATUS_NO_SUCH_FILE;

                    } else {

                        Status = STATUS_NO_MORE_FILES;
                    }
                }

                try_return( Status );
            }

            //
            //  Protect access to the user buffer with an exception handler.
            //  Since (at our request) IO doesn't buffer these requests, we have
            //  to guard against a user messing with the page protection and other
            //  such trickery.
            //
            
            try {
                
                if (LongFileName.Length == 0) {

                    //
                    //  Now we have an entry to return to our caller.  We'll convert
                    //  the name from the form in the dirent to a <name>.<ext> form.
                    //  We'll case on the type of information requested and fill up
                    //  the user buffer if everything fits.
                    //

                    Fat8dot3ToString( IrpContext, Dirent, TRUE, &Fat8Dot3String );
    
                    //
                    //  Determine the UNICODE length of the file name.
                    //
    
                    FileNameLength = RtlOemStringToCountedUnicodeSize(&Fat8Dot3String);

                    //
                    //  Here are the rules concerning filling up the buffer:
                    //
                    //  1.  The Io system garentees that there will always be
                    //      enough room for at least one base record.
                    //
                    //  2.  If the full first record (including file name) cannot
                    //      fit, as much of the name as possible is copied and
                    //      STATUS_BUFFER_OVERFLOW is returned.
                    //
                    //  3.  If a subsequent record cannot completely fit into the
                    //      buffer, none of it (as in 0 bytes) is copied, and
                    //      STATUS_SUCCESS is returned.  A subsequent query will
                    //      pick up with this record.
                    //
    
                    BytesRemainingInBuffer = UserBufferLength - NextEntry;
    
                    if ( (NextEntry != 0) &&
                         ( (BaseLength + FileNameLength > BytesRemainingInBuffer) ||
                           (UserBufferLength < NextEntry) ) ) {
    
                        DebugTrace(0, Dbg, "Next entry won't fit\n", 0);
    
                        try_return( Status = STATUS_SUCCESS );
                    }
    
                    ASSERT( BytesRemainingInBuffer >= BaseLength );

                    //
                    //  Zero the base part of the structure.
                    //

                    RtlZeroMemory( &Buffer[NextEntry], BaseLength );

                    switch ( FileInformationClass ) {
    
                    //
                    //  Now fill the base parts of the strucure that are applicable.
                    //
    
                    case FileBothDirectoryInformation:
                    case FileFullDirectoryInformation:
                    case FileIdBothDirectoryInformation:
                    case FileIdFullDirectoryInformation:

                        DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file full directory information\n", 0);
    
                        //
                        //  Get the Ea file length.
                        //
    
                        FullDirInfo = (PFILE_FULL_DIR_INFORMATION)&Buffer[NextEntry];
    
                        //
                        //  If the EAs are corrupt, ignore the error.  We don't want
                        //  to abort the directory query.
                        //
    
                        try {
    
                            FatGetEaLength( IrpContext,
                                            Vcb,
                                            Dirent,
                                            &FullDirInfo->EaSize );
    
                        } except(EXCEPTION_EXECUTE_HANDLER) {
    
                              FatResetExceptionState( IrpContext );
                              FullDirInfo->EaSize = 0;
                        }
                        
                    case FileDirectoryInformation:
    
                        DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];
    
                        FatGetDirTimes( IrpContext, Dirent, DirInfo );
    
                        DirInfo->EndOfFile.QuadPart = Dirent->FileSize;
    
                        if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
    
                            DirInfo->AllocationSize.QuadPart =
                               (((Dirent->FileSize + DiskAllocSize - 1) / DiskAllocSize) *
                                DiskAllocSize );
                        }
    
                        DirInfo->FileAttributes = Dirent->Attributes != 0 ?
                                                  Dirent->Attributes :
                                                  FILE_ATTRIBUTE_NORMAL;
    
                        DirInfo->FileIndex = NextVbo;
    
                        DirInfo->FileNameLength = FileNameLength;
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String);
    
                        break;
    
                    case FileNamesInformation:
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file names information\n", 0);
    
                        NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];
    
                        NamesInfo->FileIndex = NextVbo;
    
                        NamesInfo->FileNameLength = FileNameLength;
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String );
    
                        break;
    
                    default:
    
                        FatBugCheck( FileInformationClass, 0, 0 );
                    }

                    BytesConverted = 0;
    
                    Status = RtlOemToUnicodeN( (PWCH)&Buffer[NextEntry + BaseLength],
                                               BytesRemainingInBuffer - BaseLength,
                                               &BytesConverted,
                                               Fat8Dot3String.Buffer,
                                               Fat8Dot3String.Length );
                    
                    //
                    //  Check for the case that a single entry doesn't fit.
                    //  This should only get this far on the first entry
                    //
    
                    if (BytesConverted < FileNameLength) {
    
                        ASSERT( NextEntry == 0 );
                        Status = STATUS_BUFFER_OVERFLOW;
                    }
    
                    //
                    //  Set up the previous next entry offset
                    //
    
                    *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;
    
                    //
                    //  And indicate how much of the user buffer we have currently
                    //  used up.  We must compute this value before we long align
                    //  ourselves for the next entry
                    //
    
                    Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information ) +
                                                BaseLength + BytesConverted;
    
                    //
                    //  If something happened with the conversion, bail here.
                    //
    
                    if ( !NT_SUCCESS( Status ) ) {
    
                        try_return( NOTHING );
                    }

                } else {

                    ULONG ShortNameLength;
    
                    FileNameLength = LongFileName.Length;
    
                    //
                    //  Here are the rules concerning filling up the buffer:
                    //
                    //  1.  The Io system garentees that there will always be
                    //      enough room for at least one base record.
                    //
                    //  2.  If the full first record (including file name) cannot
                    //      fit, as much of the name as possible is copied and
                    //      STATUS_BUFFER_OVERFLOW is returned.
                    //
                    //  3.  If a subsequent record cannot completely fit into the
                    //      buffer, none of it (as in 0 bytes) is copied, and
                    //      STATUS_SUCCESS is returned.  A subsequent query will
                    //      pick up with this record.
                    //
    
                    BytesRemainingInBuffer = UserBufferLength - NextEntry;
    
                    if ( (NextEntry != 0) &&
                         ( (BaseLength + FileNameLength > BytesRemainingInBuffer) ||
                           (UserBufferLength < NextEntry) ) ) {
    
                        DebugTrace(0, Dbg, "Next entry won't fit\n", 0);
    
                        try_return( Status = STATUS_SUCCESS );
                    }
    
                    ASSERT( BytesRemainingInBuffer >= BaseLength );
    
                    //
                    //  Zero the base part of the structure.
                    //

                    RtlZeroMemory( &Buffer[NextEntry], BaseLength );

                    switch ( FileInformationClass ) {
    
                    //
                    //  Now fill the base parts of the strucure that are applicable.
                    //
    
                    case FileBothDirectoryInformation:
                    case FileIdBothDirectoryInformation:
    
                        BothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&Buffer[NextEntry];
    
                        //
                        //  Now we have an entry to return to our caller.  We'll convert
                        //  the name from the form in the dirent to a <name>.<ext> form.
                        //  We'll case on the type of information requested and fill up
                        //  the user buffer if everything fits.
                        //
    
                        Fat8dot3ToString( IrpContext, Dirent, FALSE, &Fat8Dot3String );
    
                        ASSERT( Fat8Dot3String.Length <= 12 );
    
                        Status = RtlOemToUnicodeN( &BothDirInfo->ShortName[0],
                                                   12*sizeof(WCHAR),
                                                   &ShortNameLength,
                                                   Fat8Dot3String.Buffer,
                                                   Fat8Dot3String.Length );
    
                        ASSERT( Status != STATUS_BUFFER_OVERFLOW );
                        ASSERT( ShortNameLength <= 12*sizeof(WCHAR) );
    
                        //
                        //  Copy the length into the dirinfo structure.  Note
                        //  that the LHS below is a USHORT, so it can not
                        //  be specificed as the OUT parameter above.
                        //
    
                        BothDirInfo->ShortNameLength = (UCHAR)ShortNameLength;
    
                        //
                        //  If something happened with the conversion, bail here.
                        //
    
                        if ( !NT_SUCCESS( Status ) ) {
    
                            try_return( NOTHING );
                        }
    
                    case FileFullDirectoryInformation:
                    case FileIdFullDirectoryInformation:
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file full directory information\n", 0);
    
                        //
                        //  Get the Ea file length.
                        //
    
                        FullDirInfo = (PFILE_FULL_DIR_INFORMATION)&Buffer[NextEntry];
    
                        //
                        //  If the EAs are corrupt, ignore the error.  We don't want
                        //  to abort the directory query.
                        //
    
                        try {
    
                            FatGetEaLength( IrpContext,
                                            Vcb,
                                            Dirent,
                                            &FullDirInfo->EaSize );
    
                        } except(EXCEPTION_EXECUTE_HANDLER) {
    
                              FatResetExceptionState( IrpContext );
                              FullDirInfo->EaSize = 0;
                        }
    
                    case FileDirectoryInformation:
    
                        DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];
    
                        FatGetDirTimes( IrpContext, Dirent, DirInfo );
    
                        DirInfo->EndOfFile.QuadPart = Dirent->FileSize;
    
                        if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
    
                            DirInfo->AllocationSize.QuadPart = (
                                                            (( Dirent->FileSize
                                                               + DiskAllocSize - 1 )
                                                             / DiskAllocSize )
                                                            * DiskAllocSize );
                        }
    
                        DirInfo->FileAttributes = Dirent->Attributes != 0 ?
                                                  Dirent->Attributes :
                                                  FILE_ATTRIBUTE_NORMAL;
    
                        DirInfo->FileIndex = NextVbo;
    
                        DirInfo->FileNameLength = FileNameLength;
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String);
    
                        break;
    
                    case FileNamesInformation:
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file names information\n", 0);
    
                        NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];
    
                        NamesInfo->FileIndex = NextVbo;
    
                        NamesInfo->FileNameLength = FileNameLength;
    
                        DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String );
    
                        break;
    
                    default:
    
                        FatBugCheck( FileInformationClass, 0, 0 );
                    }

                    BytesConverted = BytesRemainingInBuffer - BaseLength >= FileNameLength ?
                                     FileNameLength :
                                     BytesRemainingInBuffer - BaseLength;
    
                    RtlCopyMemory( &Buffer[NextEntry + BaseLength],
                                   &LongFileName.Buffer[0],
                                   BytesConverted );
    
                    //
                    //  Set up the previous next entry offset
                    //
    
                    *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;

                    //
                    //  And indicate how much of the user buffer we have currently
                    //  used up.  We must compute this value before we long align
                    //  ourselves for the next entry
                    //
    
                    Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information ) +
                                                BaseLength + BytesConverted;

                    //
                    //  Check for the case that a single entry doesn't fit.
                    //  This should only get this far on the first entry.
                    //

                    if (BytesConverted < FileNameLength) {

                        ASSERT( NextEntry == 0 );

                        try_return( Status = STATUS_BUFFER_OVERFLOW );
                    }
                }

                //
                //  Finish up by filling in the FileId
                //

                switch ( FileInformationClass ) {

                case FileIdBothDirectoryInformation:

                    IdBothDirInfo = (PFILE_ID_BOTH_DIR_INFORMATION)&Buffer[NextEntry];
                    IdBothDirInfo->FileId.QuadPart = FatGenerateFileIdFromDirentAndOffset( Dcb, Dirent, NextVbo );
                    break;

                case FileIdFullDirectoryInformation:

                    IdFullDirInfo = (PFILE_ID_FULL_DIR_INFORMATION)&Buffer[NextEntry];
                    IdFullDirInfo->FileId.QuadPart = FatGenerateFileIdFromDirentAndOffset( Dcb, Dirent, NextVbo );
                    break;

                default:
                    break;
                }
            
            }  except (EXCEPTION_EXECUTE_HANDLER) {

                  //
                  //  We had a problem filling in the user's buffer, so stop and
                  //  fail this request.  This is the only reason any exception
                  //  would have occured at this level.
                  //
                  
                  Irp->IoStatus.Information = 0;
                  UpdateCcb = FALSE;
                  try_return( Status = GetExceptionCode());
            }

            //
            //  Set ourselves up for the next iteration
            //

            LastEntry = NextEntry;
            NextEntry += (ULONG)QuadAlign(BaseLength + BytesConverted);

            CurrentVbo = NextVbo + sizeof( DIRENT );
        }

#endif

    try_exit: NOTHING;
    } finally {
示例#4
0
文件: dirctrl.c 项目: kcrazy/winekit
__drv_mustHoldCriticalRegion
NTSTATUS
CdQueryDirectory (
    __inout PIRP_CONTEXT IrpContext,
    __inout PIRP Irp,
    __in PIO_STACK_LOCATION IrpSp,
    __in PFCB Fcb,
    __in PCCB Ccb
    )

/*++

Routine Description:

    This routine performs the query directory operation.  It is responsible
    for either completing of enqueuing the input Irp.  We store the state of the
    search in the Ccb.

Arguments:

    Irp - Supplies the Irp to process

    IrpSp - Stack location for this Irp.

    Fcb - Fcb for this directory.

    Ccb - Ccb for this directory open.

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG Information = 0;

    ULONG LastEntry = 0;
    ULONG NextEntry = 0;

    ULONG FileNameBytes;
    ULONG SeparatorBytes;
    ULONG VersionStringBytes;

    FILE_ENUM_CONTEXT FileContext;
    PDIRENT ThisDirent = NULL;
    BOOLEAN InitialQuery;
    BOOLEAN ReturnNextEntry = FALSE;
    BOOLEAN ReturnSingleEntry;
    BOOLEAN Found;
    BOOLEAN DoCcbUpdate = FALSE;

    PCHAR UserBuffer;
    ULONG BytesRemainingInBuffer;

    ULONG BaseLength;

    PFILE_BOTH_DIR_INFORMATION DirInfo = NULL;
    PFILE_NAMES_INFORMATION NamesInfo;
    PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo;
    PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo;

    PAGED_CODE();

    //
    //  Check if we support this search mode.  Also remember the size of the base part of
    //  each of these structures.
    //

    switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {

    case FileDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
                                   FileName[0] );
        break;

    case FileFullDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
                                   FileName[0] );
        break;

    case FileIdFullDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
                                   FileName[0] );
        break;

    case FileNamesInformation:

        BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
                                   FileName[0] );
        break;

    case FileBothDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
                                   FileName[0] );
        break;

    case FileIdBothDirectoryInformation:

        BaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
                                   FileName[0] );
        break;

    default:

        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_INFO_CLASS );
        return STATUS_INVALID_INFO_CLASS;
    }

    //
    //  Get the user buffer.
    //

    CdMapUserBuffer( IrpContext, &UserBuffer);

    //
    //  Initialize our search context.
    //

    CdInitializeFileContext( IrpContext, &FileContext );

    //
    //  Acquire the directory.
    //

    CdAcquireFileShared( IrpContext, Fcb );

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Verify the Fcb is still good.
        //

        CdVerifyFcbOperation( IrpContext, Fcb );

        //
        //  Start by getting the initial state for the enumeration.  This will set up the Ccb with
        //  the initial search parameters and let us know the starting offset in the directory
        //  to search.
        //

        CdInitializeEnumeration( IrpContext,
                                 IrpSp,
                                 Fcb,
                                 Ccb,
                                 &FileContext,
                                 &ReturnNextEntry,
                                 &ReturnSingleEntry,
                                 &InitialQuery );

        //
        //  The current dirent is stored in the InitialDirent field.  We capture
        //  this here so that we have a valid restart point even if we don't
        //  find a single entry.
        //

        ThisDirent = &FileContext.InitialDirent->Dirent;

        //
        //  At this point we are about to enter our query loop.  We have
        //  determined the index into the directory file to begin the
        //  search.  LastEntry and NextEntry are used to index into the user
        //  buffer.  LastEntry is the last entry we've added, NextEntry is
        //  current one we're working on.  If NextEntry is non-zero, then
        //  at least one entry was added.
        //

        while (TRUE) {

            //
            //  If the user had requested only a single match and we have
            //  returned that, then we stop at this point.  We update the Ccb with
            //  the status based on the last entry returned.
            //

            if ((NextEntry != 0) && ReturnSingleEntry) {

                DoCcbUpdate = TRUE;
                try_leave( Status );
            }

            //
            //  We try to locate the next matching dirent.  Our search if based on a starting
            //  dirent offset, whether we should return the current or next entry, whether
            //  we should be doing a short name search and finally whether we should be
            //  checking for a version match.
            //

            Found = CdEnumerateIndex( IrpContext, Ccb, &FileContext, ReturnNextEntry );

            //
            //  Initialize the value for the next search.
            //

            ReturnNextEntry = TRUE;

            //
            //  If we didn't receive a dirent, then we are at the end of the
            //  directory.  If we have returned any files, we exit with
            //  success, otherwise we return STATUS_NO_MORE_FILES.
            //

            if (!Found) {

                if (NextEntry == 0) {

                    Status = STATUS_NO_MORE_FILES;

                    if (InitialQuery) {

                        Status = STATUS_NO_SUCH_FILE;
                    }
                }

                DoCcbUpdate = TRUE;
                try_leave( Status );
            }

            //
            //  Remember the dirent for the file we just found.
            //

            ThisDirent = &FileContext.InitialDirent->Dirent;

            //
            //  Here are the rules concerning filling up the buffer:
            //
            //  1.  The Io system garentees that there will always be
            //      enough room for at least one base record.
            //
            //  2.  If the full first record (including file name) cannot
            //      fit, as much of the name as possible is copied and
            //      STATUS_BUFFER_OVERFLOW is returned.
            //
            //  3.  If a subsequent record cannot completely fit into the
            //      buffer, none of it (as in 0 bytes) is copied, and
            //      STATUS_SUCCESS is returned.  A subsequent query will
            //      pick up with this record.
            //

            //
            //  Let's compute the number of bytes we need to transfer the current entry.
            //

            SeparatorBytes =
            VersionStringBytes = 0;

            //
            //  We can look directly at the dirent that we found.
            //

            FileNameBytes = ThisDirent->CdFileName.FileName.Length;

            //
            //  Compute the number of bytes for the version string if
            //  we will return this. Allow directories with illegal ";".
            //

            if (((Ccb->SearchExpression.VersionString.Length != 0) ||
                 (FlagOn(ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY))) &&
                (ThisDirent->CdFileName.VersionString.Length != 0)) {

                SeparatorBytes = 2;

                VersionStringBytes = ThisDirent->CdFileName.VersionString.Length;
            }

            //
            //  If the slot for the next entry would be beyond the length of the
            //  user's buffer just exit (we know we've returned at least one entry
            //  already). This will happen when we align the pointer past the end.
            //

            if (NextEntry > IrpSp->Parameters.QueryDirectory.Length) {

                ReturnNextEntry = FALSE;
                DoCcbUpdate = TRUE;
                try_leave( Status = STATUS_SUCCESS );
            }

            //
            //  Compute the number of bytes remaining in the buffer.  Round this
            //  down to a WCHAR boundary so we can copy full characters.
            //

            BytesRemainingInBuffer = IrpSp->Parameters.QueryDirectory.Length - NextEntry;
            ClearFlag( BytesRemainingInBuffer, 1 );

            //
            //  If this won't fit and we have returned a previous entry then just
            //  return STATUS_SUCCESS.
            //

            if ((BaseLength + FileNameBytes + SeparatorBytes + VersionStringBytes) > BytesRemainingInBuffer) {

                //
                //  If we already found an entry then just exit.
                //

                if (NextEntry != 0) {

                    ReturnNextEntry = FALSE;
                    DoCcbUpdate = TRUE;
                    try_leave( Status = STATUS_SUCCESS );
                }

                //
                //  Don't even try to return the version string if it doesn't all fit.
                //  Reduce the FileNameBytes to just fit in the buffer.
                //

                if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) {

                    FileNameBytes = BytesRemainingInBuffer - BaseLength;
                }

                //
                //  Don't return any version string bytes.
                //

                VersionStringBytes =
                SeparatorBytes = 0;

                //
                //  Use a status code of STATUS_BUFFER_OVERFLOW.  Also set
                //  ReturnSingleEntry so that we will exit the loop at the top.
                //

                Status = STATUS_BUFFER_OVERFLOW;
                ReturnSingleEntry = TRUE;
            }

            //
            //  Protect access to the user buffer with an exception handler.
            //  Since (at our request) IO doesn't buffer these requests, we have
            //  to guard against a user messing with the page protection and other
            //  such trickery.
            //
            
            try {
            
                //
                //  Zero and initialize the base part of the current entry.
                //

                RtlZeroMemory( Add2Ptr( UserBuffer, NextEntry, PVOID ),
                               BaseLength );
    
                //
                //  Now we have an entry to return to our caller.
                //  We'll case on the type of information requested and fill up
                //  the user buffer if everything fits.
                //

                switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
    
                case FileBothDirectoryInformation:
                case FileFullDirectoryInformation:
                case FileIdBothDirectoryInformation:
                case FileIdFullDirectoryInformation:
                case FileDirectoryInformation:
    
                    DirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_BOTH_DIR_INFORMATION );
    
                    //
                    //  Use the create time for all the time stamps.
                    //
    
                    CdConvertCdTimeToNtTime( IrpContext,
                                             FileContext.InitialDirent->Dirent.CdTime,
                                             &DirInfo->CreationTime );
    
                    DirInfo->LastWriteTime = DirInfo->ChangeTime = DirInfo->CreationTime;
    
                    //
                    //  Set the attributes and sizes separately for directories and
                    //  files.
                    //
    
                    if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
    
                        DirInfo->EndOfFile.QuadPart = DirInfo->AllocationSize.QuadPart = 0;
    
                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
                        
                    } else {
    
                        DirInfo->EndOfFile.QuadPart = FileContext.FileSize;
                        DirInfo->AllocationSize.QuadPart = LlSectorAlign( FileContext.FileSize );
                        
                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_READONLY);
                    }

                    if (FlagOn( ThisDirent->DirentFlags,
                                CD_ATTRIBUTE_HIDDEN )) {
    
                        SetFlag( DirInfo->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
                    }
    
                    DirInfo->FileIndex = ThisDirent->DirentOffset;
    
                    DirInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
    
                    break;
    
                case FileNamesInformation:
    
                    NamesInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_NAMES_INFORMATION );
    
                    NamesInfo->FileIndex = ThisDirent->DirentOffset;
    
                    NamesInfo->FileNameLength = FileNameBytes + SeparatorBytes + VersionStringBytes;
    
                    break;
                }

                //
                //  Fill in the FileId
                //

                switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {

                case FileIdBothDirectoryInformation:

                    IdBothDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_BOTH_DIR_INFORMATION );
                    CdSetFidFromParentAndDirent( IdBothDirInfo->FileId, Fcb, ThisDirent );
                    break;

                case FileIdFullDirectoryInformation:

                    IdFullDirInfo = Add2Ptr( UserBuffer, NextEntry, PFILE_ID_FULL_DIR_INFORMATION );
                    CdSetFidFromParentAndDirent( IdFullDirInfo->FileId, Fcb, ThisDirent );
                    break;

                default:
                    break;
                }
    
                //
                //  Now copy as much of the name as possible.  We also may have a version
                //  string to copy.
                //
    
                if (FileNameBytes != 0) {
    
                    //
                    //  This is a Unicode name, we can copy the bytes directly.
                    //
    
                    RtlCopyMemory( Add2Ptr( UserBuffer, NextEntry + BaseLength, PVOID ),
                                   ThisDirent->CdFileName.FileName.Buffer,
                                   FileNameBytes );
    
                    if (SeparatorBytes != 0) {
    
                        *(Add2Ptr( UserBuffer,
                                   NextEntry + BaseLength + FileNameBytes,
                                   PWCHAR )) = L';';
    
                        if (VersionStringBytes != 0) {
    
                            RtlCopyMemory( Add2Ptr( UserBuffer,
                                                    NextEntry + BaseLength + FileNameBytes + sizeof( WCHAR ),
                                                    PVOID ),
                                           ThisDirent->CdFileName.VersionString.Buffer,
                                           VersionStringBytes );
                        }
                    }
                }

                //
                //  Fill in the short name if we got STATUS_SUCCESS.  The short name
                //  may already be in the file context.  Otherwise we will check
                //  whether the long name is 8.3.  Special case the self and parent
                //  directory names.
                //

                if ((Status == STATUS_SUCCESS) &&
                    (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation ||
                     IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation) &&
                    (Ccb->SearchExpression.VersionString.Length == 0) &&
                    !FlagOn( ThisDirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
    
                    //
                    //  If we already have the short name then copy into the user's buffer.
                    //
    
                    if (FileContext.ShortName.FileName.Length != 0) {
    
                        RtlCopyMemory( DirInfo->ShortName,
                                       FileContext.ShortName.FileName.Buffer,
                                       FileContext.ShortName.FileName.Length );
    
                        DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
    
                    //
                    //  If the short name length is currently zero then check if
                    //  the long name is not 8.3.  We can copy the short name in
                    //  unicode form directly into the caller's buffer.
                    //
    
                    } else {
    
                        if (!CdIs8dot3Name( IrpContext,
                                            ThisDirent->CdFileName.FileName )) {
    
                            CdGenerate8dot3Name( IrpContext,
                                                 &ThisDirent->CdCaseFileName.FileName,
                                                 ThisDirent->DirentOffset,
                                                 DirInfo->ShortName,
                                                 &FileContext.ShortName.FileName.Length );
    
                            DirInfo->ShortNameLength = (CCHAR) FileContext.ShortName.FileName.Length;
                        }
                    }
    
                }

                //
                //  Sum the total number of bytes for the information field.
                //

                FileNameBytes += SeparatorBytes + VersionStringBytes;

                //
                //  Update the information with the number of bytes stored in the
                //  buffer.  We quad-align the existing buffer to add any necessary
                //  pad bytes.
                //

                Information = NextEntry + BaseLength + FileNameBytes;

                //
                //  Go back to the previous entry and fill in the update to this entry.
                //

                *(Add2Ptr( UserBuffer, LastEntry, PULONG )) = NextEntry - LastEntry;

                //
                //  Set up our variables for the next dirent.
                //

                InitialQuery = FALSE;

                LastEntry = NextEntry;
                NextEntry = QuadAlign( Information );
            
            } except (EXCEPTION_EXECUTE_HANDLER) {

                  //
                  //  We had a problem filling in the user's buffer, so stop and
                  //  fail this request.  This is the only reason any exception
                  //  would have occured at this level.
                  //
                  
                  Information = 0;
                  try_leave( Status = GetExceptionCode());
            }
        }
        
        DoCcbUpdate = TRUE;

    } finally {

        //
        //  Cleanup our search context - *before* aquiring the FCB mutex exclusive,
        //  else can block on threads in cdcreateinternalstream/purge which 
        //  hold the FCB but are waiting for all maps in this stream to be released.
        //

        CdCleanupFileContext( IrpContext, &FileContext );

        //
        //  Now we can safely aqure the FCB mutex if we need to.
        //

        if (DoCcbUpdate && !NT_ERROR( Status )) {
        
            //
            //  Update the Ccb to show the current state of the enumeration.
            //

            CdLockFcb( IrpContext, Fcb );
            
            Ccb->CurrentDirentOffset = ThisDirent->DirentOffset;

            ClearFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );

            if (ReturnNextEntry) {

                SetFlag( Ccb->Flags, CCB_FLAG_ENUM_RETURN_NEXT );
            }

            CdUnlockFcb( IrpContext, Fcb );
        }

        //
        //  Release the Fcb.
        //

        CdReleaseFile( IrpContext, Fcb );
    }

    //
    //  Complete the request here.
    //

    Irp->IoStatus.Information = Information;

    CdCompleteRequest( IrpContext, Irp, Status );
    return Status;
}
示例#5
0
ULONG
DokanFillDirectoryInformation(FILE_INFORMATION_CLASS DirectoryInfo,
                              PVOID Buffer, PULONG LengthRemaining,
                              PWIN32_FIND_DATAW FindData, ULONG Index,
                              PDOKAN_INSTANCE DokanInstance) {
  ULONG nameBytes;
  ULONG thisEntrySize;

  nameBytes = (ULONG)wcslen(FindData->cFileName) * sizeof(WCHAR);

  thisEntrySize = nameBytes;

  switch (DirectoryInfo) {
  case FileDirectoryInformation:
    thisEntrySize += sizeof(FILE_DIRECTORY_INFORMATION);
    break;
  case FileFullDirectoryInformation:
    thisEntrySize += sizeof(FILE_FULL_DIR_INFORMATION);
    break;
  case FileNamesInformation:
    thisEntrySize += sizeof(FILE_NAMES_INFORMATION);
    break;
  case FileBothDirectoryInformation:
    thisEntrySize += sizeof(FILE_BOTH_DIR_INFORMATION);
    break;
  case FileIdBothDirectoryInformation:
    thisEntrySize += sizeof(FILE_ID_BOTH_DIR_INFORMATION);
    break;
  default:
    break;
  }

  // Must be align on a 8-byte boundary.
  thisEntrySize = QuadAlign(thisEntrySize);

  // no more memory, don't fill any more
  if (*LengthRemaining < thisEntrySize) {
    DbgPrint("  no memory\n");
    return 0;
  }

  RtlZeroMemory(Buffer, thisEntrySize);

  switch (DirectoryInfo) {
  case FileDirectoryInformation:
    DokanFillDirInfo(Buffer, FindData, Index, DokanInstance);
    break;
  case FileFullDirectoryInformation:
    DokanFillFullDirInfo(Buffer, FindData, Index, DokanInstance);
    break;
  case FileNamesInformation:
    DokanFillNamesInfo(Buffer, FindData, Index);
    break;
  case FileBothDirectoryInformation:
    DokanFillBothDirInfo(Buffer, FindData, Index, DokanInstance);
    break;
  case FileIdBothDirectoryInformation:
    DokanFillIdBothDirInfo(Buffer, FindData, Index, DokanInstance);
    break;
  default:
    break;
  }

  *LengthRemaining -= thisEntrySize;

  return thisEntrySize;
}
示例#6
0
NTSTATUS
AFSProcessRequest( IN ULONG RequestType,
                   IN ULONG RequestFlags,
                   IN GUID *AuthGroup,
                   IN PUNICODE_STRING FileName,
                   IN AFSFileID *FileId,
                   IN void  *Data,
                   IN ULONG DataLength,
                   IN OUT void *ResultBuffer,
                   IN OUT PULONG ResultBufferLength)
{

    NTSTATUS         ntStatus = STATUS_SUCCESS;
    AFSPoolEntry     stPoolEntry, *pPoolEntry = NULL;
    AFSCommSrvcCB   *pCommSrvc = NULL;
    BOOLEAN          bReleasePool = FALSE;
    AFSDeviceExt    *pControlDevExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension;
    AFSDeviceExt    *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
    BOOLEAN          bWait = BooleanFlagOn( RequestFlags, AFS_REQUEST_FLAG_SYNCHRONOUS);
    ULONG            ulPoolEntryLength = 0;
    BOOLEAN          bDecrementCount = FALSE;

    __try
    {

        if( BooleanFlagOn( pRDRDevExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN))
        {
            try_return( ntStatus = STATUS_DEVICE_NOT_READY);
        }

        if( InterlockedIncrement( &pControlDevExt->Specific.Control.OutstandingServiceRequestCount) == 1)
        {
            KeClearEvent( &pControlDevExt->Specific.Control.OutstandingServiceRequestEvent);
        }

        bDecrementCount = TRUE;

        pCommSrvc = &pControlDevExt->Specific.Control.CommServiceCB;

        //
        // Grab the pool resource and check the state
        //

        AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
                      AFS_TRACE_LEVEL_VERBOSE,
                      "AFSProcessRequest Acquiring IrpPoolLock lock %08lX EXCL %08lX\n",
                      &pCommSrvc->IrpPoolLock,
                      PsGetCurrentThread());

        AFSAcquireExcl( &pCommSrvc->IrpPoolLock,
                        TRUE);

        bReleasePool = TRUE;

        if( pCommSrvc->IrpPoolControlFlag != POOL_ACTIVE)
        {

            //
            // Pool not running so bail.
            //

            try_return( ntStatus = STATUS_DEVICE_NOT_READY);
        }

        //
        // If this is an async request we need to allocate a pool entry for the request
        //

        pPoolEntry = &stPoolEntry;

        if( !bWait)
        {

            ASSERT( ResultBuffer == NULL);

            ulPoolEntryLength = sizeof( AFSPoolEntry) + QuadAlign( DataLength);

            if( FileName != NULL)
            {

                ulPoolEntryLength += FileName->Length;
            }

            pPoolEntry = (AFSPoolEntry *)AFSExAllocatePoolWithTag( NonPagedPool,
                                                                   ulPoolEntryLength,
                                                                   AFS_POOL_ENTRY_TAG);

            if( pPoolEntry == NULL)
            {

                try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
            }

            RtlZeroMemory( pPoolEntry,
                           ulPoolEntryLength);

            pPoolEntry->Data = (void *)((char *)pPoolEntry + sizeof( AFSPoolEntry));

            pPoolEntry->FileName.Buffer = (WCHAR *)((char *)pPoolEntry->Data + DataLength);
        }
        else
        {

            RtlZeroMemory( pPoolEntry,
                           sizeof( AFSPoolEntry));

            KeInitializeEvent( &pPoolEntry->Event,
                               NotificationEvent,
                               FALSE);
        }

        pPoolEntry->RequestType = RequestType;

        pPoolEntry->RequestIndex = pCommSrvc->IrpPoolRequestIndex++;

        pPoolEntry->RequestFlags = RequestFlags;

        pPoolEntry->ResultBufferLength = 0;

        if( FileId != NULL)
        {

            pPoolEntry->FileId = *FileId;
        }

        pPoolEntry->FileName.Length = 0;

        if( FileName != NULL)
        {

            if( bWait)
            {

                pPoolEntry->FileName = *FileName;
            }
            else
            {

                pPoolEntry->FileName.Length = FileName->Length;

                pPoolEntry->FileName.MaximumLength = pPoolEntry->FileName.Length;

                RtlCopyMemory( pPoolEntry->FileName.Buffer,
                               FileName->Buffer,
                               pPoolEntry->FileName.Length);
            }
        }

        //
        // Move in the data if there is some
        //

        pPoolEntry->DataLength = DataLength;

        if( Data != NULL &&
            DataLength > 0)
        {

            if( bWait)
            {

                pPoolEntry->Data = Data;
            }
            else
            {

                RtlCopyMemory( pPoolEntry->Data,
                               Data,
                               DataLength);
            }
        }

        pPoolEntry->ResultBuffer = ResultBuffer;

        pPoolEntry->ResultBufferLength = ResultBufferLength;

        //
        // Store off the auth group
        //

        if( AuthGroup == NULL)
        {
            AFSRetrieveAuthGroup( (ULONGLONG)PsGetCurrentProcessId(),
                                  (ULONGLONG)PsGetCurrentThreadId(),
                                  &pPoolEntry->AuthGroup);
        }
        else
        {
            RtlCopyMemory( &pPoolEntry->AuthGroup,
                           AuthGroup,
                           sizeof( GUID));
        }

        if( AFSIsLocalSystemAuthGroup( &pPoolEntry->AuthGroup))
        {
            SetFlag( pPoolEntry->RequestFlags, AFS_REQUEST_LOCAL_SYSTEM_PAG);
        }

        if( AFSIsNoPAGAuthGroup( &pPoolEntry->AuthGroup))
        {
            AFSDbgLogMsg( 0,
                          0,
                          "AFSProcessRequest NoPAG Auth Group %08lX\n",
                          PsGetCurrentThread());
        }

        //
        // Indicate the type of process
        //

#ifdef AMD64

        if( !AFSIs64BitProcess( (ULONGLONG)PsGetCurrentProcessId()))
        {
            SetFlag( pPoolEntry->RequestFlags, AFS_REQUEST_FLAG_WOW64);
        }

#endif

        //
        // Insert the entry into the request pool
        //

        ntStatus = AFSInsertRequest( pCommSrvc,
                                     pPoolEntry);

        if( !NT_SUCCESS( ntStatus))
        {

            if( !bWait)
            {

                ExFreePool( pPoolEntry);
            }

            try_return( ntStatus);
        }

        //
        // Drop the lock on the pool prior to waiting
        //

        AFSReleaseResource( &pCommSrvc->IrpPoolLock);

        bReleasePool = FALSE;

        //
        // Wait for the result if this is NOT an asynchronous request
        //

        if( bWait)
        {

            //
            // Wait for the result of the request. We specify no timeout ...
            //

            ntStatus = KeWaitForSingleObject( &pPoolEntry->Event,
                                              Executive,
                                              KernelMode,
                                              FALSE,
                                              NULL);

            //
            // Process the result of the request
            //

            if( ntStatus == STATUS_SUCCESS)
            {

                ntStatus = pPoolEntry->ResultStatus;
            }
            else
            {

                ntStatus = STATUS_DEVICE_NOT_READY;
            }
        }

try_exit:

        if( bReleasePool)
        {

            AFSReleaseResource( &pCommSrvc->IrpPoolLock);
        }

        if( bDecrementCount &&
            InterlockedDecrement( &pControlDevExt->Specific.Control.OutstandingServiceRequestCount) == 0)
        {
            KeSetEvent( &pControlDevExt->Specific.Control.OutstandingServiceRequestEvent,
                        0,
                        FALSE);
        }
    }
    __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()))
    {

        AFSDumpTraceFilesFnc();

        if( bReleasePool)
        {

            AFSReleaseResource( &pCommSrvc->IrpPoolLock);
        }

        if( bDecrementCount &&
            InterlockedDecrement( &pControlDevExt->Specific.Control.OutstandingServiceRequestCount) == 0)
        {
            KeSetEvent( &pControlDevExt->Specific.Control.OutstandingServiceRequestEvent,
                        0,
                        FALSE);
        }

        if ( ntStatus == STATUS_SUCCESS)
        {

            ntStatus = STATUS_UNSUCCESSFUL;
        }
    }

    return ntStatus;
}
示例#7
0
BOOLEAN
NtfsCheckFileRecord (
    IN PVCB Vcb,
    IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
    IN PFILE_REFERENCE FileReference OPTIONAL,
    OUT PULONG CorruptionHint
    )

/*++

Routine Description:

    Consistency check for file records.

Arguments:

    Vcb - the vcb it belongs to

    FileRecord - the filerecord to check

    FileReference - if specified double check the sequence number and self ref.
        fileref against it

    CorruptionHint - hint for debugging on where corruption occured;

Return Value:

    FALSE - if the file record is not valid
    TRUE - if it is

--*/
{
    PATTRIBUTE_RECORD_HEADER Attribute;
    PFILE_RECORD_SEGMENT_HEADER EndOfFileRecord;
    ULONG BytesPerFileRecordSegment = Vcb->BytesPerFileRecordSegment;
    BOOLEAN StandardInformationSeen = FALSE;
    ULONG BytesInOldHeader;

    PAGED_CODE();

    *CorruptionHint = 0;

    EndOfFileRecord = Add2Ptr( FileRecord, BytesPerFileRecordSegment );

    //
    //  Check the file record header for consistency.
    //

    if ((*(PULONG)FileRecord->MultiSectorHeader.Signature != *(PULONG)FileSignature)

            ||

        ((ULONG)FileRecord->MultiSectorHeader.UpdateSequenceArrayOffset >
         (SEQUENCE_NUMBER_STRIDE -
          (PAGE_SIZE / SEQUENCE_NUMBER_STRIDE + 1) * sizeof(USHORT)))

            ||

        ((ULONG)((FileRecord->MultiSectorHeader.UpdateSequenceArraySize - 1) * SEQUENCE_NUMBER_STRIDE) !=
         BytesPerFileRecordSegment)

            ||

        !FlagOn(FileRecord->Flags, FILE_RECORD_SEGMENT_IN_USE)) {

        DebugTrace( 0, 0, ("Invalid file record: %08lx\n", FileRecord) );

        *CorruptionHint = 1;
#if !__NDAS_NTFS_SECONDARY__
        ASSERTMSG( "Invalid resident file record\n", FALSE );
#endif
        return FALSE;
    }

    BytesInOldHeader = QuadAlign( sizeof( FILE_RECORD_SEGMENT_HEADER_V0 ) + (UpdateSequenceArraySize( BytesPerFileRecordSegment ) - 1) * sizeof( USHORT ));

    //
    //  Offset bounds checks
    //

    if ((FileRecord->FirstFreeByte > BytesPerFileRecordSegment) ||
        (FileRecord->FirstFreeByte < BytesInOldHeader) ||

        (FileRecord->BytesAvailable != BytesPerFileRecordSegment) ||

        (((ULONG)FileRecord->FirstAttributeOffset < BytesInOldHeader)   ||
         ((ULONG)FileRecord->FirstAttributeOffset >
                 BytesPerFileRecordSegment - SIZEOF_RESIDENT_ATTRIBUTE_HEADER)) ||

        (!IsQuadAligned( FileRecord->FirstAttributeOffset ))) {

        *CorruptionHint = 2;
        ASSERTMSG( "Out of bound offset in frs\n", FALSE );
        return FALSE;
    }

    //
    //  Optional fileref number check
    //

    if (ARGUMENT_PRESENT( FileReference )) {

        if ((FileReference->SequenceNumber != FileRecord->SequenceNumber) ||
            ((FileRecord->FirstAttributeOffset > BytesInOldHeader) &&
             ((FileRecord->SegmentNumberHighPart != FileReference->SegmentNumberHighPart) ||
              (FileRecord->SegmentNumberLowPart != FileReference->SegmentNumberLowPart)))) {

            *CorruptionHint = 3;
            ASSERTMSG( "Filerecord fileref doesn't match expected value\n", FALSE );
            return FALSE;
        }
    }

    //
    //  Loop to check all of the attributes.
    //

    for (Attribute = NtfsFirstAttribute(FileRecord);
         Attribute->TypeCode != $END;
         Attribute = NtfsGetNextRecord(Attribute)) {

//      if (!StandardInformationSeen &&
//          (Attribute->TypeCode != $STANDARD_INFORMATION) &&
//          XxEqlZero(FileRecord->BaseFileRecordSegment)) {
//
//          DebugTrace( 0, 0, ("Standard Information missing: %08lx\n", Attribute) );
//
//          ASSERTMSG( "Standard Information missing\n", FALSE );
//          return FALSE;
//      }

        StandardInformationSeen = TRUE;

        if (!NtfsCheckAttributeRecord( Vcb,
                                       FileRecord,
                                       Attribute,
                                       FALSE,
                                       CorruptionHint )) {

            return FALSE;
        }
    }
    return TRUE;
}
示例#8
0
ULONG
DokanEnumerateNamedStreams(
	PFILE_STREAM_INFORMATION	StreamInfo,
	PDOKAN_FILE_INFO			FileInfo,
	PEVENT_CONTEXT				EventContext,
	PDOKAN_INSTANCE				DokanInstance,
	PULONG						RemainingLength)
{
	WCHAR streamName[SHRT_MAX + 1];
	ULONG streamNameLength;
	LONGLONG streamSize;
	ULONG entrySize = 0;
	PVOID enumContext = NULL;
	int result = 0;

	if (DokanInstance->DokanOptions->Version < DOKAN_ENUMERATE_STREAMS_SUPPORTED_VERSION || !DokanInstance->DokanOperations->EnumerateNamedStreams) {
		return STATUS_NOT_IMPLEMENTED;
	}

	if (*RemainingLength < sizeof(FILE_STREAM_INFORMATION)) {
		return STATUS_BUFFER_OVERFLOW;
	}

	while (result > -1) {
		ZeroMemory(streamName, sizeof(streamName));
		streamNameLength = 0;
		streamSize = 0;
		result = DokanInstance->DokanOperations->EnumerateNamedStreams(
			EventContext->Operation.File.FileName,
			&enumContext,
			streamName,
			&streamNameLength,
			&streamSize,
			FileInfo);
		
		if (result > -1) {
			if (*RemainingLength < sizeof(FILE_STREAM_INFORMATION)) {
				return STATUS_BUFFER_OVERFLOW;
			}

			// Not the first entry, set the offset before filling the new entry
			if (entrySize > 0) {
				StreamInfo->NextEntryOffset = entrySize;
				StreamInfo = (PFILE_STREAM_INFORMATION)((LPBYTE)StreamInfo + StreamInfo->NextEntryOffset);
			}

			entrySize = sizeof(FILE_STREAM_INFORMATION) + streamNameLength;
			// Must be align on a 8-byte boundary.
			entrySize = QuadAlign(entrySize);
			if (*RemainingLength < entrySize) {
				return STATUS_BUFFER_OVERFLOW;
			}

			// Fill the new entry
			StreamInfo->StreamNameLength = streamNameLength;
			wcscpy_s(StreamInfo->StreamName, streamNameLength + 1, streamName);
			StreamInfo->StreamSize.QuadPart = streamSize;
			StreamInfo->StreamAllocationSize.QuadPart = streamSize;
			ALIGN_ALLOCATION_SIZE(&StreamInfo->StreamAllocationSize);

			*RemainingLength -= entrySize;
		}
	}

	return STATUS_SUCCESS;
}
示例#9
0
文件: dir.c 项目: BillTheBest/WinNT4
NTSTATUS
NpQueryDirectory (
    IN PROOT_DCB RootDcb,
    IN PROOT_DCB_CCB Ccb,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the work routine for querying a directory.

Arugments:

    RootDcb - Supplies the dcb being queried

    Ccb - Supplies the context of the caller

    Irp - Supplies the Irp being processed

Return Value:

    NTSTATUS - The return status for the operation.

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;

    PUCHAR Buffer;
    CLONG SystemBufferLength;

    UNICODE_STRING FileName;
    ULONG FileIndex;
    FILE_INFORMATION_CLASS FileInformationClass;
    BOOLEAN RestartScan;
    BOOLEAN ReturnSingleEntry;
    BOOLEAN IndexSpecified;

    static WCHAR Star = L'*';

    BOOLEAN CaseInsensitive = TRUE; //*** Make searches case insensitive

    ULONG CurrentIndex;

    ULONG LastEntry;
    ULONG NextEntry;

    PLIST_ENTRY Links;
    PFCB Fcb;

    PFILE_DIRECTORY_INFORMATION DirInfo;
    PFILE_NAMES_INFORMATION NamesInfo;

    PAGED_CODE();

    //
    //  Get the current stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "NpQueryDirectory\n", 0 );
    DebugTrace( 0, Dbg, "RootDcb              = %08lx\n", RootDcb);
    DebugTrace( 0, Dbg, "Ccb                  = %08lx\n", Ccb);
    DebugTrace( 0, Dbg, "SystemBuffer         = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
    DebugTrace( 0, Dbg, "Length               = %08lx\n", IrpSp->Parameters.QueryDirectory.Length);
    DebugTrace( 0, Dbg, "FileName             = %Z\n",    IrpSp->Parameters.QueryDirectory.FileName);
    DebugTrace( 0, Dbg, "FileIndex            = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex);
    DebugTrace( 0, Dbg, "FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
    DebugTrace( 0, Dbg, "RestartScan          = %08lx\n", FlagOn(IrpSp->Flags, SL_RESTART_SCAN));
    DebugTrace( 0, Dbg, "ReturnSingleEntry    = %08lx\n", FlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY));
    DebugTrace( 0, Dbg, "IndexSpecified       = %08lx\n", FlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED));

    //
    //  Save references to the input parameters within the Irp
    //

    SystemBufferLength   = IrpSp->Parameters.QueryDirectory.Length;

    FileIndex            = IrpSp->Parameters.QueryDirectory.FileIndex;

    FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;

    RestartScan          = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
    ReturnSingleEntry    = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
    IndexSpecified       = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);

    if (IrpSp->Parameters.QueryDirectory.FileName != NULL) {

        FileName = *(PUNICODE_STRING)IrpSp->Parameters.QueryDirectory.FileName;

    } else {

        FileName.Length = 0;
        FileName.Buffer = NULL;
    }

    //
    //  Check if the ccb already has a query template attached.  If it
    //  does not already have one then we either use the string we are
    //  given or we attach our own containing "*"
    //

    if (Ccb->QueryTemplate == NULL) {

        //
        //  This is our first time calling query directory so we need
        //  to either set the query template to the user specified string
        //  or to "*"
        //

        if (FileName.Buffer == NULL) {

            DebugTrace(0, Dbg, "Set template to *\n", 0);

            FileName.Length = 2;
            FileName.Buffer = &Star;
        }

        DebugTrace(0, Dbg, "Set query template -> %Z\n", &FileName);

        //
        //  Allocate space for the query template
        //

        Ccb->QueryTemplate = FsRtlAllocatePool( PagedPool,
                                                sizeof(UNICODE_STRING) + FileName.Length );

        //
        //  Initialize the query template and copy over the string
        //

        Ccb->QueryTemplate->Length = FileName.Length;
        Ccb->QueryTemplate->Buffer = (PWCH)Ccb->QueryTemplate +
                                     sizeof(UNICODE_STRING) / sizeof(WCHAR);

        RtlCopyMemory( Ccb->QueryTemplate->Buffer,
                       FileName.Buffer,
                       FileName.Length );

        //
        //  Now zero out the FileName so we won't think we're to use it
        //  as a subsearch string.
        //

        FileName.Length = 0;
        FileName.Buffer = NULL;
    }

    //
    //  Check if we were given an index to start with or if we need to
    //  restart the scan or if we should use the index that was saved in
    //  the ccb
    //

    if (RestartScan) {

        FileIndex = 0;

    } else if (!IndexSpecified) {

        FileIndex = Ccb->IndexOfLastCcbReturned + 1;
    }

    //
    //  Now we are committed to completing the Irp, we do that in
    //  the finally clause of the following try.
    //

    try {

        ULONG BaseLength;
        ULONG LengthAdded;

        //
        // Map the user buffer.
        //

        Buffer = NpMapUserBuffer( Irp );

        //
        //  At this point we are about to enter our query loop.  We have
        //  already decided which Fcb index we need to return.  The variables
        //  LastEntry and NextEntry are used to index into the user buffer.
        //  LastEntry is the last entry we added to the user buffer, and
        //  NextEntry is the current one we're working on.  CurrentIndex
        //  is the Fcb index that we are looking at next.  Logically the
        //  way the loop works is as follows.
        //
        //  Scan all of the Fcb in the directory
        //
        //      if the Fcb matches the query template then
        //
        //          if the CurrentIndex is >= the FileIndex then
        //
        //              process this fcb, and decide if we should
        //              continue the main loop
        //
        //          end if
        //
        //          Increment the current index
        //
        //      end if
        //
        //  end scan
        //

        CurrentIndex = 0;

        LastEntry = 0;
        NextEntry =0;

        switch (FileInformationClass) {

        case FileDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
                                       FileName[0] );
            break;

        case FileFullDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
                                       FileName[0] );
            break;

        case FileNamesInformation:

            BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
                                       FileName[0] );
            break;

        case FileBothDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
                                       FileName[0] );
            break;

        default:

            try_return( Status = STATUS_INVALID_INFO_CLASS );
        }

        for (Links = RootDcb->Specific.Dcb.ParentDcbQueue.Flink;
             Links != &RootDcb->Specific.Dcb.ParentDcbQueue;
             Links = Links->Flink) {

            Fcb = CONTAINING_RECORD(Links, FCB, ParentDcbLinks);

            ASSERT(Fcb->NodeTypeCode == NPFS_NTC_FCB);

            DebugTrace(0, Dbg, "Top of Loop\n", 0);
            DebugTrace(0, Dbg, "Fcb          = %08lx\n", Fcb);
            DebugTrace(0, Dbg, "CurrentIndex = %08lx\n", CurrentIndex);
            DebugTrace(0, Dbg, "FileIndex    = %08lx\n", FileIndex);
            DebugTrace(0, Dbg, "LastEntry    = %08lx\n", LastEntry);
            DebugTrace(0, Dbg, "NextEntry    = %08lx\n", NextEntry);

            //
            //  Check if the Fcb represents a named pipe that is part of
            //  our query template
            //

            if (FsRtlIsNameInExpression( Ccb->QueryTemplate,
                                         &Fcb->LastFileName,
                                         CaseInsensitive,
                                         NULL )) {

                //
                //  The fcb is in the query template so now check if
                //  this is the index we should start returning
                //

                if (CurrentIndex >= FileIndex) {

                    ULONG BytesToCopy;
                    ULONG BytesRemainingInBuffer;

                    //
                    //  Here are the rules concerning filling up the buffer:
                    //
                    //  1.  The Io system garentees that there will always be
                    //      enough room for at least one base record.
                    //
                    //  2.  If the full first record (including file name) cannot
                    //      fit, as much of the name as possible is copied and
                    //      STATUS_BUFFER_OVERFLOW is returned.
                    //
                    //  3.  If a subsequent record cannot completely fit into the
                    //      buffer, none of it (as in 0 bytes) is copied, and
                    //      STATUS_SUCCESS is returned.  A subsequent query will
                    //      pick up with this record.
                    //

                    BytesRemainingInBuffer = SystemBufferLength - NextEntry;

                    if ( (NextEntry != 0) &&
                         ( (BaseLength + Fcb->LastFileName.Length > BytesRemainingInBuffer) ||
                           (SystemBufferLength < NextEntry) ) ) {

                        DebugTrace(0, Dbg, "Next entry won't fit\n", 0);

                        try_return( Status = STATUS_SUCCESS );
                    }

                    ASSERT( BytesRemainingInBuffer >= BaseLength );

                    //
                    //  See how much of the name we will be able to copy into
                    //  the system buffer.  This also dictates out return
                    //  value.
                    //

                    if ( BaseLength + Fcb->LastFileName.Length <=
                         BytesRemainingInBuffer ) {

                        BytesToCopy = Fcb->LastFileName.Length;
                        Status = STATUS_SUCCESS;

                    } else {

                        BytesToCopy = BytesRemainingInBuffer - BaseLength;
                        Status = STATUS_BUFFER_OVERFLOW;
                    }

                    //
                    //  Note how much of buffer we are consuming and zero
                    //  the base part of the structure.
                    //

                    LengthAdded = BaseLength + BytesToCopy;

                    RtlZeroMemory( &Buffer[NextEntry], BaseLength );

                    //
                    //  Now fill the base parts of the strucure that are
                    //  applicable.
                    //

                    switch (FileInformationClass) {

                    case FileBothDirectoryInformation:

                        //
                        //  We don't need short name
                        //

                        DebugTrace(0, Dbg, "Getting directory full information\n", 0);

                    case FileFullDirectoryInformation:

                        //
                        //  We don't use EaLength, so fill in nothing here.
                        //

                        DebugTrace(0, Dbg, "Getting directory full information\n", 0);

                    case FileDirectoryInformation:

                        DebugTrace(0, Dbg, "Getting directory information\n", 0);

                        //
                        //  The eof indicates the number of instances and
                        //  allocation size is the maximum allowed
                        //

                        DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];

                        DirInfo->EndOfFile.QuadPart = Fcb->OpenCount;
                        DirInfo->AllocationSize.QuadPart = Fcb->Specific.Fcb.MaximumInstances;

                        DirInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;

                        DirInfo->FileNameLength = Fcb->LastFileName.Length;

                        break;

                    case FileNamesInformation:

                        DebugTrace(0, Dbg, "Getting names information\n", 0);


                        NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];

                        NamesInfo->FileNameLength = Fcb->LastFileName.Length;

                        break;

                    default:

                        NpBugCheck( FileInformationClass, 0, 0 );
                    }

                    RtlCopyMemory( &Buffer[NextEntry + BaseLength],
                                   Fcb->LastFileName.Buffer,
                                   BytesToCopy );

                    //
                    //  Update the ccb to the index we've just used
                    //

                    Ccb->IndexOfLastCcbReturned = CurrentIndex;

                    //
                    //  And indicate how much of the system buffer we have
                    //  currently used up.  We must compute this value before
                    //  we long align outselves for the next entry
                    //

                    Irp->IoStatus.Information = NextEntry + LengthAdded;

                    //
                    //  Setup the previous next entry offset
                    //

                    *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;

                    //
                    //  Check if the last entry didn't completely fit
                    //

                    if ( Status == STATUS_BUFFER_OVERFLOW ) {

                        try_return( NOTHING );
                    }

                    //
                    //  Check if we are only to return a single entry
                    //

                    if (ReturnSingleEntry) {

                        try_return( Status = STATUS_SUCCESS );
                    }

                    //
                    //  Set ourselves up for the next iteration
                    //

                    LastEntry = NextEntry;
                    NextEntry += (ULONG)QuadAlign( LengthAdded );
                }

                //
                //  Increment the current index by one
                //

                CurrentIndex += 1;
            }
        }

        //
        //  At this point we've scanned the entire list of Fcb so if
        //  the NextEntry is zero then we haven't found anything so we
        //  will return no more files, otherwise we return success.
        //

        if (NextEntry == 0) {

            Status = STATUS_NO_MORE_FILES;

        } else {

            Status = STATUS_SUCCESS;
        }

    try_exit: NOTHING;
    } finally {

        if (!AbnormalTermination()) {

            NpCompleteRequest( Irp, Status );
        }

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

    return Status;
}
示例#10
-1
NTSTATUS
DfsDriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
) {
    NTSTATUS Status;
    UNICODE_STRING UnicodeString;
    PDEVICE_OBJECT DeviceObject;
    OBJECT_ATTRIBUTES ObjectAttributes;
    PWSTR p;
    int i;
    HANDLE hTemp;
    HANDLE DirHandle;
    IO_STATUS_BLOCK iosb;

    //
    // See if someone else has already created a File System Device object
    // with the name we intend to use. If so, we bail.
    //

    RtlInitUnicodeString( &UnicodeString, DFS_DRIVER_NAME );

    InitializeObjectAttributes(
        &ObjectAttributes,
        &UnicodeString,
        OBJ_CASE_INSENSITIVE,
        0,
        NULL);

    Status = ZwCreateFile(
                 &hTemp,
                 SYNCHRONIZE,
                 &ObjectAttributes,
                 &iosb,
                 NULL,
                 FILE_ATTRIBUTE_NORMAL,
                 FILE_SHARE_READ | FILE_SHARE_WRITE,
                 FILE_OPEN,
                 0,
                 NULL,
                 0);

    if (NT_SUCCESS(Status)) {
        ZwClose( hTemp );
        DfsDbgTrace(0, Dbg, "Dfs driver already loaded!\n", 0);
        return( STATUS_UNSUCCESSFUL );
    }

    //
    // Create the filesystem device object.
    //

    Status = IoCreateDevice( DriverObject,
             0,
             &UnicodeString,
             FILE_DEVICE_DFS_FILE_SYSTEM,
             FILE_REMOTE_DEVICE,
             FALSE,
             &DeviceObject );
    if ( !NT_SUCCESS( Status ) ) {
        return Status;
    }

    //
    // Create a permanent object directory in which the logical root
    // device objects will reside.  Make the directory temporary, so
    // we can just close the handle to make it go away.
    //

    UnicodeString.Buffer = p = LogicalRootDevPath;
    UnicodeString.Length = 0;
    UnicodeString.MaximumLength = MAX_LOGICAL_ROOT_LEN;
    while (*p++ != UNICODE_NULL)
        UnicodeString.Length += sizeof (WCHAR);

    InitializeObjectAttributes(
        &ObjectAttributes,
        &UnicodeString,
        OBJ_PERMANENT,
        NULL,
        NULL );

    Status = ZwCreateDirectoryObject(
                &DirHandle,
                DIRECTORY_ALL_ACCESS,
                &ObjectAttributes);

    if ( !NT_SUCCESS( Status ) ) {
        return Status;
    }

    ZwMakeTemporaryObject(DirHandle);

    p[-1] = UNICODE_PATH_SEP;
    UnicodeString.Length += sizeof (WCHAR);

    //
    // Initialize the driver object with this driver's entry points.
    // Most are simply passed through to some other device driver.
    //

    for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
        DriverObject->MajorFunction[i] = DfsVolumePassThrough;
    }

    DriverObject->MajorFunction[IRP_MJ_CREATE]      = (PDRIVER_DISPATCH)DfsFsdCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]       = (PDRIVER_DISPATCH)DfsFsdClose;
    DriverObject->MajorFunction[IRP_MJ_CLEANUP]     = (PDRIVER_DISPATCH)DfsFsdCleanup;
    DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)DfsFsdQueryInformation;
    DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)DfsFsdSetInformation;
    DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)DfsFsdFileSystemControl;
    DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION]= (PDRIVER_DISPATCH)DfsFsdQueryVolumeInformation;
    DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION]= (PDRIVER_DISPATCH)DfsFsdSetVolumeInformation;

    DriverObject->FastIoDispatch = &FastIoDispatch;

    //
    //  Initialize the global data structures
    //

    RtlZeroMemory(&DfsData, sizeof (DFS_DATA));

    DfsData.NodeTypeCode = DSFS_NTC_DATA_HEADER;
    DfsData.NodeByteSize = sizeof( DFS_DATA );

    InitializeListHead( &DfsData.VcbQueue );
    InitializeListHead( &DfsData.DeletedVcbQueue );

    InitializeListHead( &DfsData.Credentials );
    InitializeListHead( &DfsData.DeletedCredentials );

    DfsData.DriverObject = DriverObject;
    DfsData.FileSysDeviceObject = DeviceObject;

    DfsData.LogRootDevName = UnicodeString;

    ExInitializeResource( &DfsData.Resource );
    KeInitializeEvent( &DfsData.PktWritePending, NotificationEvent, TRUE );
    KeInitializeSemaphore( &DfsData.PktReferralRequests, 1, 1 );

    DfsData.MachineState = DFS_CLIENT;

    //
    //  Allocate Provider structures.
    //

    DfsData.pProvider = ExAllocatePool( PagedPool,
                       sizeof ( PROVIDER_DEF ) * MAX_PROVIDERS);

    for (i = 0; i < MAX_PROVIDERS; i++) {
        DfsData.pProvider[i].NodeTypeCode = DSFS_NTC_PROVIDER;
        DfsData.pProvider[i].NodeByteSize = sizeof ( PROVIDER_DEF );
    }

    DfsData.cProvider = 0;
    DfsData.maxProvider = MAX_PROVIDERS;

    //
    //  Initialize the system wide PKT
    //

    PktInitialize(&DfsData.Pkt);

    {
    ULONG SystemSizeMultiplier;
    ULONG ZoneSegmentSize;

    switch (MmQuerySystemSize()) {
    default:
    case MmSmallSystem:
        SystemSizeMultiplier = 4;
        break;
    case MmMediumSystem:
        SystemSizeMultiplier = 8;
        break;

    case MmLargeSystem:
        SystemSizeMultiplier = 16;
        break;
    }

    //
    //  Allocate the DFS_FCB hash table structure.  The number of hash buckets
    //  will depend upon the memory size of the system.
    //

    Status = DfsInitFcbs(SystemSizeMultiplier * 2);

    //
    //  Now initialize the zone structures for allocating IRP context
    //  records.  The size of the zone will depend upon the memory
    //  available in the system.
    //

    KeInitializeSpinLock( &DfsData.IrpContextSpinLock );

    ZoneSegmentSize = (SystemSizeMultiplier *
               QuadAlign(sizeof(IRP_CONTEXT))) +
              sizeof(ZONE_SEGMENT_HEADER);

    (VOID) ExInitializeZone( &DfsData.IrpContextZone,
                 QuadAlign(sizeof(IRP_CONTEXT)),
                 FsRtlAllocatePool( NonPagedPool,
                            ZoneSegmentSize ),
                 ZoneSegmentSize );

    }

    //
    //  Set up global pointer to the system process.
    //

    DfsData.OurProcess = PsGetCurrentProcess();

    //
    //  Register the file system with the I/O system
    //

    IoRegisterFileSystem( DeviceObject );

    //
    //  Initialize the provider definitions from the registry.
    //

    if (!NT_SUCCESS( ProviderInit() )) {

        DfsDbgTrace(0,DEBUG_TRACE_ERROR,
               "Could not initialize some or all providers!\n", 0);

    }

    //
    // Initialize the logical roots device objects. These are what form the
    // link between the outside world and the Dfs driver.
    //

    Status = DfsInitializeLogicalRoot( DD_DFS_DEVICE_NAME, NULL, NULL, 0);

    if (!NT_SUCCESS(Status)) {
      DfsDbgTrace(-1, DEBUG_TRACE_ERROR, "Failed creation of root logical root %08lx\n", Status);
      return(Status);
    }

    //
    // Let us start off the Timer Routine.
    //

    RtlZeroMemory(&DfsTimerContext, sizeof(DFS_TIMER_CONTEXT));
    DfsTimerContext.InUse = FALSE;
    DfsTimerContext.TickCount = 0;
    IoInitializeTimer(DeviceObject, DfsIoTimerRoutine, &DfsTimerContext);
    DfsDbgTrace(0, Dbg, "Initialized the Timer routine\n", 0);

    //
    //  Let us start the timer now.
    //

    IoStartTimer(DeviceObject);

    return STATUS_SUCCESS;
}