// Copyright (C) 2014 Ivan Komissarov // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QSTORAGEINFO_P_H #define QSTORAGEINFO_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include "qstorageinfo.h" #ifdef Q_OS_UNIX #include // dev_t #endif QT_BEGIN_NAMESPACE inline Q_LOGGING_CATEGORY(lcStorageInfo, "qt.core.qstorageinfo", QtWarningMsg) class QStorageInfoPrivate : public QSharedData { public: QStorageInfoPrivate() = default; void doStat(); static QList mountedVolumes(); 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) void initRootPath(); void retrieveVolumeInfo(); void retrieveDiskFreeSpace(); bool queryStorageProperty(); void queryFileFsSectorSizeInformation(); #elif defined(Q_OS_DARWIN) void initRootPath(); void retrievePosixInfo(); void retrieveUrlProperties(bool initRootPath = false); void retrieveLabel(); #elif defined(Q_OS_LINUX) void retrieveVolumeInfo(); public: struct MountInfo { QString mountPoint; QByteArray fsType; QByteArray device; QByteArray fsRoot; dev_t stDev = 0; }; void setFromMountInfo(MountInfo &&info) { rootPath = std::move(info.mountPoint); fileSystemType = std::move(info.fsType); device = std::move(info.device); subvolume = std::move(info.fsRoot); } QStorageInfoPrivate(MountInfo &&info) { setFromMountInfo(std::move(info)); } #elif defined(Q_OS_UNIX) void initRootPath(); void retrieveVolumeInfo(); #endif public: QString rootPath; QByteArray device; QByteArray subvolume; QByteArray fileSystemType; QString name; qint64 bytesTotal = -1; qint64 bytesFree = -1; qint64 bytesAvailable = -1; int blockSize = -1; bool readOnly = false; bool ready = false; bool valid = false; }; // Common helper functions template static bool isParentOf(const String &parent, const QString &dirName) { return dirName.startsWith(parent) && (dirName.size() == parent.size() || dirName.at(parent.size()) == u'/' || parent.size() == 1); } static inline bool shouldIncludeFs(const QString &mountDir, const QByteArray &fsType) { #if defined(Q_OS_ANDROID) // "rootfs" is the filesystem type of "/" on Android static constexpr char RootFsStr[] = ""; #else // "rootfs" is a type of ramfs on Linux, used in the initrd on some distros static constexpr char RootFsStr[] = "rootfs"; #endif using namespace Qt::StringLiterals; /* * This function implements a heuristic algorithm to determine whether a * given mount should be reported to the user. Our objective is to list * only entries that the end-user would find useful. * * We therefore ignore: * - mounted in /dev, /proc, /sys: special mounts * (this will catch /sys/fs/cgroup, /proc/sys/fs/binfmt_misc, /dev/pts, * some of which are tmpfs on Linux) * - mounted in /var/run or /var/lock: most likely pseudofs * (on earlier systemd versions, /var/run was a bind-mount of /run, so * everything would be unnecessarily duplicated) * - filesystem type is "rootfs": artifact of the root-pivot on some Linux * initrd * - if the filesystem total size is zero, it's a pseudo-fs (not checked here). */ if (isParentOf("/dev"_L1, mountDir) || isParentOf("/proc"_L1, mountDir) || isParentOf("/sys"_L1, mountDir) || isParentOf("/var/run"_L1, mountDir) || isParentOf("/var/lock"_L1, mountDir)) { return false; } if (!fsType.isEmpty() && fsType == RootFsStr) return false; // size checking in QStorageInfo::mountedVolumes() return true; } QT_END_NAMESPACE #endif // QSTORAGEINFO_P_H