/*++

Copyright (c) 1989 - 1999 Microsoft Corporation

Module Name:

    fileinfo.c

Abstract:

    This module implements the mini redirector call down routines pertaining to retrieval/
    update of file/directory/volume information.

--*/

#include "precomp.h"
#pragma hdrstop
#pragma warning(error:4101)   // Unreferenced local variable

//
//  The local debug trace level
//

#define Dbg                              (DEBUG_TRACE_FILEINFO)

NTSTATUS
NulMRxQueryDirectory(
    IN OUT PRX_CONTEXT            RxContext
    )
/*++

Routine Description:

   This routine does a directory query. Only the NT-->NT path is implemented.

Arguments:

    RxContext - the RDBSS context

Return Value:

    NTSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_INVALID_PARAMETER;
    FILE_INFORMATION_CLASS FileInformationClass;
    PVOID   Buffer;
    PULONG  pLengthRemaining;
	ULONG	CopySize;

    FileInformationClass = RxContext->Info.FileInformationClass;
    Buffer = RxContext->Info.Buffer;
    pLengthRemaining = &RxContext->Info.LengthRemaining;

    switch (FileInformationClass)
    {
	    case FileDirectoryInformation:
		{
	        PFILE_DIRECTORY_INFORMATION pDirInfo = (PFILE_DIRECTORY_INFORMATION) Buffer;
			CopySize = sizeof( FILE_DIRECTORY_INFORMATION );
			if ( *pLengthRemaining > CopySize )
			{
	            RtlZeroMemory( pDirInfo, CopySize );
			    pDirInfo->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
			    pDirInfo->FileNameLength = sizeof( WCHAR );
			    pDirInfo->FileName[0] = L'.';
				*pLengthRemaining = CopySize;
				Status = RxContext->QueryDirectory.InitialQuery ?
				             STATUS_SUCCESS : STATUS_NO_MORE_FILES;
			}
		}
		break;

	    case FileFullDirectoryInformation:
		{
	        PFILE_FULL_DIR_INFORMATION pFullDirInfo = (PFILE_FULL_DIR_INFORMATION) Buffer;
			CopySize = sizeof( FILE_FULL_DIR_INFORMATION );
			if ( *pLengthRemaining > CopySize )
			{
	            RtlZeroMemory( pFullDirInfo, CopySize );
			    pFullDirInfo->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
			    pFullDirInfo->FileNameLength = sizeof( WCHAR );
			    pFullDirInfo->FileName[0] = L'.';
				*pLengthRemaining = CopySize;
				Status = RxContext->QueryDirectory.InitialQuery ?
				             STATUS_SUCCESS : STATUS_NO_MORE_FILES;
			}
		}
        break;

		case FileBothDirectoryInformation:
		{
	        PFILE_BOTH_DIR_INFORMATION pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION) Buffer;
			CopySize = sizeof( FILE_BOTH_DIR_INFORMATION );
			if ( *pLengthRemaining > CopySize )
			{
	            RtlZeroMemory( pBothDirInfo, CopySize );
			    pBothDirInfo->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
			    pBothDirInfo->FileNameLength = sizeof( WCHAR );
			    pBothDirInfo->FileName[0] = L'.';
			    pBothDirInfo->ShortNameLength = sizeof( WCHAR );
			    pBothDirInfo->ShortName[0] = L'.';
				*pLengthRemaining = CopySize;
				Status = RxContext->QueryDirectory.InitialQuery ?
				             STATUS_SUCCESS : STATUS_NO_MORE_FILES;
			}
		}
        break;

		case FileNamesInformation:
		{
	        PFILE_NAMES_INFORMATION pNamesDirInfo = (PFILE_NAMES_INFORMATION) Buffer;
			CopySize = sizeof( FILE_NAMES_INFORMATION );
			if ( *pLengthRemaining > CopySize )
			{
	            RtlZeroMemory( pNamesDirInfo, CopySize );
			    pNamesDirInfo->FileNameLength = sizeof( WCHAR );
			    pNamesDirInfo->FileName[0] = L'.';
				*pLengthRemaining = CopySize;
				Status = RxContext->QueryDirectory.InitialQuery ?
				             STATUS_SUCCESS : STATUS_NO_MORE_FILES;
			}
		}
        break;

		default:
			RxDbgTrace( 0, Dbg, ("NulMRxQueryDirectory: Invalid FS information class\n"));
			Status = STATUS_INVALID_PARAMETER;
			break;
	}

    DbgPrint("NulMRxQueryDirectory \n");
    return(Status);
}


NTSTATUS
NulMRxQueryVolumeInformation(
      IN OUT PRX_CONTEXT          RxContext
      )
/*++

Routine Description:

   This routine queries the volume information

Arguments:

    pRxContext         - the RDBSS context

    FsInformationClass - the kind of Fs information desired.

    pBuffer            - the buffer for copying the information

    pBufferLength      - the buffer length ( set to buffer length on input and set
                         to the remaining length on output)

Return Value:

    NTSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_INVALID_PARAMETER;
    RxCaptureFcb;

    ULONG    OriginalLength = RxContext->Info.LengthRemaining;
    FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
    PVOID OriginalBuffer = RxContext->Info.Buffer;
    UNICODE_STRING ustrVolume;
    ULONG BytesToCopy;

    RxTraceEnter("NulMRxQueryVolumeInformation");

    switch( FsInformationClass ) {
        case FileFsVolumeInformation:
		{
    		PFILE_FS_VOLUME_INFORMATION pVolInfo = (PFILE_FS_VOLUME_INFORMATION) OriginalBuffer;
            RtlZeroMemory( pVolInfo, sizeof(FILE_FS_VOLUME_INFORMATION) );
            pVolInfo->VolumeCreationTime.QuadPart = 0;
            pVolInfo->VolumeSerialNumber = 0xBABAFACE;
            pVolInfo->VolumeLabelLength = sizeof(L"NULMRX");
            pVolInfo->SupportsObjects = FALSE;
            RtlInitUnicodeString( &ustrVolume, L"NULMRX" );

            RxContext->Info.LengthRemaining -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);

            if (RxContext->Info.LengthRemaining >= (LONG)pVolInfo->VolumeLabelLength) {
                BytesToCopy = pVolInfo->VolumeLabelLength;
            } else {
                BytesToCopy = RxContext->Info.LengthRemaining;
            }

            RtlCopyMemory( &pVolInfo->VolumeLabel[0], (PVOID)ustrVolume.Buffer, BytesToCopy );
            RxContext->Info.LengthRemaining -= BytesToCopy;
            pVolInfo->VolumeLabelLength = BytesToCopy;
           
            Status = STATUS_SUCCESS;            
            DbgPrint("FileFsVolumeInformation\n");
		}
        break;
    
        case FileFsLabelInformation:
            DbgPrint("FileFsLabelInformation\n");
            break;
        
        case FileFsSizeInformation:
            DbgPrint("FileFsSizeInformation\n");
            break;
    
        case FileFsDeviceInformation:
            DbgPrint("FileFsDeviceInformation\n");
            break;
    
        case FileFsAttributeInformation:
		{
			PFILE_FS_ATTRIBUTE_INFORMATION pAttribInfo =
				(PFILE_FS_ATTRIBUTE_INFORMATION) OriginalBuffer;

			pAttribInfo->FileSystemAttributes = 0;
			pAttribInfo->MaximumComponentNameLength = 32;

            RxContext->Info.LengthRemaining -= FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0]);
			pAttribInfo->FileSystemNameLength = sizeof(L"SampleFS");
            if (RxContext->Info.LengthRemaining >= (LONG)pAttribInfo->FileSystemNameLength) {
                BytesToCopy = pAttribInfo->FileSystemNameLength;
            } else {
                BytesToCopy = RxContext->Info.LengthRemaining;
            }
            RtlCopyMemory( pAttribInfo->FileSystemName, L"SampleFS", BytesToCopy );
            RxContext->Info.LengthRemaining -= BytesToCopy;
			pAttribInfo->FileSystemNameLength = BytesToCopy;
           
            Status = STATUS_SUCCESS;            
            
            DbgPrint("FileFsAttributeInformation\n");
		}
        break;
    
        case FileFsControlInformation:
            DbgPrint("FileFsControlInformation\n");
            break;
    
        case FileFsFullSizeInformation:
            DbgPrint("FileFsFullSizeInformation\n");
            break;
    
        case FileFsObjectIdInformation:
            DbgPrint("FileFsObjectIdInformation\n");
            break;
    
        case FileFsMaximumInformation:
            DbgPrint("FileFsMaximumInformation\n");
            break;
    
        default:
            break;
    }

    RxTraceLeave(Status);
    return(Status);
}

NTSTATUS
NulMRxSetVolumeInformation(
      IN OUT PRX_CONTEXT              pRxContext
      )
/*++

Routine Description:

   This routine sets the volume information

Arguments:

    pRxContext - the RDBSS context

    FsInformationClass - the kind of Fs information desired.

    pBuffer            - the buffer for copying the information

    BufferLength       - the buffer length

Return Value:

    NTSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_NOT_IMPLEMENTED;

    DbgPrint("NulMRxSetVolumeInformation \n");
    return(Status);
}


NTSTATUS
NulMRxQueryFileInformation(
      IN PRX_CONTEXT            RxContext
      )
/*++

Routine Description:

   This routine does a query file info. Only the NT-->NT path is implemented.

   The NT-->NT path works by just remoting the call basically without further ado.

Arguments:

    RxContext - the RDBSS context

Return Value:

    NTSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb;
    FILE_INFORMATION_CLASS FunctionalityRequested = 
            RxContext->Info.FileInformationClass;
    PFILE_STANDARD_INFORMATION pFileStdInfo = 
            (PFILE_STANDARD_INFORMATION) RxContext->Info.Buffer;

    RxTraceEnter("NulMRxQueryFileInformation");

    switch( FunctionalityRequested ) {
        case FileBasicInformation:
            RxContext->Info.LengthRemaining -= sizeof(FILE_BASIC_INFORMATION);
            break;
    
        case FileInternalInformation:
            RxContext->Info.LengthRemaining -= sizeof(FILE_INTERNAL_INFORMATION);
            break;
            
        case FileEaInformation:
            RxContext->Info.LengthRemaining -= sizeof(FILE_EA_INFORMATION);
            break;
            
        case FileStandardInformation:

            RxDbgTrace(0, Dbg, ("FileSize is %d AllocationSize is %d\n",
                pFileStdInfo->EndOfFile.LowPart,pFileStdInfo->AllocationSize.LowPart));
            //(RxContext->CurrentIrp)->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
            RxContext->Info.LengthRemaining -= sizeof(FILE_STANDARD_INFORMATION);
            break;
        
        default:
            break;
    }
    
    RxTraceLeave(Status);
    return(Status);
}

NTSTATUS
NulMRxSetFileInformation(
      IN PRX_CONTEXT            RxContext
      )
/*++

Routine Description:

   This routine does a set file info. Only the NT-->NT path is implemented.

   The NT-->NT path works by just remoting the call basically without further ado.

Arguments:

    RxContext - the RDBSS context

Return Value:

    NTSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb;
    FILE_INFORMATION_CLASS FunctionalityRequested = 
            RxContext->Info.FileInformationClass;
    PFILE_END_OF_FILE_INFORMATION pEndOfFileInfo = 
            (PFILE_END_OF_FILE_INFORMATION) RxContext->Info.Buffer;
    LARGE_INTEGER NewAllocationSize;

    RxTraceEnter("NulMRxSetFileInformation");

    switch( FunctionalityRequested ) {
        case FileBasicInformation:
            RxDbgTrace(0, Dbg, ("FileBasicInformation\n"));
            break;
    
        case FileDispositionInformation:
            RxDbgTrace(0, Dbg, ("FileDispositionInformation\n"));
            break;
    
        case FilePositionInformation:
            RxDbgTrace(0, Dbg, ("FilePositionInformation\n"));
            break;
    
        case FileAllocationInformation:
            RxDbgTrace(0, Dbg, ("FileAllocationInformation\n"));
            RxDbgTrace(0, Dbg, ("AllocSize is %d AllocSizeHigh is %d\n",
            pEndOfFileInfo->EndOfFile.LowPart,pEndOfFileInfo->EndOfFile.HighPart));
            break;
    
        case FileEndOfFileInformation:
            RxDbgTrace(0, Dbg, ("FileSize is %d FileSizeHigh is %d\n",
            capFcb->Header.AllocationSize.LowPart,capFcb->Header.AllocationSize.HighPart));

            if( pEndOfFileInfo->EndOfFile.QuadPart > 
                    capFcb->Header.AllocationSize.QuadPart ) {
            
                Status = NulMRxExtendFile(
                                RxContext,
                                &pEndOfFileInfo->EndOfFile,
                                &NewAllocationSize
                                );

                RxDbgTrace(0, Dbg, ("AllocSize is %d AllocSizeHigh is %d\n",
                            NewAllocationSize.LowPart,NewAllocationSize.HighPart));

                //
                //  Change the file allocation
                //
                capFcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart;
            } else {
                Status = NulMRxTruncateFile(
                                RxContext,
                                &pEndOfFileInfo->EndOfFile,
                                &NewAllocationSize
                                );
            }

            RxContext->Info.LengthRemaining -= sizeof(FILE_END_OF_FILE_INFORMATION);
            break;
    
        case FileRenameInformation:
            RxDbgTrace(0, Dbg, ("FileRenameInformation\n"));
            break;
    
        default:
            break;
    }
    
    RxTraceLeave(Status);
    return Status;
}

NTSTATUS
NulMRxSetFileInformationAtCleanup(
      IN PRX_CONTEXT            RxContext
      )
/*++

Routine Description:

   This routine sets the file information on cleanup. the old rdr just swallows this operation (i.e.
   it doesn't generate it). we are doing the same..........

Arguments:

    pRxContext           - the RDBSS context

Return Value:

    NTSTATUS - The return status for the operation

--*/
{
    NTSTATUS Status = STATUS_NOT_IMPLEMENTED;

    return(Status);
}