VirtualBox

Changeset 78536 in vbox for trunk/src/VBox/Additions/WINNT


Ignore:
Timestamp:
May 15, 2019 11:51:30 PM (6 years ago)
Author:
vboxsync
Message:

winnt/vboxsf: The file system string returned by FileFsAttributeInformation should not be zero terminated according to NTFS, FAT, and RDR2. Cleaned up the remaining classes we respond to in VBoxMRxQueryVolumeInfo. Implemented FileFsSectorSizeInformation. Hacked around weird IOS values in unimplemented classes when FsPerf was passing a directory handle (see comment in code). bugref:9172

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/SharedFolders/driver/info.cpp

    r78533 r78536  
    563563            pVBoxFcbX->VolInfo.fsProperties.fCaseSensitive   = pReq->VolInfo.fsProperties.fCaseSensitive;
    564564            pVBoxFcbX->VolInfo.fsProperties.fReadOnly        = pReq->VolInfo.fsProperties.fReadOnly;
     565            /** @todo Use SHFL_FN_QUERY_MAP_INFO to get the correct read-only status of
     566             *        the share. */
    565567            pVBoxFcbX->VolInfo.fsProperties.fSupportsUnicode = pReq->VolInfo.fsProperties.fSupportsUnicode;
    566568            pVBoxFcbX->VolInfo.fsProperties.fCompressed      = pReq->VolInfo.fsProperties.fCompressed;
     
    715717{
    716718    /*
    717      * NtQueryVolumeInformationFile should've checked the minimum buffer size
    718      * but just in case.
    719      */
    720     AssertReturnStmt(cbInfo >= sizeof(FILE_FS_SIZE_INFORMATION),
    721                      pRxContext->InformationToReturn = sizeof(FILE_FS_SIZE_INFORMATION),
    722                      STATUS_BUFFER_TOO_SMALL);
     719     * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
     720     */
     721    AssertReturnStmt(cbInfo >= sizeof(*pInfo), pRxContext->InformationToReturn = sizeof(*pInfo), STATUS_BUFFER_TOO_SMALL);
    723722
    724723    /*
     
    783782{
    784783    /*
    785      * NtQueryVolumeInformationFile should've checked the minimum buffer size
    786      * but just in case.
    787      */
    788     AssertReturnStmt(cbInfo >= sizeof(FILE_FS_SIZE_INFORMATION),
    789                      pRxContext->InformationToReturn = sizeof(FILE_FS_SIZE_INFORMATION),
    790                      STATUS_BUFFER_TOO_SMALL);
     784     * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
     785     */
     786    AssertReturnStmt(cbInfo >= sizeof(*pInfo), pRxContext->InformationToReturn = sizeof(*pInfo), STATUS_BUFFER_TOO_SMALL);
    791787
    792788    /*
     
    841837}
    842838
    843 
     839/**
     840 * Handles NtQueryVolumeInformationFile / FileFsDeviceInformation
     841 */
     842static NTSTATUS vbsfNtQueryFsDeviceInfo(IN OUT PRX_CONTEXT pRxContext,
     843                                        PFILE_FS_DEVICE_INFORMATION pInfo,
     844                                        ULONG cbInfo,
     845                                        PMRX_NET_ROOT pNetRoot)
     846{
     847    /*
     848     * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
     849     */
     850    AssertReturnStmt(cbInfo >= sizeof(*pInfo), pRxContext->InformationToReturn = sizeof(*pInfo), STATUS_BUFFER_TOO_SMALL);
     851
     852    /*
     853     * Produce the requested data.
     854     */
     855    pInfo->DeviceType      = pNetRoot->DeviceType;
     856    pInfo->Characteristics = FILE_REMOTE_DEVICE;
     857
     858    Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: DeviceType = %#x\n", pInfo->DeviceType));
     859    Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: Characteristics = %#x (FILE_REMOTE_DEVICE)\n", FILE_REMOTE_DEVICE));
     860
     861    /*
     862     * Update the return length in the context.
     863     */
     864    pRxContext->Info.LengthRemaining = cbInfo - sizeof(*pInfo);
     865    pRxContext->InformationToReturn  = sizeof(*pInfo); /* whatever */
     866    return STATUS_SUCCESS;
     867}
     868
     869/**
     870 * Handles NtQueryVolumeInformationFile / FileFsDeviceInformation
     871 */
     872static NTSTATUS vbsfNtQueryFsAttributeInfo(IN OUT PRX_CONTEXT pRxContext,
     873                                           PFILE_FS_ATTRIBUTE_INFORMATION pInfo,
     874                                           ULONG cbInfo,
     875                                           PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
     876                                           PMRX_VBOX_FOBX pVBoxFobx,
     877                                           PVBSFNTFCBEXT pVBoxFcbX)
     878{
     879    static WCHAR const s_wszFsName[] = MRX_VBOX_FILESYS_NAME_U;
     880    static ULONG const s_cbFsName    = sizeof(s_wszFsName) - sizeof(s_wszFsName[0]);
     881    ULONG const        cbNeeded      = RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) + s_cbFsName;
     882
     883    /*
     884     * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
     885     */
     886    AssertReturnStmt(cbInfo >= RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName),
     887                     pRxContext->InformationToReturn = cbNeeded,
     888                     STATUS_BUFFER_TOO_SMALL);
     889
     890    /*
     891     * Get up-to-date information about filename length and such.
     892     */
     893    if (pVBoxFcbX->nsVolInfoUpToDate - RTTimeSystemNanoTS() < RT_NS_100MS /** @todo implement proper volume info TTL */ )
     894    {
     895        /* Must fetch the info. */
     896        NTSTATUS Status = vbsfNtUpdateFcbVolInfo(pVBoxFcbX, pNetRootExtension, pVBoxFobx);
     897        if (NT_SUCCESS(Status))
     898        { /* likely */ }
     899        else
     900            return Status;
     901    }
     902
     903    /*
     904     * Produce the requested data.
     905     *
     906     * Note! The MaximumComponentNameLength is documented (1) to be in bytes, but
     907     *       NTFS and FAT32 both return 255, indicating that it is really a UTF-16 char count.
     908     *
     909     * Note! Both NTFS and FAT32 seems to be setting Ios.Information and FileSystemNameLength
     910     *       the number of bytes returned in the STATUS_BUFFER_OVERFLOW case, making it
     911     *       impossible to guess the length from the returned data.  RDR2 forwards information
     912     *       from the server, and samba returns a fixed FileSystemNameLength.
     913     *
     914     * (1) https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/ns-ntifs-_file_fs_attribute_information
     915     */
     916    pInfo->FileSystemAttributes         = FILE_CASE_PRESERVED_NAMES;
     917    /** @todo Implement FILE_RETURNS_CLEANUP_RESULT_INFO. */
     918    if (pVBoxFcbX->VolInfo.fsProperties.fSupportsUnicode)
     919        pInfo->FileSystemAttributes    |= FILE_UNICODE_ON_DISK;
     920    if (pVBoxFcbX->VolInfo.fsProperties.fReadOnly)
     921        pInfo->FileSystemAttributes    |= FILE_READ_ONLY_VOLUME;
     922    if (pVBoxFcbX->VolInfo.fsProperties.fFileCompression)
     923        pInfo->FileSystemAttributes    |= FILE_FILE_COMPRESSION;
     924    else if (pVBoxFcbX->VolInfo.fsProperties.fCompressed)
     925        pInfo->FileSystemAttributes    |= FILE_VOLUME_IS_COMPRESSED;
     926    pInfo->MaximumComponentNameLength   = pVBoxFcbX->VolInfo.fsProperties.cbMaxComponent
     927                                        ? pVBoxFcbX->VolInfo.fsProperties.cbMaxComponent : 255;
     928    ULONG const cbStrCopied = RT_MIN(cbInfo - RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName), s_cbFsName);
     929    pInfo->FileSystemNameLength         = s_cbFsName;
     930    if (cbStrCopied > 0)
     931        memcpy(pInfo->FileSystemName, MRX_VBOX_FILESYS_NAME_U, cbStrCopied);
     932
     933    /*
     934     * Update the return length in the context.
     935     */
     936    pRxContext->Info.LengthRemaining = cbInfo - cbStrCopied - RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
     937    pRxContext->InformationToReturn  = cbStrCopied + RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName); /* whatever */
     938    return cbInfo >= cbNeeded ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
     939}
     940
     941/**
     942 * Handles NtQueryVolumeInformationFile / FileFsSectorSizeInformation
     943 */
     944static NTSTATUS vbsfNtQueryFsSectorSizeInfo(IN OUT PRX_CONTEXT pRxContext,
     945                                            PFILE_FS_SECTOR_SIZE_INFORMATION pInfo,
     946                                            ULONG cbInfo,
     947                                            PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
     948                                            PMRX_VBOX_FOBX pVBoxFobx,
     949                                            PVBSFNTFCBEXT pVBoxFcbX)
     950{
     951    /*
     952     * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
     953     */
     954    AssertReturnStmt(cbInfo >= sizeof(*pInfo), pRxContext->InformationToReturn = sizeof(*pInfo), STATUS_BUFFER_TOO_SMALL);
     955
     956    /*
     957     * Get up-to-date sector size info.
     958     */
     959    if (pVBoxFcbX->nsVolInfoUpToDate - RTTimeSystemNanoTS() < RT_NS_100MS /** @todo implement proper volume info TTL */ )
     960    {
     961        /* Must fetch the info. */
     962        NTSTATUS Status = vbsfNtUpdateFcbVolInfo(pVBoxFcbX, pNetRootExtension, pVBoxFobx);
     963        if (NT_SUCCESS(Status))
     964        { /* likely */ }
     965        else
     966            return Status;
     967    }
     968
     969    /*
     970     * Produce the requested data (currently no way to query more than the
     971     * basic sector size here, so just repeat it).
     972     */
     973    uint32_t const cbSector = pVBoxFcbX->VolInfo.ulBytesPerSector ? pVBoxFcbX->VolInfo.ulBytesPerSector : 512;
     974    pInfo->LogicalBytesPerSector                                 = cbSector;
     975    pInfo->PhysicalBytesPerSectorForAtomicity                    = cbSector;
     976    pInfo->PhysicalBytesPerSectorForPerformance                  = cbSector;
     977    pInfo->FileSystemEffectivePhysicalBytesPerSectorForAtomicity = cbSector;
     978    pInfo->Flags                                                 = 0;
     979    pInfo->ByteOffsetForSectorAlignment                          = SSINFO_OFFSET_UNKNOWN;
     980    pInfo->ByteOffsetForPartitionAlignment                       = SSINFO_OFFSET_UNKNOWN;
     981
     982    /*
     983     * Update the return length in the context.
     984     */
     985    pRxContext->Info.LengthRemaining = cbInfo - sizeof(*pInfo);
     986    pRxContext->InformationToReturn  = sizeof(*pInfo); /* whatever */
     987    return STATUS_SUCCESS;
     988}
     989
     990
     991#include <iprt/mem.h>
    844992/**
    845993 * Handles NtQueryVolumeInformationFile and similar.
     994 *
     995 * The RDBSS library does not do a whole lot for these queries.  No FCB locking.
     996 *
     997 *
     998 * The IO_STATUS_BLOCK updating differs too,  setting of Ios.Information is
     999 * limited to cbInitialBuf
     1000 * - RxContext->Info.LengthRemaining.
    8461001 */
    8471002NTSTATUS VBoxMRxQueryVolumeInfo(IN OUT PRX_CONTEXT RxContext)
    8481003{
     1004#ifdef LOG_ENABLED
     1005    static const char * const s_apszNames[] =
     1006    {
     1007        "FileFsInvalidZeroEntry",      "FileFsVolumeInformation",       "FileFsLabelInformation",
     1008        "FileFsSizeInformation",       "FileFsDeviceInformation",       "FileFsAttributeInformation",
     1009        "FileFsControlInformation",    "FileFsFullSizeInformation",     "FileFsObjectIdInformation",
     1010        "FileFsDriverPathInformation", "FileFsVolumeFlagsInformation",  "FileFsSectorSizeInformation",
     1011        "FileFsDataCopyInformation",   "FileFsMetadataSizeInformation", "FileFsFullSizeInformationEx",
     1012    };
     1013#endif
     1014
    8491015    NTSTATUS Status;
    8501016
     
    8541020    PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
    8551021    PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
    856 
    857     FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
    858     PVOID pInfoBuffer = RxContext->Info.Buffer;
    859     ULONG cbInfoBuffer = RxContext->Info.LengthRemaining;
    860     ULONG cbToCopy = 0;
    861     ULONG cbString = 0;
    8621022
    8631023    Log(("VBOXSF: MrxQueryVolumeInfo: pInfoBuffer = %p, cbInfoBuffer = %d\n",
    8641024         RxContext->Info.Buffer, RxContext->Info.LengthRemaining));
    8651025    Log(("VBOXSF: MrxQueryVolumeInfo: vboxFobx = %p, Handle = 0x%RX64\n",
    866          pVBoxFobx, pVBoxFobx? pVBoxFobx->hFile: 0));
    867 
    868     Status = STATUS_INVALID_PARAMETER;
    869 
    870     switch (FsInformationClass)
     1026         pVBoxFobx, pVBoxFobx ? pVBoxFobx->hFile : 0));
     1027
     1028/** @todo Consolidate the tail code that updates LengthRemaining. */
     1029    switch (RxContext->Info.FsInformationClass)
    8711030    {
    8721031        case FileFsVolumeInformation:
     
    8781037            return Status;
    8791038
    880         case FileFsLabelInformation:
    881             AssertFailed(/* Only for setting, not for querying. */);
    882             Status = STATUS_INVALID_INFO_CLASS;
    883             break;
    884 
    8851039        case FileFsSizeInformation:
    8861040            Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsSizeInformation\n"));
     
    9001054
    9011055        case FileFsDeviceInformation:
    902         {
    903             PFILE_FS_DEVICE_INFORMATION pInfo = (PFILE_FS_DEVICE_INFORMATION)pInfoBuffer;
    904             PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
    905 
    906             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsDeviceInformation: Type = %d\n",
    907                  NetRoot->DeviceType));
    908 
    909             cbToCopy = sizeof(FILE_FS_DEVICE_INFORMATION);
    910 
    911             if (cbInfoBuffer < cbToCopy)
     1056            Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsDeviceInformation\n"));
     1057            AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
     1058            Status = vbsfNtQueryFsDeviceInfo(RxContext, (PFILE_FS_DEVICE_INFORMATION)RxContext->Info.Buffer,
     1059                                             RxContext->Info.Length, capFcb->pNetRoot);
     1060            return Status;
     1061
     1062        case FileFsAttributeInformation:
     1063            Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsAttributeInformation\n"));
     1064            AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
     1065            Status = vbsfNtQueryFsAttributeInfo(RxContext, (PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer,
     1066                                                RxContext->Info.Length, pNetRootExtension, pVBoxFobx,
     1067                                                VBoxMRxGetFcbExtension(capFcb));
     1068            return Status;
     1069
     1070        case FileFsSectorSizeInformation:
     1071            Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsSectorSizeInformation\n"));
     1072            AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
     1073            Status = vbsfNtQueryFsSectorSizeInfo(RxContext, (PFILE_FS_SECTOR_SIZE_INFORMATION)RxContext->Info.Buffer,
     1074                                                 RxContext->Info.Length, pNetRootExtension, pVBoxFobx,
     1075                                                 VBoxMRxGetFcbExtension(capFcb));
     1076            return Status;
     1077
     1078        case FileFsLabelInformation:
     1079            AssertFailed(/* Only for setting, not for querying. */);
     1080            RT_FALL_THRU();
     1081        default:
     1082        {
     1083            Log(("VBOXSF: MrxQueryVolumeInfo: Not supported FS_INFORMATION_CLASS value: %d (%s)!\n",
     1084                 RxContext->Info.FsInformationClass,
     1085                 (ULONG)RxContext->Info.FsInformationClass < RT_ELEMENTS(s_apszNames)
     1086                 ? s_apszNames[RxContext->Info.FsInformationClass] : "??"));
     1087            /* Here is a weird issue I couldn't quite figure out.  When working directories, I
     1088               seem to get semi-random stuff back in the IO_STATUS_BLOCK.  Difference between
     1089               directories and files seemed to be the IRP_SYNCHRONOUS_API flag.  Poking around
     1090               a little bit more, the UserIosb seems to be a ring-0 stack address rather than
     1091               the usermode one and IopSynchronousApiServiceTail being used for copying it back
     1092               to user mode because the handle wasn't synchronous or something.
     1093
     1094               So, the following is kludge to make the IOS values 0,0 like FAT does it.  The
     1095               real fix for this escapes me, but this should do the trick... */
     1096            PIRP pIrp = RxContext->CurrentIrp;
     1097            if (   pIrp
     1098                && (pIrp->Flags & IRP_SYNCHRONOUS_API)
     1099                && RTR0MemKernelIsValidAddr(pIrp->UserIosb))
    9121100            {
    913                 Status = STATUS_BUFFER_TOO_SMALL;
    914                 break;
     1101                Log9(("VBOXSF: MrxQueryVolumeInfo: IRP_SYNCHRONOUS_API hack: Setting UserIosb (%p) values to zero!\n", \
     1102                      pIrp->UserIosb));
     1103                __try
     1104                {
     1105                    pIrp->UserIosb->Status      = 0;
     1106                    pIrp->UserIosb->Information = 0;
     1107                }
     1108                __except(EXCEPTION_EXECUTE_HANDLER)
     1109                {
     1110#ifdef LOG_ENABLED
     1111                    NTSTATUS rcNt = GetExceptionCode();
     1112                    Log(("VBOXSF: MrxQueryVolumeInfo: Oops %#x accessing %p\n", rcNt, pIrp->UserIosb));
     1113#endif
     1114                }
    9151115            }
    916 
    917             pInfo->DeviceType = NetRoot->DeviceType;
    918             pInfo->Characteristics = FILE_REMOTE_DEVICE;
    919 
    920             Status = STATUS_SUCCESS;
    921             break;
    922         }
    923 
    924         case FileFsAttributeInformation:
    925         {
    926             PFILE_FS_ATTRIBUTE_INFORMATION pInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)pInfoBuffer;
    927 
    928             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsAttributeInformation\n"));
    929 
    930             cbToCopy = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
    931 
    932             cbString = sizeof(MRX_VBOX_FILESYS_NAME_U);
    933 
    934             if (cbInfoBuffer < cbToCopy)
    935             {
    936                 Status = STATUS_BUFFER_TOO_SMALL;
    937                 break;
    938             }
    939 
    940             pInfo->FileSystemAttributes = 0; /** @todo set unicode, case sensitive etc? */
    941             pInfo->MaximumComponentNameLength = 255; /** @todo should query from the host */
    942 
    943             if (cbInfoBuffer >= cbToCopy + cbString)
    944             {
    945                 RtlCopyMemory(pInfo->FileSystemName,
    946                               MRX_VBOX_FILESYS_NAME_U,
    947                               sizeof(MRX_VBOX_FILESYS_NAME_U));
    948             }
    949             else
    950             {
    951                 cbString = cbInfoBuffer - cbToCopy;
    952 
    953                 RtlCopyMemory(pInfo->FileSystemName,
    954                               MRX_VBOX_FILESYS_NAME_U,
    955                               RT_MIN(cbString, sizeof(MRX_VBOX_FILESYS_NAME_U)));
    956             }
    957 
    958             pInfo->FileSystemNameLength = cbString;
    959 
    960             cbToCopy += cbString;
    961 
    962             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsAttributeInformation: FileSystemNameLength %d\n",
    963                  pInfo->FileSystemNameLength));
    964 
    965             Status = STATUS_SUCCESS;
    966             break;
    967         }
    968 
    969         case FileFsControlInformation:
    970             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsControlInformation: not supported\n"));
    971             Status = STATUS_INVALID_PARAMETER;
    972             break;
    973 
    974         case FileFsObjectIdInformation:
    975             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsObjectIdInformation: not supported\n"));
    976             Status = STATUS_INVALID_PARAMETER;
    977             break;
    978 
    979         case FileFsMaximumInformation:
    980             Log(("VBOXSF: MrxQueryVolumeInfo: FileFsMaximumInformation: not supported\n"));
    981             Status = STATUS_INVALID_PARAMETER;
    982             break;
    983 
    984         default:
    985             Log(("VBOXSF: MrxQueryVolumeInfo: Not supported FsInformationClass %d!\n",
    986                  FsInformationClass));
    987             Status = STATUS_INVALID_PARAMETER;
    988             break;
    989     }
    990 
    991     if (Status == STATUS_SUCCESS)
    992         RxContext->Info.LengthRemaining = cbInfoBuffer - cbToCopy;
    993     else if (Status == STATUS_BUFFER_TOO_SMALL)
    994     {
    995         Log(("VBOXSF: MrxQueryVolumeInfo: Insufficient buffer size %d, required %d\n",
    996              cbInfoBuffer, cbToCopy));
    997         RxContext->InformationToReturn = cbToCopy;
    998     }
    999 
    1000     Log(("VBOXSF: MrxQueryVolumeInfo: cbToCopy = %d, LengthRemaining = %d, Status = 0x%08X\n",
    1001          cbToCopy, RxContext->Info.LengthRemaining, Status));
    1002 
    1003     return Status;
     1116            return STATUS_INVALID_PARAMETER;
     1117        }
     1118    }
    10041119}
    10051120
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette