| 1 | // Copyright (C) 2022 The Qt Company Ltd. | 
| 2 | // Copyright (C) 2015 Ivan Komissarov <ABBAPOH@gmail.com> | 
| 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | 
| 4 |  | 
| 5 | #include "qstorageinfo.h" | 
| 6 | #include "qstorageinfo_p.h" | 
| 7 |  | 
| 8 | #include "qdebug.h" | 
| 9 |  | 
| 10 | QT_BEGIN_NAMESPACE | 
| 11 |  | 
| 12 | QT_IMPL_METATYPE_EXTERN(QStorageInfo) | 
| 13 |  | 
| 14 | /*! | 
| 15 |     \class QStorageInfo | 
| 16 |     \inmodule QtCore | 
| 17 |     \since 5.4 | 
| 18 |     \brief Provides information about currently mounted storage and drives. | 
| 19 |  | 
| 20 |     \ingroup io | 
| 21 |     \ingroup shared | 
| 22 |  | 
| 23 |     \compares equality | 
| 24 |  | 
| 25 |     Allows retrieving information about the volume's space, its mount point, | 
| 26 |     label, and filesystem name. | 
| 27 |  | 
| 28 |     You can create an instance of QStorageInfo by passing the path to the | 
| 29 |     volume's mount point as a constructor parameter, or you can set it using | 
| 30 |     the setPath() method. The static mountedVolumes() method can be used to get the | 
| 31 |     list of all mounted filesystems. | 
| 32 |  | 
| 33 |     QStorageInfo always caches the retrieved information, but you can call | 
| 34 |     refresh() to invalidate the cache. | 
| 35 |  | 
| 36 |     The following example retrieves the most common information about the root | 
| 37 |     volume of the system, and prints information about it. | 
| 38 |  | 
| 39 |     \snippet code/src_corelib_io_qstorageinfo.cpp 2 | 
| 40 | */ | 
| 41 |  | 
| 42 | QStorageInfo::QStorageInfo(QStorageInfoPrivate &dd) | 
| 43 |     : d(&dd) | 
| 44 | { | 
| 45 | } | 
| 46 |  | 
| 47 | /*! | 
| 48 |     Constructs an empty QStorageInfo object. | 
| 49 |  | 
| 50 |     Objects created with the default constructor will be invalid and therefore | 
| 51 |     not ready for use. | 
| 52 |  | 
| 53 |     \sa setPath(), isReady(), isValid() | 
| 54 | */ | 
| 55 | QStorageInfo::QStorageInfo() | 
| 56 |     : d(new QStorageInfoPrivate) | 
| 57 | { | 
| 58 | } | 
| 59 |  | 
| 60 | /*! | 
| 61 |     Constructs a new QStorageInfo object that gives information about the volume | 
| 62 |     mounted at \a path. | 
| 63 |  | 
| 64 |     If you pass a directory or file, the QStorageInfo object will refer to the | 
| 65 |     volume where this directory or file is located. | 
| 66 |     You can check if the created object is correct using the isValid() method. | 
| 67 |  | 
| 68 |     The following example shows how to get the volume on which the application is | 
| 69 |     located. It is recommended to always check that the volume is ready and valid. | 
| 70 |  | 
| 71 |     \snippet code/src_corelib_io_qstorageinfo.cpp 0 | 
| 72 |  | 
| 73 |     \sa setPath() | 
| 74 | */ | 
| 75 | QStorageInfo::QStorageInfo(const QString &path) | 
| 76 |     : d(new QStorageInfoPrivate) | 
| 77 | { | 
| 78 |     setPath(path); | 
| 79 | } | 
| 80 |  | 
| 81 | /*! | 
| 82 |     Constructs a new QStorageInfo object that gives information about the volume | 
| 83 |     containing the \a dir folder. | 
| 84 | */ | 
| 85 | QStorageInfo::QStorageInfo(const QDir &dir) | 
| 86 |     : d(new QStorageInfoPrivate) | 
| 87 | { | 
| 88 |     setPath(dir.absolutePath()); | 
| 89 | } | 
| 90 |  | 
| 91 | /*! | 
| 92 |     Constructs a new QStorageInfo object that is a copy of the \a other QStorageInfo object. | 
| 93 | */ | 
| 94 | QStorageInfo::QStorageInfo(const QStorageInfo &other) | 
| 95 |     : d(other.d) | 
| 96 | { | 
| 97 | } | 
| 98 |  | 
| 99 | /*! | 
| 100 |     Destroys the QStorageInfo object and frees its resources. | 
| 101 | */ | 
| 102 | QStorageInfo::~QStorageInfo() | 
| 103 | { | 
| 104 | } | 
| 105 |  | 
| 106 | /*! | 
| 107 |     Makes a copy of the QStorageInfo object \a other and assigns it to this QStorageInfo object. | 
| 108 | */ | 
| 109 | QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other) | 
| 110 | { | 
| 111 |     d = other.d; | 
| 112 |     return *this; | 
| 113 | } | 
| 114 |  | 
| 115 | /*! | 
| 116 |     \fn QStorageInfo &QStorageInfo::operator=(QStorageInfo &&other) | 
| 117 |  | 
| 118 |     Assigns \a other to this QStorageInfo instance. | 
| 119 | */ | 
| 120 |  | 
| 121 | /*! | 
| 122 |     \fn void QStorageInfo::swap(QStorageInfo &other) | 
| 123 |     \memberswap{volume info} | 
| 124 | */ | 
| 125 |  | 
| 126 | /*! | 
| 127 |     Sets this QStorageInfo object to the filesystem mounted where \a path is located. | 
| 128 |  | 
| 129 |     \a path can either be a root path of the filesystem, a directory, or a file | 
| 130 |     within that filesystem. | 
| 131 |  | 
| 132 |     \sa rootPath() | 
| 133 | */ | 
| 134 | void QStorageInfo::setPath(const QString &path) | 
| 135 | { | 
| 136 |     if (d->rootPath == path) | 
| 137 |         return; | 
| 138 |     d.detach(); | 
| 139 |     d->rootPath = path; | 
| 140 |     d->doStat(); | 
| 141 | } | 
| 142 |  | 
| 143 | /*! | 
| 144 |     Returns the mount point of the filesystem this QStorageInfo object | 
| 145 |     represents. | 
| 146 |  | 
| 147 |     On Windows, it returns the volume letter in case the volume is not mounted to | 
| 148 |     a directory. | 
| 149 |  | 
| 150 |     Note that the value returned by rootPath() is the real mount point of a | 
| 151 |     volume, and may not be equal to the value passed to the constructor or setPath() | 
| 152 |     method. For example, if you have only the root volume in the system, and | 
| 153 |     pass '/directory' to setPath(), then this method will return '/'. | 
| 154 |  | 
| 155 |     \sa setPath(), device() | 
| 156 | */ | 
| 157 | QString QStorageInfo::rootPath() const | 
| 158 | { | 
| 159 |     return d->rootPath; | 
| 160 | } | 
| 161 |  | 
| 162 | /*! | 
| 163 |     Returns the size (in bytes) available for the current user. It returns | 
| 164 |     the total size available if the user is the root user or a system administrator. | 
| 165 |  | 
| 166 |     This size can be less than or equal to the free size returned by | 
| 167 |     bytesFree() function. | 
| 168 |  | 
| 169 |     Returns -1 if QStorageInfo object is not valid. | 
| 170 |  | 
| 171 |     \sa bytesTotal(), bytesFree() | 
| 172 | */ | 
| 173 | qint64 QStorageInfo::bytesAvailable() const | 
| 174 | { | 
| 175 |     return d->bytesAvailable; | 
| 176 | } | 
| 177 |  | 
| 178 | /*! | 
| 179 |     Returns the number of free bytes in a volume. Note that if there are | 
| 180 |     quotas on the filesystem, this value can be larger than the value | 
| 181 |     returned by bytesAvailable(). | 
| 182 |  | 
| 183 |     Returns -1 if QStorageInfo object is not valid. | 
| 184 |  | 
| 185 |     \sa bytesTotal(), bytesAvailable() | 
| 186 | */ | 
| 187 | qint64 QStorageInfo::bytesFree() const | 
| 188 | { | 
| 189 |     return d->bytesFree; | 
| 190 | } | 
| 191 |  | 
| 192 | /*! | 
| 193 |     Returns the total volume size in bytes. | 
| 194 |  | 
| 195 |     Returns -1 if QStorageInfo object is not valid. | 
| 196 |  | 
| 197 |     \sa bytesFree(), bytesAvailable() | 
| 198 | */ | 
| 199 | qint64 QStorageInfo::bytesTotal() const | 
| 200 | { | 
| 201 |     return d->bytesTotal; | 
| 202 | } | 
| 203 |  | 
| 204 | /*! | 
| 205 |     \since 5.6 | 
| 206 |     Returns the optimal transfer block size for this filesystem. | 
| 207 |  | 
| 208 |     Returns -1 if QStorageInfo could not determine the size or if the QStorageInfo | 
| 209 |     object is not valid. | 
| 210 |  */ | 
| 211 | int QStorageInfo::blockSize() const | 
| 212 | { | 
| 213 |     return d->blockSize; | 
| 214 | } | 
| 215 |  | 
| 216 | /*! | 
| 217 |     Returns the type name of the filesystem. | 
| 218 |  | 
| 219 |     This is a platform-dependent function, and filesystem names can vary | 
| 220 |     between different operating systems. For example, on Windows filesystems | 
| 221 |     they can be named \c NTFS, and on Linux they can be named \c ntfs-3g or \c fuseblk. | 
| 222 |  | 
| 223 |     \sa name() | 
| 224 | */ | 
| 225 | QByteArray QStorageInfo::fileSystemType() const | 
| 226 | { | 
| 227 |     return d->fileSystemType; | 
| 228 | } | 
| 229 |  | 
| 230 | /*! | 
| 231 |     Returns the device for this volume. | 
| 232 |  | 
| 233 |     For example, on Unix filesystems (including \macos), this returns the | 
| 234 |     devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC | 
| 235 |     path starting with \c \\\\?\\ for local storages (in other words, the volume GUID). | 
| 236 |  | 
| 237 |     \sa rootPath(), subvolume() | 
| 238 | */ | 
| 239 | QByteArray QStorageInfo::device() const | 
| 240 | { | 
| 241 |     return d->device; | 
| 242 | } | 
| 243 |  | 
| 244 | /*! | 
| 245 |     \since 5.9 | 
| 246 |     Returns the subvolume name for this volume. | 
| 247 |  | 
| 248 |     Some filesystem types allow multiple subvolumes inside one device, which | 
| 249 |     may be mounted in different paths (e.g. 'bind' mounts on Unix, or Btrfs | 
| 250 |     filesystem subvolumes). If the subvolume could be detected, its name is | 
| 251 |     returned by this function. The format of the subvolume name is specific | 
| 252 |     to each filesystem type. | 
| 253 |  | 
| 254 |     If this volume was not mounted from a subvolume of a larger filesystem or | 
| 255 |     if the subvolume could not be detected, this function returns an empty byte | 
| 256 |     array. | 
| 257 |  | 
| 258 |     \sa device() | 
| 259 | */ | 
| 260 | QByteArray QStorageInfo::subvolume() const | 
| 261 | { | 
| 262 |     return d->subvolume; | 
| 263 | } | 
| 264 |  | 
| 265 | /*! | 
| 266 |     Returns the human-readable name of a filesystem, usually called \c label. | 
| 267 |  | 
| 268 |     Not all filesystems support this feature. In this case, the value returned by | 
| 269 |     this method could be empty. An empty string is returned if the file system | 
| 270 |     does not support labels, or if no label is set. | 
| 271 |  | 
| 272 |     On Linux, retrieving the volume's label requires \c udev to be present in the | 
| 273 |     system. | 
| 274 |  | 
| 275 |     \sa fileSystemType() | 
| 276 | */ | 
| 277 | QString QStorageInfo::name() const | 
| 278 | { | 
| 279 |     return d->name; | 
| 280 | } | 
| 281 |  | 
| 282 | /*! | 
| 283 |     Returns the volume's name, if available, or the root path if not. | 
| 284 | */ | 
| 285 | QString QStorageInfo::displayName() const | 
| 286 | { | 
| 287 |     if (!d->name.isEmpty()) | 
| 288 |         return d->name; | 
| 289 |     return d->rootPath; | 
| 290 | } | 
| 291 |  | 
| 292 | /*! | 
| 293 |     \fn bool QStorageInfo::isRoot() const | 
| 294 |  | 
| 295 |     Returns true if this QStorageInfo represents the system root volume; false | 
| 296 |     otherwise. | 
| 297 |  | 
| 298 |     On Unix filesystems, the root volume is a volume mounted on \c /. On Windows, | 
| 299 |     the root volume is the volume where the OS is installed. | 
| 300 |  | 
| 301 |     \sa root() | 
| 302 | */ | 
| 303 |  | 
| 304 | /*! | 
| 305 |     Returns true if the current filesystem is protected from writing; false | 
| 306 |     otherwise. | 
| 307 | */ | 
| 308 | bool QStorageInfo::isReadOnly() const | 
| 309 | { | 
| 310 |     return d->readOnly; | 
| 311 | } | 
| 312 |  | 
| 313 | /*! | 
| 314 |     Returns true if the current filesystem is ready to work; false otherwise. For | 
| 315 |     example, false is returned if the CD volume is not inserted. | 
| 316 |  | 
| 317 |     Note that fileSystemType(), name(), bytesTotal(), bytesFree(), and | 
| 318 |     bytesAvailable() will return invalid data until the volume is ready. | 
| 319 |  | 
| 320 |     \sa isValid() | 
| 321 | */ | 
| 322 | bool QStorageInfo::isReady() const | 
| 323 | { | 
| 324 |     return d->ready; | 
| 325 | } | 
| 326 |  | 
| 327 | /*! | 
| 328 |     Returns true if the QStorageInfo specified by rootPath exists and is mounted | 
| 329 |     correctly. | 
| 330 |  | 
| 331 |     \sa isReady() | 
| 332 | */ | 
| 333 | bool QStorageInfo::isValid() const | 
| 334 | { | 
| 335 |     return d->valid; | 
| 336 | } | 
| 337 |  | 
| 338 | /*! | 
| 339 |     Resets QStorageInfo's internal cache. | 
| 340 |  | 
| 341 |     QStorageInfo caches information about storage to speed up performance. | 
| 342 |     QStorageInfo retrieves information during object construction and/or when calling | 
| 343 |     the setPath() method. You have to manually reset the cache by calling this | 
| 344 |     function to update storage information. | 
| 345 | */ | 
| 346 | void QStorageInfo::refresh() | 
| 347 | { | 
| 348 |     d.detach(); | 
| 349 |     d->doStat(); | 
| 350 | } | 
| 351 |  | 
| 352 | /*! | 
| 353 |     Returns the list of QStorageInfo objects that corresponds to the list of currently | 
| 354 |     mounted filesystems. | 
| 355 |  | 
| 356 |     On Windows, this returns the drives visible in the \gui{My Computer} folder. On Unix | 
| 357 |     operating systems, it returns the list of all mounted filesystems (except for | 
| 358 |     pseudo filesystems). | 
| 359 |  | 
| 360 |     Returns all currently mounted filesystems by default. | 
| 361 |  | 
| 362 |     The example shows how to retrieve all available filesystems, skipping read-only ones. | 
| 363 |  | 
| 364 |     \snippet code/src_corelib_io_qstorageinfo.cpp 1 | 
| 365 |  | 
| 366 |     \sa root() | 
| 367 | */ | 
| 368 | QList<QStorageInfo> QStorageInfo::mountedVolumes() | 
| 369 | { | 
| 370 |     return QStorageInfoPrivate::mountedVolumes(); | 
| 371 | } | 
| 372 |  | 
| 373 | Q_GLOBAL_STATIC(QStorageInfo, getRoot, QStorageInfoPrivate::root()) | 
| 374 |  | 
| 375 | /*! | 
| 376 |     Returns a QStorageInfo object that represents the system root volume. | 
| 377 |  | 
| 378 |     On Unix systems this call returns the root ('/') volume; in Windows the volume where | 
| 379 |     the operating system is installed. | 
| 380 |  | 
| 381 |     \sa isRoot() | 
| 382 | */ | 
| 383 | QStorageInfo QStorageInfo::root() | 
| 384 | { | 
| 385 |     return *getRoot(); | 
| 386 | } | 
| 387 |  | 
| 388 | /*! | 
| 389 |     \fn bool QStorageInfo::operator==(const QStorageInfo &lhs, const QStorageInfo &rhs) | 
| 390 |  | 
| 391 |     Returns \c true if the QStorageInfo object \a lhs refers to the same drive or | 
| 392 |     volume as the QStorageInfo object \a rhs; otherwise it returns \c false. | 
| 393 |  | 
| 394 |     Note that the result of comparing two invalid QStorageInfo objects is always | 
| 395 |     positive. | 
| 396 | */ | 
| 397 |  | 
| 398 | /*! | 
| 399 |     \fn bool QStorageInfo::operator!=(const QStorageInfo &lhs, const QStorageInfo &rhs) | 
| 400 |  | 
| 401 |     Returns \c true if the QStorageInfo object \a lhs refers to a different drive or | 
| 402 |     volume than the QStorageInfo object \a rhs; otherwise returns \c false. | 
| 403 | */ | 
| 404 |  | 
| 405 | bool comparesEqual(const QStorageInfo &lhs, const QStorageInfo &rhs) noexcept | 
| 406 | { | 
| 407 |     if (lhs.d == rhs.d) | 
| 408 |         return true; | 
| 409 |     return lhs.d->device == rhs.d->device && lhs.d->rootPath == rhs.d->rootPath; | 
| 410 | } | 
| 411 |  | 
| 412 | #ifndef QT_NO_DEBUG_STREAM | 
| 413 | QDebug operator<<(QDebug debug, const QStorageInfo &s) | 
| 414 | { | 
| 415 |     QDebugStateSaver saver(debug); | 
| 416 |     debug.nospace(); | 
| 417 |     debug.noquote(); | 
| 418 |     debug << "QStorageInfo(" ; | 
| 419 |     if (s.isValid()) { | 
| 420 |         const QStorageInfoPrivate *d = s.d.constData(); | 
| 421 |         debug << '"' << d->rootPath << '"'; | 
| 422 |         if (!d->fileSystemType.isEmpty()) | 
| 423 |             debug << ", type="  << d->fileSystemType; | 
| 424 |         if (!d->name.isEmpty()) | 
| 425 |             debug << ", name=\""  << d->name << '"'; | 
| 426 |         if (!d->device.isEmpty()) | 
| 427 |             debug << ", device=\""  << d->device << '"'; | 
| 428 |         if (!d->subvolume.isEmpty()) | 
| 429 |             debug << ", subvolume=\""  << d->subvolume << '"'; | 
| 430 |         if (d->readOnly) | 
| 431 |             debug << " [read only]" ; | 
| 432 |         debug << (d->ready ? " [ready]"  : " [not ready]" ); | 
| 433 |         if (d->bytesTotal > 0) { | 
| 434 |             debug << ", bytesTotal="  << d->bytesTotal << ", bytesFree="  << d->bytesFree | 
| 435 |                   << ", bytesAvailable="  << d->bytesAvailable; | 
| 436 |         } | 
| 437 |     } else { | 
| 438 |         debug << "invalid" ; | 
| 439 |     } | 
| 440 |     debug << ')'; | 
| 441 |     return debug; | 
| 442 | } | 
| 443 | #endif // !QT_NO_DEBUG_STREAM | 
| 444 |  | 
| 445 | QT_END_NAMESPACE | 
| 446 |  |