summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/CMakeLists.txt1
-rw-r--r--src/corelib/io/qntdll_p.h96
-rw-r--r--src/corelib/io/qstorageinfo_p.h2
-rw-r--r--src/corelib/io/qstorageinfo_win.cpp142
4 files changed, 240 insertions, 1 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index e02f79b8f0..8bb040ca96 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -481,6 +481,7 @@ qt_internal_extend_target(Core CONDITION WIN32
io/qstorageinfo_win.cpp
io/qwindowspipereader.cpp io/qwindowspipereader_p.h
io/qwindowspipewriter.cpp io/qwindowspipewriter_p.h
+ io/qntdll_p.h
kernel/qcoreapplication_win.cpp
kernel/qelapsedtimer_win.cpp
kernel/qeventdispatcher_win.cpp kernel/qeventdispatcher_win_p.h
diff --git a/src/corelib/io/qntdll_p.h b/src/corelib/io/qntdll_p.h
new file mode 100644
index 0000000000..caf34ddb5f
--- /dev/null
+++ b/src/corelib/io/qntdll_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNTDLL_P_H
+#define QNTDLL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <winternl.h>
+
+QT_BEGIN_NAMESPACE
+
+// keep the following structure as is, taken from
+// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_fs_sector_size_information
+// Unfortunately we can't include the ntddk.h header, so we duplicate the code here.
+typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION {
+ ULONG LogicalBytesPerSector;
+ ULONG PhysicalBytesPerSectorForAtomicity;
+ ULONG PhysicalBytesPerSectorForPerformance;
+ ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
+ ULONG Flags;
+ ULONG ByteOffsetForSectorAlignment;
+ ULONG ByteOffsetForPartitionAlignment;
+} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;
+
+#if !defined(Q_CC_CLANG) && !defined(Q_CC_MINGW)
+// keep the following enumeration as is, taken from
+// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-_fsinfoclass
+// Unfortunately we can't include the wdm.h header, so we duplicate the code here.
+typedef enum _FSINFOCLASS {
+ FileFsVolumeInformation,
+ FileFsLabelInformation,
+ FileFsSizeInformation,
+ FileFsDeviceInformation,
+ FileFsAttributeInformation,
+ FileFsControlInformation,
+ FileFsFullSizeInformation,
+ FileFsObjectIdInformation,
+ FileFsDriverPathInformation,
+ FileFsVolumeFlagsInformation,
+ FileFsSectorSizeInformation,
+ FileFsDataCopyInformation,
+ FileFsMetadataSizeInformation,
+ FileFsFullSizeInformationEx,
+ FileFsMaximumInformation
+} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QNTDLL_P_H
diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h
index 421e364311..c0f7595c08 100644
--- a/src/corelib/io/qstorageinfo_p.h
+++ b/src/corelib/io/qstorageinfo_p.h
@@ -74,6 +74,8 @@ protected:
#if defined(Q_OS_WIN)
void retrieveVolumeInfo();
void retrieveDiskFreeSpace();
+ bool queryStorageProperty();
+ void queryFileFsSectorSizeInformation();
#elif defined(Q_OS_MAC)
void retrievePosixInfo();
void retrieveUrlProperties(bool initRootPath = false);
diff --git a/src/corelib/io/qstorageinfo_win.cpp b/src/corelib/io/qstorageinfo_win.cpp
index 5a65b78d63..d594551425 100644
--- a/src/corelib/io/qstorageinfo_win.cpp
+++ b/src/corelib/io/qstorageinfo_win.cpp
@@ -41,11 +41,13 @@
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qvarlengtharray.h>
#include "qfilesystementry_p.h"
+#include "private/qsystemlibrary_p.h"
-#include <qt_windows.h>
+#include "qntdll_p.h"
QT_BEGIN_NAMESPACE
@@ -134,6 +136,9 @@ void QStorageInfoPrivate::doStat()
return;
device = getDevice(rootPath);
retrieveDiskFreeSpace();
+
+ if (!queryStorageProperty())
+ queryFileFsSectorSizeInformation();
}
void QStorageInfoPrivate::retrieveVolumeInfo()
@@ -204,4 +209,139 @@ QStorageInfo QStorageInfoPrivate::root()
return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive"))));
}
+bool QStorageInfoPrivate::queryStorageProperty()
+{
+ QString path = QDir::toNativeSeparators(uR"(\\.\)" + rootPath);
+ if (path.endsWith(u'\\'))
+ path.chop(1);
+
+ HANDLE handle = CreateFile(reinterpret_cast<const wchar_t *>(path.utf16()),
+ 0, // no access to the drive
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ 0,
+ nullptr);
+ if (handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ STORAGE_PROPERTY_QUERY spq;
+ memset(&spq, 0, sizeof(spq));
+ spq.PropertyId = StorageAccessAlignmentProperty;
+ spq.QueryType = PropertyStandardQuery;
+
+ STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR saad;
+ memset(&saad, 0, sizeof(saad));
+
+ DWORD bytes = 0;
+ BOOL result = DeviceIoControl(handle,
+ IOCTL_STORAGE_QUERY_PROPERTY,
+ &spq, sizeof(spq),
+ &saad, sizeof(saad),
+ &bytes,
+ nullptr);
+ CloseHandle(handle);
+ if (result)
+ blockSize = saad.BytesPerPhysicalSector;
+ return result;
+}
+
+struct Helper
+{
+ QBasicMutex mutex;
+ QSystemLibrary ntdll {u"ntdll"_qs};
+};
+Q_GLOBAL_STATIC(Helper, gNtdllHelper)
+
+inline QFunctionPointer resolveSymbol(QSystemLibrary *ntdll, const char *name)
+{
+ QFunctionPointer symbolFunctionPointer = ntdll->resolve(name);
+ if (Q_UNLIKELY(!symbolFunctionPointer))
+ qWarning("Failed to resolve the symbol: %s", name);
+ return symbolFunctionPointer;
+}
+
+#define GENERATE_SYMBOL(symbolName, returnType, ...) \
+using Qt##symbolName = returnType (NTAPI *) (__VA_ARGS__); \
+static Qt##symbolName qt##symbolName = nullptr;
+
+#define RESOLVE_SYMBOL(name) \
+ do { \
+ qt##name = reinterpret_cast<Qt##name>(resolveSymbol(ntdll, #name)); \
+ if (!qt##name) \
+ return false; \
+ } while (false)
+
+GENERATE_SYMBOL(RtlInitUnicodeString, void, PUNICODE_STRING, PCWSTR);
+GENERATE_SYMBOL(NtCreateFile, NTSTATUS, PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
+ PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
+GENERATE_SYMBOL(NtQueryVolumeInformationFile, NTSTATUS, HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG,
+ FS_INFORMATION_CLASS);
+
+void QStorageInfoPrivate::queryFileFsSectorSizeInformation()
+{
+ static bool symbolsResolved = [](auto ntdllHelper) {
+ QMutexLocker locker(&ntdllHelper->mutex);
+ auto ntdll = &ntdllHelper->ntdll;
+ if (!ntdll->isLoaded()) {
+ if (!ntdll->load()) {
+ qWarning("Unable to load ntdll.dll.");
+ return false;
+ }
+ }
+
+ RESOLVE_SYMBOL(RtlInitUnicodeString);
+ RESOLVE_SYMBOL(NtCreateFile);
+ RESOLVE_SYMBOL(NtQueryVolumeInformationFile);
+
+ return true;
+ }(gNtdllHelper());
+ if (!symbolsResolved)
+ return;
+
+ FILE_FS_SECTOR_SIZE_INFORMATION ffssi;
+ memset(&ffssi, 0, sizeof(ffssi));
+
+ HANDLE handle = nullptr;
+
+ OBJECT_ATTRIBUTES attrs;
+ memset(&attrs, 0, sizeof(attrs));
+
+ IO_STATUS_BLOCK isb;
+ memset(&isb, 0, sizeof(isb));
+
+ QString path = QDir::toNativeSeparators(uR"(\??\\)" + rootPath);
+ if (!path.endsWith(u'\\'))
+ path.append(u'\\');
+
+ UNICODE_STRING name;
+ qtRtlInitUnicodeString(&name, reinterpret_cast<const wchar_t *>(path.utf16()));
+
+ InitializeObjectAttributes(&attrs, &name, 0, nullptr, nullptr);
+
+ NTSTATUS status = qtNtCreateFile(&handle,
+ FILE_READ_ATTRIBUTES,
+ &attrs,
+ &isb,
+ nullptr,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0,
+ nullptr,
+ 0);
+ if (!NT_SUCCESS(status))
+ return;
+
+ memset(&isb, 0, sizeof(isb));
+ status = qtNtQueryVolumeInformationFile(handle,
+ &isb,
+ &ffssi,
+ sizeof(ffssi),
+ FS_INFORMATION_CLASS(10)); // FileFsSectorSizeInformation
+ CloseHandle(handle);
+ if (NT_SUCCESS(status))
+ blockSize = ffssi.PhysicalBytesPerSectorForAtomicity;
+}
+
QT_END_NAMESPACE