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:
parent
4fe704eff9
commit
536696196c
@ -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
|
||||
|
172
src/corelib/io/qstorageinfo_linux.cpp
Normal file
172
src/corelib/io/qstorageinfo_linux.cpp
Normal 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
|
@ -160,9 +160,4 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
|
||||
return volumes;
|
||||
}
|
||||
|
||||
QStorageInfo QStorageInfoPrivate::root()
|
||||
{
|
||||
return QStorageInfo(QStringLiteral("/"));
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user