QStorageInfo: Add support for obtaining subvolume names

[ChangeLog][QtCore][QStorageInfo] Added QStorageInfo::subvolume(), which
returns the name of the subvolume of a volume that was mounted, if one
was detected. This is currently implemented only for btrfs on Linux.

Change-Id: Ib57b52598e2f452985e9fffd1459f3145d733ce5
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Thiago Macieira 2016-06-20 17:53:42 -07:00
parent 6cabb18bc2
commit 590ca43603
5 changed files with 83 additions and 6 deletions

View File

@ -260,13 +260,33 @@ QByteArray QStorageInfo::fileSystemType() const
devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC
path starting with \c \\\\?\\ for local storages (in other words, the volume GUID).
\sa rootPath()
\sa rootPath(), subvolume()
*/
QByteArray QStorageInfo::device() const
{
return d->device;
}
/*!
\since 5.8
Returns the subvolume name for this volume.
Some filesystem types allow multiple subvolumes inside one device, which
may be mounted in different paths. If the subvolume could be detected, it
is returned here. The format of the subvolume name is specific to each
filesystem type.
If this volume was not mounted from a subvolume of a larger filesystem or
if the subvolume could not be detected, this function returns an empty byte
array.
\sa device()
*/
QByteArray QStorageInfo::subvolume() const
{
return d->subvolume;
}
/*!
Returns the human-readable name of a filesystem, usually called \c label.

View File

@ -71,6 +71,7 @@ public:
QString rootPath() const;
QByteArray device() const;
QByteArray subvolume() const;
QByteArray fileSystemType() const;
QString name() const;
QString displayName() const;
@ -100,7 +101,7 @@ inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
{
if (first.d == second.d)
return true;
return first.device() == second.device();
return first.device() == second.device() && first.rootPath() == second.rootPath();
}
inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)

View File

@ -85,6 +85,7 @@ protected:
public:
QString rootPath;
QByteArray device;
QByteArray subvolume;
QByteArray fileSystemType;
QString name;

View File

@ -120,6 +120,7 @@ public:
inline QString rootPath() const;
inline QByteArray fileSystemType() const;
inline QByteArray device() const;
inline QByteArray options() const;
private:
#if defined(Q_OS_BSD4)
QT_STATFSBUF *stat_buf;
@ -133,6 +134,7 @@ private:
QByteArray m_rootPath;
QByteArray m_fileSystemType;
QByteArray m_device;
QByteArray m_options;
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
FILE *fp;
mntent mnt;
@ -228,6 +230,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(stat_buf[currentIndex].f_mntfromname);
}
inline QByteArray QStorageIterator::options() const
{
return QByteArray();
}
#elif defined(Q_OS_SOLARIS)
static const char pathMounted[] = "/etc/mnttab";
@ -301,6 +308,7 @@ inline bool QStorageIterator::next()
m_device = data.at(0);
m_rootPath = data.at(1);
m_fileSystemType = data.at(2);
m_options = data.at(3);
return true;
}
@ -320,6 +328,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
inline QByteArray QStorageIterator::options() const
{
return m_options;
}
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
static const char pathMounted[] = "/etc/mtab";
@ -363,6 +376,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(mnt.mnt_fsname);
}
inline QByteArray QStorageIterator::options() const
{
return QByteArray(mnt.mnt_opts);
}
#elif defined(Q_OS_HAIKU)
inline QStorageIterator::QStorageIterator()
{
@ -420,6 +438,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
inline QByteArray QStorageIterator::options() const
{
return QByteArray();
}
#else
inline QStorageIterator::QStorageIterator()
@ -455,8 +478,35 @@ inline QByteArray QStorageIterator::device() const
return QByteArray();
}
inline QByteArray QStorageIterator::options() const
{
return QByteArray();
}
#endif
static QByteArray extractSubvolume(const QStorageIterator &it)
{
#ifdef Q_OS_LINUX
if (it.fileSystemType() == "btrfs") {
const QByteArrayList opts = it.options().split(',');
QByteArray id;
for (const QByteArray &opt : opts) {
static const char subvol[] = "subvol=";
static const char subvolid[] = "subvolid=";
if (opt.startsWith(subvol))
return std::move(opt).mid(strlen(subvol));
if (opt.startsWith(subvolid))
id = std::move(opt).mid(strlen(subvolid));
}
// if we didn't find the subvolume name, return the subvolume ID
return id;
}
#endif
return QByteArray();
}
void QStorageInfoPrivate::initRootPath()
{
rootPath = QFileInfo(rootPath).canonicalFilePath();
@ -483,6 +533,7 @@ void QStorageInfoPrivate::initRootPath()
rootPath = mountDir;
device = it.device();
fileSystemType = fsName;
subvolume = extractSubvolume(it);
}
}
}

View File

@ -48,11 +48,15 @@ void printVolumes(const QList<QStorageInfo> &volumes, int (*printer)(const char
if (info.fileSystemType() != fsAndType)
fsAndType += " (" + info.fileSystemType() + ')';
printf("%-19s R%c ", fsAndType.constData(), info.isReadOnly() ? 'O' : 'W');
printer("%-19s R%c ", fsAndType.constData(), info.isReadOnly() ? 'O' : 'W');
if (fsAndType.size() > 19)
printf("\n%23s", "");
printer("\n%23s", "");
printf("%10llu %10llu %5u ", info.bytesTotal() / 1024, info.bytesFree() / 1024, info.blockSize());
printf("%-16s %s\n", qPrintable(info.name()), qPrintable(info.rootPath()));
printer("%10llu %10llu %5u ", info.bytesTotal() / 1024, info.bytesFree() / 1024, info.blockSize());
if (!info.subvolume().isEmpty())
printer("subvol=%-18s ", qPrintable(info.subvolume()));
else
printer("%-25s ", qPrintable(info.name()));
printer("%s\n", qPrintable(info.rootPath()));
}
}