/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*-
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 * Editor Settings: expandtabs and use 4 spaces for indentation */

/*
 * Copyright Likewise Software
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.  You should have received a copy of the GNU General
 * Public License along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
 * TERMS AS WELL.  IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
 * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
 * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
 * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE.  IF YOU
 * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
 * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
 * license@likewisesoftware.com
 */

/*
 * Copyright (C) Likewise Software. All rights reserved.
 *
 * Module Name:
 *
 *        getfileinfo.c
 *
 * Abstract:
 *
 *        Likewise IO (LWIO) - SRV
 *
 *        Protocols API - SMBV2
 *
 *        Query File Information
 *
 * Authors: Krishna Ganugapati (kganugapati@likewise.com)
 *          Sriram Nambakam (snambakam@likewise.com)
 *
 *
 */

#include "includes.h"

static
NTSTATUS
SrvMarshalFileName_SMB_V2(
    PLWIO_SRV_TREE_2 pTree,
    PWSTR pwszFileName,
    PULONG pulFileNameLength,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    );

static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileInternalInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileEAInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileBasicInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileStandardInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileNetworkOpenInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileAccessInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFilePositionInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileModeInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileAllInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileAlignmentInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileNameInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileAttrTagInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileStreamInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileFullEAInfo_SMB_V2;
static GET_INFO_CLASS_MARSHAL_FUNC SrvMarshalFileCompressionInfo_SMB_V2;

static GET_INFO_CLASS_DISPATCH_ENTRY FileInfoClassDispatchTable_SMB_V2[] =
{
    [SMB2_FILE_INFO_CLASS_INTERNAL]         =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileInternalInfo_SMB_V2,
        FileInternalInformation,
        sizeof(SMB_FILE_INTERNAL_INFO),
        sizeof(FILE_INTERNAL_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_EA]               =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileEAInfo_SMB_V2,
        FileEaInformation,
        sizeof(SMB_FILE_EA_INFORMATION),
        sizeof(FILE_EA_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_BASIC]            =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileBasicInfo_SMB_V2,
        FileBasicInformation,
        sizeof(SMB2_FILE_BASIC_INFORMATION),
        sizeof(FILE_BASIC_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_STANDARD]         =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileStandardInfo_SMB_V2,
        FileStandardInformation,
        sizeof(SMB2_FILE_STANDARD_INFORMATION),
        sizeof(FILE_STANDARD_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_NETWORK_OPEN]     =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileNetworkOpenInfo_SMB_V2,
        FileNetworkOpenInformation,
        sizeof(SMB2_FILE_NETWORK_OPEN_INFORMATION),
        sizeof(FILE_NETWORK_OPEN_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_ACCESS]           =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileAccessInfo_SMB_V2,
        FileAccessInformation,
        sizeof(SMB2_FILE_ACCESS_INFORMATION),
        sizeof(FILE_ACCESS_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_POSITION]         =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFilePositionInfo_SMB_V2,
        FilePositionInformation,
        sizeof(SMB2_FILE_POSITION_INFORMATION),
        sizeof(FILE_POSITION_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_MODE]             =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileModeInfo_SMB_V2,
        FileModeInformation,
        sizeof(SMB2_FILE_MODE_INFORMATION),
        sizeof(FILE_MODE_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_ALL]              =
    {
        SrvGetFileInfoGeneric_WithFileName,
        SrvMarshalFileAllInfo_SMB_V2,
        FileAllInformation,
        sizeof(SMB2_FILE_ALL_INFO_HEADER),
        LW_FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName)
    },
    [SMB2_FILE_INFO_CLASS_ALIGNMENT]        =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileAlignmentInfo_SMB_V2,
        FileAlignmentInformation,
        sizeof(SMB2_FILE_ALIGNMENT_INFORMATION),
        sizeof(FILE_ALIGNMENT_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_ALTERNATE_NAME]   =
    {
        SrvGetFileInfoGeneric_WithFileName,
        SrvMarshalFileNameInfo_SMB_V2,
        FileAlternateNameInformation,
        sizeof(SMB2_FILE_NAME_INFORMATION),
        sizeof(FILE_NAME_INFORMATION),
    },
    [SMB2_FILE_INFO_CLASS_ATTRIBUTE_TAG]    =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileAttrTagInfo_SMB_V2,
        FileAttributeTagInformation,
        sizeof(SMB2_FILE_ATTRIBUTE_TAG_INFORMATION),
        sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_STREAM]           =
    {
        SrvGetFileInfoGeneric_WithString,
        SrvMarshalFileStreamInfo_SMB_V2,
        FileStreamInformation,
        sizeof(SMB2_FILE_STREAM_INFO_HEADER),
        LW_FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName)
    },
    [SMB2_FILE_INFO_CLASS_FULL_EA]          =
    {
        SrvGetFileInfoGeneric_WithString,
        SrvMarshalFileFullEAInfo_SMB_V2,
        FileFullEaInformation,
        sizeof(SMB2_FILE_FULL_EA_INFO_HEADER),
        LW_FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName)
    },
    [SMB2_FILE_INFO_CLASS_COMPRESSION]      =
    {
        SrvGetFileInfoGeneric,
        SrvMarshalFileCompressionInfo_SMB_V2,
        FileCompressionInformation,
        sizeof(SMB2_FILE_COMPRESSION_INFORMATION),
        sizeof(FILE_COMPRESSION_INFORMATION)
    },
    [SMB2_FILE_INFO_CLASS_NAME]             =
    {
        SrvGetFileInfoGeneric_WithFileName,
        SrvMarshalFileNameInfo_SMB_V2,
        FileNameInformation,
        sizeof(SMB2_FILE_NAME_INFORMATION),
        sizeof(FILE_NAME_INFORMATION),
    },
    /* Currently unsuported but not invalid */
    [SMB2_FILE_INFO_CLASS_PIPE]             =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_PIPE_LOCAL]       =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_PIPE_REMOTE]      =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_MAILSLOT_QUERY]   =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_COMPLETION]       =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_QUOTA]            =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_REPARSE_POINT]    =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_FS_ATTRIBUTE]     =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_FS_SIZE]          =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_SFIO_RESERVE]     =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_SFIO_VOLUME]      =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_HARD_LINK]        =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_UNKNOWN_2F]       =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_NORMALIZED_NAME]  =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_UNKNOWN_31]       =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_UNKNOWN_33]       =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_UNKNOWN_34]       =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_UNKNOWN_35]       =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_STANDARD_LINK]    =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    },
    [SMB2_FILE_INFO_CLASS_UNKNOWN_37]       =
    {
        SrvGetUnsupportedInfo,
        SrvMarshalUnsupportedInfo,
    }
};

PGET_INFO_CLASS_DISPATCH_ENTRY
SrvGetFileInfoDispatchTable_SMB_V2(
    VOID
    )
{
    return FileInfoClassDispatchTable_SMB_V2;
}

size_t
SrvGetFileInfoDispatchTableSize_SMB_V2(
    VOID
    )
{
    return LW_ARRAY_SIZE(FileInfoClassDispatchTable_SMB_V2);
}

static
NTSTATUS
SrvMarshalFileInternalInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_INTERNAL_INFORMATION      pFileInternalInfo    = NULL;
    PSMB2_FILE_INTERNAL_INFORMATION pSMBFileInternalInfo = NULL;

    pFileInternalInfo    = (PFILE_INTERNAL_INFORMATION)pInfoState->pData;
    pSMBFileInternalInfo = (PSMB2_FILE_INTERNAL_INFORMATION)pOutBuffer;

    pSMBFileInternalInfo->llIndexNumber = pFileInternalInfo->IndexNumber;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileEAInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_EA_INFORMATION       pFileEAInfo    = NULL;
    PSMB_FILE_EA_INFORMATION   pSMBFileEAInfo = NULL;

    pFileEAInfo    = (PFILE_EA_INFORMATION)pInfoState->pData;
    pSMBFileEAInfo = (PSMB_FILE_EA_INFORMATION)pOutBuffer;

    pSMBFileEAInfo->ulEaSize = pFileEAInfo->EaSize;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileBasicInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_BASIC_INFORMATION      pFileBasicInfo    = NULL;
    PSMB2_FILE_BASIC_INFORMATION pSMBFileBasicInfo = NULL;

    pFileBasicInfo    = (PFILE_BASIC_INFORMATION)pInfoState->pData;
    pSMBFileBasicInfo = (PSMB2_FILE_BASIC_INFORMATION)pOutBuffer;

    pSMBFileBasicInfo->ChangeTime     = pFileBasicInfo->ChangeTime;
    pSMBFileBasicInfo->CreationTime   = pFileBasicInfo->CreationTime;
    pSMBFileBasicInfo->FileAttributes = pFileBasicInfo->FileAttributes;
    pSMBFileBasicInfo->LastAccessTime = pFileBasicInfo->LastAccessTime;
    pSMBFileBasicInfo->LastWriteTime  = pFileBasicInfo->LastWriteTime;
    pSMBFileBasicInfo->unknown        = 0;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileStandardInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_STANDARD_INFORMATION      pFileStandardInfo    = NULL;
    PSMB2_FILE_STANDARD_INFORMATION pSMBFileStandardInfo = NULL;

    pFileStandardInfo    = (PFILE_STANDARD_INFORMATION)pInfoState->pData;
    pSMBFileStandardInfo = (PSMB2_FILE_STANDARD_INFORMATION)pOutBuffer;

    pSMBFileStandardInfo->AllocationSize = pFileStandardInfo->AllocationSize;
    pSMBFileStandardInfo->EndOfFile      = pFileStandardInfo->EndOfFile;
    pSMBFileStandardInfo->NumberOfLinks  = pFileStandardInfo->NumberOfLinks;
    pSMBFileStandardInfo->DeletePending  = pFileStandardInfo->DeletePending;
    pSMBFileStandardInfo->Directory      = pFileStandardInfo->Directory;
    memset(pSMBFileStandardInfo->Pad, 0, sizeof(pSMBFileStandardInfo->Pad));

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileNetworkOpenInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_NETWORK_OPEN_INFORMATION      pFileNetOpenInfo    = NULL;
    PSMB2_FILE_NETWORK_OPEN_INFORMATION pSMBFileNetOpenInfo = NULL;

    pFileNetOpenInfo    = (PFILE_NETWORK_OPEN_INFORMATION)pInfoState->pData;
    pSMBFileNetOpenInfo = (PSMB2_FILE_NETWORK_OPEN_INFORMATION)pOutBuffer;

    pSMBFileNetOpenInfo->llChangeTime      = pFileNetOpenInfo->ChangeTime;
    pSMBFileNetOpenInfo->llCreationTime    = pFileNetOpenInfo->CreationTime;
    pSMBFileNetOpenInfo->llLastAccessTime  = pFileNetOpenInfo->LastAccessTime;
    pSMBFileNetOpenInfo->llLastWriteTime   = pFileNetOpenInfo->LastWriteTime;
    pSMBFileNetOpenInfo->ullAllocationSize = pFileNetOpenInfo->AllocationSize;
    pSMBFileNetOpenInfo->ullEndOfFile      = pFileNetOpenInfo->EndOfFile;
    pSMBFileNetOpenInfo->ulFileAttributes  = pFileNetOpenInfo->FileAttributes;
    pSMBFileNetOpenInfo->ulPad             = 0;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileAccessInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_ACCESS_INFORMATION      pFileAccessInfo    = NULL;
    PSMB2_FILE_ACCESS_INFORMATION pSMBFileAccessInfo = NULL;

    pFileAccessInfo    = (PFILE_ACCESS_INFORMATION)pInfoState->pData;
    pSMBFileAccessInfo = (PSMB2_FILE_ACCESS_INFORMATION)pOutBuffer;

    pSMBFileAccessInfo->AccessFlags = pFileAccessInfo->AccessFlags;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFilePositionInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_POSITION_INFORMATION      pFilePosInfo    = NULL;
    PSMB2_FILE_POSITION_INFORMATION pSMBFilePosInfo = NULL;

    pFilePosInfo    = (PFILE_POSITION_INFORMATION)pInfoState->pData;
    pSMBFilePosInfo = (PSMB2_FILE_POSITION_INFORMATION)pOutBuffer;

    /* XXX MS_SMB2 3.3.5.20.1: CurrentByteOffset should always be zero. */
    pSMBFilePosInfo->ullCurrentByteOffset = pFilePosInfo->CurrentByteOffset;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileModeInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_MODE_INFORMATION      pFileModeInfo    = NULL;
    PSMB2_FILE_MODE_INFORMATION pSMBFileModeInfo = NULL;

    pFileModeInfo    = (PFILE_MODE_INFORMATION)pInfoState->pData;
    pSMBFileModeInfo = (PSMB2_FILE_MODE_INFORMATION)pOutBuffer;

    pSMBFileModeInfo->Mode = pFileModeInfo->Mode;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileAllInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    NTSTATUS                   ntStatus        = STATUS_SUCCESS;
    PFILE_ALL_INFORMATION      pFileAllInfo    = NULL;
    PSMB2_FILE_ALL_INFO_HEADER pSMBFileAllInfo = NULL;
    ULONG                      ulFileNameLen   = 0;
    ULONG                      ulBytesNeeded   = 0;

    *pulBytesUsed   = 0;
    pFileAllInfo    = (PFILE_ALL_INFORMATION)pInfoState->pData;
    pSMBFileAllInfo = (PSMB2_FILE_ALL_INFO_HEADER)pOutBuffer;

    /* The file name is the dynamic portion of what the FS returned. */
    ulFileNameLen = pInfoState->ulActualDataLen - pInfoEntry->IOStructSize;
    ulBytesNeeded = pInfoEntry->ProtoStructSize + ulFileNameLen;

    LW_ASSERT(ulBytesAvailable >= ulBytesNeeded);

    pSMBFileAllInfo->llChangeTime         =
        pFileAllInfo->BasicInformation.ChangeTime;
    pSMBFileAllInfo->llCreationTime       =
        pFileAllInfo->BasicInformation.CreationTime;
    pSMBFileAllInfo->llLastAccessTime     =
        pFileAllInfo->BasicInformation.LastAccessTime;
    pSMBFileAllInfo->llLastWriteTime      =
        pFileAllInfo->BasicInformation.LastWriteTime;
    pSMBFileAllInfo->ulFileAttributes     =
        pFileAllInfo->BasicInformation.FileAttributes;
    pSMBFileAllInfo->ulReserved           = 0;
    pSMBFileAllInfo->ullAllocationSize    =
        pFileAllInfo->StandardInformation.AllocationSize;
    pSMBFileAllInfo->ullEndOfFile         =
        pFileAllInfo->StandardInformation.EndOfFile;
    pSMBFileAllInfo->ulNumberOfLinks      =
        pFileAllInfo->StandardInformation.NumberOfLinks;
    pSMBFileAllInfo->ucDeletePending      =
        pFileAllInfo->StandardInformation.DeletePending;
    pSMBFileAllInfo->ucIsDirectory        =
        pFileAllInfo->StandardInformation.Directory;
    pSMBFileAllInfo->usReserved           = 0;
    pSMBFileAllInfo->ullIndexNumber       =
        pFileAllInfo->InternalInformation.IndexNumber;
    pSMBFileAllInfo->ulEaSize             = pFileAllInfo->EaInformation.EaSize;
    pSMBFileAllInfo->ulAccessMask         =
        pFileAllInfo->AccessInformation.AccessFlags;
    pSMBFileAllInfo->ullCurrentByteOffset =
        pFileAllInfo->PositionInformation.CurrentByteOffset;
    pSMBFileAllInfo->ulMode               = pFileAllInfo->ModeInformation.Mode;
    pSMBFileAllInfo->ulAlignment          =
        pFileAllInfo->AlignmentInformation.AlignmentRequirement;

    ntStatus = SrvMarshalFileName_SMB_V2(
                    /* Absolute Path */NULL,
                    pFileAllInfo->NameInformation.FileName,
                    &ulFileNameLen,
                    (PBYTE)&pSMBFileAllInfo->wszFilename,
                    ulBytesAvailable - pInfoEntry->ProtoStructSize,
                    pulBytesUsed);
    BAIL_ON_NT_STATUS(ntStatus);

    pSMBFileAllInfo->ulFilenameLength = ulFileNameLen;
    *pulBytesUsed += pInfoEntry->ProtoStructSize;

error:

    return ntStatus;
}

static
NTSTATUS
SrvMarshalFileAlignmentInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_ALIGNMENT_INFORMATION      pFileAlignmentInfo    = NULL;
    PSMB2_FILE_ALIGNMENT_INFORMATION pSMBFileAlignmentInfo = NULL;

    pFileAlignmentInfo    = (PFILE_ALIGNMENT_INFORMATION)pInfoState->pData;
    pSMBFileAlignmentInfo = (PSMB2_FILE_ALIGNMENT_INFORMATION)pOutBuffer;

    pSMBFileAlignmentInfo->AlignmentRequirement =
        pFileAlignmentInfo->AlignmentRequirement;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileNameInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PSRV_EXEC_CONTEXT_SMB_V2    pCtxSmb2         = pExecContext->pProtocolContext;
    NTSTATUS                    ntStatus         = STATUS_SUCCESS;
    PLWIO_SRV_TREE_2            pTree            = NULL;
    PFILE_NAME_INFORMATION      pFileNameInfo    = NULL;
    PSMB2_FILE_NAME_INFORMATION pSMBFileNameInfo = NULL;
    ULONG                       ulFileNameLen    = 0;

    *pulBytesUsed    = 0;
    pFileNameInfo    = (PFILE_NAME_INFORMATION)pInfoState->pData;
    pSMBFileNameInfo = (PSMB2_FILE_NAME_INFORMATION)pOutBuffer;
    ulFileNameLen    = pFileNameInfo->FileNameLength;

    if (pInfoState->usInfoClass == FileAlternateNameInformation)
    {
        pTree = pCtxSmb2->pTree;
    }

    ntStatus = SrvMarshalFileName_SMB_V2(
                    pTree,
                    pFileNameInfo->FileName,
                    &ulFileNameLen,
                    (PBYTE)&pSMBFileNameInfo->FileName,
                    ulBytesAvailable - pInfoEntry->ProtoStructSize,
                    pulBytesUsed);
    BAIL_ON_NT_STATUS(ntStatus);

    pSMBFileNameInfo->ulFileNameLength = ulFileNameLen;
    *pulBytesUsed += pInfoEntry->ProtoStructSize;

error:

    return ntStatus;
}

static
NTSTATUS
SrvMarshalFileName_SMB_V2(
    PLWIO_SRV_TREE_2 pTree,
    PWSTR pwszFileName,
    PULONG pulFileNameLength,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    NTSTATUS ntStatus       = STATUS_SUCCESS;
    PWSTR    pRawSharePath  = NULL;
    PWSTR    pwszTreePath   = NULL;
    ULONG    ulPrefixLength = 0;
    BOOLEAN  bShareInLock   = FALSE;

    if (pTree) {
        LWIO_LOCK_RWMUTEX_SHARED(bShareInLock, &pTree->pShareInfo->Mutex);
    
        ntStatus = SrvShareGetPath(
                pTree->pShareInfo,
                pTree->pSession->pNetbiosDomain,
                pTree->pSession->pSamAccountName,
                &pRawSharePath);
        BAIL_ON_NT_STATUS(ntStatus);
    
        LWIO_UNLOCK_RWMUTEX(bShareInLock, &pTree->pShareInfo->Mutex);
    
        // pwszTreePath is a reference to pRawSharePath, not a substring copy.
        ntStatus = SrvGetTreeRelativePath(pRawSharePath, &pwszTreePath);
        BAIL_ON_NT_STATUS(ntStatus);
    
        ntStatus = SrvMatchPathPrefix(
                        pwszFileName,
                        *pulFileNameLength/sizeof(wchar16_t),
                        pwszTreePath);
    
        if (STATUS_SUCCESS != ntStatus)
        {
            ntStatus = STATUS_INTERNAL_ERROR;
            BAIL_ON_NT_STATUS(ntStatus);
        }
    
        ulPrefixLength      = wc16slen(pwszTreePath) * sizeof(wchar16_t);
        *pulFileNameLength -= ulPrefixLength;
    }

    *pulBytesUsed = SMB_MIN(*pulFileNameLength, ulBytesAvailable);
    memcpy(pOutBuffer, (PBYTE)pwszFileName + ulPrefixLength, *pulBytesUsed);

cleanup:

    LWIO_UNLOCK_RWMUTEX(bShareInLock, &pTree->pShareInfo->Mutex);

    RTL_FREE(&pRawSharePath);

    return ntStatus;

error:

    goto cleanup;
}

static
NTSTATUS
SrvMarshalFileAttrTagInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_ATTRIBUTE_TAG_INFORMATION      pFileAttrTagInfo     = NULL;
    PSMB2_FILE_ATTRIBUTE_TAG_INFORMATION pSMB2FileAttrTagInfo = NULL;

    pFileAttrTagInfo = (PFILE_ATTRIBUTE_TAG_INFORMATION)pInfoState->pData;
    pSMB2FileAttrTagInfo = (PSMB2_FILE_ATTRIBUTE_TAG_INFORMATION)pOutBuffer;

    pSMB2FileAttrTagInfo->FileAttributes = pFileAttrTagInfo->FileAttributes;
    pSMB2FileAttrTagInfo->ulReparseTag = pFileAttrTagInfo->ReparseTag;

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileStreamInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_STREAM_INFORMATION      pFileStreamInfo        = NULL;
    PSMB2_FILE_STREAM_INFO_HEADER pSMBFileStreamInfo     = NULL;
    ULONG                         ulIoBytesAvailable     = 0;

    *pulBytesUsed       = 0;
    pFileStreamInfo     = (PFILE_STREAM_INFORMATION)pInfoState->pData;
    ulIoBytesAvailable  = pInfoState->ulActualDataLen;

    while (ulIoBytesAvailable > sizeof(*pFileStreamInfo))
    {
        ULONG  ulInfoBytesRequired = 0;
        USHORT usAlign             = 0;

        ulInfoBytesRequired += sizeof(*pSMBFileStreamInfo);
        ulInfoBytesRequired += pFileStreamInfo->StreamNameLength;

        /* Null terminate all stream names but the last. */
        if (pFileStreamInfo->NextEntryOffset != 0)
        {
            ulInfoBytesRequired += sizeof(wchar16_t);
            usAlign             += sizeof(wchar16_t);

            if (ulInfoBytesRequired % 8)
            {
                ulInfoBytesRequired += 8 - (ulInfoBytesRequired % 8);
                usAlign             += 8 - (ulInfoBytesRequired % 8);
            }
        }

        if (ulBytesAvailable < ulInfoBytesRequired)
        {
            break;
        }

        pSMBFileStreamInfo = (PSMB2_FILE_STREAM_INFO_HEADER)pOutBuffer;
        pSMBFileStreamInfo->ulNextEntryOffset = ulInfoBytesRequired;
        pSMBFileStreamInfo->llStreamAllocationSize =
            pFileStreamInfo->StreamAllocationSize;
        pSMBFileStreamInfo->ullStreamSize = pFileStreamInfo->StreamSize;
        pSMBFileStreamInfo->ulStreamNameLength =
            pFileStreamInfo->StreamNameLength;

        pOutBuffer = (PBYTE)pSMBFileStreamInfo->wszStreamName;
        memcpy(
            pOutBuffer,
            pFileStreamInfo->StreamName,
            pSMBFileStreamInfo->ulStreamNameLength);
        pOutBuffer += pSMBFileStreamInfo->ulStreamNameLength;

        memset(pOutBuffer, 0, usAlign);
        pOutBuffer += usAlign;

        *pulBytesUsed += ulInfoBytesRequired;

        if (pFileStreamInfo->NextEntryOffset == 0)
        {
            break;
        }

        ulIoBytesAvailable -= pFileStreamInfo->NextEntryOffset;
        ulBytesAvailable -= ulInfoBytesRequired;
        pFileStreamInfo = 
            (PFILE_STREAM_INFORMATION)
            ((PBYTE)pFileStreamInfo + pFileStreamInfo->NextEntryOffset);
    }

    if (pSMBFileStreamInfo)
    {
        pSMBFileStreamInfo->ulNextEntryOffset = 0;
    }

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileFullEAInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_FULL_EA_INFORMATION      pFileFullEaInfo        = NULL;
    PSMB2_FILE_FULL_EA_INFO_HEADER pSMBFileFullEaInfo     = NULL;
    ULONG                          ulIoBytesAvailable     = 0;

    *pulBytesUsed       = 0;
    pFileFullEaInfo     = (PFILE_FULL_EA_INFORMATION)pInfoState->pData;
    ulIoBytesAvailable  = pInfoState->ulActualDataLen;

    while (ulIoBytesAvailable > sizeof(*pFileFullEaInfo))
    {
        ULONG  ulInfoBytesRequired = 0;
        USHORT usAlign             = 0;

        ulInfoBytesRequired += sizeof(*pSMBFileFullEaInfo);
        ulInfoBytesRequired +=
            pFileFullEaInfo->EaNameLength +
            /*NUL*/1 +
            pFileFullEaInfo->EaValueLength;

        /* Pad all entries but the last for 4 byte alignment. */
        if (pFileFullEaInfo->NextEntryOffset != 0 &&
            ulInfoBytesRequired % 4)
        {
            usAlign += 4 - (ulInfoBytesRequired % 4);
            ulInfoBytesRequired += usAlign;
        }

        if (ulBytesAvailable < ulInfoBytesRequired)
        {
            break;
        }

        pSMBFileFullEaInfo = (PSMB2_FILE_FULL_EA_INFO_HEADER)pOutBuffer;
        pSMBFileFullEaInfo->ulNextEntryOffset = ulInfoBytesRequired;
        pSMBFileFullEaInfo->ucFlags = pFileFullEaInfo->Flags;
        pSMBFileFullEaInfo->ucEaNameLength = pFileFullEaInfo->EaNameLength;
        pSMBFileFullEaInfo->usEaValueLength = pFileFullEaInfo->EaValueLength;

        pOutBuffer = (PBYTE)pSMBFileFullEaInfo->szEaName;
        memcpy(
            pOutBuffer,
            pFileFullEaInfo->EaName,
            pSMBFileFullEaInfo->ucEaNameLength + 1);
        pOutBuffer += pSMBFileFullEaInfo->ucEaNameLength + 1;
 
        memcpy(
            pOutBuffer,
            pFileFullEaInfo->EaName + pFileFullEaInfo->EaNameLength + 1,
            pSMBFileFullEaInfo->usEaValueLength);
        pOutBuffer += pSMBFileFullEaInfo->usEaValueLength;

        memset(pOutBuffer, 0, usAlign);
        pOutBuffer += usAlign;

        *pulBytesUsed += ulInfoBytesRequired;

        if (pFileFullEaInfo->NextEntryOffset == 0)
        {
            break;
        }

        ulIoBytesAvailable -= pFileFullEaInfo->NextEntryOffset;
        ulBytesAvailable -= ulInfoBytesRequired;
        pFileFullEaInfo = 
            (PFILE_FULL_EA_INFORMATION)
            ((PBYTE)pFileFullEaInfo + pFileFullEaInfo->NextEntryOffset);
    }

    if (pSMBFileFullEaInfo)
    {
        pSMBFileFullEaInfo->ulNextEntryOffset = 0;
    }

    return STATUS_SUCCESS;
}

static
NTSTATUS
SrvMarshalFileCompressionInfo_SMB_V2(
    PSRV_EXEC_CONTEXT pExecContext,
    PSRV_PROCESS_INFO_STATE pInfoState,
    PGET_INFO_CLASS_DISPATCH_ENTRY pInfoEntry,
    PBYTE pOutBuffer,
    ULONG ulBytesAvailable,
    PULONG pulBytesUsed
    )
{
    PFILE_COMPRESSION_INFORMATION      pFileCompInfo    = NULL;
    PSMB2_FILE_COMPRESSION_INFORMATION pSMBFileCompInfo = NULL;

    pFileCompInfo    = (PFILE_COMPRESSION_INFORMATION)pInfoState->pData;
    pSMBFileCompInfo = (PSMB2_FILE_COMPRESSION_INFORMATION)pOutBuffer;

    pSMBFileCompInfo->llCompressedFileSize = pFileCompInfo->CompressedFileSize;
    pSMBFileCompInfo->ucChunkShift = pFileCompInfo->ChunkShift;
    pSMBFileCompInfo->ucClusterShift = pFileCompInfo->ClusterShift;
    pSMBFileCompInfo->ucCompressionUnitShift =
        pFileCompInfo->CompressionUnitShift;
    pSMBFileCompInfo->usCompressionFormat = pFileCompInfo->CompressionFormat;
    memset(
        pSMBFileCompInfo->ucReserved,
        0,
        sizeof(pSMBFileCompInfo->ucReserved));

    *pulBytesUsed = pInfoEntry->ProtoStructSize;

    return STATUS_SUCCESS;
}
