| 1 | // Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> | 
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | 
| 3 |  | 
| 4 | #ifndef QSTORAGEINFO_P_H | 
| 5 | #define QSTORAGEINFO_P_H | 
| 6 |  | 
| 7 | // | 
| 8 | //  W A R N I N G | 
| 9 | //  ------------- | 
| 10 | // | 
| 11 | // This file is not part of the Qt API.  It exists purely as an | 
| 12 | // implementation detail.  This header file may change from version to | 
| 13 | // version without notice, or even be removed. | 
| 14 | // | 
| 15 | // We mean it. | 
| 16 | // | 
| 17 |  | 
| 18 | #include <QtCore/qloggingcategory.h> | 
| 19 | #include <QtCore/qsystemdetection.h> | 
| 20 | #include <QtCore/qtenvironmentvariables.h> | 
| 21 | #include <QtCore/private/qglobal_p.h> | 
| 22 | #include "qstorageinfo.h" | 
| 23 |  | 
| 24 | #ifdef Q_OS_UNIX | 
| 25 | #include <sys/types.h> // dev_t | 
| 26 | #endif | 
| 27 |  | 
| 28 | QT_BEGIN_NAMESPACE | 
| 29 |  | 
| 30 | inline Q_LOGGING_CATEGORY(lcStorageInfo, "qt.core.qstorageinfo" , QtWarningMsg) | 
| 31 |  | 
| 32 | class QStorageInfoPrivate : public QSharedData | 
| 33 | { | 
| 34 | public: | 
| 35 |     QStorageInfoPrivate() = default; | 
| 36 |  | 
| 37 |     void doStat(); | 
| 38 |  | 
| 39 |     static QList<QStorageInfo> mountedVolumes(); | 
| 40 |  | 
| 41 |     static QStorageInfo root() | 
| 42 |     { | 
| 43 | #ifdef Q_OS_WIN | 
| 44 |         return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive" )))); | 
| 45 | #else | 
| 46 |         return QStorageInfo(QStringLiteral("/" )); | 
| 47 | #endif | 
| 48 |     } | 
| 49 |  | 
| 50 | protected: | 
| 51 | #if defined(Q_OS_WIN) | 
| 52 |     void initRootPath(); | 
| 53 |     void retrieveVolumeInfo(); | 
| 54 |     void retrieveDiskFreeSpace(); | 
| 55 |     bool queryStorageProperty(); | 
| 56 |     void queryFileFsSectorSizeInformation(); | 
| 57 | #elif defined(Q_OS_DARWIN) | 
| 58 |     void initRootPath(); | 
| 59 |     void retrievePosixInfo(); | 
| 60 |     void retrieveUrlProperties(bool initRootPath = false); | 
| 61 |     void retrieveLabel(); | 
| 62 | #elif defined(Q_OS_LINUX) | 
| 63 |     void retrieveVolumeInfo(); | 
| 64 |  | 
| 65 | public: | 
| 66 |     struct MountInfo { | 
| 67 |         QString mountPoint; | 
| 68 |         QByteArray fsType; | 
| 69 |         QByteArray device; | 
| 70 |         QByteArray fsRoot; | 
| 71 |         dev_t stDev = 0; | 
| 72 |         quint64 mntid = 0; | 
| 73 |     }; | 
| 74 |  | 
| 75 |     void setFromMountInfo(MountInfo &&info) | 
| 76 |     { | 
| 77 |         rootPath = std::move(info.mountPoint); | 
| 78 |         fileSystemType = std::move(info.fsType); | 
| 79 |         device = std::move(info.device); | 
| 80 |         subvolume = std::move(info.fsRoot); | 
| 81 |     } | 
| 82 |  | 
| 83 |     QStorageInfoPrivate(MountInfo &&info) | 
| 84 |     { | 
| 85 |         setFromMountInfo(std::move(info)); | 
| 86 |     } | 
| 87 |  | 
| 88 | #elif defined(Q_OS_UNIX) | 
| 89 |     void initRootPath(); | 
| 90 |     void retrieveVolumeInfo(); | 
| 91 | #endif | 
| 92 |  | 
| 93 | #ifdef Q_OS_UNIX | 
| 94 |     // Common helper functions | 
| 95 |     template <typename String> | 
| 96 |     static bool isParentOf(const String &parent, const QString &dirName) | 
| 97 |     { | 
| 98 |         return dirName.startsWith(parent) && | 
| 99 |                 (dirName.size() == parent.size() || dirName.at(i: parent.size()) == u'/' || | 
| 100 |                  parent.size() == 1); | 
| 101 |     } | 
| 102 |     static inline bool shouldIncludeFs(const QString &mountDir, const QByteArray &fsType); | 
| 103 | #endif | 
| 104 |  | 
| 105 | public: | 
| 106 |     QString rootPath; | 
| 107 |     QByteArray device; | 
| 108 |     QByteArray subvolume; | 
| 109 |     QByteArray fileSystemType; | 
| 110 |     QString name; | 
| 111 |  | 
| 112 |     qint64 bytesTotal = -1; | 
| 113 |     qint64 bytesFree = -1; | 
| 114 |     qint64 bytesAvailable = -1; | 
| 115 |     int blockSize = -1; | 
| 116 |  | 
| 117 |     bool readOnly = false; | 
| 118 |     bool ready = false; | 
| 119 |     bool valid = false; | 
| 120 | }; | 
| 121 |  | 
| 122 | #ifdef Q_OS_UNIX | 
| 123 | bool QStorageInfoPrivate::shouldIncludeFs(const QString &mountDir, const QByteArray &fsType) | 
| 124 | { | 
| 125 | #if defined(Q_OS_ANDROID) | 
| 126 |     // "rootfs" is the filesystem type of "/" on Android | 
| 127 |     static constexpr char RootFsStr[] = "" ; | 
| 128 | #else | 
| 129 |     // "rootfs" is a type of ramfs on Linux, used in the initrd on some distros | 
| 130 |     static constexpr char RootFsStr[] = "rootfs" ; | 
| 131 | #endif | 
| 132 |  | 
| 133 |     using namespace Qt::StringLiterals; | 
| 134 |     /* | 
| 135 |      * This function implements a heuristic algorithm to determine whether a | 
| 136 |      * given mount should be reported to the user. Our objective is to list | 
| 137 |      * only entries that the end-user would find useful. | 
| 138 |      * | 
| 139 |      * We therefore ignore: | 
| 140 |      *  - mounted in /dev, /proc, /sys: special mounts | 
| 141 |      *    (this will catch /sys/fs/cgroup, /proc/sys/fs/binfmt_misc, /dev/pts, | 
| 142 |      *    some of which are tmpfs on Linux) | 
| 143 |      *  - mounted in /var/run or /var/lock: most likely pseudofs | 
| 144 |      *    (on earlier systemd versions, /var/run was a bind-mount of /run, so | 
| 145 |      *    everything would be unnecessarily duplicated) | 
| 146 |      *  - filesystem type is "rootfs": artifact of the root-pivot on some Linux | 
| 147 |      *    initrd | 
| 148 |      *  - if the filesystem total size is zero, it's a pseudo-fs (not checked here). | 
| 149 |      */ | 
| 150 |  | 
| 151 |     if (isParentOf(parent: "/dev"_L1 , dirName: mountDir) | 
| 152 |         || isParentOf(parent: "/proc"_L1 , dirName: mountDir) | 
| 153 |         || isParentOf(parent: "/sys"_L1 , dirName: mountDir) | 
| 154 |         || isParentOf(parent: "/var/run"_L1 , dirName: mountDir) | 
| 155 |         || isParentOf(parent: "/var/lock"_L1 , dirName: mountDir)) { | 
| 156 |         return false; | 
| 157 |     } | 
| 158 |  | 
| 159 |     if (!fsType.isEmpty() && fsType == RootFsStr) | 
| 160 |         return false; | 
| 161 |  | 
| 162 |     // size checking in QStorageInfo::mountedVolumes() | 
| 163 |     return true; | 
| 164 | } | 
| 165 | #endif // Q_OS_UNIX | 
| 166 |  | 
| 167 | QT_END_NAMESPACE | 
| 168 |  | 
| 169 | #endif // QSTORAGEINFO_P_H | 
| 170 |  |