QStorageInfo: split Linux specific code to a separate source file

Much less crowded.

Inline QStorageInfoPrivate::root() to ease the split; the Windows
specific code is one extra line.

Change-Id: Icec6822cf436e2b4aa1b3a04184fbfa40e508078
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ahmad Samir 2023-06-19 04:38:17 +03:00
parent 4fe704eff9
commit 536696196c
6 changed files with 193 additions and 137 deletions

View File

@ -988,7 +988,7 @@ qt_internal_extend_target(Core CONDITION APPLE AND NOT MACOS
qt_internal_extend_target(Core CONDITION ANDROID
SOURCES
io/qstandardpaths_android.cpp
io/qstorageinfo_unix.cpp
io/qstorageinfo_linux.cpp
kernel/qjnitypes.h
kernel/qjnienvironment.cpp kernel/qjnienvironment.h
kernel/qjniobject.cpp kernel/qjniobject.h
@ -1018,12 +1018,19 @@ qt_internal_extend_target(Core CONDITION HAIKU AND NOT ANDROID
be
)
qt_internal_extend_target(Core CONDITION UNIX AND NOT APPLE AND NOT HAIKU AND NOT ANDROID
qt_internal_extend_target(Core
CONDITION UNIX AND NOT LINUX AND NOT APPLE AND NOT HAIKU AND NOT ANDROID
SOURCES
io/qstandardpaths_unix.cpp
io/qstorageinfo_unix.cpp
)
qt_internal_extend_target(Core CONDITION LINUX AND NOT ANDROID
SOURCES
io/qstandardpaths_unix.cpp
io/qstorageinfo_linux.cpp
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_itemmodel
SOURCES
itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h

View File

@ -0,0 +1,172 @@
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
// Copyright (C) 2016 Intel Corporation.
// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstorageinfo_linux_p.h"
#include "qdiriterator.h"
#include <private/qcore_unix_p.h>
#if defined(Q_OS_ANDROID)
# include <sys/mount.h>
# include <sys/vfs.h>
# define QT_STATFS ::statfs
# define QT_STATFSBUF struct statfs
# if !defined(ST_RDONLY)
# define ST_RDONLY 1 // hack for missing define on Android
# endif
#else
# include <sys/statvfs.h>
# if defined(QT_LARGEFILE_SUPPORT)
# define QT_STATFSBUF struct statvfs64
# define QT_STATFS ::statvfs64
# else
# define QT_STATFSBUF struct statvfs
# define QT_STATFS ::statvfs
# endif // QT_LARGEFILE_SUPPORT
#endif
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
// udev encodes the labels with ID_LABEL_FS_ENC which is done with
// blkid_encode_string(). Within this function some 1-byte utf-8
// characters not considered safe (e.g. '\' or ' ') are encoded as hex
static QString decodeFsEncString(const QString &str)
{
QString decoded;
decoded.reserve(str.size());
int i = 0;
while (i < str.size()) {
if (i <= str.size() - 4) { // we need at least four characters \xAB
if (QStringView{str}.sliced(i).startsWith("\\x"_L1)) {
bool bOk;
const int code = QStringView{str}.mid(i+2, 2).toInt(&bOk, 16);
if (bOk && code >= 0x20 && code < 0x80) {
decoded += QChar(code);
i += 4;
continue;
}
}
}
decoded += str.at(i);
++i;
}
return decoded;
}
static inline QString retrieveLabel(const QByteArray &device)
{
static const char pathDiskByLabel[] = "/dev/disk/by-label";
QFileInfo devinfo(QFile::decodeName(device));
QString devicePath = devinfo.canonicalFilePath();
QDirIterator it(QLatin1StringView(pathDiskByLabel), QDir::NoDotAndDotDot);
while (it.hasNext()) {
QFileInfo fileInfo = it.nextFileInfo();
if (fileInfo.isSymLink() && fileInfo.symLinkTarget() == devicePath)
return decodeFsEncString(fileInfo.fileName());
}
return QString();
}
void QStorageInfoPrivate::doStat()
{
initRootPath();
if (rootPath.isEmpty())
return;
retrieveVolumeInfo();
name = retrieveLabel(device);
}
void QStorageInfoPrivate::retrieveVolumeInfo()
{
QT_STATFSBUF statfs_buf;
int result;
EINTR_LOOP(result, QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf));
if (result == 0) {
valid = true;
ready = true;
bytesTotal = statfs_buf.f_blocks * statfs_buf.f_frsize;
bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize;
bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;
blockSize = statfs_buf.f_bsize;
#if defined(Q_OS_ANDROID)
#if defined(_STATFS_F_FLAGS)
readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0;
#endif
#else
readOnly = (statfs_buf.f_flag & ST_RDONLY) != 0;
#endif
}
}
static std::vector<MountInfo> parseMountInfo(FilterMountInfo filter = FilterMountInfo::All)
{
QFile file(u"/proc/self/mountinfo"_s);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return {};
QByteArray mountinfo = file.readAll();
file.close();
return doParseMountInfo(mountinfo, filter);
}
void QStorageInfoPrivate::initRootPath()
{
rootPath = QFileInfo(rootPath).canonicalFilePath();
if (rootPath.isEmpty())
return;
std::vector<MountInfo> infos = parseMountInfo();
if (infos.empty()) {
rootPath = u'/';
return;
}
qsizetype maxLength = 0;
const QString oldRootPath = rootPath;
rootPath.clear();
for (auto &info : infos) {
// we try to find most suitable entry
qsizetype mpSize = info.mountPoint.size();
if (isParentOf(info.mountPoint, oldRootPath) && maxLength < mpSize) {
maxLength = mpSize;
rootPath = info.mountPoint;
device = info.device;
fileSystemType = info.fsType;
subvolume = info.fsRoot;
}
}
}
QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
{
std::vector<MountInfo> infos = parseMountInfo(FilterMountInfo::Filtered);
if (infos.empty())
return QList{root()};
QList<QStorageInfo> volumes;
for (MountInfo &info : infos) {
QStorageInfo storage(info.mountPoint);
storage.d->device = info.device;
storage.d->fileSystemType = info.fsType;
storage.d->subvolume = info.fsRoot;
if (storage.bytesTotal() == 0 && storage != root())
continue;
volumes.push_back(storage);
}
return volumes;
}
QT_END_NAMESPACE

View File

@ -160,9 +160,4 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
QStorageInfo QStorageInfoPrivate::root()
{
return QStorageInfo(QStringLiteral("/"));
}
QT_END_NAMESPACE

View File

@ -16,6 +16,8 @@
//
#include <QtCore/qloggingcategory.h>
#include <QtCore/qsystemdetection.h>
#include <QtCore/qtenvironmentvariables.h>
#include <QtCore/private/qglobal_p.h>
#include "qstorageinfo.h"
@ -35,7 +37,15 @@ public:
void doStat();
static QList<QStorageInfo> mountedVolumes();
static QStorageInfo root();
static QStorageInfo root()
{
#ifdef Q_OS_WIN
return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive"))));
#else
return QStorageInfo(QStringLiteral("/"));
#endif
};
protected:
#if defined(Q_OS_WIN)

View File

@ -15,18 +15,9 @@
#include <errno.h>
#include <sys/stat.h>
#if defined(Q_OS_LINUX)
# include "qstorageinfo_linux_p.h"
#endif
#if defined(Q_OS_BSD4)
# include <sys/mount.h>
# include <sys/statvfs.h>
#elif defined(Q_OS_ANDROID)
# include <sys/mount.h>
# include <sys/vfs.h>
#elif defined(Q_OS_LINUX)
# include <sys/statvfs.h>
#elif defined(Q_OS_HURD)
# include <mntent.h>
# include <sys/statvfs.h>
@ -60,12 +51,6 @@
# if !defined(_STATFS_F_FLAGS) && !defined(Q_OS_NETBSD)
# define _STATFS_F_FLAGS 1
# endif
#elif defined(Q_OS_ANDROID)
# define QT_STATFS ::statfs
# define QT_STATFSBUF struct statfs
# if !defined(ST_RDONLY)
# define ST_RDONLY 1 // hack for missing define on Android
# endif
#elif defined(Q_OS_HAIKU)
# define QT_STATFSBUF struct statvfs
# define QT_STATFS ::statvfs
@ -382,50 +367,9 @@ inline QByteArray QStorageIterator::subvolume() const
}
#endif
#ifdef Q_OS_LINUX
// udev encodes the labels with ID_LABEL_FS_ENC which is done with
// blkid_encode_string(). Within this function some 1-byte utf-8
// characters not considered safe (e.g. '\' or ' ') are encoded as hex
static QString decodeFsEncString(const QString &str)
{
QString decoded;
decoded.reserve(str.size());
int i = 0;
while (i < str.size()) {
if (i <= str.size() - 4) { // we need at least four characters \xAB
if (QStringView{str}.sliced(i).startsWith("\\x"_L1)) {
bool bOk;
const int code = QStringView{str}.mid(i+2, 2).toInt(&bOk, 16);
if (bOk && code >= 0x20 && code < 0x80) {
decoded += QChar(code);
i += 4;
continue;
}
}
}
decoded += str.at(i);
++i;
}
return decoded;
}
#endif
static inline QString retrieveLabel(const QByteArray &device)
{
#ifdef Q_OS_LINUX
static const char pathDiskByLabel[] = "/dev/disk/by-label";
QFileInfo devinfo(QFile::decodeName(device));
QString devicePath = devinfo.canonicalFilePath();
QDirIterator it(QLatin1StringView(pathDiskByLabel), QDir::NoDotAndDotDot);
while (it.hasNext()) {
QFileInfo fileInfo = it.nextFileInfo();
if (fileInfo.isSymLink() && fileInfo.symLinkTarget() == devicePath)
return decodeFsEncString(fileInfo.fileName());
}
#elif defined Q_OS_HAIKU
#if defined Q_OS_HAIKU
fs_info fsInfo;
memset(&fsInfo, 0, sizeof(fsInfo));
@ -484,67 +428,6 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
}
}
#if defined(Q_OS_LINUX)
static std::vector<MountInfo> parseMountInfo(FilterMountInfo filter = FilterMountInfo::All)
{
QFile file(u"/proc/self/mountinfo"_s);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return {};
QByteArray mountinfo = file.readAll();
file.close();
return doParseMountInfo(mountinfo, filter);
}
void QStorageInfoPrivate::initRootPath()
{
rootPath = QFileInfo(rootPath).canonicalFilePath();
if (rootPath.isEmpty())
return;
std::vector<MountInfo> infos = parseMountInfo();
if (infos.empty()) {
rootPath = u'/';
return;
}
qsizetype maxLength = 0;
const QString oldRootPath = rootPath;
rootPath.clear();
for (auto &info : infos) {
// we try to find most suitable entry
qsizetype mpSize = info.mountPoint.size();
if (isParentOf(info.mountPoint, oldRootPath) && maxLength < mpSize) {
maxLength = mpSize;
rootPath = info.mountPoint;
device = info.device;
fileSystemType = info.fsType;
subvolume = info.fsRoot;
}
}
}
QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
{
std::vector<MountInfo> infos = parseMountInfo(FilterMountInfo::Filtered);
if (infos.empty())
return QList{root()};
QList<QStorageInfo> volumes;
for (MountInfo &info : infos) {
QStorageInfo storage(info.mountPoint);
storage.d->device = info.device;
storage.d->fileSystemType = info.fsType;
storage.d->subvolume = info.fsRoot;
if (storage.bytesTotal() == 0 && storage != root())
continue;
volumes.push_back(storage);
}
return volumes;
}
#else // defined(Q_OS_LINUX)
void QStorageInfoPrivate::initRootPath()
{
rootPath = QFileInfo(rootPath).canonicalFilePath();
@ -600,11 +483,5 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
#endif // defined(Q_OS_LINUX)
QStorageInfo QStorageInfoPrivate::root()
{
return QStorageInfo(QStringLiteral("/"));
}
QT_END_NAMESPACE

View File

@ -170,11 +170,6 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
QStorageInfo QStorageInfoPrivate::root()
{
return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive"))));
}
bool QStorageInfoPrivate::queryStorageProperty()
{
QString path = QDir::toNativeSeparators(uR"(\\.\)" + rootPath);