7#include <QtCore/qdir.h>
8#include <QtCore/qfileinfo.h>
9#include <QtCore/qmutex.h>
10#include <QtCore/qvarlengtharray.h>
11#include <QtCore/private/wcharhelpers_win_p.h>
17extern "C" NTSTATUS NTSYSCALLAPI NTAPI NtQueryVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG,
18 FS_INFORMATION_CLASS);
22using namespace Qt::StringLiterals;
28 QString path = QDir::toNativeSeparators(QFileInfo(rootPath).canonicalFilePath());
32 if (path.startsWith(
"\\\\?\\"_L1))
34 if (path.length() < 2 || path.at(1) != u':')
37 path[0] = path[0].toUpper();
38 if (!(path.at(0).unicode() >=
'A' && path.at(0).unicode() <=
'Z'))
40 if (!path.endsWith(u'\\'))
45void QStorageInfoPrivate::initRootPath()
49 const QString path = QFileSystemEntry::isDriveRootPath(rootPath)
50 ? QDir::toNativeSeparators(rootPath)
51 : canonicalPath(rootPath);
54 valid = ready =
false;
59 wchar_t buffer[defaultBufferSize];
60 if (::GetVolumePathName(
reinterpret_cast<
const wchar_t *>(path.utf16()), buffer, defaultBufferSize))
61 rootPath = QDir::fromNativeSeparators(QString::fromWCharArray(buffer));
63 valid = ready =
false;
68 const QString path = QDir::toNativeSeparators(rootPath);
69 const UINT type = ::GetDriveType(
reinterpret_cast<
const wchar_t *>(path.utf16()));
70 if (type == DRIVE_REMOTE) {
71 QVarLengthArray<
char, 256> buffer(256);
72 DWORD bufferLength = buffer.size();
74 UNIVERSAL_NAME_INFO *remoteNameInfo;
76 buffer.resize(bufferLength);
77 remoteNameInfo =
reinterpret_cast<UNIVERSAL_NAME_INFO *>(buffer.data());
78 result = ::WNetGetUniversalName(
reinterpret_cast<
const wchar_t *>(path.utf16()),
79 UNIVERSAL_NAME_INFO_LEVEL,
82 }
while (result == ERROR_MORE_DATA);
83 if (result == NO_ERROR)
84 return QString::fromWCharArray(remoteNameInfo->lpUniversalName).toUtf8();
88 wchar_t deviceBuffer[51];
89 if (::GetVolumeNameForVolumeMountPoint(
reinterpret_cast<
const wchar_t *>(path.utf16()),
91 sizeof(deviceBuffer) /
sizeof(
wchar_t))) {
92 return QString::fromWCharArray(deviceBuffer).toLatin1();
97void QStorageInfoPrivate::doStat()
101 if (!valid || !ready)
104 retrieveVolumeInfo();
105 if (!valid || !ready)
107 device = getDevice(rootPath);
108 retrieveDiskFreeSpace();
110 if (!queryStorageProperty())
111 queryFileFsSectorSizeInformation();
114void QStorageInfoPrivate::retrieveVolumeInfo()
116 const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
118 const QString path = QDir::toNativeSeparators(rootPath);
119 wchar_t nameBuffer[defaultBufferSize];
120 wchar_t fileSystemTypeBuffer[defaultBufferSize];
121 DWORD fileSystemFlags = 0;
122 const bool result = ::GetVolumeInformation(
reinterpret_cast<
const wchar_t *>(path.utf16()),
128 fileSystemTypeBuffer,
132 valid = ::GetLastError() == ERROR_NOT_READY;
134 fileSystemType = QString::fromWCharArray(fileSystemTypeBuffer).toLatin1();
135 name = QString::fromWCharArray(nameBuffer);
137 readOnly = (fileSystemFlags & FILE_READ_ONLY_VOLUME) != 0;
140 ::SetErrorMode(oldmode);
143void QStorageInfoPrivate::retrieveDiskFreeSpace()
145 const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
147 const QString path = QDir::toNativeSeparators(rootPath);
148 ready = ::GetDiskFreeSpaceEx(
reinterpret_cast<
const wchar_t *>(path.utf16()),
149 PULARGE_INTEGER(&bytesAvailable),
150 PULARGE_INTEGER(&bytesTotal),
151 PULARGE_INTEGER(&bytesFree));
153 ::SetErrorMode(oldmode);
156QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
158 QList<QStorageInfo> volumes;
160 QString driveName = QStringLiteral(
"A:/");
161 const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
162 quint32 driveBits = quint32(::GetLogicalDrives()) & 0x3ffffff;
163 ::SetErrorMode(oldmode);
166 QStorageInfo drive(driveName);
167 if (!drive.rootPath().isEmpty())
168 volumes.append(drive);
170 driveName[0] = QChar(driveName[0].unicode() + 1);
171 driveBits = driveBits >> 1;
177bool QStorageInfoPrivate::queryStorageProperty()
179 QString path = QDir::toNativeSeparators(uR"(\\.\)" + rootPath);
180 if (path.endsWith(u'\\'))
183 HANDLE handle = CreateFile(qt_castToWchar(path),
185 FILE_SHARE_READ | FILE_SHARE_WRITE,
190 if (handle == INVALID_HANDLE_VALUE)
193 STORAGE_PROPERTY_QUERY spq;
194 memset(&spq, 0,
sizeof(spq));
195 spq.PropertyId = StorageAccessAlignmentProperty;
196 spq.QueryType = PropertyStandardQuery;
198 STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR saad;
199 memset(&saad, 0,
sizeof(saad));
202 BOOL result = DeviceIoControl(handle,
203 IOCTL_STORAGE_QUERY_PROPERTY,
210 blockSize =
int(saad.BytesPerPhysicalSector);
214void QStorageInfoPrivate::queryFileFsSectorSizeInformation()
216 FILE_FS_SECTOR_SIZE_INFORMATION ffssi;
217 memset(&ffssi, 0,
sizeof(ffssi));
219 HANDLE handle =
nullptr;
221 OBJECT_ATTRIBUTES attrs;
222 memset(&attrs, 0,
sizeof(attrs));
225 memset(&isb, 0,
sizeof(isb));
227 QString path = QDir::toNativeSeparators(uR"(\??\\)" + rootPath);
228 if (!path.endsWith(u'\\'))
232 ::RtlInitUnicodeString(&name, qt_castToWchar(path));
234 InitializeObjectAttributes(&attrs, &name, 0,
nullptr,
nullptr);
236 NTSTATUS status = ::NtCreateFile(&handle,
237 FILE_READ_ATTRIBUTES,
241 FILE_ATTRIBUTE_NORMAL,
242 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
247 if (!NT_SUCCESS(status))
250 memset(&isb, 0,
sizeof(isb));
251 status = ::NtQueryVolumeInformationFile(handle,
255 FS_INFORMATION_CLASS(10));
257 if (NT_SUCCESS(status))
258 blockSize = ffssi.PhysicalBytesPerSectorForAtomicity;
static QString canonicalPath(const QString &rootPath)
static QByteArray getDevice(const QString &rootPath)
static const int defaultBufferSize