diff options
author | Ivan Komissarov <ABBAPOH@gmail.com> | 2014-05-06 16:10:10 +0000 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@digia.com> | 2014-08-13 16:09:58 +0200 |
commit | 6c3c1a4cb8e4973b8e603edfbe608e1b1587f3f2 (patch) | |
tree | a5f94686383fc913b88ef23d949621face11d816 /src/corelib/io | |
parent | 091653e9e71c3e2ada54efe6b3592340e16eaa85 (diff) |
Add the QStorageInfo class
Allows to retrieve information about mounted volumes such as label,
total/available size, filesystem type and so on.
Possible use cases are:
- allows to do checks about filesystem before performing actual
operation (such as available/maximum volume size)
- allows to retrive information about volume that can be shown in file
dialogs
- allows to retrieve volume for specific path and check if two or more
paths belong to the same volume or not
[ChangeLog][QtCore] Added QStorageInfo class to retrive information
about mounted volumes and drives
Change-Id: Ibf9c2e6b53ef39c5605894a4422acdbbca4030c4
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/io.pri | 31 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo.cpp | 398 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo.h | 122 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_mac.cpp | 213 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_p.h | 103 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_stub.cpp | 69 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_unix.cpp | 454 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_win.cpp | 193 |
8 files changed, 1576 insertions, 7 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 5e389b19a6..bdc362ef22 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -32,6 +32,8 @@ HEADERS += \ io/qresource_iterator_p.h \ io/qsavefile.h \ io/qstandardpaths.h \ + io/qstorageinfo.h \ + io/qstorageinfo_p.h \ io/qurl.h \ io/qurl_p.h \ io/qurlquery.h \ @@ -70,6 +72,7 @@ SOURCES += \ io/qlockfile.cpp \ io/qnoncontiguousbytedevice.cpp \ io/qprocess.cpp \ + io/qstorageinfo.cpp \ io/qtextstream.cpp \ io/qtemporarydir.cpp \ io/qtemporaryfile.cpp \ @@ -108,7 +111,8 @@ win32 { SOURCES += io/qstandardpaths_win.cpp wince* { - SOURCES += io/qprocess_wince.cpp + SOURCES += io/qprocess_wince.cpp \ + io/qstorageinfo_stub.cpp } else { HEADERS += \ io/qwinoverlappedionotifier_p.h \ @@ -116,12 +120,15 @@ win32 { SOURCES += \ io/qprocess_win.cpp \ io/qwinoverlappedionotifier.cpp \ - io/qwindowspipereader.cpp + io/qwindowspipereader.cpp \ + io/qstorageinfo_win.cpp + LIBS += -lmpr } } else { SOURCES += \ io/qstandardpaths_winrt.cpp \ - io/qsettings_winrt.cpp + io/qsettings_winrt.cpp \ + io/qstorageinfo_stub.cpp } } else:unix|integrity { SOURCES += \ @@ -141,18 +148,28 @@ win32 { HEADERS += io/qfilesystemwatcher_fsevents_p.h } macx { - SOURCES += io/qstandardpaths_mac.cpp + SOURCES += \ + io/qstorageinfo_mac.cpp \ + io/qstandardpaths_mac.cpp + LIBS += -framework DiskArbitration -framework IOKit } else:ios { OBJECTIVE_SOURCES += io/qstandardpaths_ios.mm + SOURCES += io/qstorageinfo_mac.cpp } else { SOURCES += io/qstandardpaths_unix.cpp } } else:blackberry { - SOURCES += io/qstandardpaths_blackberry.cpp + SOURCES += \ + io/qstandardpaths_blackberry.cpp \ + io/qstorageinfo_unix.cpp } else:android:!android-no-sdk { - SOURCES += io/qstandardpaths_android.cpp + SOURCES += \ + io/qstandardpaths_android.cpp \ + io/qstorageinfo_unix.cpp } else { - SOURCES += io/qstandardpaths_unix.cpp + SOURCES += \ + io/qstandardpaths_unix.cpp \ + io/qstorageinfo_unix.cpp } linux|if(qnx:contains(QT_CONFIG, inotify)) { diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp new file mode 100644 index 0000000000..205ab3f62c --- /dev/null +++ b/src/corelib/io/qstorageinfo.cpp @@ -0,0 +1,398 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstorageinfo.h" +#include "qstorageinfo_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QStorageInfo + \inmodule QtCore + \since 5.4 + \brief Provides information about currently mounted storages and drives. + + \ingroup io + \ingroup shared + + Allows retrieving information about the volume's space, its mount point, + label, filesystem name. + + You can create an instance of QStorageInfo by passing the path to the + volume's mount point as the constructor parameter, or you can set it using + setPath() method. The static mountedVolumes() method can be used to get the + list of all mounted filesystems. + + QStorageInfo always caches the retrieved information but you can call + refresh() to invalidate the cache. + + The following example retrieves the most common information about the root + volume of the system and prints information about it. + + \snippet code/src_corelib_io_qstorageinfo.cpp 2 +*/ + +/*! + Constructs an empty QStorageInfo object. + + This object is not ready for use, invalid and all its parameters are empty. + + \sa setPath(), isReady(), isValid() +*/ +QStorageInfo::QStorageInfo() + : d(new QStorageInfoPrivate) +{ +} + +/*! + Constructs a new QStorageInfo that gives information about the volume + mounted at \a path. + + If you pass a directory or file, the QStorageInfo object will refer to the + volume where this directory or file is located. + You can check if the created object is correct using the isValid() method. + + The following example shows how to get volume on which application is + located. It is recommended to always check that volume is ready and valid. + + \snippet code/src_corelib_io_qstorageinfo.cpp 0 + + \sa setPath() +*/ +QStorageInfo::QStorageInfo(const QString &path) + : d(new QStorageInfoPrivate) +{ + setPath(path); +} + +/*! + Constructs a new QStorageInfo that gives information about the volume + that contains the \a dir folder. +*/ +QStorageInfo::QStorageInfo(const QDir &dir) + : d(new QStorageInfoPrivate) +{ + setPath(dir.absolutePath()); +} + +/*! + Constructs a new QStorageInfo that is a copy of the \a other QStorageInfo. +*/ +QStorageInfo::QStorageInfo(const QStorageInfo &other) + : d(other.d) +{ +} + +/*! + Destroys the QStorageInfo and frees its resources. +*/ +QStorageInfo::~QStorageInfo() +{ +} + +/*! + Makes a copy of \a other QStorageInfo and assigns it to this QStorageInfo. +*/ +QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other) +{ + d = other.d; + return *this; +} + +/*! + \fn QStorageInfo &QStorageInfo::operator=(QStorageInfo &&other) + + Move-assigns \a other to this QStorageInfo instance. +*/ + +/*! + \fn void QStorageInfo::swap(QStorageInfo &other) + + Swaps this volume info with the \a other. This function is very fast and + never fails. +*/ + +/*! + Sets QStorageInfo to the filesystem mounted where \a path is located. + + Path can either be a root path of the filesystem, or a directory or a file + within that filesystem. + + \sa rootPath() +*/ +void QStorageInfo::setPath(const QString &path) +{ + if (d->rootPath == path) + return; + d.detach(); + d->rootPath = path; + d->doStat(); +} + +/*! + Returns the mount point of the filesystem this QStorageInfo object + represents. + + On Windows, returns the volume letter in case the volume is not mounted to + a directory. + + Note that the value returned by rootPath() is the real mount point of a + volume and may not be equal to the value passed to constructor or setPath() + method. For example, if you have only the root volume in the system and + pass '/directory' to setPath(), then this method will return '/'. + + \sa setPath(), device() +*/ +QString QStorageInfo::rootPath() const +{ + return d->rootPath; +} + +/*! + Returns the size (in bytes) available for the current user. If the user is + the root user or a system administrator returns all available size. + + This size can be less than or equal to the free size, returned by + bytesFree() function. + + \sa bytesTotal(), bytesFree() +*/ +qint64 QStorageInfo::bytesAvailable() const +{ + return d->bytesAvailable; +} + +/*! + Returns the number of free bytes on a volume. Note, that if there are some + kind of quotas on the filesystem, this value can be bigger than + bytesAvailable(). + + \sa bytesTotal(), bytesAvailable() +*/ +qint64 QStorageInfo::bytesFree() const +{ + return d->bytesFree; +} + +/*! + Returns total volume size in bytes. + + \sa bytesFree(), bytesAvailable() +*/ +qint64 QStorageInfo::bytesTotal() const +{ + return d->bytesTotal; +} + +/*! + Returns the type name of the filesystem. + + This is a platform-dependent function, and filesystem names can vary + between different operating systems. For example, on Windows filesystems + can be named as 'NTFS' and on Linux as 'ntfs-3g' or 'fuseblk'. + + \sa name() +*/ +QByteArray QStorageInfo::fileSystemType() const +{ + return d->fileSystemType; +} + +/*! + Returns the device for this volume. + + For example, on Unix filesystems (including OS X), this returns the + devpath like '/dev/sda0' for local storages. On Windows, returns the UNC + path starting with \\\\?\\ for local storages (i.e. volume GUID). + + \sa rootPath() +*/ +QByteArray QStorageInfo::device() const +{ + return d->device; +} + +/*! + Returns the human-readable name of a filesystem, usually called 'label'. + + Not all filesystems support this feature, in this case value returned by + this method could be empty. An empty string is returned if the file system + does not support labels or no label is set. + + On Linux, retrieving the volume's label requires udev to be present in the + system. + + \sa fileSystemType() +*/ +QString QStorageInfo::name() const +{ + return d->name; +} + +/*! + Returns the volume's name, if available, or the root path if not. +*/ +QString QStorageInfo::displayName() const +{ + if (!d->name.isEmpty()) + return d->name; + return d->rootPath; +} + +/*! + \fn bool QStorageInfo::isRoot() const + + Returns true if this QStorageInfo represents the system root volume; false + otherwise. + + On Unix filesystems, the root volume is a volume mounted at "/", on Windows + the root volume is the volume where OS is installed. + + \sa root() +*/ + +/*! + Returns true if the current filesystem is protected from writing; false + otherwise. +*/ +bool QStorageInfo::isReadOnly() const +{ + return d->readOnly; +} + +/*! + Returns true if current filesystem is ready to work; false otherwise. For + example, false is returned if CD volume is not inserted. + + Note that fileSystemType(), name(), bytesTotal(), bytesFree(), and + bytesAvailable() will return invalid data until the volume is ready. + + \sa isValid() +*/ +bool QStorageInfo::isReady() const +{ + return d->ready; +} + +/*! + Returns true if the QStorageInfo specified by rootPath exists and is mounted + correctly. + + \sa isReady() +*/ +bool QStorageInfo::isValid() const +{ + return d->valid; +} + +/*! + Resets QStorageInfo's internal cache. + + QStorageInfo caches information about storages to speed up performance - + QStorageInfo retrieves information during object construction and/or call + to setPath() method. You have to manually reset the cache by calling this + function to update storage information. +*/ +void QStorageInfo::refresh() +{ + d.detach(); + d->doStat(); +} + +/*! + Returns list of QStorageInfos that corresponds to the list of currently + mounted filesystems. + + On Windows, this returns drives presented in 'My Computer' folder. On Unix + operating systems, returns list of all mounted filesystems (except for + pseudo filesystems). + + By default, returns all currently mounted filesystems. + + The example shows how to retrieve all storages present in the system and + skip read-only storages. + + \snippet code/src_corelib_io_qstorageinfo.cpp 1 + + \sa root() +*/ +QList<QStorageInfo> QStorageInfo::mountedVolumes() +{ + return QStorageInfoPrivate::mountedVolumes(); +} + +Q_GLOBAL_STATIC_WITH_ARGS(QStorageInfo, getRoot, (QStorageInfoPrivate::root())) + +/*! + Returns a QStorageInfo object that represents the system root volume. + + On Unix systems this call returns '/' volume, on Windows the volume where + operating system is installed is returned. + + \sa isRoot() +*/ +QStorageInfo QStorageInfo::root() +{ + return *getRoot(); +} + +/*! + \fn inline bool operator==(const QStorageInfo &first, const QStorageInfo &second) + + \relates QStorageInfo + + Returns true if \a first QStorageInfo object refers to the same drive or volume + as the \a second; otherwise returns false. + + Note that the result of comparing two invalid QStorageInfo objects is always + positive. +*/ + +/*! + \fn inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second) + + \relates QStorageInfo + + Returns true if \a first QStorageInfo object refers to a different drive or + volume than the one specified by \a second; otherwise returns false. +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h new file mode 100644 index 0000000000..0a4a620205 --- /dev/null +++ b/src/corelib/io/qstorageinfo.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTORAGEINFO_H +#define QSTORAGEINFO_H + +#include <QtCore/qbytearray.h> +#include <QtCore/qdir.h> +#include <QtCore/qlist.h> +#include <QtCore/qmetatype.h> +#include <QtCore/qstring.h> +#include <QtCore/qshareddata.h> + +QT_BEGIN_NAMESPACE + +class QStorageInfoPrivate; +class Q_CORE_EXPORT QStorageInfo +{ +public: + QStorageInfo(); + explicit QStorageInfo(const QString &path); + explicit QStorageInfo(const QDir &dir); + QStorageInfo(const QStorageInfo &other); + ~QStorageInfo(); + + QStorageInfo &operator=(const QStorageInfo &other); +#ifdef Q_COMPILER_RVALUE_REFS + inline QStorageInfo &operator=(QStorageInfo &&other) + { qSwap(d, other.d); return *this; } +#endif + + inline void swap(QStorageInfo &other) + { qSwap(d, other.d); } + + void setPath(const QString &path); + + QString rootPath() const; + QByteArray device() const; + QByteArray fileSystemType() const; + QString name() const; + QString displayName() const; + + qint64 bytesTotal() const; + qint64 bytesFree() const; + qint64 bytesAvailable() const; + + inline bool isRoot() const; + bool isReadOnly() const; + bool isReady() const; + bool isValid() const; + + void refresh(); + + static QList<QStorageInfo> mountedVolumes(); + static QStorageInfo root(); + +private: + friend class QStorageInfoPrivate; + friend bool operator==(const QStorageInfo &first, const QStorageInfo &second); + QExplicitlySharedDataPointer<QStorageInfoPrivate> d; +}; + +inline bool operator==(const QStorageInfo &first, const QStorageInfo &second) +{ + if (first.d == second.d) + return true; + return first.device() == second.device(); +} + +inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second) +{ + return !(first == second); +} + +inline bool QStorageInfo::isRoot() const +{ return *this == QStorageInfo::root(); } + +Q_DECLARE_SHARED(QStorageInfo) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QStorageInfo) + +#endif // QSTORAGEINFO_H diff --git a/src/corelib/io/qstorageinfo_mac.cpp b/src/corelib/io/qstorageinfo_mac.cpp new file mode 100644 index 0000000000..060e16b948 --- /dev/null +++ b/src/corelib/io/qstorageinfo_mac.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstorageinfo_p.h" + +#include <QtCore/qfileinfo.h> +#include <QtCore/private/qcore_mac_p.h> + +#include <CoreFoundation/CoreFoundation.h> +#include <CoreFoundation/CFURLEnumerator.h> + +#include <sys/mount.h> + +#define QT_STATFSBUF struct statfs +#define QT_STATFS ::statfs + +QT_BEGIN_NAMESPACE + +void QStorageInfoPrivate::initRootPath() +{ + rootPath = QFileInfo(rootPath).canonicalFilePath(); + + if (rootPath.isEmpty()) + return; + + retrieveUrlProperties(true); +} + +void QStorageInfoPrivate::doStat() +{ + initRootPath(); + + if (rootPath.isEmpty()) + return; + + retrieveLabel(); + retrievePosixInfo(); + retrieveUrlProperties(); +} + +void QStorageInfoPrivate::retrievePosixInfo() +{ + QT_STATFSBUF statfs_buf; + int result = QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf); + if (result == 0) { + device = QByteArray(statfs_buf.f_mntfromname); + readOnly = (statfs_buf.f_flags & MNT_RDONLY) != 0; + fileSystemType = QByteArray(statfs_buf.f_fstypename); + } +} + +static inline qint64 CFDictionaryGetInt64(CFDictionaryRef dictionary, const void *key) +{ + CFNumberRef cfNumber = (CFNumberRef)CFDictionaryGetValue(dictionary, key); + if (!cfNumber) + return -1; + qint64 result; + bool ok = CFNumberGetValue(cfNumber, kCFNumberSInt64Type, &result); + if (!ok) + return -1; + return result; +} + +void QStorageInfoPrivate::retrieveUrlProperties(bool initRootPath) +{ + static const void *rootPathKeys[] = { kCFURLVolumeURLKey }; + static const void *propertyKeys[] = { + // kCFURLVolumeNameKey, // 10.7 + // kCFURLVolumeLocalizedNameKey, // 10.7 + kCFURLVolumeTotalCapacityKey, + kCFURLVolumeAvailableCapacityKey, + // kCFURLVolumeIsReadOnlyKey // 10.7 + }; + size_t size = (initRootPath ? sizeof(rootPathKeys) : sizeof(propertyKeys)) / sizeof(void*); + QCFType<CFArrayRef> keys = CFArrayCreate(kCFAllocatorDefault, + initRootPath ? rootPathKeys : propertyKeys, + size, + Q_NULLPTR); + + if (!keys) + return; + + const QCFString cfPath = rootPath; + if (initRootPath) + rootPath.clear(); + + QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, + cfPath, + kCFURLPOSIXPathStyle, + true); + if (!url) + return; + + CFErrorRef error; + QCFType<CFDictionaryRef> map = CFURLCopyResourcePropertiesForKeys(url, keys, &error); + + if (!map) + return; + + if (initRootPath) { + const CFURLRef rootUrl = (CFURLRef)CFDictionaryGetValue(map, kCFURLVolumeURLKey); + if (!rootUrl) + return; + + rootPath = QCFString(CFURLCopyFileSystemPath(rootUrl, kCFURLPOSIXPathStyle)); + valid = true; + ready = true; + + return; + } + + bytesTotal = CFDictionaryGetInt64(map, kCFURLVolumeTotalCapacityKey); + bytesAvailable = CFDictionaryGetInt64(map, kCFURLVolumeAvailableCapacityKey); + bytesFree = bytesAvailable; +} + +void QStorageInfoPrivate::retrieveLabel() +{ +#if !defined(Q_OS_IOS) + // deprecated since 10.8 + FSRef ref; + FSPathMakeRef(reinterpret_cast<const UInt8*>(QFile::encodeName(rootPath).constData()), + &ref, + Q_NULLPTR); + + // deprecated since 10.8 + FSCatalogInfo catalogInfo; + OSErr error; + error = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &catalogInfo, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR); + if (error != noErr) + return; + + // deprecated (use CFURLCopyResourcePropertiesForKeys for 10.7 and higher) + HFSUniStr255 volumeName; + error = FSGetVolumeInfo(catalogInfo.volume, + 0, + Q_NULLPTR, + kFSVolInfoFSInfo, + Q_NULLPTR, + &volumeName, + Q_NULLPTR); + if (error == noErr) + name = QCFString(FSCreateStringFromHFSUniStr(Q_NULLPTR, &volumeName)); +#endif +} + +QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes() +{ + QList<QStorageInfo> volumes; + + QCFType<CFURLEnumeratorRef> enumerator; + enumerator = CFURLEnumeratorCreateForMountedVolumes(Q_NULLPTR, + kCFURLEnumeratorSkipInvisibles, + Q_NULLPTR); + + CFURLEnumeratorResult result = kCFURLEnumeratorSuccess; + do { + CFURLRef url; + CFErrorRef error; + result = CFURLEnumeratorGetNextURL(enumerator, &url, &error); + if (result == kCFURLEnumeratorSuccess) { + const QCFString urlString = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + volumes.append(QStorageInfo(urlString)); + } + } while (result != kCFURLEnumeratorEnd); + + 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 new file mode 100644 index 0000000000..9c8e51f475 --- /dev/null +++ b/src/corelib/io/qstorageinfo_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#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 "qstorageinfo.h" + +QT_BEGIN_NAMESPACE + +class QStorageInfoPrivate : public QSharedData +{ +public: + inline QStorageInfoPrivate() : QSharedData(), + bytesTotal(0), bytesFree(0), bytesAvailable(0), + readOnly(false), ready(false), valid(false) + {} + + void initRootPath(); + void doStat(); + + static QList<QStorageInfo> mountedVolumes(); + static QStorageInfo root(); + +protected: +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) + void retreiveVolumeInfo(); + void retreiveDiskFreeSpace(); +#elif defined(Q_OS_MAC) + void retrievePosixInfo(); + void retrieveUrlProperties(bool initRootPath = false); + void retrieveLabel(); +#elif defined(Q_OS_UNIX) + void retreiveVolumeInfo(); +#endif + +public: + QString rootPath; + QByteArray device; + QByteArray fileSystemType; + QString name; + + qint64 bytesTotal; + qint64 bytesFree; + qint64 bytesAvailable; + + bool readOnly; + bool ready; + bool valid; +}; + +QT_END_NAMESPACE + +#endif // QSTORAGEINFO_P_H diff --git a/src/corelib/io/qstorageinfo_stub.cpp b/src/corelib/io/qstorageinfo_stub.cpp new file mode 100644 index 0000000000..7e70cb1386 --- /dev/null +++ b/src/corelib/io/qstorageinfo_stub.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstorageinfo_p.h" + +QT_BEGIN_NAMESPACE + +void QStorageInfoPrivate::initRootPath() +{ + Q_UNIMPLEMENTED(); + rootPath = QString(); +} + +void QStorageInfoPrivate::doStat() +{ + Q_UNIMPLEMENTED(); +} + +QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes() +{ + Q_UNIMPLEMENTED(); + return QList<QStorageInfo>(); +} + +QStorageInfo QStorageInfoPrivate::root() +{ + Q_UNIMPLEMENTED(); + return QStorageInfo(); +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp new file mode 100644 index 0000000000..a7a812fb67 --- /dev/null +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -0,0 +1,454 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstorageinfo_p.h" + +#include <QtCore/qdiriterator.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qtextstream.h> + +#include <QtCore/private/qcore_unix_p.h> + +#include <errno.h> +#include <sys/stat.h> + +#if defined(Q_OS_BSD4) +# include <sys/mount.h> +#elif defined(Q_OS_ANDROID) +# include <sys/mount.h> +# include <sys/vfs.h> +# include <mntent.h> +#elif defined(Q_OS_QNX) +# include <sys/statvfs.h> +#elif defined(Q_OS_LINUX) +# include <mntent.h> +# include <sys/statvfs.h> +#elif defined(Q_OS_SOLARIS) +# include <sys/mnttab.h> +#endif + +#if defined(Q_OS_BSD4) +# define QT_STATFSBUF struct statvfs +# define QT_STATFS ::statvfs +#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 +#else +# 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 // Q_OS_BSD4 + +QT_BEGIN_NAMESPACE + +static bool isPseudoFs(const QString &mountDir, const QByteArray &type) +{ + if (mountDir.startsWith(QStringLiteral("/dev")) + || mountDir.startsWith(QStringLiteral("/proc")) + || mountDir.startsWith(QStringLiteral("/run")) + || mountDir.startsWith(QStringLiteral("/sys")) + || mountDir.startsWith(QStringLiteral("/var/run")) + || mountDir.startsWith(QStringLiteral("/var/lock"))) { + return true; + } +#if defined(Q_OS_LINUX) + if (type == "rootfs") + return true; +#else + Q_UNUSED(type); +#endif + + return false; +} + +class QStorageIterator +{ +public: + QStorageIterator(); + ~QStorageIterator(); + + inline bool isValid() const; + inline bool next(); + inline QString rootPath() const; + inline QByteArray fileSystemType() const; + inline QByteArray device() const; +private: +#if defined(Q_OS_BSD4) + statfs *stat_buf; + int entryCount; + int currentIndex; +#elif defined(Q_OS_SOLARIS) + FILE *fp; + mnttab mnt; +#elif defined(Q_OS_ANDROID) + QFile file; + QByteArray m_rootPath; + QByteArray m_fileSystemType; + QByteArray m_device; +#elif defined(Q_OS_LINUX) + FILE *fp; + mntent mnt; + QByteArray buffer; +#endif +}; + +#if defined(Q_OS_BSD4) + +inline QStorageIterator::QStorageIterator() + : entryCount(::getmntinfo(&stat_buf, 0)), + currentIndex(-1) +{ +} + +inline QStorageIterator::~QStorageIterator() +{ +} + +inline bool QStorageIterator::isValid() const +{ + return entryCount != -1; +} + +inline bool QStorageIterator::next() +{ + return ++currentIndex < entryCount; +} + +inline QString QStorageIterator::rootPath() const +{ + return QFile::decodeName(stat_buf[currentIndex].f_mntonname); +} + +inline QByteArray QStorageIterator::fileSystemType() const +{ + return QByteArray(stat_buf[currentIndex].f_fstypename); +} + +inline QByteArray QStorageIterator::device() const +{ + return QByteArray(stat_buf[currentIndex].f_mntfromname); +} + +#elif defined(Q_OS_SOLARIS) + +static const char pathMounted[] = "/etc/mnttab"; + +inline QStorageIterator::QStorageIterator() +{ + const int fd = qt_safe_open(pathMounted, O_RDONLY); + fp = ::fdopen(fd, "r"); +} + +inline QStorageIterator::~QStorageIterator() +{ + if (fp) + ::fclose(fp); +} + +inline bool QStorageIterator::isValid() const +{ + return fp != Q_NULLPTR; +} + +inline bool QStorageIterator::next() +{ + return ::getmntent(fp, &mnt) == Q_NULLPTR; +} + +inline QString QStorageIterator::rootPath() const +{ + return QFile::decodeName(mnt->mnt_mountp); +} + +inline QByteArray QStorageIterator::fileSystemType() const +{ + return QByteArray(mnt->mnt_fstype); +} + +inline QByteArray QStorageIterator::device() const +{ + return QByteArray(mnt->mnt_mntopts); +} + +#elif defined(Q_OS_ANDROID) + +static const char pathMounted[] = "/proc/mounts"; + +inline QStorageIterator::QStorageIterator() +{ + file.setFileName(pathMounted); + file.open(QIODevice::ReadOnly | QIODevice::Text); +} + +inline QStorageIterator::~QStorageIterator() +{ +} + +inline bool QStorageIterator::isValid() const +{ + return file.isOpen(); +} + +inline bool QStorageIterator::next() +{ + QList<QByteArray> data; + do { + const QByteArray line = file.readLine(); + data = line.split(' '); + } while (data.count() < 3 && !file.atEnd()); + + if (file.atEnd()) + return false; + m_device = data.at(0); + m_rootPath = data.at(1); + m_fileSystemType = data.at(2); + + return true; +} + +inline QString QStorageIterator::rootPath() const +{ + return QFile::decodeName(m_rootPath); +} + +inline QByteArray QStorageIterator::fileSystemType() const +{ + return m_fileSystemType; +} + +inline QByteArray QStorageIterator::device() const +{ + return m_device; +} + +#elif defined(Q_OS_LINUX) + +static const char pathMounted[] = "/etc/mtab"; +static const int bufferSize = 3*PATH_MAX; // 2 paths (mount point+device) and metainfo + +inline QStorageIterator::QStorageIterator() : + buffer(QByteArray(bufferSize, 0)) +{ + fp = ::setmntent(pathMounted, "r"); +} + +inline QStorageIterator::~QStorageIterator() +{ + if (fp) + ::endmntent(fp); +} + +inline bool QStorageIterator::isValid() const +{ + return fp != Q_NULLPTR; +} + +inline bool QStorageIterator::next() +{ + return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != Q_NULLPTR; +} + +inline QString QStorageIterator::rootPath() const +{ + return QFile::decodeName(mnt.mnt_dir); +} + +inline QByteArray QStorageIterator::fileSystemType() const +{ + return QByteArray(mnt.mnt_type); +} + +inline QByteArray QStorageIterator::device() const +{ + return QByteArray(mnt.mnt_fsname); +} + +#else + +inline QStorageIterator::QStorageIterator() +{ +} + +inline QStorageIterator::~QStorageIterator() +{ +} + +inline bool QStorageIterator::isValid() const +{ + return false; +} + +inline bool QStorageIterator::next() +{ + return false; +} + +inline QString QStorageIterator::rootPath() const +{ + return QString(); +} + +inline QByteArray QStorageIterator::fileSystemType() const +{ + return QByteArray(); +} + +inline QByteArray QStorageIterator::device() const +{ + return QByteArray(); +} + +#endif + +void QStorageInfoPrivate::initRootPath() +{ + rootPath = QFileInfo(rootPath).canonicalFilePath(); + + if (rootPath.isEmpty()) + return; + + QStorageIterator it; + if (!it.isValid()) { + rootPath = QStringLiteral("/"); + return; + } + + int maxLength = 0; + const QString oldRootPath = rootPath; + rootPath.clear(); + + while (it.next()) { + const QString mountDir = it.rootPath(); + const QByteArray fsName = it.fileSystemType(); + if (isPseudoFs(mountDir, fsName)) + continue; + // we try to find most suitable entry + if (oldRootPath.startsWith(mountDir) && maxLength < mountDir.length()) { + maxLength = mountDir.length(); + rootPath = mountDir; + device = it.device(); + fileSystemType = fsName; + } + } +} + +static inline QString retrieveLabel(const QByteArray &device) +{ +#ifdef Q_OS_LINUX + static const char pathDiskByLabel[] = "/dev/disk/by-label"; + + QDirIterator it(QLatin1String(pathDiskByLabel), QDir::NoDotAndDotDot); + while (it.hasNext()) { + it.next(); + QFileInfo fileInfo(it.fileInfo()); + if (fileInfo.isSymLink() && fileInfo.symLinkTarget().toLocal8Bit() == device) + return fileInfo.fileName(); + } +#else + Q_UNUSED(device); +#endif + + return QString(); +} + +void QStorageInfoPrivate::doStat() +{ + initRootPath(); + if (rootPath.isEmpty()) + return; + + retreiveVolumeInfo(); + name = retrieveLabel(device); +} + +void QStorageInfoPrivate::retreiveVolumeInfo() +{ + 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_bsize; + bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize; + bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize; +#if defined(Q_OS_ANDROID) + readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0; +#else + readOnly = (statfs_buf.f_flag & ST_RDONLY) != 0; +#endif + } +} + +QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes() +{ + QStorageIterator it; + if (!it.isValid()) + return QList<QStorageInfo>() << root(); + + QList<QStorageInfo> volumes; + + while (it.next()) { + const QString mountDir = it.rootPath(); + const QByteArray fsName = it.fileSystemType(); + if (isPseudoFs(mountDir, fsName)) + continue; + + volumes.append(QStorageInfo(mountDir)); + } + + return volumes; +} + +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 new file mode 100644 index 0000000000..aa970778e6 --- /dev/null +++ b/src/corelib/io/qstorageinfo_win.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstorageinfo_p.h" + +#include <QtCore/qdir.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qvarlengtharray.h> + +#include <Windows.h> + +QT_BEGIN_NAMESPACE + +static const int defaultBufferSize = MAX_PATH + 1; + +void QStorageInfoPrivate::initRootPath() +{ + rootPath = QFileInfo(rootPath).canonicalFilePath(); + + if (rootPath.isEmpty()) + return; + + QString path = QDir::toNativeSeparators(rootPath); + rootPath.clear(); + + if (path.startsWith(QStringLiteral("\\\\?\\"))) + path.remove(0, 4); + if (path.length() < 2 || path.at(1) != QLatin1Char(':')) + return; + path[0] = path[0].toUpper(); + if (!(path.at(0).unicode() >= 'A' && path.at(0).unicode() <= 'Z')) + return; + if (!path.endsWith(QLatin1Char('\\'))) + path.append(QLatin1Char('\\')); + + // ### test if disk mounted to folder on other disk + wchar_t buffer[defaultBufferSize]; + if (::GetVolumePathName(reinterpret_cast<const wchar_t *>(path.utf16()), buffer, defaultBufferSize)) + rootPath = QDir::fromNativeSeparators(QString::fromWCharArray(buffer)); +} + +static inline QByteArray getDevice(const QString &rootPath) +{ + const QString path = QDir::toNativeSeparators(rootPath); + const UINT type = ::GetDriveType(reinterpret_cast<const wchar_t *>(path.utf16())); + if (type == DRIVE_REMOTE) { + QVarLengthArray<char, 256> buffer(256); + DWORD bufferLength = buffer.size(); + DWORD result; + UNIVERSAL_NAME_INFO *remoteNameInfo; + do { + buffer.resize(bufferLength); + remoteNameInfo = reinterpret_cast<UNIVERSAL_NAME_INFO *>(buffer.data()); + result = ::WNetGetUniversalName(reinterpret_cast<const wchar_t *>(path.utf16()), + UNIVERSAL_NAME_INFO_LEVEL, + remoteNameInfo, + &bufferLength); + } while (result == ERROR_MORE_DATA); + if (result == NO_ERROR) + return QString::fromWCharArray(remoteNameInfo->lpUniversalName).toUtf8(); + return QByteArray(); + } + + wchar_t deviceBuffer[51]; + if (::GetVolumeNameForVolumeMountPoint(reinterpret_cast<const wchar_t *>(path.utf16()), + deviceBuffer, + sizeof(deviceBuffer) / sizeof(wchar_t))) { + return QString::fromWCharArray(deviceBuffer).toLatin1(); + } + return QByteArray(); +} + +void QStorageInfoPrivate::doStat() +{ + initRootPath(); + if (rootPath.isEmpty()) + return; + + retreiveVolumeInfo(); + device = getDevice(rootPath); + retreiveDiskFreeSpace(); +} + +void QStorageInfoPrivate::retreiveVolumeInfo() +{ + const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + + const QString path = QDir::toNativeSeparators(rootPath); + wchar_t nameBuffer[defaultBufferSize]; + wchar_t fileSystemTypeBuffer[defaultBufferSize]; + DWORD fileSystemFlags = 0; + const bool result = ::GetVolumeInformation(reinterpret_cast<const wchar_t *>(path.utf16()), + nameBuffer, + defaultBufferSize, + Q_NULLPTR, + Q_NULLPTR, + &fileSystemFlags, + fileSystemTypeBuffer, + defaultBufferSize); + if (!result) { + ready = false; + valid = ::GetLastError() == ERROR_NOT_READY; + } else { + ready = true; + valid = true; + + fileSystemType = QString::fromWCharArray(fileSystemTypeBuffer).toLatin1(); + name = QString::fromWCharArray(nameBuffer); + + readOnly = (fileSystemFlags & FILE_READ_ONLY_VOLUME) != 0; + } + + ::SetErrorMode(oldmode); +} + +void QStorageInfoPrivate::retreiveDiskFreeSpace() +{ + const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + + const QString path = QDir::toNativeSeparators(rootPath); + ::GetDiskFreeSpaceEx(reinterpret_cast<const wchar_t *>(path.utf16()), + PULARGE_INTEGER(&bytesAvailable), + PULARGE_INTEGER(&bytesTotal), + PULARGE_INTEGER(&bytesFree)); + + ::SetErrorMode(oldmode); +} + +QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes() +{ + QList<QStorageInfo> volumes; + + QString driveName = QStringLiteral("A:/"); + const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + quint32 driveBits = quint32(::GetLogicalDrives()) & 0x3ffffff; + ::SetErrorMode(oldmode); + while (driveBits) { + if (driveBits & 1) { + QStorageInfo drive(driveName); + if (!drive.rootPath().isEmpty()) // drive exists, but not mounted + volumes.append(drive); + } + driveName[0] = driveName[0].unicode() + 1; + driveBits = driveBits >> 1; + } + + return volumes; +} + +QStorageInfo QStorageInfoPrivate::root() +{ + return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive")))); +} + +QT_END_NAMESPACE |