From 3b9f5c82f521fa1f7eb94a9d69cc6d9f840309ca Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 6 Aug 2024 14:14:49 -0700 Subject: [PATCH] QFileSystemEngine/Unix: implement getting the size of block devices Implemented for Linux, macOS, and FreeBSD. This works only on open files because of the need to ioctl(). Before: "/dev/system/stuff2" : 0 After: "/dev/system/stuff2" : 68719476736 [Linux] "/dev/ada1" : 42949672960 [FreeBSD] "/dev/disk0" : 500277792768 [macOS] "/dev/disk2" : 39306240 [macOS] With: if (f.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) qDebug() << f.fileName() << ':' << f.size(); [ChangeLog][QtCore][QFile] For open block devices on Unix systems, size() now returns the size of the underlying device. Previously, it would always return 0. Change-Id: I8a96935cf6c742259c9dfffd17e9402bdbd6b963 Reviewed-by: Fabian Kosmale --- src/corelib/io/qfilesystemengine_unix.cpp | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index abcc82dd408..217af10e0bb 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -36,6 +36,11 @@ # define _PATH_TMP "/tmp" #endif +#if __has_include() +// BSDs (including Apple Darwin) +# include +#endif + #if defined(Q_OS_DARWIN) # include # include @@ -362,6 +367,33 @@ inline void QFileSystemMetaData::fillFromStatxBuf(const struct statx &) //static bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data) { + auto getSizeForBlockDev = [&](mode_t st_mode) { +#ifdef BLKGETSIZE64 + // Linux + if (quint64 sz; (st_mode & S_IFMT) == S_IFBLK && ioctl(fd, BLKGETSIZE64, &sz) == 0) + data.size_ = sz; // returns byte count +#elif defined(BLKGETSIZE) + // older Linux + if (ulong sz; (st_mode & S_IFMT) == S_IFBLK && ioctl(fd, BLKGETSIZE, &sz) == 0) + data.size_ = sz * 512; // returns 512-byte sector count +#elif defined(DKIOCGETBLOCKCOUNT) + // Apple Darwin + qint32 blksz; + if (quint64 count; (st_mode & S_IFMT) == S_IFBLK + && ioctl(fd, DKIOCGETBLOCKCOUNT, &count) == 0 + && ioctl(fd, DKIOCGETBLOCKSIZE, &blksz) == 0) + data.size_ = count * blksz; +#elif defined(DIOCGMEDIASIZE) + // FreeBSD + // see Linux-compat implementation in + // http://fxr.watson.org/fxr/source/compat/linux/linux_ioctl.c?v=FREEBSD-13-STABLE#L282 + // S_IFCHR is correct: FreeBSD doesn't have block devices any more + if (QT_OFF_T sz; (st_mode & S_IFMT) == S_IFCHR && ioctl(fd, DIOCGMEDIASIZE, &sz) == 0) + data.size_ = sz; // returns byte count +#else + Q_UNUSED(st_mode); +#endif + }; data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags; data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags; @@ -371,6 +403,7 @@ bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data) if (ret != -ENOSYS) { if (ret == 0) { data.fillFromStatxBuf(statxBuffer); + getSizeForBlockDev(statxBuffer.stx_mode); return true; } return false; @@ -380,6 +413,7 @@ bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data) if (QT_FSTAT(fd, &statBuffer) == 0) { data.fillFromStatBuf(statBuffer); + getSizeForBlockDev(statBuffer.st_mode); return true; }