Skip to content

Commit

Permalink
QFileSystemEngine/Unix: implement getting the size of block devices
Browse files Browse the repository at this point in the history
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 <fabian.kosmale@qt.io>
  • Loading branch information
thiagomacieira committed Sep 25, 2024
1 parent 731b115 commit 3b9f5c8
Showing 1 changed file with 34 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/corelib/io/qfilesystemengine_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
# define _PATH_TMP "/tmp"
#endif

#if __has_include(<sys/disk.h>)
// BSDs (including Apple Darwin)
# include <sys/disk.h>
#endif

#if defined(Q_OS_DARWIN)
# include <QtCore/private/qcore_mac_p.h>
# include <CoreFoundation/CFBundle.h>
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;
}

Expand Down

0 comments on commit 3b9f5c8

Please sign in to comment.