QStorageInfo/Linux: use FS_IOC_GETFSLABEL to get the labels
This ioctl was introduced in kernel version 4.18 and before that it was used for btrfs alone. It is currently (kernel v6.7) supported by: * btrfs * ext2/ext4 * f2fs * gfs2 * xfs See man ioctl_fslabel(2) This means we won't need to list the /dev/disks/by-label directory if you only have mounted filesystems like the above or tmpfs (which doesn't support labels). On my system, there are still two cases that cause the listing: * a mount point not readable by my user, such as /.snapshots and /root * a FAT32 filesystem mounted on /boot/efi Change-Id: I76ffba14ece04f24b43efffd17ab3dced74ffd2c Reviewed-by: Ahmad Samir <a.samirh78@gmail.com> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> (cherry picked from commit 14115da183d2271dbc25446e4f9eda478722eff8) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
a3b4b060cf
commit
59b94a3158
@ -13,8 +13,17 @@
|
||||
#include <q20memory.h>
|
||||
|
||||
#include <linux/mount.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
// so we don't have to #include <linux/fs.h>, which is known to cause conflicts
|
||||
#ifndef FSLABEL_MAX
|
||||
# define FSLABEL_MAX 256
|
||||
#endif
|
||||
#ifndef FS_IOC_GETFSLABEL
|
||||
# define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX])
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
@ -118,9 +127,29 @@ static inline auto retrieveLabels()
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline QString retrieveLabel(const QByteArray &device, quint64 deviceId)
|
||||
static std::optional<QString> retrieveLabelViaIoctl(const QString &path)
|
||||
{
|
||||
deviceId = retrieveDeviceId(device, deviceId);
|
||||
// FS_IOC_GETFSLABEL was introduced in v4.18; previously it was btrfs-specific.
|
||||
int fd = qt_safe_open(QFile::encodeName(path).constData(), QT_OPEN_RDONLY);
|
||||
if (fd < 0)
|
||||
return std::nullopt;
|
||||
|
||||
// Note: it doesn't append the null terminator (despite what the man page
|
||||
// says) and the return code on success (0) does not indicate the length.
|
||||
char label[FSLABEL_MAX] = {};
|
||||
int r = ioctl(fd, FS_IOC_GETFSLABEL, &label);
|
||||
close(fd);
|
||||
if (r < 0)
|
||||
return std::nullopt;
|
||||
return QString::fromUtf8(label);
|
||||
}
|
||||
|
||||
static inline QString retrieveLabel(const QStorageInfoPrivate &d, quint64 deviceId)
|
||||
{
|
||||
if (auto label = retrieveLabelViaIoctl(d.rootPath))
|
||||
return *label;
|
||||
|
||||
deviceId = retrieveDeviceId(d.device, deviceId);
|
||||
if (!deviceId)
|
||||
return QString();
|
||||
|
||||
@ -211,7 +240,7 @@ void QStorageInfoPrivate::doStat()
|
||||
if (best) {
|
||||
auto stDev = best->stDev;
|
||||
setFromMountInfo(std::move(*best));
|
||||
name = retrieveLabel(device, stDev);
|
||||
name = retrieveLabel(*this, stDev);
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,11 +250,21 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
|
||||
if (infos.empty())
|
||||
return QList{root()};
|
||||
|
||||
auto labelForDevice = [labelMap = retrieveLabels()](const QByteArray &device, quint64 devid) {
|
||||
devid = retrieveDeviceId(device, devid);
|
||||
std::optional<decltype(retrieveLabels())> labelMap;
|
||||
auto labelForDevice = [&labelMap](const QStorageInfoPrivate &d, quint64 devid) {
|
||||
if (d.fileSystemType == "tmpfs")
|
||||
return QString();
|
||||
|
||||
if (auto label = retrieveLabelViaIoctl(d.rootPath))
|
||||
return *label;
|
||||
|
||||
devid = retrieveDeviceId(d.device, devid);
|
||||
if (!devid)
|
||||
return QString();
|
||||
for (auto &[deviceLabel, deviceId] : labelMap) {
|
||||
|
||||
if (!labelMap)
|
||||
labelMap = retrieveLabels();
|
||||
for (auto &[deviceLabel, deviceId] : std::as_const(*labelMap)) {
|
||||
if (devid == deviceId)
|
||||
return deviceLabel;
|
||||
}
|
||||
@ -240,7 +279,7 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
|
||||
continue;
|
||||
if (info.stDev != deviceIdForPath(d.rootPath))
|
||||
continue; // probably something mounted over this mountpoint
|
||||
d.name = labelForDevice(d.device, info.stDev);
|
||||
d.name = labelForDevice(d, info.stDev);
|
||||
volumes.emplace_back(QStorageInfo(*new QStorageInfoPrivate(std::move(d))));
|
||||
}
|
||||
return volumes;
|
||||
|
Loading…
x
Reference in New Issue
Block a user