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>
bb10
Ivan Komissarov 2014-05-06 16:10:10 +00:00 committed by Shawn Rutledge
parent 091653e9e7
commit 6c3c1a4cb8
12 changed files with 1849 additions and 7 deletions

View File

@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2014 Ivan Komissarov
** 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$
**
****************************************************************************/
//! [0]
QStorageInfo storage(qApp->applicationDirPath());
if (storage.isValid() && storage.isReady()) {
// ...
}
//! [0]
//! [1]
foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes()) {
if (storage.isValid() && storage.isReady()) {
if (!storage.isReadOnly()) {
// ...
}
}
}
//! [1]
//! [2]
QStorageInfo storage = QStorageInfo::root();
qDebug() << storage.rootPath();
if (storage.isReadOnly())
qDebug() << "isReadOnly:" << storage.isReadOnly();
qDebug() << "name:" << storage.name();
qDebug() << "fileSystemType:" << storage.fileSystemType();
qDebug() << "size:" << storage.bytesTotal()/1000/1000 << "MB";
qDebug() << "availableSize:" << storage.bytesAvailable()/1000/1000 << "MB";
//! [2]

View File

@ -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)) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -26,6 +26,7 @@ SUBDIRS=\
qsettings \
qsavefile \
qstandardpaths \
qstorageinfo \
qtemporarydir \
qtemporaryfile \
qtextstream \

View File

@ -0,0 +1,4 @@
CONFIG += testcase
TARGET = tst_qstorageinfo
QT = core-private testlib
SOURCES = tst_qstorageinfo.cpp

View File

@ -0,0 +1,198 @@
/****************************************************************************
**
** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite 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 <QtTest/QtTest>
#include <QStorageInfo>
class tst_QStorageInfo : public QObject
{
Q_OBJECT
private slots:
void defaultValues();
void operatorEqual();
#ifndef Q_OS_WINRT
void operatorNotEqual();
void root();
void currentStorage();
void storageList();
void tempFile();
void caching();
#endif
};
void tst_QStorageInfo::defaultValues()
{
QStorageInfo storage;
QVERIFY(!storage.isValid());
QVERIFY(!storage.isReady());
QVERIFY(storage.rootPath().isEmpty());
QVERIFY(!storage.isRoot());
QVERIFY(storage.device().isEmpty());
QVERIFY(storage.fileSystemType().isEmpty());
QVERIFY(storage.bytesTotal() == 0);
QVERIFY(storage.bytesFree() == 0);
QVERIFY(storage.bytesAvailable() == 0);
}
void tst_QStorageInfo::operatorEqual()
{
{
QStorageInfo storage1 = QStorageInfo::root();
QStorageInfo storage2(QDir::rootPath());
QVERIFY(storage1 == storage2);
}
{
QStorageInfo storage1(QCoreApplication::applicationDirPath());
QStorageInfo storage2(QCoreApplication::applicationFilePath());
QVERIFY(storage1 == storage2);
}
{
QStorageInfo storage1;
QStorageInfo storage2;
QVERIFY(storage1 == storage2);
}
}
#ifndef Q_OS_WINRT
void tst_QStorageInfo::operatorNotEqual()
{
QStorageInfo storage1 = QStorageInfo::root();
QStorageInfo storage2;
QVERIFY(storage1 != storage2);
}
void tst_QStorageInfo::root()
{
QStorageInfo storage = QStorageInfo::root();
QVERIFY(storage.isValid());
QVERIFY(storage.isReady());
QCOMPARE(storage.rootPath(), QDir::rootPath());
QVERIFY(storage.isRoot());
QVERIFY(!storage.device().isEmpty());
QVERIFY(!storage.fileSystemType().isEmpty());
QVERIFY(storage.bytesTotal() > 0);
QVERIFY(storage.bytesFree() > 0);
QVERIFY(storage.bytesAvailable() > 0);
}
void tst_QStorageInfo::currentStorage()
{
QString appPath = QCoreApplication::applicationFilePath();
QStorageInfo storage(appPath);
QVERIFY(storage.isValid());
QVERIFY(storage.isReady());
QVERIFY(appPath.startsWith(storage.rootPath(), Qt::CaseInsensitive));
QVERIFY(!storage.device().isEmpty());
QVERIFY(!storage.fileSystemType().isEmpty());
QVERIFY(storage.bytesTotal() > 0);
QVERIFY(storage.bytesFree() > 0);
QVERIFY(storage.bytesAvailable() > 0);
}
void tst_QStorageInfo::storageList()
{
QStorageInfo root = QStorageInfo::root();
QList<QStorageInfo> volumes = QStorageInfo::mountedVolumes();
// at least, root storage should be present
QVERIFY(volumes.contains(root));
volumes.removeOne(root);
QVERIFY(!volumes.contains(root));
foreach (const QStorageInfo &storage, volumes) {
if (!storage.isReady())
continue;
QVERIFY(storage.isValid());
QVERIFY(!storage.isRoot());
#ifndef Q_OS_WIN
QVERIFY(!storage.device().isEmpty());
QVERIFY(!storage.fileSystemType().isEmpty());
#endif
}
}
void tst_QStorageInfo::tempFile()
{
QTemporaryFile file;
QVERIFY(file.open());
QStorageInfo storage1(file.fileName());
qint64 free = storage1.bytesFree();
file.write(QByteArray(1024*1024, '1'));
file.flush();
file.close();
QStorageInfo storage2(file.fileName());
QVERIFY(free != storage2.bytesFree());
}
void tst_QStorageInfo::caching()
{
QTemporaryFile file;
QVERIFY(file.open());
QStorageInfo storage1(file.fileName());
qint64 free = storage1.bytesFree();
QStorageInfo storage2(storage1);
QVERIFY(free == storage2.bytesFree());
file.write(QByteArray(1024*1024, '\0'));
file.flush();
QVERIFY(free == storage1.bytesFree());
QVERIFY(free == storage2.bytesFree());
storage2.refresh();
QVERIFY(storage1 == storage2);
QVERIFY(free != storage2.bytesFree());
}
#endif
QTEST_MAIN(tst_QStorageInfo)
#include "tst_qstorageinfo.moc"