Esempio n. 1
0
/**
 * @internal
 * @brief Retrieves the volume label.
 * @param[in] hRoot handle to the
 * root directory.
 * @param[out] pointer to the structure
 * receiving the volume label.
 */
static void get_volume_label(HANDLE hRoot,winx_volume_information *v)
{
    FILE_FS_VOLUME_INFORMATION *ffvi;
    int buffer_size;
    IO_STATUS_BLOCK IoStatusBlock;
    NTSTATUS status;
    
    /* reset label */
    v->label[0] = 0;
    
    /* allocate memory */
    buffer_size = (sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(wchar_t)) + (MAX_PATH + 1) * sizeof(wchar_t);
    ffvi = winx_malloc(buffer_size);
    
    /* try to get actual label */
    RtlZeroMemory(ffvi,buffer_size);
    status = NtQueryVolumeInformationFile(hRoot,&IoStatusBlock,ffvi,
                buffer_size,FileFsVolumeInformation);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot get volume label of drive %c:",
            v->volume_letter);
        winx_free(ffvi);
        return;
    }
    wcsncpy(v->label,ffvi->VolumeLabel,MAX_PATH);
    v->label[MAX_PATH] = 0;
    winx_free(ffvi);
}
Esempio n. 2
0
static int winfs_statfs(struct file *f, struct statfs64 *buf)
{
	AcquireSRWLockShared(&f->rw_lock);
	struct winfs_file *winfile = (struct winfs_file *) f;
	FILE_FS_FULL_SIZE_INFORMATION info;
	IO_STATUS_BLOCK status_block;
	NTSTATUS status = NtQueryVolumeInformationFile(winfile->handle, &status_block, &info, sizeof(info), FileFsFullSizeInformation);
	int r = 0;
	if (!NT_SUCCESS(status))
	{
		log_warning("NtQueryVolumeInformationFile() failed, status: %x", status);
		r = -L_EIO;
		goto out;
	}
	buf->f_type = 0x5346544e; /* NTFS_SB_MAGIC */
	buf->f_bsize = info.SectorsPerAllocationUnit * info.BytesPerSector;
	buf->f_blocks = info.TotalAllocationUnits.QuadPart;
	buf->f_bfree = info.ActualAvailableAllocationUnits.QuadPart;
	buf->f_bavail = info.CallerAvailableAllocationUnits.QuadPart;
	buf->f_files = 0;
	buf->f_ffree = 0;
	buf->f_fsid.val[0] = 0;
	buf->f_fsid.val[1] = 0;
	buf->f_namelen = PATH_MAX;
	buf->f_frsize = 0;
	buf->f_flags = 0;
	buf->f_spare[0] = 0;
	buf->f_spare[1] = 0;
	buf->f_spare[2] = 0;
	buf->f_spare[3] = 0;
out:
	ReleaseSRWLockShared(&f->rw_lock);
	return r;
}
Esempio n. 3
0
BOOLEAN DiskDriveQueryVolumeFreeSpace(
    _In_ HANDLE DosDeviceHandle,
    _Out_ ULONG64* TotalLength,
    _Out_ ULONG64* FreeLength
    )
{
    IO_STATUS_BLOCK isb;
    FILE_FS_FULL_SIZE_INFORMATION result;

    memset(&result, 0, sizeof(FILE_FS_FULL_SIZE_INFORMATION));

    if (NT_SUCCESS(NtQueryVolumeInformationFile(
        DosDeviceHandle,
        &isb,
        &result,
        sizeof(FILE_FS_FULL_SIZE_INFORMATION),
        FileFsFullSizeInformation
        )))
    {
        *TotalLength = result.TotalAllocationUnits.QuadPart * result.SectorsPerAllocationUnit * result.BytesPerSector;
        *FreeLength = result.ActualAvailableAllocationUnits.QuadPart * result.SectorsPerAllocationUnit * result.BytesPerSector;
        return TRUE;
    }

    return FALSE;
}
Esempio n. 4
0
RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
{
    *penmType = RTFSTYPE_UNKNOWN;

    AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);
    AssertReturn(*pszFsPath, VERR_INVALID_PARAMETER);

    /*
     * Convert the path and try open it.
     */
    PRTUTF16 pwszFsPath;
    int rc = RTStrToUtf16(pszFsPath, &pwszFsPath);
    if (RT_SUCCESS(rc))
    {
        HANDLE hFile = CreateFileW(pwszFsPath,
                                   GENERIC_READ,
                                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                   NULL,
                                   OPEN_EXISTING,
                                   FILE_FLAG_BACKUP_SEMANTICS,
                                   NULL);
        if (hFile != INVALID_HANDLE_VALUE)
        {
            /*
             * Use the NT api directly to get the file system name.
             */
            char            abBuf[8192];
            IO_STATUS_BLOCK Ios;
            NTSTATUS        rcNt = NtQueryVolumeInformationFile(hFile, &Ios,
                                                                abBuf, sizeof(abBuf),
                                                                FileFsAttributeInformation);
            if (rcNt >= 0)
            {
                PFILE_FS_ATTRIBUTE_INFORMATION pFsAttrInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)abBuf;
                if (pFsAttrInfo->FIleSystemNameLength)
                {
                }
#define IS_FS(szName) \
    rtFsWinAreEqual(pFsAttrInfo->FileSystemName, pFsAttrInfo->FIleSystemNameLength, szName, sizeof(szName) - 1)
                if (IS_FS("NTFS"))
                    *penmType = RTFSTYPE_NTFS;
                else if (IS_FS("FAT"))
                    *penmType = RTFSTYPE_FAT;
                else if (IS_FS("FAT32"))
                    *penmType = RTFSTYPE_FAT;
                else if (IS_FS("VBoxSharedFolderFS"))
                    *penmType = RTFSTYPE_VBOXSHF;
#undef IS_FS
            }
            else
                rc = RTErrConvertFromNtStatus(rcNt);
            CloseHandle(hFile);
        }
        else
            rc = RTErrConvertFromWin32(GetLastError());
        RTUtf16Free(pwszFsPath);
    }
    return rc;
}
Esempio n. 5
0
NTSTATUS DiskDriveQueryVolumeAttributes(
    _In_ HANDLE DosDeviceHandle,
    _Out_ PFILE_FS_ATTRIBUTE_INFORMATION* AttributeInfo
    )
{
    NTSTATUS status;
    ULONG bufferLength;
    IO_STATUS_BLOCK isb;
    PFILE_FS_ATTRIBUTE_INFORMATION buffer;

    bufferLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
    buffer = PhAllocate(bufferLength);
    memset(buffer, 0, bufferLength);

    status = NtQueryVolumeInformationFile(
        DosDeviceHandle,
        &isb,
        buffer,
        bufferLength,
        FileFsAttributeInformation
        );

    if (status == STATUS_BUFFER_OVERFLOW)
    {
        bufferLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + buffer->FileSystemNameLength;
        buffer = PhReAllocate(buffer, bufferLength);
        memset(buffer, 0, bufferLength);

        status = NtQueryVolumeInformationFile(
            DosDeviceHandle,
            &isb,
            buffer,
            bufferLength,
            FileFsAttributeInformation
            );
    }

    if (NT_SUCCESS(status))
    {
        *AttributeInfo = buffer;
        return status;
    }

    PhFree(buffer);
    return status;
}
Esempio n. 6
0
RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
{
    /*
     * Validate input.
     */
    *penmType = RTFSTYPE_UNKNOWN;
    AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);
    AssertReturn(*pszFsPath, VERR_INVALID_PARAMETER);

    /*
     * Open the file/dir/whatever.
     */
    HANDLE hFile;
    int rc = rtNtPathOpen(pszFsPath,
                          GENERIC_READ,
                          FILE_ATTRIBUTE_NORMAL,
                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                          FILE_OPEN,
                          FILE_OPEN_FOR_BACKUP_INTENT,
                          OBJ_CASE_INSENSITIVE,
                          &hFile,
                          NULL);
    if (RT_SUCCESS(rc))
    {
        /*
         * Get the file system name.
         */
        union
        {
            FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
            uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096];
        } u;
        IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
        NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation);
        if (NT_SUCCESS(rcNt))
        {
#define IS_FS(a_szName) \
    rtNtCompWideStrAndAscii(u.FsAttrInfo.FileSystemName, u.FsAttrInfo.FileSystemNameLength, RT_STR_TUPLE(a_szName))
            if (IS_FS("NTFS"))
                *penmType = RTFSTYPE_NTFS;
            else if (IS_FS("FAT"))
                *penmType = RTFSTYPE_FAT;
            else if (IS_FS("FAT32"))
                *penmType = RTFSTYPE_FAT;
            else if (IS_FS("VBoxSharedFolderFS"))
                *penmType = RTFSTYPE_VBOXSHF;
#undef IS_FS
        }
        else
            rc = RTErrConvertFromNtStatus(rcNt);

        rtNtPathClose(hFile);
    }
    return rc;
}
/**
 * Queries information from a file or directory handle.
 *
 * This is shared between the RTPathQueryInfo, RTFileQueryInfo and
 * RTDirQueryInfo code.
 *
 * @returns IPRT status code.
 * @param   hFile               The handle to query information from.  Must have
 *                              the necessary privileges.
 * @param   pvBuf               Pointer to a scratch buffer.
 * @param   cbBuf               The size of the buffer.  This must be large
 *                              enough to hold a FILE_ALL_INFORMATION struct.
 * @param   pObjInfo            Where to return information about the handle.
 * @param   enmAddAttr          What extra info to return.
 * @param   pszPath             The path if this is a file (for exe detect).
 * @param   uReparseTag         The reparse tag number (0 if not applicable) for
 *                              symlink detection/whatnot.
 */
DECLHIDDEN(int) rtPathNtQueryInfoFromHandle(HANDLE hFile, void *pvBuf, size_t cbBuf, PRTFSOBJINFO pObjInfo,
                                            RTFSOBJATTRADD enmAddAttr, const char *pszPath, ULONG uReparseTag)
{
    Assert(cbBuf >= sizeof(FILE_ALL_INFORMATION));

    /** @todo Try optimize this for when RTFSOBJATTRADD_UNIX isn't set? */
    IO_STATUS_BLOCK  Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, pvBuf, sizeof(FILE_ALL_INFORMATION), FileAllInformation);
    if (   NT_SUCCESS(rcNt)
        || rcNt == STATUS_BUFFER_OVERFLOW)
    {
        FILE_ALL_INFORMATION *pAllInfo = (FILE_ALL_INFORMATION *)pvBuf;
        pObjInfo->cbObject    = pAllInfo->StandardInformation.EndOfFile.QuadPart;
        pObjInfo->cbAllocated = pAllInfo->StandardInformation.AllocationSize.QuadPart;
        RTTimeSpecSetNtTime(&pObjInfo->BirthTime,         pAllInfo->BasicInformation.CreationTime.QuadPart);
        RTTimeSpecSetNtTime(&pObjInfo->AccessTime,        pAllInfo->BasicInformation.LastAccessTime.QuadPart);
        RTTimeSpecSetNtTime(&pObjInfo->ModificationTime,  pAllInfo->BasicInformation.LastWriteTime.QuadPart);
        RTTimeSpecSetNtTime(&pObjInfo->ChangeTime,        pAllInfo->BasicInformation.ChangeTime.QuadPart);
        pObjInfo->Attr.fMode = rtFsModeFromDos(  (pAllInfo->BasicInformation.FileAttributes << RTFS_DOS_SHIFT)
                                               & RTFS_DOS_MASK_NT,
                                               pszPath, pszPath ? strlen(pszPath) : 0, uReparseTag);
        pObjInfo->Attr.enmAdditional = enmAddAttr;
        if (enmAddAttr == RTFSOBJATTRADD_UNIX)
        {
            pObjInfo->Attr.u.Unix.uid             = ~0U;
            pObjInfo->Attr.u.Unix.gid             = ~0U;
            pObjInfo->Attr.u.Unix.cHardlinks      = RT_MAX(1, pAllInfo->StandardInformation.NumberOfLinks);
            pObjInfo->Attr.u.Unix.INodeIdDevice   = 0; /* below */
            pObjInfo->Attr.u.Unix.INodeId         = pAllInfo->InternalInformation.IndexNumber.QuadPart;
            pObjInfo->Attr.u.Unix.fFlags          = 0;
            pObjInfo->Attr.u.Unix.GenerationId    = 0;
            pObjInfo->Attr.u.Unix.Device          = 0;

            /* Get the serial number. */
            rcNt = NtQueryVolumeInformationFile(hFile, &Ios, pvBuf, (ULONG)RT_MIN(cbBuf, _2K), FileFsVolumeInformation);
            if (NT_SUCCESS(rcNt) || rcNt == STATUS_BUFFER_OVERFLOW)
            {
                FILE_FS_VOLUME_INFORMATION *pVolInfo = (FILE_FS_VOLUME_INFORMATION *)pvBuf;
                pObjInfo->Attr.u.Unix.INodeIdDevice = pVolInfo->VolumeSerialNumber;
            }
        }

        return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr);
    }
    return RTErrConvertFromNtStatus(rcNt);
}
Esempio n. 8
0
NTSTATUS WINAPI SafeNtQueryVolumeInformationFile(
  HANDLE               FileHandle,
  PIO_STATUS_BLOCK     IoStatusBlock,
  PVOID                FileSystemInformation,
  ULONG                Length,
  FS_INFORMATION_CLASS FileSystemInformationClass 
)
{
	NTSTATUS rc;

	if (CheckOldFunction(&OldNtQueryVolumeInformationFile))
		rc=OldNtQueryVolumeInformationFile(FileHandle,IoStatusBlock,FileSystemInformation,Length,FileSystemInformationClass);
	else
		rc=NtQueryVolumeInformationFile(FileHandle,IoStatusBlock,FileSystemInformation,Length,FileSystemInformationClass);

	return rc;
}
Esempio n. 9
0
/**
 * @internal
 * @brief Retrieves the drive geometry.
 * @param[in] hRoot handle to the
 * root directory.
 * @param[out] pointer to the structure
 * receiving the drive geometry.
 * @return Zero for success, negative
 * value otherwise.
 */
static int get_drive_geometry(HANDLE hRoot,winx_volume_information *v)
{
    FILE_FS_SIZE_INFORMATION ffs;
    IO_STATUS_BLOCK IoStatusBlock;
    NTSTATUS status;
    WINX_FILE *f;
    DISK_GEOMETRY dg;
    char buffer[32];
    
    /* get drive geometry */
    RtlZeroMemory(&ffs,sizeof(FILE_FS_SIZE_INFORMATION));
    status = NtQueryVolumeInformationFile(hRoot,&IoStatusBlock,&ffs,
                sizeof(FILE_FS_SIZE_INFORMATION),FileFsSizeInformation);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot get geometry of drive %c:",v->volume_letter);
        return (-1);
    }
    
    /* fill all geometry related fields of the output structure */
    v->total_bytes = (ULONGLONG)ffs.TotalAllocationUnits.QuadPart * \
        ffs.SectorsPerAllocationUnit * ffs.BytesPerSector;
    v->free_bytes = (ULONGLONG)ffs.AvailableAllocationUnits.QuadPart * \
        ffs.SectorsPerAllocationUnit * ffs.BytesPerSector;
    v->total_clusters = (ULONGLONG)ffs.TotalAllocationUnits.QuadPart;
    v->bytes_per_cluster = ffs.SectorsPerAllocationUnit * ffs.BytesPerSector;
    v->sectors_per_cluster = ffs.SectorsPerAllocationUnit;
    v->bytes_per_sector = ffs.BytesPerSector;
    
    /* optional: get device capacity */
    v->device_capacity = 0;
    f = winx_vopen(v->volume_letter);
    if(f != NULL){
        if(winx_ioctl(f,IOCTL_DISK_GET_DRIVE_GEOMETRY,
          "get_drive_geometry: device geometry request",NULL,0,
          &dg,sizeof(dg),NULL) >= 0){
            v->device_capacity = dg.Cylinders.QuadPart * \
                dg.TracksPerCylinder * dg.SectorsPerTrack * dg.BytesPerSector;
            winx_bytes_to_hr(v->device_capacity,1,buffer,sizeof(buffer));
            itrace("%c: device capacity = %s",v->volume_letter,buffer);
        }
        winx_fclose(f);
    }
    return 0;
}
Esempio n. 10
0
RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
{
    /*
     * Validate & get valid root path.
     */
    AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);
    AssertPtrReturn(pu32Serial, VERR_INVALID_POINTER);

    /*
     * Open the file/dir/whatever.
     */
    HANDLE hFile;
    int rc = rtNtPathOpen(pszFsPath,
                          GENERIC_READ,
                          FILE_ATTRIBUTE_NORMAL,
                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                          FILE_OPEN,
                          FILE_OPEN_FOR_BACKUP_INTENT,
                          OBJ_CASE_INSENSITIVE,
                          &hFile,
                          NULL);
    if (RT_SUCCESS(rc))
    {
        /*
         * Get the volume information.
         */
        union
        {
             FILE_FS_VOLUME_INFORMATION FsVolInfo;
             uint8_t abBuf[sizeof(FILE_FS_VOLUME_INFORMATION) + 4096];
        } u;
        IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
        NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsVolumeInformation);
        if (NT_SUCCESS(rcNt))
            *pu32Serial = u.FsVolInfo.VolumeSerialNumber;
        else
            rc = RTErrConvertFromNtStatus(rcNt);

        rtNtPathClose(hFile);
    }
    return rc;
}
Esempio n. 11
0
/*
* SfuCalcVolumeMD5
*
* Purpose:
*
* Calculate MD5 from system volume information.
*
*/
BOOLEAN SfuCalcVolumeMD5(
	_Inout_ PBYTE MD5Hash
	)
{
	OBJECT_ATTRIBUTES           obja;
	IO_STATUS_BLOCK             iost;
	UNICODE_STRING              str;
	NTSTATUS                    Status;
	BOOLEAN                     result = FALSE;
	HANDLE                      hVolume = NULL;
	FILE_FS_VOLUME_INFORMATION  fsVolumeInfo;
	MD5_CTX                     ctx;

	if (MD5Hash == NULL)
		return result;

	RtlSecureZeroMemory(&str, sizeof(str));
	RtlInitUnicodeString(&str, L"\\systemroot");
	InitializeObjectAttributes(&obja, &str, OBJ_CASE_INSENSITIVE, NULL, NULL);

	Status = NtOpenFile(&hVolume, FILE_GENERIC_READ, &obja, &iost,
		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);

	if (NT_SUCCESS(Status)) {

		Status = NtQueryVolumeInformationFile(hVolume, &iost, &fsVolumeInfo,
			sizeof(FILE_FS_VOLUME_INFORMATION), FileFsVolumeInformation);

		if ((NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)) {
			fsVolumeInfo.VolumeCreationTime.HighPart ^= 0x1010101;
			MD5Init(&ctx);
			MD5Update(&ctx, (unsigned char*)&fsVolumeInfo.VolumeCreationTime, sizeof(LARGE_INTEGER));
			MD5Final(&ctx);
			RtlCopyMemory(MD5Hash, &ctx.buf, 16);
			result = TRUE;
		}
		NtClose(hVolume);
	}
	return result;
}
Esempio n. 12
0
/**
 * @internal
 * @brief Retrieves the name of the file system.
 * @param[in] hRoot handle to the root directory.
 * @param[out] pointer to the structure receiving
 * the filesystem name.
 * @return Zero for success, negative value otherwise.
 * @note We could analyze the first sector of the 
 * partition directly, but this method is not so swift
 * as it accesses the disk physically.
 */
static int get_filesystem_name(HANDLE hRoot,winx_volume_information *v)
{
    FILE_FS_ATTRIBUTE_INFORMATION *pfa;
    int fs_attr_info_size;
    IO_STATUS_BLOCK IoStatusBlock;
    NTSTATUS status;
    wchar_t fs_name[MAX_FS_NAME_LENGTH + 1];
    int length;

    fs_attr_info_size = MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
    pfa = winx_malloc(fs_attr_info_size);
    
    RtlZeroMemory(pfa,fs_attr_info_size);
    status = NtQueryVolumeInformationFile(hRoot,&IoStatusBlock,pfa,
                fs_attr_info_size,FileFsAttributeInformation);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot get file system name of drive %c:",v->volume_letter);
        winx_free(pfa);
        return (-1);
    }
    
    /*
    * pfa->FileSystemName.Buffer may be not NULL terminated
    * (theoretically), so name extraction is more tricky
    * than it should be.
    */
    length = min(MAX_FS_NAME_LENGTH,pfa->FileSystemNameLength / sizeof(wchar_t));
    wcsncpy(fs_name,pfa->FileSystemName,length);
    fs_name[length] = 0;
    _snprintf(v->fs_name,MAX_FS_NAME_LENGTH,"%ws",fs_name);
    v->fs_name[MAX_FS_NAME_LENGTH] = 0;

    /* cleanup */
    winx_free(pfa);
    return 0;
}
Esempio n. 13
0
/**
 * @brief A Win32 GetDriveType() native equivalent.
 * @param[in] letter the volume letter
 * @return The drive type, negative value indicates failure.
 */
int winx_get_drive_type(char letter)
{
    wchar_t link_name[] = L"\\??\\A:";
    #define MAX_TARGET_LENGTH 256
    wchar_t link_target[MAX_TARGET_LENGTH];
    PROCESS_DEVICEMAP_INFORMATION pdi;
    FILE_FS_DEVICE_INFORMATION ffdi;
    IO_STATUS_BLOCK iosb;
    NTSTATUS status;
    int drive_type;
    HANDLE hRoot;

    /* The additional checks for DFS were suggested by Stefan Pendl ([email protected]). */
    /* DFS shares have DRIVE_NO_ROOT_DIR type though they are actually remote. */

    letter = winx_toupper(letter);
    if(letter < 'A' || letter > 'Z'){
        etrace("invalid letter %c",letter);
        return (-1);
    }
    
    /* check for the drive existence */
    link_name[4] = (wchar_t)letter;
    if(winx_query_symbolic_link(link_name,link_target,MAX_TARGET_LENGTH) < 0)
        return (-1);
    
    /* check for an assignment made by subst command */
    if(wcsstr(link_target,L"\\??\\") == (wchar_t *)link_target)
        return DRIVE_ASSIGNED_BY_SUBST_COMMAND;

    /* check for classical floppies */
    if(wcsstr(link_target,L"Floppy"))
        return DRIVE_REMOVABLE;
    
    /* try to define exactly which type has the specified drive */
    RtlZeroMemory(&pdi,sizeof(PROCESS_DEVICEMAP_INFORMATION));
    status = NtQueryInformationProcess(NtCurrentProcess(),
                    ProcessDeviceMap,&pdi,
                    sizeof(PROCESS_DEVICEMAP_INFORMATION),
                    NULL);
    if(NT_SUCCESS(status)){
        drive_type = (int)pdi.Query.DriveType[letter - 'A'];
        /*
        * Type DRIVE_NO_ROOT_DIR have the following drives:
        * 1. assigned by subst command
        * 2. SCSI external drives
        * 3. RAID volumes
        * 4. DFS shares
        * We need additional checks to know exactly.
        */
        if(drive_type != DRIVE_NO_ROOT_DIR)
            return drive_type;
    } else {
        strace(status,"cannot get device map");
        return (-1);
    }
    
    /* try to define exactly again which type has the specified drive */
    /* note that the drive motor can be powered on during this check */
    hRoot = OpenRootDirectory(letter);
    if(hRoot == NULL)
        return (-1);
    RtlZeroMemory(&ffdi,sizeof(FILE_FS_DEVICE_INFORMATION));
    status = NtQueryVolumeInformationFile(hRoot,&iosb,
                    &ffdi,sizeof(FILE_FS_DEVICE_INFORMATION),
                    FileFsDeviceInformation);
    NtClose(hRoot);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot get volume type for \'%c\'",letter);
        return (-1);
    }

    /* detect remote/cd/dvd/unknown drives */
    if(ffdi.Characteristics & FILE_REMOTE_DEVICE)
        return DRIVE_REMOTE;
    switch(ffdi.DeviceType){
    case FILE_DEVICE_CD_ROM:
    case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
    case FILE_DEVICE_DVD:
        return DRIVE_CDROM;
    case FILE_DEVICE_NETWORK_FILE_SYSTEM:
    case FILE_DEVICE_NETWORK: /* ? */
    case FILE_DEVICE_NETWORK_BROWSER: /* ? */
    case FILE_DEVICE_DFS_FILE_SYSTEM:
    case FILE_DEVICE_DFS_VOLUME:
    case FILE_DEVICE_DFS:
        return DRIVE_REMOTE;
    case FILE_DEVICE_UNKNOWN:
        return DRIVE_UNKNOWN;
    }

    /* detect removable disks */
    if(ffdi.Characteristics & FILE_REMOVABLE_MEDIA)
        return DRIVE_REMOVABLE;

    /* detect fixed disks */
    switch(ffdi.DeviceType){
    case FILE_DEVICE_DISK:
    case FILE_DEVICE_FILE_SYSTEM: /* ? */
    /*case FILE_DEVICE_VIRTUAL_DISK:*/
    /*case FILE_DEVICE_MASS_STORAGE:*/
    case FILE_DEVICE_DISK_FILE_SYSTEM:
        return DRIVE_FIXED;
    default:
        break;
    }
    
    /* nothing detected => drive type is unknown */
    return DRIVE_UNKNOWN;
}
Esempio n. 14
0
NTSTATUS
NTAPI
SmpGetVolumeFreeSpace(IN PSMP_VOLUME_DESCRIPTOR Volume)
{
    NTSTATUS Status;
    LARGE_INTEGER FreeSpace, FinalFreeSpace;
    FILE_FS_SIZE_INFORMATION SizeInfo;
    IO_STATUS_BLOCK IoStatusBlock;
    OBJECT_ATTRIBUTES ObjectAttributes;
    UNICODE_STRING VolumeName;
    HANDLE VolumeHandle;
    WCHAR PathString[32];
    ASSERT(Volume->Flags & SMP_VOLUME_IS_BOOT); // ASSERT says "BootVolume == 1"

    /* Build the standard path */
    wcscpy(PathString, L"\\??\\A:\\");
    RtlInitUnicodeString(&VolumeName, PathString);
    VolumeName.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Volume->DriveLetter;
    DPRINT("SMSS:PFILE: Querying volume `%wZ' for free space \n", &VolumeName);

    /* Open the volume */
    InitializeObjectAttributes(&ObjectAttributes,
                               &VolumeName,
                               OBJ_CASE_INSENSITIVE,
                               NULL,
                               NULL);
    Status = NtOpenFile(&VolumeHandle,
                        FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
                        &ObjectAttributes,
                        &IoStatusBlock,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X \n", &VolumeName, Status);
        return Status;
    }

    /* Now get size information on the volume */
    Status = NtQueryVolumeInformationFile(VolumeHandle,
                                          &IoStatusBlock,
                                          &SizeInfo,
                                          sizeof(SizeInfo),
                                          FileFsSizeInformation);
    if (!NT_SUCCESS(Status))
    {
        /* We failed */
        DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed"
                " with status %X \n",
                &VolumeName,
                VolumeHandle,
                Status);
        NtClose(VolumeHandle);
        return Status;
    }
    NtClose(VolumeHandle);

    /* Compute how much free space we have */
    FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart *
                         SizeInfo.SectorsPerAllocationUnit;
    FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector;

    /* Check if there's less than 32MB free so we don't starve the disk */
    if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE)
    {
        /* In this case, act as if there's no free space  */
        Volume->FreeSpace.QuadPart = 0;
    }
    else
    {
        /* Trim off 32MB to give the disk a bit of breathing room */
        Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart -
                                     MINIMUM_TO_KEEP_FREE;
    }

    return STATUS_SUCCESS;
}
/**
 * Worker for RTPathQueryInfoEx and RTDirRelPathQueryInfo.
 *
 * @returns IPRT status code.
 * @param   hRootDir            The root directory that pNtName is relative to.
 * @param   pNtName             The NT path which we want to query info for.
 * @param   pObjInfo            Where to return the info.
 * @param   enmAddAttr          What additional info to get/fake.
 * @param   fFlags              Query flags (RTPATH_F_XXX).
 * @param   pszPath             The path for detecting executables and such.
 *                              Pass empty string if not applicable/available.
 */
DECLHIDDEN(int) rtPathNtQueryInfoWorker(HANDLE hRootDir, UNICODE_STRING *pNtName, PRTFSOBJINFO pObjInfo,
                                        RTFSOBJATTRADD enmAddAttr, uint32_t fFlags, const char *pszPath)
{
    /*
     * There are a three different ways of doing this:
     *   1. Use NtQueryFullAttributesFile to the get basic file info.
     *   2. Open whatever the path points to and use NtQueryInformationFile.
     *   3. Open the parent directory and use NtQueryDirectoryFile like RTDirReadEx.
     *
     * The first two options may fail with sharing violations or access denied,
     * in which case we must use the last one as fallback.
     */
    HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
    IO_STATUS_BLOCK     Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    NTSTATUS            rcNt;
    OBJECT_ATTRIBUTES   ObjAttr;
    union
    {
        FILE_NETWORK_OPEN_INFORMATION   NetOpenInfo;
        FILE_ALL_INFORMATION            AllInfo;
        FILE_FS_VOLUME_INFORMATION      VolInfo;
        FILE_BOTH_DIR_INFORMATION       Both;
        FILE_ID_BOTH_DIR_INFORMATION    BothId;
        uint8_t                         abPadding[sizeof(FILE_ID_BOTH_DIR_INFORMATION) + RTPATH_MAX * sizeof(wchar_t)];
    } uBuf;

    /*
     * We can only use the first option if no additional UNIX attribs are
     * requested and it isn't a symbolic link.  NT directory object
     */
    int rc = VINF_TRY_AGAIN;
    if (   enmAddAttr != RTFSOBJATTRADD_UNIX
        && g_pfnNtQueryFullAttributesFile)
    {
        InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL);
        rcNt = g_pfnNtQueryFullAttributesFile(&ObjAttr, &uBuf.NetOpenInfo);
        if (NT_SUCCESS(rcNt))
        {
            if (!(uBuf.NetOpenInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
            {
                pObjInfo->cbObject    = uBuf.NetOpenInfo.EndOfFile.QuadPart;
                pObjInfo->cbAllocated = uBuf.NetOpenInfo.AllocationSize.QuadPart;
                RTTimeSpecSetNtTime(&pObjInfo->BirthTime,         uBuf.NetOpenInfo.CreationTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->AccessTime,        uBuf.NetOpenInfo.LastAccessTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->ModificationTime,  uBuf.NetOpenInfo.LastWriteTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->ChangeTime,        uBuf.NetOpenInfo.ChangeTime.QuadPart);
                pObjInfo->Attr.fMode = rtFsModeFromDos((uBuf.NetOpenInfo.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
                                                       pszPath, strlen(pszPath), 0 /*uReparseTag*/);
                pObjInfo->Attr.enmAdditional = enmAddAttr;

                return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr);
            }
        }
        else if (   rcNt == STATUS_OBJECT_TYPE_MISMATCH
                 || rcNt == STATUS_OBJECT_NAME_INVALID
                 || rcNt == STATUS_INVALID_PARAMETER)
        {
            rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt);
            if (RT_SUCCESS(rc))
                return rc;
        }
        else if (   rcNt != STATUS_ACCESS_DENIED
                 && rcNt != STATUS_SHARING_VIOLATION)
            rc = RTErrConvertFromNtStatus(rcNt);
        else
            RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
    }

    /*
     * Try the 2nd option.  We might have to redo this if not following symbolic
     * links and the reparse point isn't a symbolic link but a mount point or similar.
     * We want to return information about the mounted root directory if we can, not
     * the directory in which it was mounted.
     */
    if (rc == VINF_TRY_AGAIN)
    {
        static int volatile g_fReparsePoints = -1;
        uint32_t            fOptions         = FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT;
        int fReparsePoints = g_fReparsePoints;
        if (fReparsePoints != 0 && !(fFlags & RTPATH_F_FOLLOW_LINK))
            fOptions |= FILE_OPEN_REPARSE_POINT;

        InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL);
        rcNt = NtCreateFile(&hFile,
                            FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                            &ObjAttr,
                            &Ios,
                            NULL /*pcbFile*/,
                            FILE_ATTRIBUTE_NORMAL,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN,
                            fOptions,
                            NULL /*pvEaBuffer*/,
                            0 /*cbEa*/);
        if (   (   rcNt == STATUS_INVALID_PARAMETER
                || rcNt == STATUS_INVALID_PARAMETER_9)
            && fReparsePoints == -1
            && (fOptions & FILE_OPEN_REPARSE_POINT))
        {
            fOptions &= ~FILE_OPEN_REPARSE_POINT;
            rcNt = NtCreateFile(&hFile,
                                FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                                &ObjAttr,
                                &Ios,
                                NULL /*pcbFile*/,
                                FILE_ATTRIBUTE_NORMAL,
                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                FILE_OPEN,
                                fOptions,
                                NULL /*pvEaBuffer*/,
                                0 /*cbEa*/);
            if (rcNt != STATUS_INVALID_PARAMETER)
                g_fReparsePoints = fReparsePoints = 0;
        }
        if (NT_SUCCESS(rcNt))
        {
            /* Query tag information first in order to try re-open non-symlink reparse points. */
            FILE_ATTRIBUTE_TAG_INFORMATION TagInfo;
            rcNt = NtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), FileAttributeTagInformation);
            if (!NT_SUCCESS(rcNt))
                TagInfo.FileAttributes = TagInfo.ReparseTag = 0;
            if (   !(TagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
                || TagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK
                || (fFlags & RTPATH_F_FOLLOW_LINK))
            { /* likely */ }
            else
            {
                /* Reparse point that isn't a symbolic link, try follow the reparsing. */
                HANDLE hFile2;
                RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
                rcNt = NtCreateFile(&hFile2,
                                    FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                                    &ObjAttr,
                                    &Ios,
                                    NULL /*pcbFile*/,
                                    FILE_ATTRIBUTE_NORMAL,
                                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                    FILE_OPEN,
                                    FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
                                    NULL /*pvEaBuffer*/,
                                    0 /*cbEa*/);
                if (NT_SUCCESS(rcNt))
                {
                    NtClose(hFile);
                    hFile = hFile2;
                    TagInfo.FileAttributes = TagInfo.ReparseTag = 0;
                }
            }

            /*
             * Get the information we need and convert it.
             */
            rc = rtPathNtQueryInfoFromHandle(hFile, &uBuf, sizeof(uBuf), pObjInfo, enmAddAttr, pszPath, TagInfo.ReparseTag);
            NtClose(hFile);
            if (RT_SUCCESS(rc))
                return rc;

            if (RT_FAILURE(rc))
                rc = VINF_TRY_AGAIN;
        }
        else if (   rcNt == STATUS_OBJECT_TYPE_MISMATCH
                 || rcNt == STATUS_OBJECT_NAME_INVALID
                 /*|| rcNt == STATUS_INVALID_PARAMETER*/)
        {
            rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt);
            if (RT_SUCCESS(rc))
                return rc;
        }
        else if (   rcNt != STATUS_ACCESS_DENIED
                 && rcNt != STATUS_SHARING_VIOLATION)
            rc = RTErrConvertFromNtStatus(rcNt);
        else
            RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
    }

    /*
     * Try the 3rd option if none of the other worked.
     * If none of the above worked, try open the directory and enumerate
     * the file we're after.  This
     */
    if (rc == VINF_TRY_AGAIN)
    {
        /* Split up the name into parent directory path and filename. */
        UNICODE_STRING NtDirName;
        UNICODE_STRING NtFilter;
        ntPathNtSplitName(pNtName, &NtDirName, &NtFilter, false /*fNoParentDirSlash*/);

        /* Try open the directory. */
        InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, hRootDir, NULL);
        rcNt = NtCreateFile(&hFile,
                            FILE_LIST_DIRECTORY | SYNCHRONIZE,
                            &ObjAttr,
                            &Ios,
                            NULL /*pcbFile*/,
                            FILE_ATTRIBUTE_NORMAL,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN,
                            FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
                            NULL /*pvEaBuffer*/,
                            0 /*cbEa*/);
        if (NT_SUCCESS(rcNt))
        {
            FILE_INFORMATION_CLASS enmInfoClass;
            if (RT_MAKE_U64(RTNtCurrentPeb()->OSMinorVersion, RTNtCurrentPeb()->OSMajorVersion) > RT_MAKE_U64(0,5) /* > W2K */)
                enmInfoClass = FileIdBothDirectoryInformation; /* Introduced in XP, from I can tell. */
            else
                enmInfoClass = FileBothDirectoryInformation;
            rcNt = NtQueryDirectoryFile(hFile,
                                        NULL /* Event */,
                                        NULL /* ApcRoutine */,
                                        NULL /* ApcContext */,
                                        &Ios,
                                        &uBuf,
                                        RT_MIN(sizeof(uBuf), 0xfff0),
                                        enmInfoClass,
                                        TRUE /*ReturnSingleEntry */,
                                        &NtFilter,
                                        FALSE /*RestartScan */);
            if (NT_SUCCESS(rcNt))
            {
                pObjInfo->cbObject    = uBuf.Both.EndOfFile.QuadPart;
                pObjInfo->cbAllocated = uBuf.Both.AllocationSize.QuadPart;

                RTTimeSpecSetNtTime(&pObjInfo->BirthTime,         uBuf.Both.CreationTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->AccessTime,        uBuf.Both.LastAccessTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->ModificationTime,  uBuf.Both.LastWriteTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->ChangeTime,        uBuf.Both.ChangeTime.QuadPart);

                pObjInfo->Attr.fMode  = rtFsModeFromDos((uBuf.Both.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
                                                        pszPath, strlen(pszPath), uBuf.Both.EaSize);

                pObjInfo->Attr.enmAdditional = enmAddAttr;
                if (enmAddAttr == RTFSOBJATTRADD_UNIX)
                {
                    pObjInfo->Attr.u.Unix.uid             = ~0U;
                    pObjInfo->Attr.u.Unix.gid             = ~0U;
                    pObjInfo->Attr.u.Unix.cHardlinks      = 1;
                    pObjInfo->Attr.u.Unix.INodeIdDevice   = 0; /* below */
                    pObjInfo->Attr.u.Unix.INodeId         = enmInfoClass == FileIdBothDirectoryInformation
                                                          ? uBuf.BothId.FileId.QuadPart : 0;
                    pObjInfo->Attr.u.Unix.fFlags          = 0;
                    pObjInfo->Attr.u.Unix.GenerationId    = 0;
                    pObjInfo->Attr.u.Unix.Device          = 0;

                    /* Get the serial number. */
                    rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &uBuf, RT_MIN(sizeof(uBuf), _2K),
                                                        FileFsVolumeInformation);
                    if (NT_SUCCESS(rcNt))
                        pObjInfo->Attr.u.Unix.INodeIdDevice = uBuf.VolInfo.VolumeSerialNumber;
                }

                rc = rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr);
            }
            else
                rc = RTErrConvertFromNtStatus(rcNt);

            NtClose(hFile);
        }
        /*
         * Quite possibly a object directory.
         */
        else if (   rcNt == STATUS_OBJECT_NAME_INVALID  /* with trailing slash */
                 || rcNt == STATUS_OBJECT_TYPE_MISMATCH /* without trailing slash */ )
        {
            InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL);
            rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt);
            if (RT_FAILURE(rc))
                rc = RTErrConvertFromNtStatus(rcNt);
        }
        else
            rc = RTErrConvertFromNtStatus(rcNt);
    }

    return rc;
}
/**
 * Fetches more data from the file system.
 *
 * @returns IPRT status code
 * @param   pThis       The directory instance data.
 */
static int rtDirNtFetchMore(PRTDIRINTERNAL pThis)
{
    Assert(!pThis->fDataUnread);

    /*
     * Allocate the buffer the first time around.
     * We do this in lazy fashion as some users of RTDirOpen will not actually
     * list any files, just open it for various reasons.
     *
     * We also reduce the buffer size for networked devices as the windows 7-8.1,
     * server 2012, ++ CIFS servers or/and IFSes screws up buffers larger than 64KB.
     * There is an alternative hack below, btw.  We'll leave both in for now.
     */
    bool fFirst = false;
    if (!pThis->pabBuffer)
    {
        pThis->cbBufferAlloc = _256K;
        if (true) /** @todo skip for known local devices, like the boot device? */
        {
            IO_STATUS_BLOCK Ios2 = RTNT_IO_STATUS_BLOCK_INITIALIZER;
            FILE_FS_DEVICE_INFORMATION Info = { 0, 0 };
            NTSTATUS rcNt2 = NtQueryVolumeInformationFile(pThis->hDir, &Ios2, &Info, sizeof(Info), FileFsDeviceInformation);
            if (   !NT_SUCCESS(rcNt2)
                || (Info.Characteristics & FILE_REMOTE_DEVICE)
                || Info.DeviceType == FILE_DEVICE_NETWORK
                || Info.DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM
                || Info.DeviceType == FILE_DEVICE_NETWORK_REDIRECTOR
                || Info.DeviceType == FILE_DEVICE_SMB)
                pThis->cbBufferAlloc = _64K;
        }

        fFirst = false;
        pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
        if (!pThis->pabBuffer)
        {
            do
            {
                pThis->cbBufferAlloc /= 4;
                pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
            } while (pThis->pabBuffer == NULL && pThis->cbBufferAlloc > _4K);
            if (!pThis->pabBuffer)
                return VERR_NO_MEMORY;
        }

        /*
         * Also try determining the device number.
         */
        PFILE_FS_VOLUME_INFORMATION pVolInfo = (PFILE_FS_VOLUME_INFORMATION)pThis->pabBuffer;
        pVolInfo->VolumeSerialNumber = 0;
        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
        NTSTATUS rcNt = NtQueryVolumeInformationFile(pThis->hDir, &Ios,
                                                     pVolInfo, RT_MIN(_2K, pThis->cbBufferAlloc),
                                                     FileFsVolumeInformation);
        if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
            pThis->uDirDev = pVolInfo->VolumeSerialNumber;
        else
            pThis->uDirDev = 0;
        AssertCompile(sizeof(pThis->uDirDev) == sizeof(pVolInfo->VolumeSerialNumber));
        /** @todo Grow RTDEV to 64-bit and add low dword of VolumeCreationTime to the top of uDirDev. */
    }

    /*
     * Read more.
     */
    NTSTATUS rcNt;
    IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0)
    {
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
        if (pThis->enmInfoClass == FileMaximumInformation)
        {
            Ios.Information = 0;
            Ios.Status = rcNt = NtQueryDirectoryObject(pThis->hDir,
                                                       pThis->pabBuffer,
                                                       pThis->cbBufferAlloc,
                                                       RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                                       pThis->fRestartScan,
                                                       &pThis->uObjDirCtx,
                                                       (PULONG)&Ios.Information);
        }
        else
#endif
            rcNt = NtQueryDirectoryFile(pThis->hDir,
                                        NULL /* Event */,
                                        NULL /* ApcRoutine */,
                                        NULL /* ApcContext */,
                                        &Ios,
                                        pThis->pabBuffer,
                                        pThis->cbBufferAlloc,
                                        pThis->enmInfoClass,
                                        RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                        pThis->pNtFilterStr,
                                        pThis->fRestartScan);
    }
    else
    {
        /*
         * The first time around we have to figure which info class we can use
         * as well as the right buffer size.  We prefer an info class which
         * gives us file IDs (Vista+ IIRC) and we prefer large buffers (for long
         * ReFS file names and such), but we'll settle for whatever works...
         *
         * The windows 7 thru 8.1 CIFS servers have been observed to have
         * trouble with large buffers, but weirdly only when listing large
         * directories.  Seems 0x10000 is the max.  (Samba does not exhibit
         * these problems, of course.)
         *
         * This complicates things.  The buffer size issues causes an
         * STATUS_INVALID_PARAMETER error.  Now, you would expect the lack of
         * FileIdBothDirectoryInformation support to return
         * STATUS_INVALID_INFO_CLASS, but I'm not entirely sure if we can 100%
         * depend on third IFSs to get that right.  Nor, am I entirely confident
         * that we can depend on them to check the class before the buffer size.
         *
         * Thus the mess.
         */
        if (RT_MAKE_U64(RTNtCurrentPeb()->OSMinorVersion, RTNtCurrentPeb()->OSMajorVersion) > RT_MAKE_U64(0,5) /* > W2K */)
            pThis->enmInfoClass = FileIdBothDirectoryInformation; /* Introduced in XP, from I can tell. */
        else
            pThis->enmInfoClass = FileBothDirectoryInformation;
        rcNt = NtQueryDirectoryFile(pThis->hDir,
                                    NULL /* Event */,
                                    NULL /* ApcRoutine */,
                                    NULL /* ApcContext */,
                                    &Ios,
                                    pThis->pabBuffer,
                                    pThis->cbBufferAlloc,
                                    pThis->enmInfoClass,
                                    RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                    pThis->pNtFilterStr,
                                    pThis->fRestartScan);
        if (NT_SUCCESS(rcNt))
        { /* likely */ }
        else
        {
            bool fRestartScan = pThis->fRestartScan;
            for (unsigned iRetry = 0; iRetry < 2; iRetry++)
            {
                if (   rcNt == STATUS_INVALID_INFO_CLASS
                    || rcNt == STATUS_INVALID_PARAMETER_8
                    || iRetry != 0)
                    pThis->enmInfoClass = FileBothDirectoryInformation;

                uint32_t cbBuffer = pThis->cbBufferAlloc;
                if (   rcNt == STATUS_INVALID_PARAMETER
                    || rcNt == STATUS_INVALID_PARAMETER_7
                    || rcNt == STATUS_INVALID_NETWORK_RESPONSE
                    || iRetry != 0)
                {
                    cbBuffer = RT_MIN(cbBuffer / 2, _64K);
                    fRestartScan = true;
                }

                for (;;)
                {
                    rcNt = NtQueryDirectoryFile(pThis->hDir,
                                                NULL /* Event */,
                                                NULL /* ApcRoutine */,
                                                NULL /* ApcContext */,
                                                &Ios,
                                                pThis->pabBuffer,
                                                cbBuffer,
                                                pThis->enmInfoClass,
                                                RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                                pThis->pNtFilterStr,
                                                fRestartScan);
                    if (   NT_SUCCESS(rcNt)
                        || cbBuffer == pThis->cbBufferAlloc
                        || cbBuffer <= sizeof(*pThis->uCurData.pBothId) + sizeof(WCHAR) * 260)
                        break;

                    /* Reduce the buffer size agressivly and try again.  We fall back to
                       FindFirstFile values for the final lap.  This means we'll do 4 rounds
                       with the current initial buffer size (64KB, 8KB, 1KB, 0x278/0x268). */
                    cbBuffer /= 8;
                    if (cbBuffer < 1024)
                        cbBuffer = pThis->enmInfoClass == FileIdBothDirectoryInformation
                                 ? sizeof(*pThis->uCurData.pBothId) + sizeof(WCHAR) * 260
                                 : sizeof(*pThis->uCurData.pBoth)   + sizeof(WCHAR) * 260;
                }
                if (NT_SUCCESS(rcNt))
                {
                    pThis->cbBufferAlloc = cbBuffer;
                    break;
                }
            }
        }
    }
    if (!NT_SUCCESS(rcNt))
    {
        /* Note! VBoxSVR and CIFS file systems both ends up with STATUS_NO_SUCH_FILE here instead of STATUS_NO_MORE_FILES. */
        if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES || rcNt == STATUS_NO_SUCH_FILE)
            return VERR_NO_MORE_FILES;
        return RTErrConvertFromNtStatus(rcNt);
    }
    pThis->fRestartScan = false;
    AssertMsg(  Ios.Information
              > (pThis->enmInfoClass == FileMaximumInformation ? sizeof(*pThis->uCurData.pObjDir) : sizeof(*pThis->uCurData.pBoth)),
              ("Ios.Information=%#x\n", Ios.Information));

    /*
     * Set up the data members.
     */
    pThis->uCurData.u  = (uintptr_t)pThis->pabBuffer;
    pThis->cbBuffer    = Ios.Information;

    int rc = rtDirNtCheckRecord(pThis);
    pThis->fDataUnread = RT_SUCCESS(rc);

    return rc;
}
Esempio n. 17
0
NTSTATUS
NTAPI
SmpCreateVolumeDescriptors(VOID)
{
    NTSTATUS Status;
    UNICODE_STRING VolumePath;
    BOOLEAN BootVolumeFound = FALSE;
    WCHAR StartChar, Drive, DriveDiff;
    HANDLE VolumeHandle;
    OBJECT_ATTRIBUTES ObjectAttributes;
    IO_STATUS_BLOCK IoStatusBlock;
    PROCESS_DEVICEMAP_INFORMATION ProcessInformation;
    FILE_FS_DEVICE_INFORMATION DeviceInfo;
    FILE_FS_SIZE_INFORMATION SizeInfo;
    PSMP_VOLUME_DESCRIPTOR Volume;
    LARGE_INTEGER FreeSpace, FinalFreeSpace;
    WCHAR Buffer[32];

    /* We should be starting with an empty list */
    ASSERT(IsListEmpty(&SmpVolumeDescriptorList));

    /* Query the device map so we can get the drive letters */
    Status = NtQueryInformationProcess(NtCurrentProcess(),
                                       ProcessDeviceMap,
                                       &ProcessInformation,
                                       sizeof(ProcessInformation),
                                       NULL);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("SMSS:PFILE: Query(ProcessDeviceMap) failed with status %X \n",
                Status);
        return Status;
    }

    /* Build the volume string, starting with A: (we'll edit this in place) */
    wcscpy(Buffer, L"\\??\\A:\\");
    RtlInitUnicodeString(&VolumePath, Buffer);

    /* Start with the C drive except on weird Japanese NECs... */
    StartChar = SharedUserData->AlternativeArchitecture ? L'A' : L'C';
    for (Drive = StartChar, DriveDiff = StartChar - L'A'; Drive <= L'Z'; Drive++, DriveDiff++)
    {
        /* Skip the disk if it's not in the drive map */
        if (!((1 << DriveDiff) & ProcessInformation.Query.DriveMap)) continue;

        /* Write the drive letter and try to open the volume */
        VolumePath.Buffer[STANDARD_DRIVE_LETTER_OFFSET] = Drive;
        InitializeObjectAttributes(&ObjectAttributes,
                                   &VolumePath,
                                   OBJ_CASE_INSENSITIVE,
                                   NULL,
                                   NULL);
        Status = NtOpenFile(&VolumeHandle,
                            FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
                            &ObjectAttributes,
                            &IoStatusBlock,
                            FILE_SHARE_READ | FILE_SHARE_WRITE,
                            FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
        if (!NT_SUCCESS(Status))
        {
            /* Skip the volume if we failed */
            DPRINT1("SMSS:PFILE: Open volume `%wZ' failed with status %X \n",
                    &VolumePath, Status);
            continue;
        }

        /* Now query device information on the volume */
        Status = NtQueryVolumeInformationFile(VolumeHandle,
                                              &IoStatusBlock,
                                              &DeviceInfo,
                                              sizeof(DeviceInfo),
                                              FileFsDeviceInformation);
        if (!NT_SUCCESS(Status))
        {
            /* Move to the next volume if we failed */
            DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for device info"
                    " failed with status %X \n",
                    &VolumePath,
                    VolumeHandle,
                    Status);
            NtClose(VolumeHandle);
            continue;
        }

        /* Check if this is a fixed disk */
        if (DeviceInfo.Characteristics & (FILE_FLOPPY_DISKETTE |
                                          FILE_READ_ONLY_DEVICE |
                                          FILE_REMOTE_DEVICE |
                                          FILE_REMOVABLE_MEDIA))
        {
            /* It isn't, so skip it */
            DPRINT1("SMSS:PFILE: Volume `%wZ' (%X) cannot store a paging file \n",
                    &VolumePath,
                    DeviceInfo.Characteristics);
            NtClose(VolumeHandle);
            continue;
        }

        /* We found a fixed volume, allocate a descriptor for it */
        Volume = RtlAllocateHeap(RtlGetProcessHeap(),
                                 HEAP_ZERO_MEMORY,
                                 sizeof(SMP_VOLUME_DESCRIPTOR));
        if (!Volume)
        {
            /* Failed to allocate memory, try the next disk */
            DPRINT1("SMSS:PFILE: Failed to allocate a volume descriptor (%u bytes) \n",
                    sizeof(SMP_VOLUME_DESCRIPTOR));
            NtClose(VolumeHandle);
            continue;
        }

        /* Save the drive letter and device information */
        Volume->DriveLetter = Drive;
        Volume->DeviceInfo = DeviceInfo;

        /* Check if this is the boot volume */
        if (RtlUpcaseUnicodeChar(Drive) ==
                RtlUpcaseUnicodeChar(SharedUserData->NtSystemRoot[0]))
        {
            /* Save it */
            ASSERT(BootVolumeFound == FALSE);
            Volume->Flags |= SMP_VOLUME_IS_BOOT;
            BootVolumeFound = TRUE;
        }

        /* Now get size information on the volume */
        Status = NtQueryVolumeInformationFile(VolumeHandle,
                                              &IoStatusBlock,
                                              &SizeInfo,
                                              sizeof(SizeInfo),
                                              FileFsSizeInformation);
        if (!NT_SUCCESS(Status))
        {
            /* We failed -- keep going */
            DPRINT1("SMSS:PFILE: Query volume `%wZ' (handle %p) for size failed"
                    " with status %X \n",
                    &VolumePath,
                    VolumeHandle,
                    Status);
            RtlFreeHeap(RtlGetProcessHeap(), 0, Volume);
            NtClose(VolumeHandle);
            continue;
        }

        /* Done querying volume information, close the handle */
        NtClose(VolumeHandle);

        /* Compute how much free space we have */
        FreeSpace.QuadPart = SizeInfo.AvailableAllocationUnits.QuadPart *
                             SizeInfo.SectorsPerAllocationUnit;
        FinalFreeSpace.QuadPart = FreeSpace.QuadPart * SizeInfo.BytesPerSector;

        /* Check if there's less than 32MB free so we don't starve the disk */
        if (FinalFreeSpace.QuadPart <= MINIMUM_TO_KEEP_FREE)
        {
            /* In this case, act as if there's no free space  */
            Volume->FreeSpace.QuadPart = 0;
        }
        else
        {
            /* Trim off 32MB to give the disk a bit of breathing room */
            Volume->FreeSpace.QuadPart = FinalFreeSpace.QuadPart -
                                         MINIMUM_TO_KEEP_FREE;
        }

        /* All done, add this volume to our descriptor list */
        InsertTailList(&SmpVolumeDescriptorList, &Volume->Entry);
        Volume->Flags |= SMP_VOLUME_INSERTED;
        DPRINT("SMSS:PFILE: Created volume descriptor for`%wZ' \n", &VolumePath);
    }

    /* We must've found at least the boot volume */
    ASSERT(BootVolumeFound == TRUE);
    ASSERT(!IsListEmpty(&SmpVolumeDescriptorList));
    if (!IsListEmpty(&SmpVolumeDescriptorList)) return STATUS_SUCCESS;

    /* Something is really messed up if we found no disks at all */
    return STATUS_UNEXPECTED_IO_ERROR;
}
Esempio n. 18
0
RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties)
{
    /*
     * Validate & get valid root path.
     */
    AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);
    AssertPtrReturn(pProperties, VERR_INVALID_POINTER);

    /*
     * Open the file/dir/whatever.
     */
    HANDLE hFile;
    int rc = rtNtPathOpen(pszFsPath,
                          GENERIC_READ,
                          FILE_ATTRIBUTE_NORMAL,
                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                          FILE_OPEN,
                          FILE_OPEN_FOR_BACKUP_INTENT,
                          OBJ_CASE_INSENSITIVE,
                          &hFile,
                          NULL);
    if (RT_SUCCESS(rc))
    {
        /*
         * Get the volume information.
         */
        union
        {
            FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
            uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096];
        } u;
        IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
        NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation);
        if (NT_SUCCESS(rcNt))
        {
            FILE_FS_DEVICE_INFORMATION FsDevInfo;
            rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &FsDevInfo, sizeof(FsDevInfo), FileFsDeviceInformation);
            if (NT_SUCCESS(rcNt))
            {
                /*
                 * Fill in the return structure.
                 */
                memset(pProperties, 0, sizeof(*pProperties));
                pProperties->cbMaxComponent   = u.FsAttrInfo.MaximumComponentNameLength;
                pProperties->fFileCompression = !!(u.FsAttrInfo.FileSystemAttributes & FILE_FILE_COMPRESSION);
                pProperties->fCompressed      = !!(u.FsAttrInfo.FileSystemAttributes & FILE_VOLUME_IS_COMPRESSED);
                pProperties->fReadOnly        = !!(u.FsAttrInfo.FileSystemAttributes & FILE_READ_ONLY_VOLUME);
                pProperties->fSupportsUnicode = !!(u.FsAttrInfo.FileSystemAttributes & FILE_UNICODE_ON_DISK);
                pProperties->fCaseSensitive   = false;    /* win32 is case preserving only */
                /** @todo r=bird: What about FILE_CASE_SENSITIVE_SEARCH ?  Is this set for NTFS
                 *        as well perchance?  If so, better mention it instead of just setting
                 *        fCaseSensitive to false. */

                /* figure the remote stuff */
                pProperties->fRemote          = RT_BOOL(FsDevInfo.Characteristics & FILE_REMOTE_DEVICE);
            }
            else
                rc = RTErrConvertFromNtStatus(rcNt);
        }
        else
            rc = RTErrConvertFromNtStatus(rcNt);

        rtNtPathClose(hFile);
    }
    return rc;
}
Esempio n. 19
0
/*
 * @implemented
 */
BOOL
WINAPI
GetVolumeInformationW(IN LPCWSTR lpRootPathName,
                      IN LPWSTR lpVolumeNameBuffer,
                      IN DWORD nVolumeNameSize,
                      OUT LPDWORD lpVolumeSerialNumber OPTIONAL,
                      OUT LPDWORD lpMaximumComponentLength OPTIONAL,
                      OUT LPDWORD lpFileSystemFlags OPTIONAL,
                      OUT LPWSTR lpFileSystemNameBuffer OPTIONAL,
                      IN DWORD nFileSystemNameSize)
{
  PFILE_FS_VOLUME_INFORMATION FileFsVolume;
  PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
  IO_STATUS_BLOCK IoStatusBlock;
  WCHAR RootPathName[MAX_PATH];
  UCHAR Buffer[max(FS_VOLUME_BUFFER_SIZE, FS_ATTRIBUTE_BUFFER_SIZE)];

  HANDLE hFile;
  NTSTATUS errCode;

  FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
  FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;

  TRACE("FileFsVolume %p\n", FileFsVolume);
  TRACE("FileFsAttribute %p\n", FileFsAttribute);

  if (!lpRootPathName || !wcscmp(lpRootPathName, L""))
  {
      GetCurrentDirectoryW (MAX_PATH, RootPathName);
  }
  else
  {
      wcsncpy (RootPathName, lpRootPathName, 3);
  }
  RootPathName[3] = 0;

  hFile = InternalOpenDirW(RootPathName, FALSE);
  if (hFile == INVALID_HANDLE_VALUE)
    {
      return FALSE;
    }

  TRACE("hFile: %p\n", hFile);
  errCode = NtQueryVolumeInformationFile(hFile,
                                         &IoStatusBlock,
                                         FileFsVolume,
                                         FS_VOLUME_BUFFER_SIZE,
                                         FileFsVolumeInformation);
  if ( !NT_SUCCESS(errCode) )
    {
      WARN("Status: %x\n", errCode);
      CloseHandle(hFile);
      BaseSetLastNTError (errCode);
      return FALSE;
    }

  if (lpVolumeSerialNumber)
    *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;

  if (lpVolumeNameBuffer)
    {
      if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
        {
	  memcpy(lpVolumeNameBuffer,
		 FileFsVolume->VolumeLabel,
		 FileFsVolume->VolumeLabelLength);
	  lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
	}
      else
        {
	  CloseHandle(hFile);
	  SetLastError(ERROR_MORE_DATA);
	  return FALSE;
	}
    }

  errCode = NtQueryVolumeInformationFile (hFile,
	                                  &IoStatusBlock,
	                                  FileFsAttribute,
	                                  FS_ATTRIBUTE_BUFFER_SIZE,
	                                  FileFsAttributeInformation);
  CloseHandle(hFile);
  if (!NT_SUCCESS(errCode))
    {
      WARN("Status: %x\n", errCode);
      BaseSetLastNTError (errCode);
      return FALSE;
    }

  if (lpFileSystemFlags)
    *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
  if (lpMaximumComponentLength)
    *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
  if (lpFileSystemNameBuffer)
    {
      if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
        {
	  memcpy(lpFileSystemNameBuffer,
		 FileFsAttribute->FileSystemName,
		 FileFsAttribute->FileSystemNameLength);
	  lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
	}
      else
        {
	  SetLastError(ERROR_MORE_DATA);
	  return FALSE;
	}
    }
  return TRUE;
}
Esempio n. 20
0
RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pcbFree,
                             uint32_t *pcbBlock, uint32_t *pcbSector)
{
    AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER);

    /*
     * Open the file/dir/whatever.
     */
    HANDLE hFile;
    int rc = rtNtPathOpen(pszFsPath,
                          GENERIC_READ,
                          FILE_ATTRIBUTE_NORMAL,
                          FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                          FILE_OPEN,
                          FILE_OPEN_FOR_BACKUP_INTENT,
                          OBJ_CASE_INSENSITIVE,
                          &hFile,
                          NULL);
    if (RT_SUCCESS(rc))
    {
        /*
         * Get the volume information.
         */
        FILE_FS_SIZE_INFORMATION FsSizeInfo;
        IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
        NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &FsSizeInfo, sizeof(FsSizeInfo), FileFsSizeInformation);
        if (NT_SUCCESS(rcNt))
        {
            /*
             * Calculate the return values.
             */
            if (pcbTotal)
            {
                *pcbTotal = FsSizeInfo.TotalAllocationUnits.QuadPart
                          * FsSizeInfo.SectorsPerAllocationUnit
                          * FsSizeInfo.BytesPerSector;
                if (   *pcbTotal / FsSizeInfo.SectorsPerAllocationUnit / FsSizeInfo.BytesPerSector
                    != FsSizeInfo.TotalAllocationUnits.QuadPart)
                    *pcbTotal = UINT64_MAX;
            }

            if (pcbFree)
            {
                *pcbFree = FsSizeInfo.AvailableAllocationUnits.QuadPart
                         * FsSizeInfo.SectorsPerAllocationUnit
                         * FsSizeInfo.BytesPerSector;
                if (   *pcbFree / FsSizeInfo.SectorsPerAllocationUnit / FsSizeInfo.BytesPerSector
                    != FsSizeInfo.AvailableAllocationUnits.QuadPart)
                    *pcbFree = UINT64_MAX;
            }

            if (pcbBlock)
            {
                *pcbBlock  = FsSizeInfo.SectorsPerAllocationUnit * FsSizeInfo.BytesPerSector;
                if (*pcbBlock / FsSizeInfo.BytesPerSector != FsSizeInfo.SectorsPerAllocationUnit)
                    rc = VERR_OUT_OF_RANGE;
            }

            if (pcbSector)
                *pcbSector = FsSizeInfo.BytesPerSector;
        }
        else
            rc = RTErrConvertFromNtStatus(rcNt);

        rtNtPathClose(hFile);
    }
    return rc;
}
Esempio n. 21
0
BOOLEAN
QueryVolumeTest(
    VOID
    )
{
    HANDLE fsHandle;
    IO_STATUS_BLOCK ioStatusBlock;
    OBJECT_ATTRIBUTES objectAttributes;
    UNICODE_STRING nameString;
    NTSTATUS status;
    PFILE_FS_ATTRIBUTE_INFORMATION fsAttributeInfo;

    RtlInitUnicodeString( &nameString, L"\\Device\\Mailslot" );

    InitializeObjectAttributes(
        &objectAttributes,
        &nameString,
        OBJ_CASE_INSENSITIVE,
        NULL,
        NULL
        );

    printf( "Attempting to open mailslot fs \"%wZ\"\n", &nameString );

    status = NtOpenFile (
                &fsHandle,
                GENERIC_READ,
                &objectAttributes,
                &ioStatusBlock,
                0,
                0L
                );

    printf( "MSFS open status = %lx\n", status );

    if (!NT_SUCCESS(status)) {
        return FALSE;
    }

    status = NtQueryVolumeInformationFile(
                fsHandle,
                &ioStatusBlock,
                Buffer,
                sizeof( Buffer ),
                FileFsAttributeInformation );

    printf("Query volume status = %lx\n", status );

    if ( !NT_SUCCESS( status )) {
        return FALSE;
    }

    status = ioStatusBlock.Status;
    printf( "Query volume final status = %d\n", status );

    fsAttributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
    printf ("  FileSystemAttributes       = %lx\n",
              fsAttributeInfo->FileSystemAttributes);
    printf ("  MaximumComponentNameLength = %ld\n",
              fsAttributeInfo->MaximumComponentNameLength);
    printf ("  FileSystemNameLength       = %ld\n",
              fsAttributeInfo->FileSystemNameLength);

    printf ("  FileSystemName             = ");
    DisplayUnicode(fsAttributeInfo->FileSystemName,
                   fsAttributeInfo->FileSystemNameLength);
    putchar ('\n');

    return( (BOOLEAN)NT_SUCCESS( status ));
}