diff options
author | Ahmad Samir <a.samirh78@gmail.com> | 2023-06-19 04:38:17 +0300 |
---|---|---|
committer | Ahmad Samir <a.samirh78@gmail.com> | 2023-07-09 01:44:49 +0300 |
commit | 536696196c4f954ffd2848bb89ea0404938262ad (patch) | |
tree | 54176e2bd1eea6c7f179b21fa22b20f3e4e0b063 /src/corelib/io | |
parent | 4fe704eff9f5352bb7b4c011fb6b010b45485d95 (diff) |
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>
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/qstorageinfo_linux.cpp | 172 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_mac.cpp | 5 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_p.h | 12 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_unix.cpp | 125 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_win.cpp | 5 |
5 files changed, 184 insertions, 135 deletions
diff --git a/src/corelib/io/qstorageinfo_linux.cpp b/src/corelib/io/qstorageinfo_linux.cpp new file mode 100644 index 0000000000..fbad091a24 --- /dev/null +++ b/src/corelib/io/qstorageinfo_linux.cpp @@ -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 diff --git a/src/corelib/io/qstorageinfo_mac.cpp b/src/corelib/io/qstorageinfo_mac.cpp index 690e7212d1..9ec5ae3f2f 100644 --- a/src/corelib/io/qstorageinfo_mac.cpp +++ b/src/corelib/io/qstorageinfo_mac.cpp @@ -160,9 +160,4 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes() return volumes; } -QStorageInfo QStorageInfoPrivate::root() -{ - return QStorageInfo(QStringLiteral("/")); -} - QT_END_NAMESPACE diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h index 77a7aa6c7d..ae4ff02f0b 100644 --- a/src/corelib/io/qstorageinfo_p.h +++ b/src/corelib/io/qstorageinfo_p.h @@ -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) diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 34ff8bff84..3c80c31453 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -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 diff --git a/src/corelib/io/qstorageinfo_win.cpp b/src/corelib/io/qstorageinfo_win.cpp index 418a8b77f8..0d2d34898c 100644 --- a/src/corelib/io/qstorageinfo_win.cpp +++ b/src/corelib/io/qstorageinfo_win.cpp @@ -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); |