Backporting QlockFile. Successful build on Windows.

--HG--
branch : develop
This commit is contained in:
Пользователь@pc2009 2015-04-04 18:47:25 +04:00
parent 94e2fe8c5a
commit 93eb3d692c
44 changed files with 10275 additions and 12 deletions

View File

@ -430,6 +430,9 @@ DEPENDPATH += $$PWD/../libs/vlayout
win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../libs/vlayout/$${DESTDIR}/vlayout.lib
else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../libs/vlayout/$${DESTDIR}/libvlayout.a
# For build qt backport code
win32: LIBS+= libole32 libuuid
# Strip after you link all libaries.
CONFIG(release, debug|release){

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,251 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QABSTRACTFILEENGINE_P_H
#define QABSTRACTFILEENGINE_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 <QFile>
#include <QDir>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifdef open
#error qabstractfileengine_p.h must be included before any header file that defines open
#endif
class QVariant;
class QAbstractFileEngineIterator;
class QAbstractFileEnginePrivate;
class QAbstractFileEngine
{
public:
enum FileFlag {
//perms (overlaps the QFile::Permission)
ReadOwnerPerm = 0x4000, WriteOwnerPerm = 0x2000, ExeOwnerPerm = 0x1000,
ReadUserPerm = 0x0400, WriteUserPerm = 0x0200, ExeUserPerm = 0x0100,
ReadGroupPerm = 0x0040, WriteGroupPerm = 0x0020, ExeGroupPerm = 0x0010,
ReadOtherPerm = 0x0004, WriteOtherPerm = 0x0002, ExeOtherPerm = 0x0001,
//types
LinkType = 0x10000,
FileType = 0x20000,
DirectoryType = 0x40000,
BundleType = 0x80000,
//flags
HiddenFlag = 0x0100000,
LocalDiskFlag = 0x0200000,
ExistsFlag = 0x0400000,
RootFlag = 0x0800000,
Refresh = 0x1000000,
//masks
PermsMask = 0x0000FFFF,
TypesMask = 0x000F0000,
FlagsMask = 0x0FF00000,
FileInfoAll = FlagsMask | PermsMask | TypesMask
};
Q_DECLARE_FLAGS(FileFlags, FileFlag)
enum FileName {
DefaultName,
BaseName,
PathName,
AbsoluteName,
AbsolutePathName,
LinkName,
CanonicalName,
CanonicalPathName,
BundleName,
NFileNames = 9
};
enum FileOwner {
OwnerUser,
OwnerGroup
};
enum FileTime {
CreationTime,
ModificationTime,
AccessTime
};
virtual ~QAbstractFileEngine();
virtual bool open(QIODevice::OpenMode openMode);
virtual bool close();
virtual bool flush();
virtual bool syncToDisk();
virtual qint64 size() const;
virtual qint64 pos() const;
virtual bool seek(qint64 pos);
virtual bool isSequential() const;
virtual bool remove();
virtual bool copy(const QString &newName);
virtual bool rename(const QString &newName);
virtual bool renameOverwrite(const QString &newName);
virtual bool link(const QString &newName);
virtual bool mkdir(const QString &dirName, bool createParentDirectories) const;
virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const;
virtual bool setSize(qint64 size);
virtual bool caseSensitive() const;
virtual bool isRelativePath() const;
virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const;
virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const;
virtual bool setPermissions(uint perms);
virtual QString fileName(FileName file=DefaultName) const;
virtual uint ownerId(FileOwner) const;
virtual QString owner(FileOwner) const;
virtual QDateTime fileTime(FileTime time) const;
virtual void setFileName(const QString &file);
virtual int handle() const;
bool atEnd() const;
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
typedef QAbstractFileEngineIterator Iterator;
virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames);
virtual Iterator *endEntryList();
virtual qint64 read(char *data, qint64 maxlen);
virtual qint64 readLine(char *data, qint64 maxlen);
virtual qint64 write(const char *data, qint64 len);
QFile::FileError error() const;
QString errorString() const;
enum Extension {
AtEndExtension,
FastReadLineExtension,
MapExtension,
UnMapExtension
};
class ExtensionOption
{};
class ExtensionReturn
{};
class MapExtensionOption : public ExtensionOption {
public:
qint64 offset;
qint64 size;
QFile::MemoryMapFlags flags;
};
class MapExtensionReturn : public ExtensionReturn {
public:
uchar *address;
};
class UnMapExtensionOption : public ExtensionOption {
public:
uchar *address;
};
virtual bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0);
virtual bool supportsExtension(Extension extension) const;
// Factory
static QAbstractFileEngine *create(const QString &fileName);
protected:
void setError(QFile::FileError error, const QString &str);
QAbstractFileEngine();
QAbstractFileEngine(QAbstractFileEnginePrivate &);
QScopedPointer<QAbstractFileEnginePrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(QAbstractFileEngine)
Q_DISABLE_COPY(QAbstractFileEngine)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractFileEngine::FileFlags)
class QAbstractFileEngineHandler
{
public:
QAbstractFileEngineHandler();
virtual ~QAbstractFileEngineHandler();
virtual QAbstractFileEngine *create(const QString &fileName) const = 0;
};
class QAbstractFileEngineIteratorPrivate;
class QAbstractFileEngineIterator
{
public:
QAbstractFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters);
virtual ~QAbstractFileEngineIterator();
virtual QString next() = 0;
virtual bool hasNext() const = 0;
QString path() const;
QStringList nameFilters() const;
QDir::Filters filters() const;
virtual QString currentFileName() const = 0;
virtual QFileInfo currentFileInfo() const;
QString currentFilePath() const;
protected:
enum EntryInfoType {
};
virtual QVariant entryInfo(EntryInfoType type) const;
private:
Q_DISABLE_COPY(QAbstractFileEngineIterator)
friend class QDirIterator;
friend class QDirIteratorPrivate;
void setPath(const QString &path);
QScopedPointer<QAbstractFileEngineIteratorPrivate> d;
};
class QAbstractFileEnginePrivate
{
public:
inline QAbstractFileEnginePrivate()
: fileError(QFile::UnspecifiedError)
{
}
inline virtual ~QAbstractFileEnginePrivate() { }
QFile::FileError fileError;
QString errorString;
QAbstractFileEngine *q_ptr;
Q_DECLARE_PUBLIC(QAbstractFileEngine)
};
QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path);
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QABSTRACTFILEENGINE_P_H

View File

@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qcore_mac_p.h"
#include <new>
#include <QVarLengthArray>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
QString QCFString::toQString(CFStringRef str)
{
if(!str)
return QString();
CFIndex length = CFStringGetLength(str);
const UniChar *chars = CFStringGetCharactersPtr(str);
if (chars)
return QString(reinterpret_cast<const QChar *>(chars), length);
QVarLengthArray<UniChar> buffer(length);
CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data());
return QString(reinterpret_cast<const QChar *>(buffer.constData()), length);
}
QCFString::operator QString() const
{
if (string.isEmpty() && type)
const_cast<QCFString*>(this)->string = toQString(type);
return string;
}
CFStringRef QCFString::toCFStringRef(const QString &string)
{
return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar *>(string.unicode()),
string.length());
}
QCFString::operator CFStringRef() const
{
if (!type)
const_cast<QCFString*>(this)->type = toCFStringRef(string);
return type;
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,131 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QCORE_MAC_P_H
#define QCORE_MAC_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of other Qt classes. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef __IMAGECAPTURE__
# define __IMAGECAPTURE__
#endif
#if defined(QT_BOOTSTRAPPED)
#include <ApplicationServices/ApplicationServices.h>
#else
#include <CoreFoundation/CoreFoundation.h>
#endif
#include <QtGlobal>
#ifdef Q_OS_MACX
#include <CoreServices/CoreServices.h>
#endif
#ifdef __OBJC__
#include <Foundation/Foundation.h>
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#include <QString>
#if defined( __OBJC__) && defined(QT_NAMESPACE)
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__)
#else
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__)
#endif
/*
Helper class that automates refernce counting for CFtypes.
After constructing the QCFType object, it can be copied like a
value-based type.
Note that you must own the object you are wrapping.
This is typically the case if you get the object from a Core
Foundation function with the word "Create" or "Copy" in it. If
you got the object from a "Get" function, either retain it or use
constructFromGet(). One exception to this rule is the
HIThemeGet*Shape functions, which in reality are "Copy" functions.
*/
template <typename T>
class QCFType
{
public:
inline QCFType(const T &t = 0) : type(t) {}
inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); }
inline ~QCFType() { if (type) CFRelease(type); }
inline operator T() { return type; }
inline QCFType operator =(const QCFType &helper)
{
if (helper.type)
CFRetain(helper.type);
CFTypeRef type2 = type;
type = helper.type;
if (type2)
CFRelease(type2);
return *this;
}
inline T *operator&() { return &type; }
template <typename X> X as() const { return reinterpret_cast<X>(type); }
static QCFType constructFromGet(const T &t)
{
CFRetain(t);
return QCFType<T>(t);
}
protected:
T type;
};
class Q_CORE_EXPORT QCFString : public QCFType<CFStringRef>
{
public:
inline QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {}
inline QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {}
inline QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {}
operator QString() const;
operator CFStringRef() const;
static QString toQString(CFStringRef cfstr);
static CFStringRef toCFStringRef(const QString &str);
#ifdef __OBJC__
static QString toQString(const NSString *nsstr);
static NSString *toNSString(const QString &string);
#endif
private:
QString string;
};
#ifdef Q_OS_IOS
QSysInfo::MacVersion qt_ios_version();
#endif
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QCORE_MAC_P_H

View File

@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** 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 "qcore_unix_p.h"
#include "qelapsedtimer.h"
#ifdef Q_OS_NACL
#elif !defined (Q_OS_VXWORKS)
# if !defined(Q_OS_HPUX) || defined(__ia64)
# include <sys/select.h>
# endif
# include <sys/time.h>
#else
# include <selectLib.h>
#endif
#include <stdlib.h>
#ifdef Q_OS_MAC
#include <mach/mach_time.h>
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
static inline bool time_update(struct timespec *tv, const struct timespec &start,
const struct timespec &timeout)
{
// clock source is (hopefully) monotonic, so we can recalculate how much timeout is left;
// if it isn't monotonic, we'll simply hope that it hasn't jumped, because we have no alternative
struct timespec now = qt_gettime();
*tv = timeout + start - now;
return tv->tv_sec >= 0;
}
int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
const struct timespec *orig_timeout)
{
if (!orig_timeout) {
// no timeout -> block forever
int ret;
EINTR_LOOP(ret, select(nfds, fdread, fdwrite, fdexcept, 0));
return ret;
}
timespec start = qt_gettime();
timespec timeout = *orig_timeout;
// loop and recalculate the timeout as needed
int ret;
forever {
#ifndef Q_OS_QNX
ret = ::pselect(nfds, fdread, fdwrite, fdexcept, &timeout, 0);
#else
timeval timeoutVal;
timeoutVal.tv_sec = timeout.tv_sec;
timeoutVal.tv_usec = timeout.tv_nsec / 1000;
ret = ::select(nfds, fdread, fdwrite, fdexcept, &timeoutVal);
#endif
if (ret != -1 || errno != EINTR)
return ret;
// recalculate the timeout
if (!time_update(&timeout, start, *orig_timeout)) {
// timeout during update
// or clock reset, fake timeout error
return 0;
}
}
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,335 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QCORE_UNIX_P_H
#define QCORE_UNIX_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of Qt code on Unix. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qplatformdefs.h"
#include "qatomic.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef Q_OS_UNIX
# error "qcore_unix_p.h included on a non-Unix system"
#endif
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#if defined(Q_OS_VXWORKS)
# include <ioLib.h>
#endif
struct sockaddr;
#if defined(Q_OS_LINUX) && defined(O_CLOEXEC)
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1
namespace QtLibcSupplement {
inline int accept4(int, sockaddr *, QT_SOCKLEN_T *, int)
{ errno = ENOSYS; return -1; }
inline int dup3(int, int, int)
{ errno = ENOSYS; return -1; }
inline int pipe2(int [], int )
{ errno = ENOSYS; return -1; }
}
using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement);
#else
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 0
#endif
#define EINTR_LOOP(var, cmd) \
do { \
var = cmd; \
} while (var == -1 && errno == EINTR)
// Internal operator functions for timespecs
inline timespec &normalizedTimespec(timespec &t)
{
while (t.tv_nsec >= 1000000000) {
++t.tv_sec;
t.tv_nsec -= 1000000000;
}
while (t.tv_nsec < 0) {
--t.tv_sec;
t.tv_nsec += 1000000000;
}
return t;
}
inline bool operator<(const timespec &t1, const timespec &t2)
{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec); }
inline bool operator==(const timespec &t1, const timespec &t2)
{ return t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec; }
inline timespec &operator+=(timespec &t1, const timespec &t2)
{
t1.tv_sec += t2.tv_sec;
t1.tv_nsec += t2.tv_nsec;
return normalizedTimespec(t1);
}
inline timespec operator+(const timespec &t1, const timespec &t2)
{
timespec tmp;
tmp.tv_sec = t1.tv_sec + t2.tv_sec;
tmp.tv_nsec = t1.tv_nsec + t2.tv_nsec;
return normalizedTimespec(tmp);
}
inline timespec operator-(const timespec &t1, const timespec &t2)
{
timespec tmp;
tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1);
tmp.tv_nsec = t1.tv_nsec - (t2.tv_nsec + 1000000000);
return normalizedTimespec(tmp);
}
inline timespec operator*(const timespec &t1, int mul)
{
timespec tmp;
tmp.tv_sec = t1.tv_sec * mul;
tmp.tv_nsec = t1.tv_nsec * mul;
return normalizedTimespec(tmp);
}
inline void qt_ignore_sigpipe()
{
// Set to ignore SIGPIPE once only.
static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
if (!atom.load()) {
// More than one thread could turn off SIGPIPE at the same time
// But that's acceptable because they all would be doing the same
// action
struct sigaction noaction;
memset(&noaction, 0, sizeof(noaction));
noaction.sa_handler = SIG_IGN;
::sigaction(SIGPIPE, &noaction, 0);
atom.store(1);
}
}
// don't call QT_OPEN or ::open
// call qt_safe_open
static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777)
{
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
int fd;
EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode));
// unknown flags are ignored, so we have no way of verifying if
// O_CLOEXEC was accepted
if (fd != -1)
::fcntl(fd, F_SETFD, FD_CLOEXEC);
return fd;
}
#undef QT_OPEN
#define QT_OPEN qt_safe_open
#ifndef Q_OS_VXWORKS // no POSIX pipes in VxWorks
// don't call ::pipe
// call qt_safe_pipe
static inline int qt_safe_pipe(int pipefd[2], int flags = 0)
{
#ifdef O_CLOEXEC
Q_ASSERT((flags & ~(O_CLOEXEC | O_NONBLOCK)) == 0);
#else
Q_ASSERT((flags & ~O_NONBLOCK) == 0);
#endif
int ret;
#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
// use pipe2
flags |= O_CLOEXEC;
ret = ::pipe2(pipefd, flags); // pipe2 is Linux-specific and is documented not to return EINTR
if (ret == 0 || errno != ENOSYS)
return ret;
#endif
ret = ::pipe(pipefd);
if (ret == -1)
return -1;
::fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
::fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
// set non-block too?
if (flags & O_NONBLOCK) {
::fcntl(pipefd[0], F_SETFL, ::fcntl(pipefd[0], F_GETFL) | O_NONBLOCK);
::fcntl(pipefd[1], F_SETFL, ::fcntl(pipefd[1], F_GETFL) | O_NONBLOCK);
}
return 0;
}
#endif // Q_OS_VXWORKS
// don't call dup or fcntl(F_DUPFD)
static inline int qt_safe_dup(int oldfd, int atleast = 0, int flags = FD_CLOEXEC)
{
Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
int ret;
#ifdef F_DUPFD_CLOEXEC
// use this fcntl
if (flags & FD_CLOEXEC) {
ret = ::fcntl(oldfd, F_DUPFD_CLOEXEC, atleast);
if (ret != -1 || errno != EINVAL)
return ret;
}
#endif
// use F_DUPFD
ret = ::fcntl(oldfd, F_DUPFD, atleast);
if (flags && ret != -1)
::fcntl(ret, F_SETFD, flags);
return ret;
}
// don't call dup2
// call qt_safe_dup2
static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
{
Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
int ret;
#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
// use dup3
if (flags & FD_CLOEXEC) {
EINTR_LOOP(ret, ::dup3(oldfd, newfd, O_CLOEXEC));
if (ret == 0 || errno != ENOSYS)
return ret;
}
#endif
EINTR_LOOP(ret, ::dup2(oldfd, newfd));
if (ret == -1)
return -1;
if (flags)
::fcntl(newfd, F_SETFD, flags);
return 0;
}
static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
{
qint64 ret = 0;
EINTR_LOOP(ret, QT_READ(fd, data, maxlen));
return ret;
}
#undef QT_READ
#define QT_READ qt_safe_read
static inline qint64 qt_safe_write(int fd, const void *data, qint64 len)
{
qint64 ret = 0;
EINTR_LOOP(ret, QT_WRITE(fd, data, len));
return ret;
}
#undef QT_WRITE
#define QT_WRITE qt_safe_write
static inline qint64 qt_safe_write_nosignal(int fd, const void *data, qint64 len)
{
qt_ignore_sigpipe();
return qt_safe_write(fd, data, len);
}
static inline int qt_safe_close(int fd)
{
int ret;
EINTR_LOOP(ret, QT_CLOSE(fd));
return ret;
}
#undef QT_CLOSE
#define QT_CLOSE qt_safe_close
// - VxWorks doesn't have processes
#if !defined(Q_OS_VXWORKS)
static inline int qt_safe_execve(const char *filename, char *const argv[],
char *const envp[])
{
int ret;
EINTR_LOOP(ret, ::execve(filename, argv, envp));
return ret;
}
static inline int qt_safe_execv(const char *path, char *const argv[])
{
int ret;
EINTR_LOOP(ret, ::execv(path, argv));
return ret;
}
static inline int qt_safe_execvp(const char *file, char *const argv[])
{
int ret;
EINTR_LOOP(ret, ::execvp(file, argv));
return ret;
}
static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
{
int ret;
EINTR_LOOP(ret, ::waitpid(pid, status, options));
return ret;
}
#endif // Q_OS_VXWORKS
#if !defined(_POSIX_MONOTONIC_CLOCK)
# define _POSIX_MONOTONIC_CLOCK -1
#endif
// in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp
timespec qt_gettime() Q_DECL_NOTHROW;
void qt_nanosleep(timespec amount);
int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, const struct timespec *tv);
// according to X/OPEN we have to define semun ourselves
// we use prefix as on some systems sem.h will have it
struct semid_ds;
union qt_semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* array for GETALL, SETALL */
};
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif

View File

@ -0,0 +1,164 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QFILEINFO_P_H
#define QFILEINFO_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 <QFileInfo>
#include <QDateTime>
#include "qatomic.h"
#include <QSharedData>
#include "qfilesystemengine_p.h"
#include <QVector>
#include "qabstractfileengine_p.h"
#include "qfilesystementry_p.h"
#include "qfilesystemmetadata_p.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
class QFileInfoPrivate : public QSharedData
{
public:
enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04,
CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40,
CachedSize =0x08, CachedPerms=0x80 };
inline QFileInfoPrivate()
: QSharedData(), fileEngine(0),
cachedFlags(0),
isDefaultConstructed(true),
cache_enabled(true), fileFlags(0), fileSize(0)
{}
inline QFileInfoPrivate(const QFileInfoPrivate &copy)
: QSharedData(copy),
fileEntry(copy.fileEntry),
metaData(copy.metaData),
fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
#ifndef QT_NO_FSFILEENGINE
isDefaultConstructed(false),
#else
isDefaultConstructed(!fileEngine),
#endif
cache_enabled(copy.cache_enabled), fileFlags(0), fileSize(0)
{}
inline QFileInfoPrivate(const QString &file)
: fileEntry(QDir::fromNativeSeparators(file)),
fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
#ifndef QT_NO_FSFILEENGINE
isDefaultConstructed(false),
#else
isDefaultConstructed(!fileEngine),
#endif
cache_enabled(true), fileFlags(0), fileSize(0)
{
}
inline QFileInfoPrivate(const QFileSystemEntry &file, const QFileSystemMetaData &data)
: QSharedData(),
fileEntry(file),
metaData(data),
fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
isDefaultConstructed(false),
cache_enabled(true), fileFlags(0), fileSize(0)
{
//If the file engine is not null, this maybe a "mount point" for a custom file engine
//in which case we can't trust the metadata
if (fileEngine)
metaData = QFileSystemMetaData();
}
inline QFileInfoPrivate(const QFileSystemEntry &file, const QFileSystemMetaData &data, QAbstractFileEngine *engine)
: fileEntry(file),
metaData(data),
fileEngine(engine),
cachedFlags(0),
#ifndef QT_NO_FSFILEENGINE
isDefaultConstructed(false),
#else
isDefaultConstructed(!fileEngine),
#endif
cache_enabled(true), fileFlags(0), fileSize(0)
{
}
inline void clearFlags() const {
fileFlags = 0;
cachedFlags = 0;
if (fileEngine)
(void)fileEngine->fileFlags(QAbstractFileEngine::Refresh);
}
inline void clear() {
metaData.clear();
clearFlags();
for (int i = QAbstractFileEngine::NFileNames - 1 ; i >= 0 ; --i)
fileNames[i].clear();
fileOwners[1].clear();
fileOwners[0].clear();
}
uint getFileFlags(QAbstractFileEngine::FileFlags) const;
QDateTime &getFileTime(QAbstractFileEngine::FileTime) const;
QString getFileName(QAbstractFileEngine::FileName) const;
QString getFileOwner(QAbstractFileEngine::FileOwner own) const;
QFileSystemEntry fileEntry;
mutable QFileSystemMetaData metaData;
QScopedPointer<QAbstractFileEngine> const fileEngine;
mutable QString fileNames[QAbstractFileEngine::NFileNames];
mutable QString fileOwners[2];
mutable uint cachedFlags : 30;
bool const isDefaultConstructed : 1; // QFileInfo is a default constructed instance
bool cache_enabled : 1;
mutable uint fileFlags;
mutable qint64 fileSize;
// ### Qt6: FIXME: This vector is essentially a plain array
// mutable QDateTime fileTimes[3], but the array is slower
// to initialize than the QVector as QDateTime has a pimpl.
// In Qt 6, QDateTime should inline its data members,
// and this here can be an array again.
mutable QVector<QDateTime> fileTimes;
inline bool getCachedFlag(uint c) const
{ return cache_enabled ? (cachedFlags & c) : 0; }
inline void setCachedFlag(uint c) const
{ if (cache_enabled) cachedFlags |= c; }
};
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QFILEINFO_P_H

View File

@ -0,0 +1,403 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qfilesystemengine_p.h"
#include <QDir>
#include <QSet>
#include <QStringBuilder>
#include "qabstractfileengine_p.h"
#ifdef QT_BUILD_CORE_LIB
#include "qresource_p.h"
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
/*!
\internal
Returns the canonicalized form of \a path (i.e., with all symlinks
resolved, and all redundant path elements removed.
*/
QString QFileSystemEngine::slowCanonicalized(const QString &path)
{
if (path.isEmpty())
return path;
QFileInfo fi;
const QChar slash(QLatin1Char('/'));
QString tmpPath = path;
int separatorPos = 0;
QSet<QString> nonSymlinks;
QSet<QString> known;
known.insert(path);
do {
#ifdef Q_OS_WIN
if (separatorPos == 0) {
if (tmpPath.size() >= 2 && tmpPath.at(0) == slash && tmpPath.at(1) == slash) {
// UNC, skip past the first two elements
separatorPos = tmpPath.indexOf(slash, 2);
} else if (tmpPath.size() >= 3 && tmpPath.at(1) == QLatin1Char(':') && tmpPath.at(2) == slash) {
// volume root, skip since it can not be a symlink
separatorPos = 2;
}
}
if (separatorPos != -1)
#endif
separatorPos = tmpPath.indexOf(slash, separatorPos + 1);
QString prefix = separatorPos == -1 ? tmpPath : tmpPath.left(separatorPos);
if (!nonSymlinks.contains(prefix)) {
fi.setFile(prefix);
if (fi.isSymLink()) {
QString target = fi.symLinkTarget();
if(QFileInfo(target).isRelative())
target = fi.absolutePath() + slash + target;
if (separatorPos != -1) {
if (fi.isDir() && !target.endsWith(slash))
target.append(slash);
target.append(tmpPath.mid(separatorPos));
}
tmpPath = QDir::cleanPath(target);
separatorPos = 0;
if (known.contains(tmpPath))
return QString();
known.insert(tmpPath);
} else {
nonSymlinks.insert(prefix);
}
}
} while (separatorPos != -1);
return QDir::cleanPath(tmpPath);
}
static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &data, bool resolvingEntry)
{
if (resolvingEntry) {
if (!QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute)
|| !data.exists()) {
data.clear();
return false;
}
}
return true;
}
static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry)
{
if (resolvingEntry) {
if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) {
delete engine;
engine = 0;
return false;
}
}
return true;
}
static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
QAbstractFileEngine *&engine, bool resolvingEntry = false)
{
QString const &filePath = entry.filePath();
if ((engine = qt_custom_file_engine_handler_create(filePath)))
return _q_checkEntry(engine, resolvingEntry);
#if defined(QT_BUILD_CORE_LIB)
for (int prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
QChar const ch = filePath[prefixSeparator];
if (ch == QLatin1Char('/'))
break;
if (ch == QLatin1Char(':')) {
if (prefixSeparator == 0) {
engine = new QResourceFileEngine(filePath);
return _q_checkEntry(engine, resolvingEntry);
}
if (prefixSeparator == 1)
break;
const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator));
for (int i = 0; i < paths.count(); i++) {
entry = QFileSystemEntry(QDir::cleanPath(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1)));
// Recurse!
if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true))
return true;
}
// entry may have been clobbered at this point.
return false;
}
// There's no need to fully validate the prefix here. Consulting the
// unicode tables could be expensive and validation is already
// performed in QDir::setSearchPaths.
//
// if (!ch.isLetterOrNumber())
// break;
}
#endif // defined(QT_BUILD_CORE_LIB)
return _q_checkEntry(entry, data, resolvingEntry);
}
/*!
\internal
Resolves the \a entry (see QDir::searchPaths) and returns an engine for
it, but never a QFSFileEngine.
Returns a file engine that can be used to access the entry. Returns 0 if
QFileSystemEngine API should be used to query and interact with the file
system object.
*/
QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
QFileSystemEntry &entry, QFileSystemMetaData &data) {
QFileSystemEntry copy = entry;
QAbstractFileEngine *engine = 0;
if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine))
// Reset entry to resolved copy.
entry = copy;
else
data.clear();
return engine;
}
//these unix functions are in this file, because they are shared by symbian port
//for open C file handles.
#ifdef Q_OS_UNIX
//static
bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data)
{
data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
QT_STATBUF statBuffer;
if (QT_FSTAT(fd, &statBuffer) == 0) {
data.fillFromStatBuf(statBuffer);
return true;
}
return false;
}
#if defined(Q_OS_QNX)
static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32)
{
statBuf64->st_mode = statBuf32.st_mode;
statBuf64->st_size = statBuf32.st_size;
statBuf64->st_ctime = statBuf32.st_ctime;
statBuf64->st_mtime = statBuf32.st_mtime;
statBuf64->st_atime = statBuf32.st_atime;
statBuf64->st_uid = statBuf32.st_uid;
statBuf64->st_gid = statBuf32.st_gid;
}
#endif
void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
{
// Permissions
if (statBuffer.st_mode & S_IRUSR)
entryFlags |= QFileSystemMetaData::OwnerReadPermission;
if (statBuffer.st_mode & S_IWUSR)
entryFlags |= QFileSystemMetaData::OwnerWritePermission;
if (statBuffer.st_mode & S_IXUSR)
entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
if (statBuffer.st_mode & S_IRGRP)
entryFlags |= QFileSystemMetaData::GroupReadPermission;
if (statBuffer.st_mode & S_IWGRP)
entryFlags |= QFileSystemMetaData::GroupWritePermission;
if (statBuffer.st_mode & S_IXGRP)
entryFlags |= QFileSystemMetaData::GroupExecutePermission;
if (statBuffer.st_mode & S_IROTH)
entryFlags |= QFileSystemMetaData::OtherReadPermission;
if (statBuffer.st_mode & S_IWOTH)
entryFlags |= QFileSystemMetaData::OtherWritePermission;
if (statBuffer.st_mode & S_IXOTH)
entryFlags |= QFileSystemMetaData::OtherExecutePermission;
// Type
if ((statBuffer.st_mode & S_IFMT) == S_IFREG)
entryFlags |= QFileSystemMetaData::FileType;
else if ((statBuffer.st_mode & S_IFMT) == S_IFDIR)
entryFlags |= QFileSystemMetaData::DirectoryType;
else
entryFlags |= QFileSystemMetaData::SequentialType;
// Attributes
entryFlags |= QFileSystemMetaData::ExistsAttribute;
size_ = statBuffer.st_size;
#if defined(Q_OS_MACX)
if (statBuffer.st_flags & UF_HIDDEN) {
entryFlags |= QFileSystemMetaData::HiddenAttribute;
knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
}
#endif
// Times
creationTime_ = statBuffer.st_ctime ? statBuffer.st_ctime : statBuffer.st_mtime;
modificationTime_ = statBuffer.st_mtime;
accessTime_ = statBuffer.st_atime;
userId_ = statBuffer.st_uid;
groupId_ = statBuffer.st_gid;
}
void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry)
{
#if defined(Q_OS_QNX)
knownFlagsMask = 0;
entryFlags = 0;
for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry);
extra = _DEXTRA_NEXT(extra)) {
if (extra->d_type == _DTYPE_STAT || extra->d_type == _DTYPE_LSTAT) {
const struct dirent_extra_stat * const extra_stat =
reinterpret_cast<struct dirent_extra_stat *>(extra);
// Remember whether this was a link or not, this saves an lstat() call later.
if (extra->d_type == _DTYPE_LSTAT) {
knownFlagsMask |= QFileSystemMetaData::LinkType;
if (S_ISLNK(extra_stat->d_stat.st_mode))
entryFlags |= QFileSystemMetaData::LinkType;
}
// For symlinks, the extra type _DTYPE_LSTAT doesn't work for filling out the meta data,
// as we need the stat() information there, not the lstat() information.
// In this case, don't use the extra information.
// Unfortunately, readdir() never seems to return extra info of type _DTYPE_STAT, so for
// symlinks, we always incur the cost of an extra stat() call later.
if (S_ISLNK(extra_stat->d_stat.st_mode) && extra->d_type == _DTYPE_LSTAT)
continue;
#if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT)
// Even with large file support, d_stat is always of type struct stat, not struct stat64,
// so it needs to be converted
struct stat64 statBuf;
fillStat64fromStat32(&statBuf, extra_stat->d_stat);
fillFromStatBuf(statBuf);
#else
fillFromStatBuf(extra_stat->d_stat);
#endif
knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
if (!S_ISLNK(extra_stat->d_stat.st_mode)) {
knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
entryFlags |= QFileSystemMetaData::ExistsAttribute;
}
}
}
#elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4)
// BSD4 includes Mac OS X
// ### This will clear all entry flags and knownFlagsMask
switch (entry.d_type)
{
case DT_DIR:
knownFlagsMask = QFileSystemMetaData::LinkType
| QFileSystemMetaData::FileType
| QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::SequentialType
| QFileSystemMetaData::ExistsAttribute;
entryFlags = QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::ExistsAttribute;
break;
case DT_BLK:
case DT_CHR:
case DT_FIFO:
case DT_SOCK:
// ### System attribute
knownFlagsMask = QFileSystemMetaData::LinkType
| QFileSystemMetaData::FileType
| QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::BundleType
| QFileSystemMetaData::AliasType
| QFileSystemMetaData::SequentialType
| QFileSystemMetaData::ExistsAttribute;
entryFlags = QFileSystemMetaData::SequentialType
| QFileSystemMetaData::ExistsAttribute;
break;
case DT_LNK:
knownFlagsMask = QFileSystemMetaData::LinkType;
entryFlags = QFileSystemMetaData::LinkType;
break;
case DT_REG:
knownFlagsMask = QFileSystemMetaData::LinkType
| QFileSystemMetaData::FileType
| QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::BundleType
| QFileSystemMetaData::SequentialType
| QFileSystemMetaData::ExistsAttribute;
entryFlags = QFileSystemMetaData::FileType
| QFileSystemMetaData::ExistsAttribute;
break;
case DT_UNKNOWN:
default:
clear();
}
#else
Q_UNUSED(entry)
#endif
}
#endif
//static
QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
{
#if defined(Q_OS_WIN)
Q_UNUSED(metaData);
return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerUser);
#else //(Q_OS_UNIX)
if (!metaData.hasFlags(QFileSystemMetaData::UserId))
QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::UserId);
return resolveUserName(metaData.userId());
#endif
}
//static
QString QFileSystemEngine::resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
{
#if defined(Q_OS_WIN)
Q_UNUSED(metaData);
return QFileSystemEngine::owner(entry, QAbstractFileEngine::OwnerGroup);
#else //(Q_OS_UNIX)
if (!metaData.hasFlags(QFileSystemMetaData::GroupId))
QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::GroupId);
return resolveGroupName(metaData.groupId());
#endif
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,120 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QFILESYSTEMENGINE_P_H
#define QFILESYSTEMENGINE_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 <QFile>
#include "qfilesystementry_p.h"
#include "qfilesystemmetadata_p.h"
#include "qsystemerror_p.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
class QFileSystemEngine
{
public:
static bool isCaseSensitive()
{
#ifndef Q_OS_WIN
return true;
#else
return false;
#endif
}
static QFileSystemEntry getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data);
static QFileSystemEntry canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
static QFileSystemEntry absoluteName(const QFileSystemEntry &entry);
static QByteArray id(const QFileSystemEntry &entry);
static QString resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
static QString resolveGroupName(const QFileSystemEntry &entry, QFileSystemMetaData &data);
#if defined(Q_OS_UNIX)
static QString resolveUserName(uint userId);
static QString resolveGroupName(uint groupId);
#endif
#if defined(Q_OS_MACX)
static QString bundleName(const QFileSystemEntry &entry);
#else
static QString bundleName(const QFileSystemEntry &entry) { Q_UNUSED(entry) return QString(); }
#endif
static bool fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what);
#if defined(Q_OS_UNIX)
static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags
#endif
#if defined(Q_OS_WIN)
static bool uncListSharesOnServer(const QString &server, QStringList *list); //Used also by QFSFileEngineIterator::hasNext()
static bool fillMetaData(int fd, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what);
static bool fillMetaData(HANDLE fHandle, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what);
static bool fillPermissions(const QFileSystemEntry &entry, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what);
static QString owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own);
static QString nativeAbsoluteFilePath(const QString &path);
#endif
//homePath, rootPath and tempPath shall return clean paths
static QString homePath();
static QString rootPath();
static QString tempPath();
static bool createDirectory(const QFileSystemEntry &entry, bool createParents);
static bool removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents);
static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
static bool removeFile(const QFileSystemEntry &entry, QSystemError &error);
static bool setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error,
QFileSystemMetaData *data = 0);
static bool setCurrentPath(const QFileSystemEntry &entry);
static QFileSystemEntry currentPath();
static QAbstractFileEngine *resolveEntryAndCreateLegacyEngine(QFileSystemEntry &entry,
QFileSystemMetaData &data);
private:
static QString slowCanonicalized(const QString &path);
#if defined(Q_OS_WIN)
static void clearWinStatData(QFileSystemMetaData &data);
#endif
};
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // include guard

View File

@ -0,0 +1,756 @@
/****************************************************************************
**
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>>
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qplatformdefs.h"
#include "qfilesystemengine_p.h"
#include <QFile>
#include <QVarLengthArray>
#include <stdlib.h> // for realpath()
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#if defined(Q_OS_MAC)
# include "qcore_mac_p.h"
# include <CoreFoundation/CFBundle.h>
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#if defined(Q_OS_MACX)
static inline bool _q_isMacHidden(const char *nativePath)
{
OSErr err;
FSRef fsRef;
err = FSPathMakeRefWithOptions(reinterpret_cast<const UInt8 *>(nativePath),
kFSPathMakeRefDoNotFollowLeafSymlink, &fsRef, 0);
if (err != noErr)
return false;
FSCatalogInfo catInfo;
err = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL);
if (err != noErr)
return false;
FileInfo * const fileInfo = reinterpret_cast<FileInfo*>(&catInfo.finderInfo);
return (fileInfo->finderFlags & kIsInvisible);
}
static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &entry)
{
if (!data.isDirectory())
return false;
QFileInfo info(entry.filePath());
QString suffix = info.suffix();
// First step: is the extenstion known ?
if (suffix == QLatin1String("app")
|| suffix == QLatin1String("debug")
|| suffix == QLatin1String("profile")
|| suffix == QLatin1String("bundle")
|| suffix == QLatin1String("pkg")) {
return true;
}
// Second step: check if an application knows the package type
const QByteArray &native = entry.nativeFilePath();
const char *nativeFilePath = native.constData();
int nativeFilePathLength = native.size();
QCFType<CFStringRef> path = CFStringCreateWithBytes(0,
reinterpret_cast<const UInt8*>(nativeFilePath),
nativeFilePathLength,
kCFStringEncodingUTF8,
false);
QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path, kCFURLPOSIXPathStyle, true);
UInt32 type, creator;
// Well created packages have the PkgInfo file
if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
return true;
// Find if an application other than Finder claims to know how to handle the package
if (suffix.length() > 0) {
QCFType<CFURLRef> application;
LSGetApplicationForURL(url,
kLSRolesEditor|kLSRolesViewer|kLSRolesViewer,
NULL,
&application);
if (application) {
CFStringRef path = CFURLGetString(application);
QString applicationPath = QCFString::toQString(path);
if (applicationPath != QLatin1String("file://localhost/System/Library/CoreServices/Finder.app/"))
return true;
}
}
// Third step: check if the directory has the package bit set
FSRef packageRef;
FSPathMakeRef((UInt8 *)nativeFilePath, &packageRef, NULL);
FSCatalogInfo catalogInfo;
FSGetCatalogInfo(&packageRef,
kFSCatInfoFinderInfo,
&catalogInfo,
NULL,
NULL,
NULL);
FolderInfo *folderInfo = reinterpret_cast<FolderInfo *>(catalogInfo.finderInfo);
return folderInfo->finderFlags & kHasBundle;
}
#else
static inline bool _q_isMacHidden(const char *nativePath)
{
Q_UNUSED(nativePath);
// no-op
return false;
}
#endif
//static
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
{
#if defined(__GLIBC__) && !defined(PATH_MAX)
#define PATH_CHUNK_SIZE 256
char *s = 0;
int len = -1;
int size = PATH_CHUNK_SIZE;
while (1) {
s = (char *) ::realloc(s, size);
Q_CHECK_PTR(s);
len = ::readlink(link.nativeFilePath().constData(), s, size);
if (len < 0) {
::free(s);
break;
}
if (len < size) {
break;
}
size *= 2;
}
#else
char s[PATH_MAX+1];
int len = readlink(link.nativeFilePath().constData(), s, PATH_MAX);
#endif
if (len > 0) {
QString ret;
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
fillMetaData(link, data, QFileSystemMetaData::DirectoryType);
if (data.isDirectory() && s[0] != '/') {
QDir parent(link.filePath());
parent.cdUp();
ret = parent.path();
if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/')))
ret += QLatin1Char('/');
}
s[len] = '\0';
ret += QFile::decodeName(QByteArray(s));
#if defined(__GLIBC__) && !defined(PATH_MAX)
::free(s);
#endif
if (!ret.startsWith(QLatin1Char('/'))) {
if (link.filePath().startsWith(QLatin1Char('/'))) {
ret.prepend(link.filePath().left(link.filePath().lastIndexOf(QLatin1Char('/')))
+ QLatin1Char('/'));
} else {
ret.prepend(QDir::currentPath() + QLatin1Char('/'));
}
}
ret = QDir::cleanPath(ret);
if (ret.size() > 1 && ret.endsWith(QLatin1Char('/')))
ret.chop(1);
return QFileSystemEntry(ret);
}
#if defined(Q_OS_MACX)
{
FSRef fref;
if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(link.filePath())).data(), &fref, 0) == noErr) {
// TODO get the meta data info from the QFileSystemMetaData object
Boolean isAlias, isFolder;
if (FSResolveAliasFile(&fref, true, &isFolder, &isAlias) == noErr && isAlias) {
AliasHandle alias;
if (FSNewAlias(0, &fref, &alias) == noErr && alias) {
QCFString cfstr;
if (FSCopyAliasInfo(alias, 0, 0, &cfstr, 0, 0) == noErr)
return QFileSystemEntry(QCFString::toQString(cfstr));
}
}
}
}
#endif
return QFileSystemEntry();
}
//static
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
{
if (entry.isEmpty() || entry.isRoot())
return entry;
#if !defined(Q_OS_MAC) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && _POSIX_VERSION < 200809L
// realpath(X,0) is not supported
Q_UNUSED(data);
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
#else
char *ret = 0;
# if defined(Q_OS_MACX)
// When using -mmacosx-version-min=10.4, we get the legacy realpath implementation,
// which does not work properly with the realpath(X,0) form. See QTBUG-28282.
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) {
ret = (char*)malloc(PATH_MAX + 1);
if (ret && realpath(entry.nativeFilePath().constData(), (char*)ret) == 0) {
const int savedErrno = errno; // errno is checked below, and free() might change it
free(ret);
errno = savedErrno;
ret = 0;
}
} else {
// on 10.5 we can use FSRef to resolve the file path.
QString path = QDir::cleanPath(entry.filePath());
FSRef fsref;
if (FSPathMakeRef((const UInt8 *)path.toUtf8().data(), &fsref, 0) == noErr) {
CFURLRef urlref = CFURLCreateFromFSRef(NULL, &fsref);
CFStringRef canonicalPath = CFURLCopyFileSystemPath(urlref, kCFURLPOSIXPathStyle);
QString ret = QCFString::toQString(canonicalPath);
CFRelease(canonicalPath);
CFRelease(urlref);
return QFileSystemEntry(ret);
}
}
# else
# if _POSIX_VERSION >= 200801L
ret = realpath(entry.nativeFilePath().constData(), (char*)0);
# else
ret = (char*)malloc(PATH_MAX + 1);
if (realpath(entry.nativeFilePath().constData(), (char*)ret) == 0) {
const int savedErrno = errno; // errno is checked below, and free() might change it
free(ret);
errno = savedErrno;
ret = 0;
}
# endif
# endif
if (ret) {
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret));
free(ret);
return QFileSystemEntry(canonicalPath);
} else if (errno == ENOENT) { // file doesn't exist
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
data.entryFlags &= ~(QFileSystemMetaData::ExistsAttribute);
return QFileSystemEntry();
}
return entry;
#endif
}
//static
QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
{
if (entry.isAbsolute() && entry.isClean())
return entry;
QByteArray orig = entry.nativeFilePath();
QByteArray result;
if (orig.isEmpty() || !orig.startsWith('/')) {
QFileSystemEntry cur(currentPath());
result = cur.nativeFilePath();
}
if (!orig.isEmpty() && !(orig.length() == 1 && orig[0] == '.')) {
if (!result.isEmpty() && !result.endsWith('/'))
result.append('/');
result.append(orig);
}
if (result.length() == 1 && result[0] == '/')
return QFileSystemEntry(result, QFileSystemEntry::FromNativePath());
const bool isDir = result.endsWith('/');
/* as long as QDir::cleanPath() operates on a QString we have to convert to a string here.
* ideally we never convert to a string since that loses information. Please fix after
* we get a QByteArray version of QDir::cleanPath()
*/
QFileSystemEntry resultingEntry(result, QFileSystemEntry::FromNativePath());
QString stringVersion = QDir::cleanPath(resultingEntry.filePath());
if (isDir)
stringVersion.append(QLatin1Char('/'));
return QFileSystemEntry(stringVersion);
}
//static
QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
{
struct stat statResult;
if (stat(entry.nativeFilePath().constData(), &statResult)) {
qErrnoWarning("stat() failed for '%s'", entry.nativeFilePath().constData());
return QByteArray();
}
QByteArray result = QByteArray::number(quint64(statResult.st_dev), 16);
result += ':';
result += QByteArray::number(quint64(statResult.st_ino));
return result;
}
//static
QString QFileSystemEngine::resolveUserName(uint userId)
{
#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
int size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
if (size_max == -1)
size_max = 1024;
QVarLengthArray<char, 1024> buf(size_max);
#endif
struct passwd *pw = 0;
#if !defined(Q_OS_INTEGRITY)
#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_VXWORKS)
struct passwd entry;
getpwuid_r(userId, &entry, buf.data(), buf.size(), &pw);
#else
pw = getpwuid(userId);
#endif
#endif
if (pw)
return QFile::decodeName(QByteArray(pw->pw_name));
return QString();
}
//static
QString QFileSystemEngine::resolveGroupName(uint groupId)
{
#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
int size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
if (size_max == -1)
size_max = 1024;
QVarLengthArray<char, 1024> buf(size_max);
#endif
struct group *gr = 0;
#if !defined(Q_OS_INTEGRITY)
#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_VXWORKS)
size_max = sysconf(_SC_GETGR_R_SIZE_MAX);
if (size_max == -1)
size_max = 1024;
buf.resize(size_max);
struct group entry;
// Some large systems have more members than the POSIX max size
// Loop over by doubling the buffer size (upper limit 250k)
for (unsigned size = size_max; size < 256000; size += size)
{
buf.resize(size);
// ERANGE indicates that the buffer was too small
if (!getgrgid_r(groupId, &entry, buf.data(), buf.size(), &gr)
|| errno != ERANGE)
break;
}
#else
gr = getgrgid(groupId);
#endif
#endif
if (gr)
return QFile::decodeName(QByteArray(gr->gr_name));
return QString();
}
#if defined(Q_OS_MACX)
//static
QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry)
{
QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, QCFString(entry.filePath()),
kCFURLPOSIXPathStyle, true);
if (QCFType<CFDictionaryRef> dict = CFBundleCopyInfoDictionaryForURL(url)) {
if (CFTypeRef name = (CFTypeRef)CFDictionaryGetValue(dict, kCFBundleNameKey)) {
if (CFGetTypeID(name) == CFStringGetTypeID())
return QCFString::toQString((CFStringRef)name);
}
}
return QString();
}
#endif
//static
bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what)
{
#if defined(Q_OS_MACX)
if (what & QFileSystemMetaData::BundleType) {
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
what |= QFileSystemMetaData::DirectoryType;
}
if (what & QFileSystemMetaData::HiddenAttribute) {
// Mac OS >= 10.5: st_flags & UF_HIDDEN
what |= QFileSystemMetaData::PosixStatFlags;
}
#endif // defined(Q_OS_MACX)
if (what & QFileSystemMetaData::PosixStatFlags)
what |= QFileSystemMetaData::PosixStatFlags;
if (what & QFileSystemMetaData::ExistsAttribute) {
// FIXME: Would other queries being performed provide this bit?
what |= QFileSystemMetaData::PosixStatFlags;
}
data.entryFlags &= ~what;
const char * nativeFilePath;
int nativeFilePathLength;
{
const QByteArray &path = entry.nativeFilePath();
nativeFilePath = path.constData();
nativeFilePathLength = path.size();
Q_UNUSED(nativeFilePathLength);
}
bool entryExists = true; // innocent until proven otherwise
QT_STATBUF statBuffer;
bool statBufferValid = false;
if (what & QFileSystemMetaData::LinkType) {
if (QT_LSTAT(nativeFilePath, &statBuffer) == 0) {
if (S_ISLNK(statBuffer.st_mode)) {
data.entryFlags |= QFileSystemMetaData::LinkType;
} else {
statBufferValid = true;
data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
}
} else {
entryExists = false;
}
data.knownFlagsMask |= QFileSystemMetaData::LinkType;
}
if (statBufferValid || (what & QFileSystemMetaData::PosixStatFlags)) {
if (entryExists && !statBufferValid)
statBufferValid = (QT_STAT(nativeFilePath, &statBuffer) == 0);
if (statBufferValid)
data.fillFromStatBuf(statBuffer);
else {
entryExists = false;
data.creationTime_ = 0;
data.modificationTime_ = 0;
data.accessTime_ = 0;
data.size_ = 0;
data.userId_ = (uint) -2;
data.groupId_ = (uint) -2;
}
// reset the mask
data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags
| QFileSystemMetaData::ExistsAttribute;
}
#if defined(Q_OS_MACX)
if (what & QFileSystemMetaData::AliasType)
{
if (entryExists) {
FSRef fref;
if (FSPathMakeRef((const UInt8 *)nativeFilePath, &fref, NULL) == noErr) {
Boolean isAlias, isFolder;
if (FSIsAliasFile(&fref, &isAlias, &isFolder) == noErr) {
if (isAlias)
data.entryFlags |= QFileSystemMetaData::AliasType;
}
}
}
data.knownFlagsMask |= QFileSystemMetaData::AliasType;
}
#endif
if (what & QFileSystemMetaData::UserPermissions) {
// calculate user permissions
if (entryExists) {
if (what & QFileSystemMetaData::UserReadPermission) {
if (QT_ACCESS(nativeFilePath, R_OK) == 0)
data.entryFlags |= QFileSystemMetaData::UserReadPermission;
}
if (what & QFileSystemMetaData::UserWritePermission) {
if (QT_ACCESS(nativeFilePath, W_OK) == 0)
data.entryFlags |= QFileSystemMetaData::UserWritePermission;
}
if (what & QFileSystemMetaData::UserExecutePermission) {
if (QT_ACCESS(nativeFilePath, X_OK) == 0)
data.entryFlags |= QFileSystemMetaData::UserExecutePermission;
}
}
data.knownFlagsMask |= (what & QFileSystemMetaData::UserPermissions);
}
if (what & QFileSystemMetaData::HiddenAttribute
&& !data.isHidden()) {
QString fileName = entry.fileName();
if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.'))
|| (entryExists && _q_isMacHidden(nativeFilePath)))
data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
}
#if defined(Q_OS_MACX)
if (what & QFileSystemMetaData::BundleType) {
if (entryExists && isPackage(data, entry))
data.entryFlags |= QFileSystemMetaData::BundleType;
data.knownFlagsMask |= QFileSystemMetaData::BundleType;
}
#endif
if (!entryExists) {
data.clearFlags(what);
return false;
}
return data.hasFlags(what);
}
//static
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
{
QString dirName = entry.filePath();
if (createParents) {
dirName = QDir::cleanPath(dirName);
for (int oldslash = -1, slash=0; slash != -1; oldslash = slash) {
slash = dirName.indexOf(QDir::separator(), oldslash+1);
if (slash == -1) {
if (oldslash == dirName.length())
break;
slash = dirName.length();
}
if (slash) {
const QByteArray chunk = QFile::encodeName(dirName.left(slash));
if (QT_MKDIR(chunk.constData(), 0777) != 0) {
if (errno == EEXIST
#if defined(Q_OS_QNX)
// On QNX the QNet (VFS paths of other hosts mounted under a directory
// such as /net) mountpoint returns ENOENT, despite existing. stat()
// on the QNet mountpoint returns successfully and reports S_IFDIR.
|| errno == ENOENT
#endif
) {
QT_STATBUF st;
if (QT_STAT(chunk.constData(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
continue;
}
return false;
}
}
}
return true;
}
#if defined(Q_OS_DARWIN) // Mac X doesn't support trailing /'s
if (dirName.endsWith(QLatin1Char('/')))
dirName.chop(1);
#endif
return (QT_MKDIR(QFile::encodeName(dirName).constData(), 0777) == 0);
}
//static
bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
{
if (removeEmptyParents) {
QString dirName = QDir::cleanPath(entry.filePath());
for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
const QByteArray chunk = QFile::encodeName(dirName.left(slash));
QT_STATBUF st;
if (QT_STAT(chunk.constData(), &st) != -1) {
if ((st.st_mode & S_IFMT) != S_IFDIR)
return false;
if (::rmdir(chunk.constData()) != 0)
return oldslash != 0;
} else {
return false;
}
slash = dirName.lastIndexOf(QDir::separator(), oldslash-1);
}
return true;
}
return rmdir(QFile::encodeName(entry.filePath()).constData()) == 0;
}
//static
bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
return true;
error = QSystemError(errno, QSystemError::StandardLibraryError);
return false;
}
//static
bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
Q_UNUSED(source);
Q_UNUSED(target);
error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); //Function not implemented
return false;
}
//static
bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
return true;
error = QSystemError(errno, QSystemError::StandardLibraryError);
return false;
}
//static
bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
{
if (unlink(entry.nativeFilePath().constData()) == 0)
return true;
error = QSystemError(errno, QSystemError::StandardLibraryError);
return false;
}
//static
bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
{
mode_t mode = 0;
if (permissions & QFile::ReadOwner)
mode |= S_IRUSR;
if (permissions & QFile::WriteOwner)
mode |= S_IWUSR;
if (permissions & QFile::ExeOwner)
mode |= S_IXUSR;
if (permissions & QFile::ReadUser)
mode |= S_IRUSR;
if (permissions & QFile::WriteUser)
mode |= S_IWUSR;
if (permissions & QFile::ExeUser)
mode |= S_IXUSR;
if (permissions & QFile::ReadGroup)
mode |= S_IRGRP;
if (permissions & QFile::WriteGroup)
mode |= S_IWGRP;
if (permissions & QFile::ExeGroup)
mode |= S_IXGRP;
if (permissions & QFile::ReadOther)
mode |= S_IROTH;
if (permissions & QFile::WriteOther)
mode |= S_IWOTH;
if (permissions & QFile::ExeOther)
mode |= S_IXOTH;
bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0;
if (success && data) {
data->entryFlags &= ~QFileSystemMetaData::Permissions;
data->entryFlags |= QFileSystemMetaData::MetaDataFlag(uint(permissions));
data->knownFlagsMask |= QFileSystemMetaData::Permissions;
}
if (!success)
error = QSystemError(errno, QSystemError::StandardLibraryError);
return success;
}
QString QFileSystemEngine::homePath()
{
QString home = QFile::decodeName(qgetenv("HOME"));
if (home.isEmpty())
home = rootPath();
return QDir::cleanPath(home);
}
QString QFileSystemEngine::rootPath()
{
return QLatin1String("/");
}
QString QFileSystemEngine::tempPath()
{
#ifdef QT_UNIX_TEMP_PATH_OVERRIDE
return QLatin1String(QT_UNIX_TEMP_PATH_OVERRIDE);
#elif defined(Q_OS_BLACKBERRY)
QString temp = QFile::decodeName(qgetenv("TEMP"));
if (temp.isEmpty())
temp = QFile::decodeName(qgetenv("TMPDIR"));
if (temp.isEmpty()) {
qWarning("Neither the TEMP nor the TMPDIR environment variable is set, falling back to /tmp.");
temp = QLatin1String("/tmp/");
}
return QDir::cleanPath(temp);
#else
QString temp = QFile::decodeName(qgetenv("TMPDIR"));
if (temp.isEmpty())
temp = QLatin1String("/tmp/");
return QDir::cleanPath(temp);
#endif
}
bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &path)
{
int r;
r = QT_CHDIR(path.nativeFilePath().constData());
return r >= 0;
}
QFileSystemEntry QFileSystemEngine::currentPath()
{
QFileSystemEntry result;
QT_STATBUF st;
if (QT_STAT(".", &st) == 0) {
#if defined(__GLIBC__) && !defined(PATH_MAX)
char *currentName = ::get_current_dir_name();
if (currentName) {
result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath());
::free(currentName);
}
#else
char currentName[PATH_MAX+1];
if (::getcwd(currentName, PATH_MAX)) {
#if defined(Q_OS_VXWORKS) && defined(VXWORKS_VXSIM)
QByteArray dir(currentName);
if (dir.indexOf(':') < dir.indexOf('/'))
dir.remove(0, dir.indexOf(':')+1);
qstrncpy(currentName, dir.constData(), PATH_MAX);
#endif
result = QFileSystemEntry(QByteArray(currentName), QFileSystemEntry::FromNativePath());
}
# if defined(QT_DEBUG)
if (result.isEmpty())
qWarning("QFileSystemEngine::currentPath: getcwd() failed");
# endif
#endif
} else {
# if defined(QT_DEBUG)
qWarning("QFileSystemEngine::currentPath: stat(\".\") failed");
# endif
}
return result;
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,388 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qfilesystementry_p.h"
#include <QDir>
#include <QFile>
#include "qfsfileengine_p.h"
#ifdef Q_OS_WIN
#include <QStringBuilder>
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifdef Q_OS_WIN
static bool isUncRoot(const QString &server)
{
QString localPath = QDir::toNativeSeparators(server);
if (!localPath.startsWith(QLatin1String("\\\\")))
return false;
int idx = localPath.indexOf(QLatin1Char('\\'), 2);
if (idx == -1 || idx + 1 == localPath.length())
return true;
localPath = localPath.right(localPath.length() - idx - 1).trimmed();
return localPath.isEmpty();
}
static inline QString fixIfRelativeUncPath(const QString &path)
{
QString currentPath = QDir::currentPath();
if (currentPath.startsWith(QLatin1String("//")))
return currentPath % QChar(QLatin1Char('/')) % path;
return path;
}
#endif
QFileSystemEntry::QFileSystemEntry()
: m_lastSeparator(-1),
m_firstDotInFileName(-1),
m_lastDotInFileName(-1)
{
}
/*!
\internal
Use this constructor when the path is supplied by user code, as it may contain a mix
of '/' and the native separator.
*/
QFileSystemEntry::QFileSystemEntry(const QString &filePath)
: m_filePath(QDir::fromNativeSeparators(filePath)),
m_lastSeparator(-2),
m_firstDotInFileName(-2),
m_lastDotInFileName(0)
{
}
/*!
\internal
Use this constructor when the path is guaranteed to be in internal format, i.e. all
directory separators are '/' and not the native separator.
*/
QFileSystemEntry::QFileSystemEntry(const QString &filePath, FromInternalPath /* dummy */)
: m_filePath(filePath),
m_lastSeparator(-2),
m_firstDotInFileName(-2),
m_lastDotInFileName(0)
{
}
/*!
\internal
Use this constructor when the path comes from a native API
*/
QFileSystemEntry::QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath /* dummy */)
: m_nativeFilePath(nativeFilePath),
m_lastSeparator(-2),
m_firstDotInFileName(-2),
m_lastDotInFileName(0)
{
}
QFileSystemEntry::QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath)
: m_filePath(QDir::fromNativeSeparators(filePath)),
m_nativeFilePath(nativeFilePath),
m_lastSeparator(-2),
m_firstDotInFileName(-2),
m_lastDotInFileName(0)
{
}
QString QFileSystemEntry::filePath() const
{
resolveFilePath();
return m_filePath;
}
QFileSystemEntry::NativePath QFileSystemEntry::nativeFilePath() const
{
resolveNativeFilePath();
return m_nativeFilePath;
}
void QFileSystemEntry::resolveFilePath() const
{
if (m_filePath.isEmpty() && !m_nativeFilePath.isEmpty()) {
#if defined(QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16)
m_filePath = QDir::fromNativeSeparators(m_nativeFilePath);
#ifdef Q_OS_WIN
if (m_filePath.startsWith(QLatin1String("//?/UNC/")))
m_filePath = m_filePath.remove(2,6);
if (m_filePath.startsWith(QLatin1String("//?/")))
m_filePath = m_filePath.remove(0,4);
#endif
#else
m_filePath = QDir::fromNativeSeparators(QFile::decodeName(m_nativeFilePath));
#endif
}
}
void QFileSystemEntry::resolveNativeFilePath() const
{
if (!m_filePath.isEmpty() && m_nativeFilePath.isEmpty()) {
#ifdef Q_OS_WIN
QString filePath = m_filePath;
if (isRelative())
filePath = fixIfRelativeUncPath(m_filePath);
m_nativeFilePath = QFSFileEnginePrivate::longFileName(QDir::toNativeSeparators(filePath));
#elif defined(QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16)
m_nativeFilePath = QDir::toNativeSeparators(m_filePath);
#else
m_nativeFilePath = QFile::encodeName(QDir::toNativeSeparators(m_filePath));
#endif
}
}
QString QFileSystemEntry::fileName() const
{
findLastSeparator();
#if defined(Q_OS_WIN)
if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
return m_filePath.mid(2);
#endif
return m_filePath.mid(m_lastSeparator + 1);
}
QString QFileSystemEntry::path() const
{
findLastSeparator();
if (m_lastSeparator == -1) {
#if defined(Q_OS_WIN)
if (m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
return QFSFileEngine::currentPath(m_filePath.left(2));
#endif
return QString(QLatin1Char('.'));
}
if (m_lastSeparator == 0)
return QString(QLatin1Char('/'));
#if defined(Q_OS_WIN)
if (m_lastSeparator == 2 && m_filePath.at(1) == QLatin1Char(':'))
return m_filePath.left(m_lastSeparator + 1);
#endif
return m_filePath.left(m_lastSeparator);
}
QString QFileSystemEntry::baseName() const
{
findFileNameSeparators();
int length = -1;
if (m_firstDotInFileName >= 0) {
length = m_firstDotInFileName;
if (m_lastSeparator != -1) // avoid off by one
length--;
}
#if defined(Q_OS_WIN)
if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
return m_filePath.mid(2, length - 2);
#endif
return m_filePath.mid(m_lastSeparator + 1, length);
}
QString QFileSystemEntry::completeBaseName() const
{
findFileNameSeparators();
int length = -1;
if (m_firstDotInFileName >= 0) {
length = m_firstDotInFileName + m_lastDotInFileName;
if (m_lastSeparator != -1) // avoid off by one
length--;
}
#if defined(Q_OS_WIN)
if (m_lastSeparator == -1 && m_filePath.length() >= 2 && m_filePath.at(1) == QLatin1Char(':'))
return m_filePath.mid(2, length - 2);
#endif
return m_filePath.mid(m_lastSeparator + 1, length);
}
QString QFileSystemEntry::suffix() const
{
findFileNameSeparators();
if (m_lastDotInFileName == -1)
return QString();
return m_filePath.mid(qMax((qint16)0, m_lastSeparator) + m_firstDotInFileName + m_lastDotInFileName + 1);
}
QString QFileSystemEntry::completeSuffix() const
{
findFileNameSeparators();
if (m_firstDotInFileName == -1)
return QString();
return m_filePath.mid(qMax((qint16)0, m_lastSeparator) + m_firstDotInFileName + 1);
}
#if defined(Q_OS_WIN)
bool QFileSystemEntry::isRelative() const
{
resolveFilePath();
return (m_filePath.isEmpty() || (!m_filePath.isEmpty() && (m_filePath[0].unicode() != '/')
&& (!(m_filePath.length() >= 2 && m_filePath[1].unicode() == ':'))));
}
bool QFileSystemEntry::isAbsolute() const
{
resolveFilePath();
return (!m_filePath.isEmpty() && ((m_filePath.length() >= 3
&& (m_filePath[0].isLetter() && m_filePath[1].unicode() == ':' && m_filePath[2].unicode() == '/'))
|| (m_filePath.length() >= 2 && (m_filePath.at(0) == QLatin1Char('/') && m_filePath.at(1) == QLatin1Char('/')))
));
}
#else
bool QFileSystemEntry::isRelative() const
{
return !isAbsolute();
}
bool QFileSystemEntry::isAbsolute() const
{
resolveFilePath();
return (!m_filePath.isEmpty() && (m_filePath[0].unicode() == '/'));
}
#endif
#if defined(Q_OS_WIN)
bool QFileSystemEntry::isDriveRoot() const
{
resolveFilePath();
return (m_filePath.length() == 3
&& m_filePath.at(0).isLetter() && m_filePath.at(1) == QLatin1Char(':')
&& m_filePath.at(2) == QLatin1Char('/'));
}
#endif
bool QFileSystemEntry::isRoot() const
{
resolveFilePath();
if (m_filePath == QLatin1String("/")
#if defined(Q_OS_WIN)
|| isDriveRoot()
|| isUncRoot(m_filePath)
#endif
)
return true;
return false;
}
bool QFileSystemEntry::isEmpty() const
{
return m_filePath.isEmpty() && m_nativeFilePath.isEmpty();
}
// private methods
void QFileSystemEntry::findLastSeparator() const
{
if (m_lastSeparator == -2) {
resolveFilePath();
m_lastSeparator = -1;
for (int i = m_filePath.size() - 1; i >= 0; --i) {
if (m_filePath[i].unicode() == '/') {
m_lastSeparator = i;
break;
}
}
}
}
void QFileSystemEntry::findFileNameSeparators() const
{
if (m_firstDotInFileName == -2) {
resolveFilePath();
int firstDotInFileName = -1;
int lastDotInFileName = -1;
int lastSeparator = m_lastSeparator;
int stop;
if (lastSeparator < 0) {
lastSeparator = -1;
stop = 0;
} else {
stop = lastSeparator;
}
int i = m_filePath.size() - 1;
for (; i >= stop; --i) {
if (m_filePath[i].unicode() == '.') {
firstDotInFileName = lastDotInFileName = i;
break;
} else if (m_filePath[i].unicode() == '/') {
lastSeparator = i;
break;
}
}
if (lastSeparator != i) {
for (--i; i >= stop; --i) {
if (m_filePath[i].unicode() == '.')
firstDotInFileName = i;
else if (m_filePath[i].unicode() == '/') {
lastSeparator = i;
break;
}
}
}
m_lastSeparator = lastSeparator;
m_firstDotInFileName = firstDotInFileName == -1 ? -1 : firstDotInFileName - qMax(0, lastSeparator);
if (lastDotInFileName == -1)
m_lastDotInFileName = -1;
else if (firstDotInFileName == lastDotInFileName)
m_lastDotInFileName = 0;
else
m_lastDotInFileName = lastDotInFileName - firstDotInFileName;
}
}
bool QFileSystemEntry::isClean() const
{
resolveFilePath();
int dots = 0;
bool dotok = true; // checking for ".." or "." starts to relative paths
bool slashok = true;
for (QString::const_iterator iter = m_filePath.constBegin(); iter != m_filePath.constEnd(); iter++) {
if (*iter == QLatin1Char('/')) {
if (dots == 1 || dots == 2)
return false; // path contains "./" or "../"
if (!slashok)
return false; // path contains "//"
dots = 0;
dotok = true;
slashok = false;
} else if (dotok) {
slashok = true;
if (*iter == QLatin1Char('.')) {
dots++;
if (dots > 2)
dotok = false;
} else {
//path element contains a character other than '.', it's clean
dots = 0;
dotok = false;
}
}
}
return (dots != 1 && dots != 2); // clean if path doesn't end in . or ..
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,106 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QFILESYSTEMENTRY_P_H
#define QFILESYSTEMENTRY_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 <QString>
#include <QByteArray>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#if defined(Q_OS_WIN)
#define QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16
#endif
class QFileSystemEntry
{
public:
#ifndef QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16
typedef QByteArray NativePath;
#else
typedef QString NativePath;
#endif
struct FromNativePath{};
struct FromInternalPath{};
QFileSystemEntry();
explicit QFileSystemEntry(const QString &filePath);
QFileSystemEntry(const QString &filePath, FromInternalPath dummy);
QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath dummy);
QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath);
QString filePath() const;
QString fileName() const;
QString path() const;
NativePath nativeFilePath() const;
QString baseName() const;
QString completeBaseName() const;
QString suffix() const;
QString completeSuffix() const;
bool isAbsolute() const;
bool isRelative() const;
bool isClean() const;
#if defined(Q_OS_WIN)
bool isDriveRoot() const;
#endif
bool isRoot() const;
bool isEmpty() const;
void clear()
{
*this = QFileSystemEntry();
}
private:
// creates the QString version out of the bytearray version
void resolveFilePath() const;
// creates the bytearray version out of the QString version
void resolveNativeFilePath() const;
// resolves the separator
void findLastSeparator() const;
// resolves the dots and the separator
void findFileNameSeparators() const;
mutable QString m_filePath; // always has slashes as separator
mutable NativePath m_nativeFilePath; // native encoding and separators
mutable qint16 m_lastSeparator; // index in m_filePath of last separator
mutable qint16 m_firstDotInFileName; // index after m_filePath for first dot (.)
mutable qint16 m_lastDotInFileName; // index after m_firstDotInFileName for last dot (.)
};
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // include guard

View File

@ -0,0 +1,94 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QFILESYSTEMITERATOR_P_H
#define QFILESYSTEMITERATOR_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 <QtGlobal>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef QT_NO_FILESYSTEMITERATOR
#include <QDir>
#include <QDirIterator>
#include <QStringList>
#include "qfilesystementry_p.h"
#include "qfilesystemmetadata_p.h"
// Platform-specific headers
#if !defined(Q_OS_WIN)
#include <QScopedPointer>
#endif
class QFileSystemIterator
{
public:
QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
const QStringList &nameFilters, QDirIterator::IteratorFlags flags
= QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
~QFileSystemIterator();
bool advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData);
private:
QFileSystemEntry::NativePath nativePath;
// Platform-specific data
#if defined(Q_OS_WIN)
QString dirPath;
HANDLE findFileHandle;
QStringList uncShares;
bool uncFallback;
int uncShareIndex;
bool onlyDirs;
#else
QT_DIR *dir;
QT_DIRENT *dirEntry;
#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
// for readdir_r
QScopedPointer<QT_DIRENT, QScopedPointerPodDeleter> mt_file;
#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R)
// for _readdir_r
size_t direntSize;
#endif
#endif
int lastError;
#endif
Q_DISABLE_COPY(QFileSystemIterator)
};
#endif // QT_NO_FILESYSTEMITERATOR
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // include guard

View File

@ -0,0 +1,112 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qplatformdefs.h"
#include "qfilesystemiterator_p.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef QT_NO_FILESYSTEMITERATOR
#include <stdlib.h>
#include <errno.h>
QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
: nativePath(entry.nativeFilePath())
, dir(0)
, dirEntry(0)
#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R)
, direntSize(0)
#endif
, lastError(0)
{
Q_UNUSED(filters)
Q_UNUSED(nameFilters)
Q_UNUSED(flags)
if ((dir = QT_OPENDIR(nativePath.constData())) == 0) {
lastError = errno;
} else {
if (!nativePath.endsWith('/'))
nativePath.append('/');
#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
// ### Race condition; we should use fpathconf and dirfd().
size_t maxPathName = ::pathconf(nativePath.constData(), _PC_NAME_MAX);
if (maxPathName == size_t(-1))
maxPathName = FILENAME_MAX;
maxPathName += sizeof(QT_DIRENT) + 1;
QT_DIRENT *p = reinterpret_cast<QT_DIRENT*>(::malloc(maxPathName));
Q_CHECK_PTR(p);
mt_file.reset(p);
#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R)
direntSize = maxPathName;
// Include extra stat information in the readdir() call (d_stat member of dirent_extra_stat).
// This is used in QFileSystemMetaData::fillFromDirEnt() to avoid extra stat() calls when iterating
// over directories
if (dircntl(dir, D_SETFLAG, D_FLAG_STAT) == -1)
lastError = errno;
#endif
#endif
}
}
QFileSystemIterator::~QFileSystemIterator()
{
if (dir)
QT_CLOSEDIR(dir);
}
bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
{
if (!dir)
return false;
#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R)
lastError = _readdir_r(dir, mt_file.data(), &dirEntry, direntSize);
if (lastError)
return false;
#elif defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN)
lastError = QT_READDIR_R(dir, mt_file.data(), &dirEntry);
if (lastError)
return false;
#else
// ### add local lock to prevent breaking reentrancy
dirEntry = QT_READDIR(dir);
#endif // _POSIX_THREAD_SAFE_FUNCTIONS
if (dirEntry) {
fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name), QFileSystemEntry::FromNativePath());
metaData.fillFromDirEnt(*dirEntry);
return true;
}
lastError = errno;
return false;
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QT_NO_FILESYSTEMITERATOR

View File

@ -0,0 +1,129 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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$
**
****************************************************************************/
#if _WIN32_WINNT < 0x0500
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include "qfilesystemiterator_p.h"
#include "qfilesystemengine_p.h"
#include "qplatformdefs.h"
#include <qt_windows.h>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
bool done = true;
QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
: nativePath(entry.nativeFilePath())
, dirPath(entry.filePath())
, findFileHandle(INVALID_HANDLE_VALUE)
, uncFallback(false)
, uncShareIndex(0)
, onlyDirs(false)
{
Q_UNUSED(nameFilters)
Q_UNUSED(flags)
if (nativePath.endsWith(QLatin1String(".lnk"))) {
QFileSystemMetaData metaData;
QFileSystemEntry link = QFileSystemEngine::getLinkTarget(entry, metaData);
nativePath = link.nativeFilePath();
}
if (!nativePath.endsWith(QLatin1Char('\\')))
nativePath.append(QLatin1Char('\\'));
nativePath.append(QLatin1Char('*'));
if (!dirPath.endsWith(QLatin1Char('/')))
dirPath.append(QLatin1Char('/'));
if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files))))
onlyDirs = true;
}
QFileSystemIterator::~QFileSystemIterator()
{
if (findFileHandle != INVALID_HANDLE_VALUE)
FindClose(findFileHandle);
}
bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
{
bool haveData = false;
WIN32_FIND_DATA findData;
if (findFileHandle == INVALID_HANDLE_VALUE && !uncFallback) {
haveData = true;
int infoLevel = 0 ; // FindExInfoStandard;
DWORD dwAdditionalFlags = 0;
#ifndef Q_OS_WINCE
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH
infoLevel = 1 ; // FindExInfoBasic;
}
#endif
int searchOps = 0; // FindExSearchNameMatch
if (onlyDirs)
searchOps = 1 ; // FindExSearchLimitToDirectories
findFileHandle = FindFirstFileEx((const wchar_t *)nativePath.utf16(), FINDEX_INFO_LEVELS(infoLevel), &findData,
FINDEX_SEARCH_OPS(searchOps), 0, dwAdditionalFlags);
if (findFileHandle == INVALID_HANDLE_VALUE) {
if (nativePath.startsWith(QLatin1String("\\\\?\\UNC\\"))) {
QStringList parts = nativePath.split(QLatin1Char('\\'), QString::SkipEmptyParts);
if (parts.count() == 4 && QFileSystemEngine::uncListSharesOnServer(
QLatin1String("\\\\") + parts.at(2), &uncShares)) {
if (uncShares.isEmpty())
return false; // No shares found in the server
else
uncFallback = true;
}
}
}
}
if (findFileHandle == INVALID_HANDLE_VALUE && !uncFallback)
return false;
// Retrieve the new file information.
if (!haveData) {
if (uncFallback) {
if (++uncShareIndex >= uncShares.count())
return false;
} else {
if (!FindNextFile(findFileHandle, &findData))
return false;
}
}
// Create the new file system entry & meta data.
if (uncFallback) {
fileEntry = QFileSystemEntry(dirPath + uncShares.at(uncShareIndex));
metaData.fillFromFileAttribute(FILE_ATTRIBUTE_DIRECTORY);
return true;
} else {
QString fileName = QString::fromWCharArray(findData.cFileName);
fileEntry = QFileSystemEntry(dirPath + fileName);
metaData = QFileSystemMetaData();
if (!fileName.endsWith(QLatin1String(".lnk"))) {
metaData.fillFromFindData(findData, true);
}
return true;
}
return false;
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,341 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QFILESYSTEMMETADATA_P_H
#define QFILESYSTEMMETADATA_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 "qplatformdefs.h"
#include <QtGlobal>
#include <QDateTime>
#include "qabstractfileengine_p.h"
// Platform-specific includes
#ifdef Q_OS_WIN
# include <QtCore/qt_windows.h>
# ifndef IO_REPARSE_TAG_SYMLINK
# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
# endif
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
class QFileSystemEngine;
class QFileSystemMetaData
{
public:
QFileSystemMetaData()
: knownFlagsMask(0)
{
}
enum MetaDataFlag {
// Permissions, overlaps with QFile::Permissions
OtherReadPermission = 0x00000004, OtherWritePermission = 0x00000002, OtherExecutePermission = 0x00000001,
GroupReadPermission = 0x00000040, GroupWritePermission = 0x00000020, GroupExecutePermission = 0x00000010,
UserReadPermission = 0x00000400, UserWritePermission = 0x00000200, UserExecutePermission = 0x00000100,
OwnerReadPermission = 0x00004000, OwnerWritePermission = 0x00002000, OwnerExecutePermission = 0x00001000,
OtherPermissions = OtherReadPermission | OtherWritePermission | OtherExecutePermission,
GroupPermissions = GroupReadPermission | GroupWritePermission | GroupExecutePermission,
UserPermissions = UserReadPermission | UserWritePermission | UserExecutePermission,
OwnerPermissions = OwnerReadPermission | OwnerWritePermission | OwnerExecutePermission,
ReadPermissions = OtherReadPermission | GroupReadPermission | UserReadPermission | OwnerReadPermission,
WritePermissions = OtherWritePermission | GroupWritePermission | UserWritePermission | OwnerWritePermission,
ExecutePermissions = OtherExecutePermission | GroupExecutePermission | UserExecutePermission | OwnerExecutePermission,
Permissions = OtherPermissions | GroupPermissions | UserPermissions | OwnerPermissions,
// Type
LinkType = 0x00010000,
FileType = 0x00020000,
DirectoryType = 0x00040000,
#if defined(Q_OS_MACX)
BundleType = 0x00080000,
AliasType = 0x08000000,
#else
BundleType = 0x0,
AliasType = 0x0,
#endif
#if defined(Q_OS_WIN)
WinLnkType = 0x08000000, // Note: Uses the same position for AliasType on Mac
#else
WinLnkType = 0x0,
#endif
SequentialType = 0x00800000, // Note: overlaps with QAbstractFileEngine::RootFlag
LegacyLinkType = LinkType | AliasType | WinLnkType,
Type = LinkType | FileType | DirectoryType | BundleType | SequentialType | AliasType,
// Attributes
HiddenAttribute = 0x00100000,
SizeAttribute = 0x00200000, // Note: overlaps with QAbstractFileEngine::LocalDiskFlag
ExistsAttribute = 0x00400000,
Attributes = HiddenAttribute | SizeAttribute | ExistsAttribute,
// Times
CreationTime = 0x01000000, // Note: overlaps with QAbstractFileEngine::Refresh
ModificationTime = 0x02000000,
AccessTime = 0x04000000,
Times = CreationTime | ModificationTime | AccessTime,
// Owner IDs
UserId = 0x10000000,
GroupId = 0x20000000,
OwnerIds = UserId | GroupId,
PosixStatFlags = QFileSystemMetaData::OtherPermissions
| QFileSystemMetaData::GroupPermissions
| QFileSystemMetaData::OwnerPermissions
| QFileSystemMetaData::FileType
| QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::SequentialType
| QFileSystemMetaData::SizeAttribute
| QFileSystemMetaData::Times
| QFileSystemMetaData::OwnerIds,
#if defined(Q_OS_WIN)
WinStatFlags = QFileSystemMetaData::FileType
| QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::HiddenAttribute
| QFileSystemMetaData::ExistsAttribute
| QFileSystemMetaData::SizeAttribute
| QFileSystemMetaData::Times,
#endif
AllMetaDataFlags = 0xFFFFFFFF
};
Q_DECLARE_FLAGS(MetaDataFlags, MetaDataFlag)
bool hasFlags(MetaDataFlags flags) const
{
return ((knownFlagsMask & flags) == flags);
}
MetaDataFlags missingFlags(MetaDataFlags flags)
{
return flags & ~knownFlagsMask;
}
void clear()
{
knownFlagsMask = 0;
}
void clearFlags(MetaDataFlags flags = AllMetaDataFlags)
{
knownFlagsMask &= ~flags;
}
bool exists() const { return (entryFlags & ExistsAttribute); }
bool isLink() const { return (entryFlags & LinkType); }
bool isFile() const { return (entryFlags & FileType); }
bool isDirectory() const { return (entryFlags & DirectoryType); }
bool isBundle() const;
bool isAlias() const;
bool isLegacyLink() const { return (entryFlags & LegacyLinkType); }
bool isSequential() const { return (entryFlags & SequentialType); }
bool isHidden() const { return (entryFlags & HiddenAttribute); }
#if defined(Q_OS_WIN)
bool isLnkFile() const { return (entryFlags & WinLnkType); }
#else
bool isLnkFile() const { return false; }
#endif
qint64 size() const { return size_; }
QFile::Permissions permissions() const { return QFile::Permissions(Permissions & entryFlags); }
QDateTime creationTime() const;
QDateTime modificationTime() const;
QDateTime accessTime() const;
QDateTime fileTime(QAbstractFileEngine::FileTime time) const;
uint userId() const;
uint groupId() const;
uint ownerId(QAbstractFileEngine::FileOwner owner) const;
#ifdef Q_OS_UNIX
void fillFromStatBuf(const QT_STATBUF &statBuffer);
void fillFromDirEnt(const QT_DIRENT &statBuffer);
#endif
#if defined(Q_OS_WIN)
inline void fillFromFileAttribute(DWORD fileAttribute, bool isDriveRoot = false);
inline void fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType = false, bool isDriveRoot = false);
inline void fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo);
#endif
private:
friend class QFileSystemEngine;
MetaDataFlags knownFlagsMask;
MetaDataFlags entryFlags;
qint64 size_;
// Platform-specific data goes here:
#if defined(Q_OS_WIN)
DWORD fileAttribute_;
FILETIME creationTime_;
FILETIME lastAccessTime_;
FILETIME lastWriteTime_;
#else
time_t creationTime_;
time_t modificationTime_;
time_t accessTime_;
uint userId_;
uint groupId_;
#endif
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags)
#if defined(Q_OS_MACX)
inline bool QFileSystemMetaData::isBundle() const { return (entryFlags & BundleType); }
inline bool QFileSystemMetaData::isAlias() const { return (entryFlags & AliasType); }
#else
inline bool QFileSystemMetaData::isBundle() const { return false; }
inline bool QFileSystemMetaData::isAlias() const { return false; }
#endif
#if defined(Q_OS_UNIX) || defined (Q_OS_WIN)
inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const
{
switch (time) {
case QAbstractFileEngine::ModificationTime:
return modificationTime();
case QAbstractFileEngine::AccessTime:
return accessTime();
case QAbstractFileEngine::CreationTime:
return creationTime();
}
return QDateTime();
}
#endif
#if defined(Q_OS_UNIX)
inline QDateTime QFileSystemMetaData::creationTime() const { return QDateTime::fromTime_t(creationTime_); }
inline QDateTime QFileSystemMetaData::modificationTime() const { return QDateTime::fromTime_t(modificationTime_); }
inline QDateTime QFileSystemMetaData::accessTime() const { return QDateTime::fromTime_t(accessTime_); }
inline uint QFileSystemMetaData::userId() const { return userId_; }
inline uint QFileSystemMetaData::groupId() const { return groupId_; }
inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const
{
if (owner == QAbstractFileEngine::OwnerUser)
return userId();
else
return groupId();
}
#endif
#if defined(Q_OS_WIN)
inline uint QFileSystemMetaData::userId() const { return (uint) -2; }
inline uint QFileSystemMetaData::groupId() const { return (uint) -2; }
inline uint QFileSystemMetaData::ownerId(QAbstractFileEngine::FileOwner owner) const
{
if (owner == QAbstractFileEngine::OwnerUser)
return userId();
else
return groupId();
}
inline void QFileSystemMetaData::fillFromFileAttribute(DWORD fileAttribute,bool isDriveRoot)
{
fileAttribute_ = fileAttribute;
// Ignore the hidden attribute for drives.
if (!isDriveRoot && (fileAttribute_ & FILE_ATTRIBUTE_HIDDEN))
entryFlags |= HiddenAttribute;
entryFlags |= ((fileAttribute & FILE_ATTRIBUTE_DIRECTORY) ? DirectoryType: FileType);
entryFlags |= ExistsAttribute;
knownFlagsMask |= FileType | DirectoryType | HiddenAttribute | ExistsAttribute;
}
inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType, bool isDriveRoot)
{
fillFromFileAttribute(findData.dwFileAttributes, isDriveRoot);
creationTime_ = findData.ftCreationTime;
lastAccessTime_ = findData.ftLastAccessTime;
lastWriteTime_ = findData.ftLastWriteTime;
if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
size_ = 0;
} else {
size_ = findData.nFileSizeHigh;
size_ <<= 32;
size_ += findData.nFileSizeLow;
}
knownFlagsMask |= Times | SizeAttribute;
if (setLinkType) {
knownFlagsMask |= LinkType;
entryFlags &= ~LinkType;
#if !defined(Q_OS_WINCE)
if ((fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT)
&& (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
entryFlags |= LinkType;
}
#endif
}
}
inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo)
{
fillFromFileAttribute(fileInfo.dwFileAttributes);
creationTime_ = fileInfo.ftCreationTime;
lastAccessTime_ = fileInfo.ftLastAccessTime;
lastWriteTime_ = fileInfo.ftLastWriteTime;
if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
size_ = 0;
} else {
size_ = fileInfo.nFileSizeHigh;
size_ <<= 32;
size_ += fileInfo.nFileSizeLow;
}
knownFlagsMask |= Times | SizeAttribute;
}
#endif
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // include guard

View File

@ -0,0 +1,942 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qfsfileengine_p.h"
#include "qfsfileengine_iterator_p.h"
#include "qfilesystemengine_p.h"
#include <QDateTime>
#include <QDirIterator>
#include <QSet>
#include <QDebug>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef QT_NO_FSFILEENGINE
#if !defined(Q_OS_WINCE)
#include <errno.h>
#endif
#if defined(Q_OS_UNIX)
#include "qcore_unix_p.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#if defined(Q_OS_MAC)
# include "qcore_mac_p.h"
#endif
#ifdef Q_OS_WIN
# ifndef S_ISREG
# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
# endif
# ifndef S_ISCHR
# define S_ISCHR(x) (((x) & S_IFMT) == S_IFCHR)
# endif
# ifndef S_ISFIFO
# define S_ISFIFO(x) false
# endif
# ifndef S_ISSOCK
# define S_ISSOCK(x) false
# endif
# ifndef INVALID_FILE_ATTRIBUTES
# define INVALID_FILE_ATTRIBUTES (DWORD (-1))
# endif
#endif
/*! \class QFSFileEngine
\inmodule QtCore
\brief The QFSFileEngine class implements Qt's default file engine.
\since 4.1
\internal
This class is part of the file engine framework in Qt. If you only want to
access files or directories, use QFile, QFileInfo or QDir instead.
QFSFileEngine is the default file engine for accessing regular files. It
is provided for convenience; by subclassing this class, you can alter its
behavior slightly, without having to write a complete QAbstractFileEngine
subclass. To install your custom file engine, you must also subclass
QAbstractFileEngineHandler and create an instance of your handler.
It can also be useful to create a QFSFileEngine object directly if you
need to use the local file system inside QAbstractFileEngine::create(), in
order to avoid recursion (as higher-level classes tend to call
QAbstractFileEngine::create()).
*/
//**************** QFSFileEnginePrivate
QFSFileEnginePrivate::QFSFileEnginePrivate() : QAbstractFileEnginePrivate()
{
init();
}
/*!
\internal
*/
void QFSFileEnginePrivate::init()
{
is_sequential = 0;
tried_stat = 0;
#if !defined(Q_OS_WINCE)
need_lstat = 1;
is_link = 0;
#endif
openMode = QIODevice::NotOpen;
fd = -1;
fh = 0;
lastIOCommand = IOFlushCommand;
lastFlushFailed = false;
closeFileHandle = false;
#ifdef Q_OS_WIN
fileAttrib = INVALID_FILE_ATTRIBUTES;
fileHandle = INVALID_HANDLE_VALUE;
mapHandle = NULL;
#ifndef Q_OS_WINCE
cachedFd = -1;
#endif
#endif
}
/*!
Constructs a QFSFileEngine for the file name \a file.
*/
QFSFileEngine::QFSFileEngine(const QString &file)
: QAbstractFileEngine(*new QFSFileEnginePrivate)
{
Q_D(QFSFileEngine);
d->fileEntry = QFileSystemEntry(file);
}
/*!
Constructs a QFSFileEngine.
*/
QFSFileEngine::QFSFileEngine() : QAbstractFileEngine(*new QFSFileEnginePrivate)
{
}
/*!
\internal
*/
QFSFileEngine::QFSFileEngine(QFSFileEnginePrivate &dd)
: QAbstractFileEngine(dd)
{
}
/*!
Destructs the QFSFileEngine.
*/
QFSFileEngine::~QFSFileEngine()
{
Q_D(QFSFileEngine);
if (d->closeFileHandle) {
if (d->fh) {
int ret;
do {
ret = fclose(d->fh);
} while (ret == EOF && errno == EINTR);
} else if (d->fd != -1) {
int ret;
do {
ret = QT_CLOSE(d->fd);
} while (ret == -1 && errno == EINTR);
}
}
QList<uchar*> keys = d->maps.keys();
for (int i = 0; i < keys.count(); ++i)
unmap(keys.at(i));
}
/*!
\reimp
*/
void QFSFileEngine::setFileName(const QString &file)
{
Q_D(QFSFileEngine);
d->init();
d->fileEntry = QFileSystemEntry(file);
}
/*!
\reimp
*/
bool QFSFileEngine::open(QIODevice::OpenMode openMode)
{
Q_D(QFSFileEngine);
if (d->fileEntry.isEmpty()) {
qWarning("QFSFileEngine::open: No file name specified");
setError(QFile::OpenError, QLatin1String("No file name specified"));
return false;
}
// Append implies WriteOnly.
if (openMode & QFile::Append)
openMode |= QFile::WriteOnly;
// WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
openMode |= QFile::Truncate;
d->openMode = openMode;
d->lastFlushFailed = false;
d->tried_stat = 0;
d->fh = 0;
d->fd = -1;
return d->nativeOpen(openMode);
}
/*!
Opens the file handle \a fh in \a openMode mode. Returns \c true on
success; otherwise returns \c false.
*/
bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh)
{
return open(openMode, fh, QFile::DontCloseHandle);
}
bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHandleFlags handleFlags)
{
Q_D(QFSFileEngine);
// Append implies WriteOnly.
if (openMode & QFile::Append)
openMode |= QFile::WriteOnly;
// WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
openMode |= QFile::Truncate;
d->openMode = openMode;
d->lastFlushFailed = false;
d->closeFileHandle = (handleFlags & QFile::AutoCloseHandle);
d->fileEntry.clear();
d->tried_stat = 0;
d->fd = -1;
return d->openFh(openMode, fh);
}
/*!
Opens the file handle \a fh using the open mode \a flags.
*/
bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
{
Q_Q(QFSFileEngine);
this->fh = fh;
fd = -1;
// Seek to the end when in Append mode.
if (openMode & QIODevice::Append) {
int ret;
do {
ret = QT_FSEEK(fh, 0, SEEK_END);
} while (ret != 0 && errno == EINTR);
if (ret != 0) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
qt_error_string(int(errno)));
this->openMode = QIODevice::NotOpen;
this->fh = 0;
return false;
}
}
return true;
}
/*!
Opens the file descriptor \a fd in \a openMode mode. Returns \c true
on success; otherwise returns \c false.
*/
bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd)
{
return open(openMode, fd, QFile::DontCloseHandle);
}
bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd, QFile::FileHandleFlags handleFlags)
{
Q_D(QFSFileEngine);
// Append implies WriteOnly.
if (openMode & QFile::Append)
openMode |= QFile::WriteOnly;
// WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
openMode |= QFile::Truncate;
d->openMode = openMode;
d->lastFlushFailed = false;
d->closeFileHandle = (handleFlags & QFile::AutoCloseHandle);
d->fileEntry.clear();
d->fh = 0;
d->fd = -1;
d->tried_stat = 0;
return d->openFd(openMode, fd);
}
/*!
Opens the file descriptor \a fd to the file engine, using the open mode \a
flags.
*/
bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
{
Q_Q(QFSFileEngine);
this->fd = fd;
fh = 0;
// Seek to the end when in Append mode.
if (openMode & QFile::Append) {
int ret;
do {
ret = QT_LSEEK(fd, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
qt_error_string(int(errno)));
this->openMode = QIODevice::NotOpen;
this->fd = -1;
return false;
}
}
return true;
}
/*!
\reimp
*/
bool QFSFileEngine::close()
{
Q_D(QFSFileEngine);
d->openMode = QIODevice::NotOpen;
return d->nativeClose();
}
/*!
\internal
*/
bool QFSFileEnginePrivate::closeFdFh()
{
Q_Q(QFSFileEngine);
if (fd == -1 && !fh)
return false;
// Flush the file if it's buffered, and if the last flush didn't fail.
bool flushed = !fh || (!lastFlushFailed && q->flush());
bool closed = true;
tried_stat = 0;
// Close the file if we created the handle.
if (closeFileHandle) {
int ret;
do {
if (fh) {
// Close buffered file.
ret = fclose(fh) != 0 ? -1 : 0;
} else {
// Close unbuffered file.
ret = QT_CLOSE(fd);
}
} while (ret == -1 && errno == EINTR);
// We must reset these guys regardless; calling close again after a
// failed close causes crashes on some systems.
fh = 0;
fd = -1;
closed = (ret == 0);
}
// Report errors.
if (!flushed || !closed) {
if (flushed) {
// If not flushed, we want the flush error to fall through.
q->setError(QFile::UnspecifiedError, qt_error_string(errno));
}
return false;
}
return true;
}
/*!
\reimp
*/
bool QFSFileEngine::flush()
{
Q_D(QFSFileEngine);
if ((d->openMode & QIODevice::WriteOnly) == 0) {
// Nothing in the write buffers, so flush succeeds in doing
// nothing.
return true;
}
return d->nativeFlush();
}
/*!
\reimp
*/
bool QFSFileEngine::syncToDisk()
{
Q_D(QFSFileEngine);
if ((d->openMode & QIODevice::WriteOnly) == 0)
return true;
return d->nativeSyncToDisk();
}
/*!
\internal
*/
bool QFSFileEnginePrivate::flushFh()
{
Q_Q(QFSFileEngine);
// Never try to flush again if the last flush failed. Otherwise you can
// get crashes on some systems (AIX).
if (lastFlushFailed)
return false;
int ret = fflush(fh);
lastFlushFailed = (ret != 0);
lastIOCommand = QFSFileEnginePrivate::IOFlushCommand;
if (ret != 0) {
q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
qt_error_string(errno));
return false;
}
return true;
}
/*!
\reimp
*/
qint64 QFSFileEngine::size() const
{
Q_D(const QFSFileEngine);
return d->nativeSize();
}
#ifndef Q_OS_WIN
/*!
\internal
*/
qint64 QFSFileEnginePrivate::sizeFdFh() const
{
Q_Q(const QFSFileEngine);
const_cast<QFSFileEngine *>(q)->flush();
tried_stat = 0;
metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
if (!doStat(QFileSystemMetaData::SizeAttribute))
return 0;
return metaData.size();
}
#endif
/*!
\reimp
*/
qint64 QFSFileEngine::pos() const
{
Q_D(const QFSFileEngine);
return d->nativePos();
}
/*!
\internal
*/
qint64 QFSFileEnginePrivate::posFdFh() const
{
if (fh)
return qint64(QT_FTELL(fh));
return QT_LSEEK(fd, 0, SEEK_CUR);
}
/*!
\reimp
*/
bool QFSFileEngine::seek(qint64 pos)
{
Q_D(QFSFileEngine);
return d->nativeSeek(pos);
}
/*!
\internal
*/
bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
{
Q_Q(QFSFileEngine);
// On Windows' stdlib implementation, the results of calling fread and
// fwrite are undefined if not called either in sequence, or if preceded
// with a call to fflush().
if (lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush())
return false;
if (pos < 0 || pos != qint64(QT_OFF_T(pos)))
return false;
if (fh) {
// Buffered stdlib mode.
int ret;
do {
ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET);
} while (ret != 0 && errno == EINTR);
if (ret != 0) {
q->setError(QFile::ReadError, qt_error_string(int(errno)));
return false;
}
} else {
// Unbuffered stdio mode.
if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) {
qWarning() << "QFile::at: Cannot set file position" << pos;
q->setError(QFile::PositionError, qt_error_string(errno));
return false;
}
}
return true;
}
/*!
\reimp
*/
int QFSFileEngine::handle() const
{
Q_D(const QFSFileEngine);
return d->nativeHandle();
}
/*!
\reimp
*/
qint64 QFSFileEngine::read(char *data, qint64 maxlen)
{
Q_D(QFSFileEngine);
// On Windows' stdlib implementation, the results of calling fread and
// fwrite are undefined if not called either in sequence, or if preceded
// with a call to fflush().
if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
flush();
d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
}
return d->nativeRead(data, maxlen);
}
/*!
\internal
*/
qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
{
Q_Q(QFSFileEngine);
if (len < 0 || len != qint64(size_t(len))) {
q->setError(QFile::ReadError, qt_error_string(EINVAL));
return -1;
}
qint64 readBytes = 0;
bool eof = false;
if (fh) {
// Buffered stdlib mode.
size_t result;
bool retry = true;
do {
result = fread(data + readBytes, 1, size_t(len - readBytes), fh);
eof = feof(fh);
if (retry && eof && result == 0) {
// On Mac OS, this is needed, e.g., if a file was written to
// through another stream since our last read. See test
// tst_QFile::appendAndRead
QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream.
retry = false;
continue;
}
readBytes += result;
} while (!eof && (result == 0 ? errno == EINTR : readBytes < len));
} else if (fd != -1) {
// Unbuffered stdio mode.
#ifdef Q_OS_WIN
int result;
#else
ssize_t result;
#endif
do {
result = QT_READ(fd, data + readBytes, size_t(len - readBytes));
} while ((result == -1 && errno == EINTR)
|| (result > 0 && (readBytes += result) < len));
eof = !(result == -1);
}
if (!eof && readBytes == 0) {
readBytes = -1;
q->setError(QFile::ReadError, qt_error_string(errno));
}
return readBytes;
}
/*!
\reimp
*/
qint64 QFSFileEngine::readLine(char *data, qint64 maxlen)
{
Q_D(QFSFileEngine);
// On Windows' stdlib implementation, the results of calling fread and
// fwrite are undefined if not called either in sequence, or if preceded
// with a call to fflush().
if (d->lastIOCommand != QFSFileEnginePrivate::IOReadCommand) {
flush();
d->lastIOCommand = QFSFileEnginePrivate::IOReadCommand;
}
return d->nativeReadLine(data, maxlen);
}
/*!
\internal
*/
qint64 QFSFileEnginePrivate::readLineFdFh(char *data, qint64 maxlen)
{
Q_Q(QFSFileEngine);
if (!fh)
return q->QAbstractFileEngine::readLine(data, maxlen);
QT_OFF_T oldPos = 0;
#ifdef Q_OS_WIN
bool seq = q->isSequential();
if (!seq)
#endif
oldPos = QT_FTELL(fh);
// QIODevice::readLine() passes maxlen - 1 to QFile::readLineData()
// because it has made space for the '\0' at the end of data. But fgets
// does the same, so we'd get two '\0' at the end - passing maxlen + 1
// solves this.
if (!fgets(data, int(maxlen + 1), fh)) {
if (!feof(fh))
q->setError(QFile::ReadError, qt_error_string(int(errno)));
return -1; // error
}
#ifdef Q_OS_WIN
if (seq)
return qstrlen(data);
#endif
qint64 lineLength = QT_FTELL(fh) - oldPos;
return lineLength > 0 ? lineLength : qstrlen(data);
}
/*!
\reimp
*/
qint64 QFSFileEngine::write(const char *data, qint64 len)
{
Q_D(QFSFileEngine);
// On Windows' stdlib implementation, the results of calling fread and
// fwrite are undefined if not called either in sequence, or if preceded
// with a call to fflush().
if (d->lastIOCommand != QFSFileEnginePrivate::IOWriteCommand) {
flush();
d->lastIOCommand = QFSFileEnginePrivate::IOWriteCommand;
}
return d->nativeWrite(data, len);
}
/*!
\internal
*/
qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
{
Q_Q(QFSFileEngine);
if (len < 0 || len != qint64(size_t(len))) {
q->setError(QFile::WriteError, qt_error_string(EINVAL));
return -1;
}
qint64 writtenBytes = 0;
if (fh) {
// Buffered stdlib mode.
size_t result;
do {
result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh);
writtenBytes += result;
} while (result == 0 ? errno == EINTR : writtenBytes < len);
} else if (fd != -1) {
// Unbuffered stdio mode.
#ifdef Q_OS_WIN
int result;
#else
ssize_t result;
#endif
do {
result = QT_WRITE(fd, data + writtenBytes, size_t(len - writtenBytes));
} while ((result == -1 && errno == EINTR)
|| (result > 0 && (writtenBytes += result) < len));
}
if (len && writtenBytes == 0) {
writtenBytes = -1;
q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno));
}
return writtenBytes;
}
#ifndef QT_NO_FILESYSTEMITERATOR
/*!
\internal
*/
QAbstractFileEngine::Iterator *QFSFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
{
return new QFSFileEngineIterator(filters, filterNames);
}
/*!
\internal
*/
QAbstractFileEngine::Iterator *QFSFileEngine::endEntryList()
{
return 0;
}
#endif // QT_NO_FILESYSTEMITERATOR
/*!
\internal
*/
QStringList QFSFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
{
return QAbstractFileEngine::entryList(filters, filterNames);
}
/*!
\reimp
*/
bool QFSFileEngine::isSequential() const
{
Q_D(const QFSFileEngine);
if (d->is_sequential == 0)
d->is_sequential = d->nativeIsSequential() ? 1 : 2;
return d->is_sequential == 1;
}
/*!
\internal
*/
#ifdef Q_OS_UNIX
bool QFSFileEnginePrivate::isSequentialFdFh() const
{
if (doStat(QFileSystemMetaData::SequentialType))
return metaData.isSequential();
return true;
}
#endif
/*!
\reimp
*/
bool QFSFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
{
Q_D(QFSFileEngine);
if (extension == AtEndExtension && d->fh && isSequential())
return feof(d->fh);
if (extension == MapExtension) {
const MapExtensionOption *options = (MapExtensionOption*)(option);
MapExtensionReturn *returnValue = static_cast<MapExtensionReturn*>(output);
returnValue->address = d->map(options->offset, options->size, options->flags);
return (returnValue->address != 0);
}
if (extension == UnMapExtension) {
UnMapExtensionOption *options = (UnMapExtensionOption*)option;
return d->unmap(options->address);
}
return false;
}
/*!
\reimp
*/
bool QFSFileEngine::supportsExtension(Extension extension) const
{
Q_D(const QFSFileEngine);
if (extension == AtEndExtension && d->fh && isSequential())
return true;
if (extension == FastReadLineExtension && d->fh)
return true;
if (extension == FastReadLineExtension && d->fd != -1 && isSequential())
return true;
if (extension == UnMapExtension || extension == MapExtension)
return true;
return false;
}
/*! \fn bool QFSFileEngine::caseSensitive() const
Returns \c true for Windows, false for Unix.
*/
/*! \fn bool QFSFileEngine::copy(const QString &copyName)
For windows, copy the file to file \a copyName.
Not implemented for Unix.
*/
/*! \fn QString QFSFileEngine::currentPath(const QString &fileName)
For Unix, returns the current working directory for the file
engine.
For Windows, returns the canonicalized form of the current path used
by the file engine for the drive specified by \a fileName. On
Windows, each drive has its own current directory, so a different
path is returned for file names that include different drive names
(e.g. A: or C:).
\sa setCurrentPath()
*/
/*! \fn QFileInfoList QFSFileEngine::drives()
For Windows, returns the list of drives in the file system as a list
of QFileInfo objects. On unix, Mac OS X and Windows CE, only the
root path is returned. On Windows, this function returns all drives
(A:\, C:\, D:\, etc.).
For Unix, the list contains just the root path "/".
*/
/*! \fn QString QFSFileEngine::fileName(FileName file) const
\reimp
*/
/*! \fn QDateTime QFSFileEngine::fileTime(FileTime time) const
\reimp
*/
/*! \fn QString QFSFileEngine::homePath()
Returns the home path of the current user.
\sa rootPath()
*/
/*! \fn bool QFSFileEngine::isRelativePath() const
\reimp
*/
/*! \fn bool QFSFileEngine::link(const QString &newName)
Creates a link from the file currently specified by fileName() to
\a newName. What a link is depends on the underlying filesystem
(be it a shortcut on Windows or a symbolic link on Unix). Returns
true if successful; otherwise returns \c false.
*/
/*! \fn bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
\reimp
*/
/*! \fn uint QFSFileEngine::ownerId(FileOwner own) const
In Unix, if stat() is successful, the \c uid is returned if
\a own is the owner. Otherwise the \c gid is returned. If stat()
is unsuccessful, -2 is reuturned.
For Windows, -2 is always returned.
*/
/*! \fn QString QFSFileEngine::owner(FileOwner own) const
\reimp
*/
/*! \fn bool QFSFileEngine::remove()
\reimp
*/
/*! \fn bool QFSFileEngine::rename(const QString &newName)
\reimp
*/
/*! \fn bool QFSFileEngine::renameOverwrite(const QString &newName)
\reimp
*/
/*! \fn bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
\reimp
*/
/*! \fn QString QFSFileEngine::rootPath()
Returns the root path.
\sa homePath()
*/
/*! \fn bool QFSFileEngine::setCurrentPath(const QString &path)
Sets the current path (e.g., for QDir), to \a path. Returns \c true if the
new path exists; otherwise this function does nothing, and returns \c false.
\sa currentPath()
*/
/*! \fn bool QFSFileEngine::setPermissions(uint perms)
\reimp
*/
/*! \fn bool QFSFileEngine::setSize(qint64 size)
\reimp
*/
/*! \fn QString QFSFileEngine::tempPath()
Returns the temporary path (i.e., a path in which it is safe
to store temporary files).
*/
/*! \fn QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const
\internal
*/
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QT_NO_FSFILEENGINE

View File

@ -0,0 +1,85 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qfsfileengine_iterator_p.h"
#include "qfileinfo_p.h"
#include <QVariant>
#ifndef QT_NO_FILESYSTEMITERATOR
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
QFSFileEngineIterator::QFSFileEngineIterator(QDir::Filters filters, const QStringList &filterNames)
: QAbstractFileEngineIterator(filters, filterNames)
, done(false)
{
}
QFSFileEngineIterator::~QFSFileEngineIterator()
{
}
bool QFSFileEngineIterator::hasNext() const
{
if (!done && !nativeIterator) {
nativeIterator.reset(new QFileSystemIterator(QFileSystemEntry(path()),
filters(), nameFilters()));
advance();
}
return !done;
}
QString QFSFileEngineIterator::next()
{
if (!hasNext())
return QString();
advance();
return currentFilePath();
}
void QFSFileEngineIterator::advance() const
{
currentInfo = nextInfo;
QFileSystemEntry entry;
QFileSystemMetaData data;
if (nativeIterator->advance(entry, data)) {
nextInfo = QFileInfo(new QFileInfoPrivate(entry, data));
} else {
done = true;
nativeIterator.reset();
}
}
QString QFSFileEngineIterator::currentFileName() const
{
return currentInfo.fileName();
}
QFileInfo QFSFileEngineIterator::currentFileInfo() const
{
return currentInfo;
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QT_NO_FILESYSTEMITERATOR

View File

@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QFSFILEENGINE_ITERATOR_P_H
#define QFSFILEENGINE_ITERATOR_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 "qabstractfileengine_p.h"
#include "qfilesystemiterator_p.h"
#include <QDir>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef QT_NO_FILESYSTEMITERATOR
class QFSFileEngineIteratorPrivate;
class QFSFileEngineIteratorPlatformSpecificData;
class QFSFileEngineIterator : public QAbstractFileEngineIterator
{
public:
QFSFileEngineIterator(QDir::Filters filters, const QStringList &filterNames);
~QFSFileEngineIterator();
QString next();
bool hasNext() const;
QString currentFileName() const;
QFileInfo currentFileInfo() const;
private:
void advance() const;
mutable QScopedPointer<QFileSystemIterator> nativeIterator;
mutable QFileInfo currentInfo;
mutable QFileInfo nextInfo;
mutable bool done;
};
#endif // QT_NO_FILESYSTEMITERATOR
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QFSFILEENGINE_ITERATOR_P_H

View File

@ -0,0 +1,218 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QFSFILEENGINE_P_H
#define QFSFILEENGINE_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 "qplatformdefs.h"
#include "qabstractfileengine_p.h"
#include "qfilesystementry_p.h"
#include "qfilesystemmetadata_p.h"
#include <QHash>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef QT_NO_FSFILEENGINE
#if defined(Q_OS_WINCE_STD) && _WIN32_WCE < 0x600
#define Q_USE_DEPRECATED_MAP_API 1
#endif
class QFSFileEnginePrivate;
class QFSFileEngine : public QAbstractFileEngine
{
Q_DECLARE_PRIVATE(QFSFileEngine)
public:
QFSFileEngine();
explicit QFSFileEngine(const QString &file);
~QFSFileEngine();
bool open(QIODevice::OpenMode openMode);
bool open(QIODevice::OpenMode flags, FILE *fh);
bool close();
bool flush();
bool syncToDisk();
qint64 size() const;
qint64 pos() const;
bool seek(qint64);
bool isSequential() const;
bool remove();
bool copy(const QString &newName);
bool rename(const QString &newName);
bool renameOverwrite(const QString &newName);
bool link(const QString &newName);
bool mkdir(const QString &dirName, bool createParentDirectories) const;
bool rmdir(const QString &dirName, bool recurseParentDirectories) const;
bool setSize(qint64 size);
bool caseSensitive() const;
bool isRelativePath() const;
QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const;
FileFlags fileFlags(FileFlags type) const;
bool setPermissions(uint perms);
QString fileName(FileName file) const;
uint ownerId(FileOwner) const;
QString owner(FileOwner) const;
QDateTime fileTime(FileTime time) const;
void setFileName(const QString &file);
int handle() const;
#ifndef QT_NO_FILESYSTEMITERATOR
Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames);
Iterator *endEntryList();
#endif
qint64 read(char *data, qint64 maxlen);
qint64 readLine(char *data, qint64 maxlen);
qint64 write(const char *data, qint64 len);
bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0);
bool supportsExtension(Extension extension) const;
//FS only!!
bool open(QIODevice::OpenMode flags, int fd);
bool open(QIODevice::OpenMode flags, int fd, QFile::FileHandleFlags handleFlags);
bool open(QIODevice::OpenMode flags, FILE *fh, QFile::FileHandleFlags handleFlags);
static bool setCurrentPath(const QString &path);
static QString currentPath(const QString &path = QString());
static QString homePath();
static QString rootPath();
static QString tempPath();
static QFileInfoList drives();
protected:
QFSFileEngine(QFSFileEnginePrivate &dd);
};
class QFSFileEnginePrivate : public QAbstractFileEnginePrivate
{
Q_DECLARE_PUBLIC(QFSFileEngine)
public:
#ifdef Q_OS_WIN
static QString longFileName(const QString &path);
#endif
QFileSystemEntry fileEntry;
QIODevice::OpenMode openMode;
bool nativeOpen(QIODevice::OpenMode openMode);
bool openFh(QIODevice::OpenMode flags, FILE *fh);
bool openFd(QIODevice::OpenMode flags, int fd);
bool nativeClose();
bool closeFdFh();
bool nativeFlush();
bool nativeSyncToDisk();
bool flushFh();
qint64 nativeSize() const;
#ifndef Q_OS_WIN
qint64 sizeFdFh() const;
#endif
qint64 nativePos() const;
qint64 posFdFh() const;
bool nativeSeek(qint64);
bool seekFdFh(qint64);
qint64 nativeRead(char *data, qint64 maxlen);
qint64 readFdFh(char *data, qint64 maxlen);
qint64 nativeReadLine(char *data, qint64 maxlen);
qint64 readLineFdFh(char *data, qint64 maxlen);
qint64 nativeWrite(const char *data, qint64 len);
qint64 writeFdFh(const char *data, qint64 len);
int nativeHandle() const;
bool nativeIsSequential() const;
#ifndef Q_OS_WIN
bool isSequentialFdFh() const;
#endif
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
mutable QFileSystemMetaData metaData;
FILE *fh;
#ifdef Q_OS_WIN
HANDLE fileHandle;
HANDLE mapHandle;
QHash<uchar *, DWORD /* offset % AllocationGranularity */> maps;
#ifndef Q_OS_WINCE
mutable int cachedFd;
#endif
mutable DWORD fileAttrib;
#else
QHash<uchar *, QPair<int /*offset % PageSize*/, size_t /*length + offset % PageSize*/> > maps;
#endif
int fd;
enum LastIOCommand
{
IOFlushCommand,
IOReadCommand,
IOWriteCommand
};
LastIOCommand lastIOCommand;
bool lastFlushFailed;
bool closeFileHandle;
mutable uint is_sequential : 2;
mutable uint could_stat : 1;
mutable uint tried_stat : 1;
#if !defined(Q_OS_WINCE)
mutable uint need_lstat : 1;
mutable uint is_link : 1;
#endif
#if defined(Q_OS_WIN)
bool doStat(QFileSystemMetaData::MetaDataFlags flags) const;
#else
bool doStat(QFileSystemMetaData::MetaDataFlags flags = QFileSystemMetaData::PosixStatFlags) const;
#endif
bool isSymlink() const;
#if defined(Q_OS_WIN32)
int sysOpen(const QString &, int flags);
#endif
protected:
QFSFileEnginePrivate();
void init();
QAbstractFileEngine::FileFlags getPermissions(QAbstractFileEngine::FileFlags type) const;
};
#endif // QT_NO_FSFILEENGINE
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QFSFILEENGINE_P_H

View File

@ -0,0 +1,749 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qplatformdefs.h"
#include "qabstractfileengine_p.h"
#include "qfsfileengine_p.h"
#include "qcore_unix_p.h"
#include "qfilesystementry_p.h"
#include "qfilesystemengine_p.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef QT_NO_FSFILEENGINE
#include <QFile>
#include <QDir>
#include <QDateTime>
#include <QVarLengthArray>
#include <sys/mman.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#if !defined(QWS) && defined(Q_OS_MAC)
# include "qcore_mac_p.h"
#endif
/*!
\internal
Returns the stdlib open string corresponding to a QIODevice::OpenMode.
*/
static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QFileSystemEntry &fileEntry,
QFileSystemMetaData &metaData)
{
QByteArray mode;
if ((flags & QIODevice::ReadOnly) && !(flags & QIODevice::Truncate)) {
mode = "rb";
if (flags & QIODevice::WriteOnly) {
metaData.clearFlags(QFileSystemMetaData::FileType);
if (!fileEntry.isEmpty()
&& QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::FileType)
&& metaData.isFile()) {
mode += '+';
} else {
mode = "wb+";
}
}
} else if (flags & QIODevice::WriteOnly) {
mode = "wb";
if (flags & QIODevice::ReadOnly)
mode += '+';
}
if (flags & QIODevice::Append) {
mode = "ab";
if (flags & QIODevice::ReadOnly)
mode += '+';
}
#if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0207
// must be glibc >= 2.7
mode += 'e';
#endif
return mode;
}
/*!
\internal
Returns the stdio open flags corresponding to a QIODevice::OpenMode.
*/
static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
{
int oflags = QT_OPEN_RDONLY;
#ifdef QT_LARGEFILE_SUPPORT
oflags |= QT_OPEN_LARGEFILE;
#endif
if ((mode & QFile::ReadWrite) == QFile::ReadWrite) {
oflags = QT_OPEN_RDWR | QT_OPEN_CREAT;
} else if (mode & QFile::WriteOnly) {
oflags = QT_OPEN_WRONLY | QT_OPEN_CREAT;
}
if (mode & QFile::Append) {
oflags |= QT_OPEN_APPEND;
} else if (mode & QFile::WriteOnly) {
if ((mode & QFile::Truncate) || !(mode & QFile::ReadOnly))
oflags |= QT_OPEN_TRUNC;
}
return oflags;
}
/*!
\internal
Sets the file descriptor to close on exec. That is, the file
descriptor is not inherited by child processes.
*/
static inline bool setCloseOnExec(int fd)
{
return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1;
}
/*!
\internal
*/
bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
{
Q_Q(QFSFileEngine);
if (openMode & QIODevice::Unbuffered) {
int flags = openModeToOpenFlags(openMode);
// Try to open the file in unbuffered mode.
do {
fd = QT_OPEN(fileEntry.nativeFilePath().constData(), flags, 0666);
} while (fd == -1 && errno == EINTR);
// On failure, return and report the error.
if (fd == -1) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
qt_error_string(errno));
return false;
}
if (!(openMode & QIODevice::WriteOnly)) {
// we don't need this check if we tried to open for writing because then
// we had received EISDIR anyway.
if (QFileSystemEngine::fillMetaData(fd, metaData)
&& metaData.isDirectory()) {
q->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
QT_CLOSE(fd);
return false;
}
}
// Seek to the end when in Append mode.
if (flags & QFile::Append) {
int ret;
do {
ret = QT_LSEEK(fd, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
qt_error_string(int(errno)));
return false;
}
}
fh = 0;
} else {
QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData);
// Try to open the file in buffered mode.
do {
fh = QT_FOPEN(fileEntry.nativeFilePath().constData(), fopenMode.constData());
} while (!fh && errno == EINTR);
// On failure, return and report the error.
if (!fh) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
qt_error_string(int(errno)));
return false;
}
if (!(openMode & QIODevice::WriteOnly)) {
// we don't need this check if we tried to open for writing because then
// we had received EISDIR anyway.
if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData)
&& metaData.isDirectory()) {
q->setError(QFile::OpenError, QLatin1String("file to open is a directory"));
fclose(fh);
return false;
}
}
setCloseOnExec(fileno(fh)); // ignore failure
// Seek to the end when in Append mode.
if (openMode & QIODevice::Append) {
int ret;
do {
ret = QT_FSEEK(fh, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
qt_error_string(int(errno)));
return false;
}
}
fd = -1;
}
closeFileHandle = true;
return true;
}
/*!
\internal
*/
bool QFSFileEnginePrivate::nativeClose()
{
return closeFdFh();
}
/*!
\internal
*/
bool QFSFileEnginePrivate::nativeFlush()
{
return fh ? flushFh() : fd != -1;
}
/*!
\internal
\since 5.1
*/
bool QFSFileEnginePrivate::nativeSyncToDisk()
{
Q_Q(QFSFileEngine);
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
const int ret = fdatasync(nativeHandle());
#else
const int ret = fsync(nativeHandle());
#endif
if (ret != 0)
q->setError(QFile::WriteError, qt_error_string(errno));
return ret == 0;
}
/*!
\internal
*/
qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len)
{
Q_Q(QFSFileEngine);
if (fh && nativeIsSequential()) {
size_t readBytes = 0;
int oldFlags = fcntl(QT_FILENO(fh), F_GETFL);
for (int i = 0; i < 2; ++i) {
// Unix: Make the underlying file descriptor non-blocking
if ((oldFlags & O_NONBLOCK) == 0)
fcntl(QT_FILENO(fh), F_SETFL, oldFlags | O_NONBLOCK);
// Cross platform stdlib read
size_t read = 0;
do {
read = fread(data + readBytes, 1, size_t(len - readBytes), fh);
} while (read == 0 && !feof(fh) && errno == EINTR);
if (read > 0) {
readBytes += read;
break;
} else {
if (readBytes)
break;
readBytes = read;
}
// Unix: Restore the blocking state of the underlying socket
if ((oldFlags & O_NONBLOCK) == 0) {
fcntl(QT_FILENO(fh), F_SETFL, oldFlags);
if (readBytes == 0) {
int readByte = 0;
do {
readByte = fgetc(fh);
} while (readByte == -1 && errno == EINTR);
if (readByte != -1) {
*data = uchar(readByte);
readBytes += 1;
} else {
break;
}
}
}
}
// Unix: Restore the blocking state of the underlying socket
if ((oldFlags & O_NONBLOCK) == 0) {
fcntl(QT_FILENO(fh), F_SETFL, oldFlags);
}
if (readBytes == 0 && !feof(fh)) {
// if we didn't read anything and we're not at EOF, it must be an error
q->setError(QFile::ReadError, qt_error_string(int(errno)));
return -1;
}
return readBytes;
}
return readFdFh(data, len);
}
/*!
\internal
*/
qint64 QFSFileEnginePrivate::nativeReadLine(char *data, qint64 maxlen)
{
return readLineFdFh(data, maxlen);
}
/*!
\internal
*/
qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
{
return writeFdFh(data, len);
}
/*!
\internal
*/
qint64 QFSFileEnginePrivate::nativePos() const
{
return posFdFh();
}
/*!
\internal
*/
bool QFSFileEnginePrivate::nativeSeek(qint64 pos)
{
return seekFdFh(pos);
}
/*!
\internal
*/
int QFSFileEnginePrivate::nativeHandle() const
{
return fh ? fileno(fh) : fd;
}
/*!
\internal
*/
bool QFSFileEnginePrivate::nativeIsSequential() const
{
return isSequentialFdFh();
}
bool QFSFileEngine::remove()
{
Q_D(QFSFileEngine);
QSystemError error;
bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
d->metaData.clear();
if (!ret) {
setError(QFile::RemoveError, error.toString());
}
return ret;
}
bool QFSFileEngine::copy(const QString &newName)
{
Q_D(QFSFileEngine);
QSystemError error;
bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(newName), error);
if (!ret) {
setError(QFile::CopyError, error.toString());
}
return ret;
}
bool QFSFileEngine::renameOverwrite(const QString &newName)
{
// On Unix, rename() overwrites.
return rename(newName);
}
bool QFSFileEngine::rename(const QString &newName)
{
Q_D(QFSFileEngine);
QSystemError error;
bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
if (!ret) {
setError(QFile::RenameError, error.toString());
}
return ret;
}
bool QFSFileEngine::link(const QString &newName)
{
Q_D(QFSFileEngine);
QSystemError error;
bool ret = QFileSystemEngine::createLink(d->fileEntry, QFileSystemEntry(newName), error);
if (!ret) {
setError(QFile::RenameError, error.toString());
}
return ret;
}
qint64 QFSFileEnginePrivate::nativeSize() const
{
return sizeFdFh();
}
bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
{
return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories);
}
bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
{
return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
}
bool QFSFileEngine::caseSensitive() const
{
return true;
}
bool QFSFileEngine::setCurrentPath(const QString &path)
{
return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
}
QString QFSFileEngine::currentPath(const QString &)
{
return QFileSystemEngine::currentPath().filePath();
}
QString QFSFileEngine::homePath()
{
return QFileSystemEngine::homePath();
}
QString QFSFileEngine::rootPath()
{
return QFileSystemEngine::rootPath();
}
QString QFSFileEngine::tempPath()
{
return QFileSystemEngine::tempPath();
}
QFileInfoList QFSFileEngine::drives()
{
QFileInfoList ret;
ret.append(QFileInfo(rootPath()));
return ret;
}
bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const
{
if (!tried_stat || !metaData.hasFlags(flags)) {
tried_stat = 1;
int localFd = fd;
if (fh && fileEntry.isEmpty())
localFd = QT_FILENO(fh);
if (localFd != -1)
QFileSystemEngine::fillMetaData(localFd, metaData);
if (metaData.missingFlags(flags) && !fileEntry.isEmpty())
QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags));
}
return metaData.exists();
}
bool QFSFileEnginePrivate::isSymlink() const
{
if (!metaData.hasFlags(QFileSystemMetaData::LinkType))
QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::LinkType);
return metaData.isLink();
}
/*!
\reimp
*/
QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
{
Q_D(const QFSFileEngine);
if (type & Refresh)
d->metaData.clear();
QAbstractFileEngine::FileFlags ret = 0;
if (type & FlagsMask)
ret |= LocalDiskFlag;
bool exists;
{
QFileSystemMetaData::MetaDataFlags queryFlags = 0;
queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type))
& QFileSystemMetaData::Permissions;
if (type & TypesMask)
queryFlags |= QFileSystemMetaData::AliasType
| QFileSystemMetaData::LinkType
| QFileSystemMetaData::FileType
| QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::BundleType;
if (type & FlagsMask)
queryFlags |= QFileSystemMetaData::HiddenAttribute
| QFileSystemMetaData::ExistsAttribute;
queryFlags |= QFileSystemMetaData::LinkType;
exists = d->doStat(queryFlags);
}
if (!exists && !d->metaData.isLink())
return ret;
if (exists && (type & PermsMask))
ret |= FileFlags(uint(d->metaData.permissions()));
if (type & TypesMask) {
if (d->metaData.isAlias()) {
ret |= LinkType;
} else {
if ((type & LinkType) && d->metaData.isLink())
ret |= LinkType;
if (exists) {
if (d->metaData.isFile()) {
ret |= FileType;
} else if (d->metaData.isDirectory()) {
ret |= DirectoryType;
if ((type & BundleType) && d->metaData.isBundle())
ret |= BundleType;
}
}
}
}
if (type & FlagsMask) {
if (exists)
ret |= ExistsFlag;
if (d->fileEntry.isRoot())
ret |= RootFlag;
else if (d->metaData.isHidden())
ret |= HiddenFlag;
}
return ret;
}
QString QFSFileEngine::fileName(FileName file) const
{
Q_D(const QFSFileEngine);
if (file == BundleName) {
return QFileSystemEngine::bundleName(d->fileEntry);
} else if (file == BaseName) {
return d->fileEntry.fileName();
} else if (file == PathName) {
return d->fileEntry.path();
} else if (file == AbsoluteName || file == AbsolutePathName) {
QFileSystemEntry entry(QFileSystemEngine::absoluteName(d->fileEntry));
if (file == AbsolutePathName) {
return entry.path();
}
return entry.filePath();
} else if (file == CanonicalName || file == CanonicalPathName) {
QFileSystemEntry entry(QFileSystemEngine::canonicalName(d->fileEntry, d->metaData));
if (file == CanonicalPathName)
return entry.path();
return entry.filePath();
} else if (file == LinkName) {
if (d->isSymlink()) {
QFileSystemEntry entry = QFileSystemEngine::getLinkTarget(d->fileEntry, d->metaData);
return entry.filePath();
}
return QString();
}
return d->fileEntry.filePath();
}
bool QFSFileEngine::isRelativePath() const
{
Q_D(const QFSFileEngine);
return d->fileEntry.filePath().length() ? d->fileEntry.filePath()[0] != QLatin1Char('/') : true;
}
uint QFSFileEngine::ownerId(FileOwner own) const
{
Q_D(const QFSFileEngine);
static const uint nobodyID = (uint) -2;
if (d->doStat(QFileSystemMetaData::OwnerIds))
return d->metaData.ownerId(own);
return nobodyID;
}
QString QFSFileEngine::owner(FileOwner own) const
{
if (own == OwnerUser)
return QFileSystemEngine::resolveUserName(ownerId(own));
return QFileSystemEngine::resolveGroupName(ownerId(own));
}
bool QFSFileEngine::setPermissions(uint perms)
{
Q_D(QFSFileEngine);
QSystemError error;
if (!QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error, 0)) {
setError(QFile::PermissionsError, error.toString());
return false;
}
return true;
}
bool QFSFileEngine::setSize(qint64 size)
{
Q_D(QFSFileEngine);
bool ret = false;
if (d->fd != -1)
ret = QT_FTRUNCATE(d->fd, size) == 0;
else if (d->fh)
ret = QT_FTRUNCATE(QT_FILENO(d->fh), size) == 0;
else
ret = QT_TRUNCATE(d->fileEntry.nativeFilePath().constData(), size) == 0;
if (!ret)
setError(QFile::ResizeError, qt_error_string(errno));
return ret;
}
QDateTime QFSFileEngine::fileTime(FileTime time) const
{
Q_D(const QFSFileEngine);
if (d->doStat(QFileSystemMetaData::Times))
return d->metaData.fileTime(time);
return QDateTime();
}
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
Q_Q(QFSFileEngine);
Q_UNUSED(flags);
if (openMode == QIODevice::NotOpen) {
q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
return 0;
}
if (offset < 0 || offset != qint64(QT_OFF_T(offset))
|| size < 0 || quint64(size) > quint64(size_t(-1))) {
q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
return 0;
}
// If we know the mapping will extend beyond EOF, fail early to avoid
// undefined behavior. Otherwise, let mmap have its say.
if (doStat(QFileSystemMetaData::SizeAttribute)
&& (QT_OFF_T(size) > metaData.size() - QT_OFF_T(offset)))
qWarning("QFSFileEngine::map: Mapping a file beyond its size is not portable");
int access = 0;
if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;
#if defined(Q_OS_INTEGRITY)
int pageSize = sysconf(_SC_PAGESIZE);
#else
int pageSize = getpagesize();
#endif
int extra = offset % pageSize;
if (quint64(size + extra) > quint64((size_t)-1)) {
q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
return 0;
}
size_t realSize = (size_t)size + extra;
QT_OFF_T realOffset = QT_OFF_T(offset);
realOffset &= ~(QT_OFF_T(pageSize - 1));
void *mapAddress = QT_MMAP((void*)0, realSize,
access, MAP_SHARED, nativeHandle(), realOffset);
if (MAP_FAILED != mapAddress) {
uchar *address = extra + static_cast<uchar*>(mapAddress);
maps[address] = QPair<int,size_t>(extra, realSize);
return address;
}
switch(errno) {
case EBADF:
q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
break;
case ENFILE:
case ENOMEM:
q->setError(QFile::ResourceError, qt_error_string(int(errno)));
break;
case EINVAL:
// size are out of bounds
default:
q->setError(QFile::UnspecifiedError, qt_error_string(int(errno)));
break;
}
return 0;
}
bool QFSFileEnginePrivate::unmap(uchar *ptr)
{
#if !defined(Q_OS_INTEGRITY)
Q_Q(QFSFileEngine);
if (!maps.contains(ptr)) {
q->setError(QFile::PermissionsError, qt_error_string(EACCES));
return false;
}
uchar *start = ptr - maps[ptr].first;
size_t len = maps[ptr].second;
if (-1 == munmap(start, len)) {
q->setError(QFile::UnspecifiedError, qt_error_string(errno));
return false;
}
maps.remove(ptr);
return true;
#else
return false;
#endif
}
#endif // QT_NO_FSFILEENGINE
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

File diff suppressed because it is too large Load Diff

View File

@ -210,7 +210,7 @@ bool QLockFile::tryLock(int timeout)
if (!d->isLocked && d->isApparentlyStale()) {
// Stale lock from another thread/process
// Ensure two processes don't remove it at the same time
QLockFile rmlock(d->fileName + QLatin1String(".rmlock"));
QLockFile rmlock(d->fileName + QStringLiteral(".rmlock"));
if (rmlock.tryLock()) {
if (d->isApparentlyStale() && d->removeStaleLock())
continue;
@ -220,7 +220,7 @@ bool QLockFile::tryLock(int timeout)
}
if (timeout == 0 || (timeout > 0 && timer.hasExpired(timeout)))
return false;
QLockFileThread::msleep(sleepTime);
QThread::msleep(sleepTime);
if (sleepTime < 5 * 1000)
sleepTime *= 2;
}

View File

@ -0,0 +1,193 @@
/****************************************************************************
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qlockfile_p.h"
#include <QTemporaryFile>
#include <QCoreApplication>
#include <QFileInfo>
#include <QDebug>
#include <QDateTime>
#include "qcore_unix_p.h" // qt_safe_open
#include "qabstractfileengine_p.h"
//#include "qtemporaryfile_p.h"
#include <sys/file.h> // flock
#include <sys/types.h> // kill
#include <signal.h> // kill
#include <unistd.h> // gethostname
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
static QByteArray localHostName() // from QHostInfo::localHostName(), modified to return a QByteArray
{
QByteArray hostName(512, Qt::Uninitialized);
if (gethostname(hostName.data(), hostName.size()) == -1)
return QByteArray();
hostName.truncate(strlen(hostName.data()));
return hostName;
}
// ### merge into qt_safe_write?
static qint64 qt_write_loop(int fd, const char *data, qint64 len)
{
qint64 pos = 0;
while (pos < len) {
const qint64 ret = qt_safe_write(fd, data + pos, len - pos);
if (ret == -1) // e.g. partition full
return pos;
pos += ret;
}
return pos;
}
int QLockFilePrivate::checkFcntlWorksAfterFlock()
{
#ifndef QT_NO_TEMPORARYFILE
QTemporaryFile file;
if (!file.open())
return 0;
const int fd = file.d_func()->engine()->handle();
#if defined(LOCK_EX) && defined(LOCK_NB)
if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs
return 0;
#endif
struct flock flockData;
flockData.l_type = F_WRLCK;
flockData.l_whence = SEEK_SET;
flockData.l_start = 0;
flockData.l_len = 0; // 0 = entire file
flockData.l_pid = getpid();
if (fcntl(fd, F_SETLK, &flockData) == -1) // for networked filesystems
return 0;
return 1;
#else
return 0;
#endif
}
static QBasicAtomicInt fcntlOK = Q_BASIC_ATOMIC_INITIALIZER(-1);
/*!
\internal
Checks that the OS isn't using POSIX locks to emulate flock().
Mac OS X is one of those.
*/
static bool fcntlWorksAfterFlock()
{
int value = fcntlOK.load();
if (Q_UNLIKELY(value == -1)) {
value = QLockFilePrivate::checkFcntlWorksAfterFlock();
fcntlOK.store(value);
}
return value == 1;
}
static bool setNativeLocks(int fd)
{
#if defined(LOCK_EX) && defined(LOCK_NB)
if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs
return false;
#endif
struct flock flockData;
flockData.l_type = F_WRLCK;
flockData.l_whence = SEEK_SET;
flockData.l_start = 0;
flockData.l_len = 0; // 0 = entire file
flockData.l_pid = getpid();
if (fcntlWorksAfterFlock() && fcntl(fd, F_SETLK, &flockData) == -1) // for networked filesystems
return false;
return true;
}
QLockFile::LockError QLockFilePrivate::tryLock_sys()
{
// Assemble data, to write in a single call to write
// (otherwise we'd have to check every write call)
// Use operator% from the fast builder to avoid multiple memory allocations.
QByteArray fileData = QByteArray::number(QCoreApplication::applicationPid()) % '\n'
% qAppName().toUtf8() % '\n'
% localHostName() % '\n';
const QByteArray lockFileName = QFile::encodeName(fileName);
const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY | O_CREAT | O_EXCL, 0644);
if (fd < 0) {
switch (errno) {
case EEXIST:
return QLockFile::LockFailedError;
case EACCES:
case EROFS:
return QLockFile::PermissionError;
default:
return QLockFile::UnknownError;
}
}
// Ensure nobody else can delete the file while we have it
if (!setNativeLocks(fd))
qWarning() << "setNativeLocks failed:" << strerror(errno);
// We hold the lock, continue.
fileHandle = fd;
QLockFile::LockError error = QLockFile::NoError;
if (qt_write_loop(fd, fileData.constData(), fileData.size()) < fileData.size())
error = QLockFile::UnknownError; // partition full
return error;
}
bool QLockFilePrivate::removeStaleLock()
{
const QByteArray lockFileName = QFile::encodeName(fileName);
const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY, 0644);
if (fd < 0) // gone already?
return false;
bool success = setNativeLocks(fd) && (::unlink(lockFileName) == 0);
close(fd);
return success;
}
bool QLockFilePrivate::isApparentlyStale() const
{
qint64 pid;
QString hostname, appname;
if (!getLockInfo(&pid, &hostname, &appname))
return false;
if (hostname == QString::fromLocal8Bit(localHostName())) {
if (::kill(pid, 0) == -1 && errno == ESRCH)
return true; // PID doesn't exist anymore
}
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
return staleLockTime > 0 && age > staleLockTime;
}
void QLockFile::unlock()
{
Q_D(QLockFile);
if (!d->isLocked)
return;
close(d->fileHandle);
d->fileHandle = -1;
QFile::remove(d->fileName);
d->lockError = QLockFile::NoError;
d->isLocked = false;
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,116 @@
/****************************************************************************
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qlockfile_p.h"
#include "qfilesystementry_p.h"
#include <qt_windows.h>
#include <QCoreApplication>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
QLockFile::LockError QLockFilePrivate::tryLock_sys()
{
SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
const QFileSystemEntry fileEntry(fileName);
// When writing, allow others to read.
// When reading, QFile will allow others to read and write, all good.
// Adding FILE_SHARE_DELETE would allow forceful deletion of stale files,
// but Windows doesn't allow recreating it while this handle is open anyway,
// so this would only create confusion (can't lock, but no lock file to read from).
const DWORD dwShareMode = FILE_SHARE_READ;
HANDLE fh = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(),
GENERIC_WRITE,
dwShareMode,
&securityAtts,
CREATE_NEW, // error if already exists
FILE_ATTRIBUTE_NORMAL,
NULL);
if (fh == INVALID_HANDLE_VALUE) {
const DWORD lastError = GetLastError();
switch (lastError) {
case ERROR_SHARING_VIOLATION:
case ERROR_ALREADY_EXISTS:
case ERROR_FILE_EXISTS:
case ERROR_ACCESS_DENIED: // readonly file, or file still in use by another process. Assume the latter, since we don't create it readonly.
return QLockFile::LockFailedError;
default:
qWarning() << "Got unexpected locking error" << lastError;
return QLockFile::UnknownError;
}
}
// We hold the lock, continue.
fileHandle = fh;
// Assemble data, to write in a single call to write
// (otherwise we'd have to check every write call)
QByteArray fileData;
fileData += QByteArray::number(QCoreApplication::applicationPid());
fileData += '\n';
fileData += qAppName().toUtf8();
fileData += '\n';
//fileData += localHostname(); // gethostname requires winsock init, see QHostInfo...
fileData += '\n';
DWORD bytesWritten = 0;
QLockFile::LockError error = QLockFile::NoError;
if (!WriteFile(fh, fileData.constData(), fileData.size(), &bytesWritten, NULL) || !FlushFileBuffers(fh))
error = QLockFile::UnknownError; // partition full
return error;
}
bool QLockFilePrivate::removeStaleLock()
{
// QFile::remove fails on Windows if the other process is still using the file, so it's not stale.
return QFile::remove(fileName);
}
bool QLockFilePrivate::isApparentlyStale() const
{
qint64 pid;
QString hostname, appname;
if (!getLockInfo(&pid, &hostname, &appname))
return false;
HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!procHandle)
return true;
// We got a handle but check if process is still alive
DWORD dwR = ::WaitForSingleObject(procHandle, 0);
::CloseHandle(procHandle);
if (dwR == WAIT_TIMEOUT)
return true;
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
return staleLockTime > 0 && age > staleLockTime;
}
void QLockFile::unlock()
{
Q_D(QLockFile);
if (!d->isLocked)
return;
CloseHandle(d->fileHandle);
QFile::remove(d->fileName);
d->lockError = QLockFile::NoError;
d->isLocked = false;
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,133 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 "qatomic.h"
#include "qmutexpool_p.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef QT_NO_THREAD
Q_GLOBAL_STATIC_WITH_ARGS(QMutexPool, globalMutexPool, (QMutex::Recursive))
/*!
\class QMutexPool
\inmodule QtCore
\brief The QMutexPool class provides a pool of QMutex objects.
\internal
\ingroup thread
QMutexPool is a convenience class that provides access to a fixed
number of QMutex objects.
Typical use of a QMutexPool is in situations where it is not
possible or feasible to use one QMutex for every protected object.
The mutex pool will return a mutex based on the address of the
object that needs protection.
For example, consider this simple class:
\snippet code/src_corelib_thread_qmutexpool.cpp 0
Adding a QMutex member to the Number class does not make sense,
because it is so small. However, in order to ensure that access to
each Number is protected, you need to use a mutex. In this case, a
QMutexPool would be ideal.
Code to calculate the square of a number would then look something
like this:
\snippet code/src_corelib_thread_qmutexpool.cpp 1
This function will safely calculate the square of a number, since
it uses a mutex from a QMutexPool. The mutex is locked and
unlocked automatically by the QMutexLocker class. See the
QMutexLocker documentation for more details.
*/
/*!
Constructs a QMutexPool, reserving space for \a size QMutexes. All
mutexes in the pool are created with \a recursionMode. By default,
all mutexes are non-recursive.
The QMutexes are created when needed, and deleted when the
QMutexPool is destructed.
*/
QMutexPool::QMutexPool(QMutex::RecursionMode recursionMode, int size)
: mutexes(size), recursionMode(recursionMode)
{
for (int index = 0; index < mutexes.count(); ++index) {
mutexes[index].store(0);
}
}
/*!
Destructs a QMutexPool. All QMutexes that were created by the pool
are deleted.
*/
QMutexPool::~QMutexPool()
{
for (int index = 0; index < mutexes.count(); ++index)
delete mutexes[index].load();
}
/*!
Returns the global QMutexPool instance.
*/
QMutexPool *QMutexPool::instance()
{
return globalMutexPool();
}
/*!
\fn QMutexPool::get(const void *address)
Returns a QMutex from the pool. QMutexPool uses the value \a address
to determine which mutex is returned from the pool.
*/
/*!
\internal
create the mutex for the given index
*/
QMutex *QMutexPool::createMutex(int index)
{
// mutex not created, create one
QMutex *newMutex = new QMutex(recursionMode);
if (!mutexes[index].testAndSetRelease(0, newMutex))
delete newMutex;
return mutexes[index].load();
}
/*!
Returns a QMutex from the global mutex pool.
*/
QMutex *QMutexPool::globalInstanceGet(const void *address)
{
QMutexPool * const globalInstance = globalMutexPool();
if (globalInstance == 0)
return 0;
return globalInstance->get(address);
}
#endif // QT_NO_THREAD
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QMUTEXPOOL_P_H
#define QMUTEXPOOL_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of QSettings. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "QtCore/qatomic.h"
#include <QMutex>
#include <QVarLengthArray>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifndef QT_NO_THREAD
class QMutexPool
{
public:
explicit QMutexPool(QMutex::RecursionMode recursionMode = QMutex::NonRecursive, int size = 131);
~QMutexPool();
inline QMutex *get(const void *address) {
int index = uint(quintptr(address)) % mutexes.count();
QMutex *m = mutexes[index].load();
if (m)
return m;
else
return createMutex(index);
}
static QMutexPool *instance();
static QMutex *globalInstanceGet(const void *address);
private:
QMutex *createMutex(int index);
QVarLengthArray<QAtomicPointer<QMutex>, 131> mutexes;
QMutex::RecursionMode recursionMode;
};
#endif // QT_NO_THREAD
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QMUTEXPOOL_P_H

View File

@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QRESOURCE_H
#define QRESOURCE_H
#include <QString>
#include <QLocale>
#include <QStringList>
#include <QList>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
class QResourcePrivate;
class QResource
{
public:
QResource(const QString &file=QString(), const QLocale &locale=QLocale());
~QResource();
void setFileName(const QString &file);
QString fileName() const;
QString absoluteFilePath() const;
void setLocale(const QLocale &locale);
QLocale locale() const;
bool isValid() const;
bool isCompressed() const;
qint64 size() const;
const uchar *data() const;
static void addSearchPath(const QString &path);
static QStringList searchPaths();
static bool registerResource(const QString &rccFilename, const QString &resourceRoot=QString());
static bool unregisterResource(const QString &rccFilename, const QString &resourceRoot=QString());
static bool registerResource(const uchar *rccData, const QString &resourceRoot=QString());
static bool unregisterResource(const uchar *rccData, const QString &resourceRoot=QString());
protected:
friend class QResourceFileEngine;
friend class QResourceFileEngineIterator;
bool isDir() const;
inline bool isFile() const { return !isDir(); }
QStringList children() const;
protected:
QScopedPointer<QResourcePrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(QResource)
};
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QRESOURCE_H

View File

@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QRESOURCE_P_H
#define QRESOURCE_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 "qabstractfileengine_p.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
class QResourceFileEnginePrivate;
class QResourceFileEngine : public QAbstractFileEngine
{
private:
Q_DECLARE_PRIVATE(QResourceFileEngine)
public:
explicit QResourceFileEngine(const QString &path);
~QResourceFileEngine();
virtual void setFileName(const QString &file);
virtual bool open(QIODevice::OpenMode flags) ;
virtual bool close();
virtual bool flush();
virtual qint64 size() const;
virtual qint64 pos() const;
virtual bool atEnd() const;
virtual bool seek(qint64);
virtual qint64 read(char *data, qint64 maxlen);
virtual qint64 write(const char *data, qint64 len);
virtual bool remove();
virtual bool copy(const QString &newName);
virtual bool rename(const QString &newName);
virtual bool link(const QString &newName);
virtual bool isSequential() const;
virtual bool isRelativePath() const;
virtual bool mkdir(const QString &dirName, bool createParentDirectories) const;
virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const;
virtual bool setSize(qint64 size);
virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const;
virtual bool caseSensitive() const;
virtual FileFlags fileFlags(FileFlags type) const;
virtual bool setPermissions(uint perms);
virtual QString fileName(QAbstractFileEngine::FileName file) const;
virtual uint ownerId(FileOwner) const;
virtual QString owner(FileOwner) const;
virtual QDateTime fileTime(FileTime time) const;
virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames);
virtual Iterator *endEntryList();
bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0);
bool supportsExtension(Extension extension) const;
};
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QRESOURCE_P_H

View File

@ -0,0 +1,154 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 <QtGlobal>
#include "qsystemerror_p.h"
#if !defined(Q_OS_WINCE)
# include <errno.h>
# if defined(Q_CC_MSVC)
# include <crtdbg.h>
# endif
#else
# if (_WIN32_WCE >= 0x700)
# include <errno.h>
# endif
#endif
#ifdef Q_OS_WIN
# include <qt_windows.h>
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#if !defined(Q_OS_WIN) && !defined(QT_NO_THREAD) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX) && \
defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L
namespace {
// There are two incompatible versions of strerror_r:
// a) the XSI/POSIX.1 version, which returns an int,
// indicating success or not
// b) the GNU version, which returns a char*, which may or may not
// be the beginning of the buffer we used
// The GNU libc manpage for strerror_r says you should use the XSI
// version in portable code. However, it's impossible to do that if
// _GNU_SOURCE is defined so we use C++ overloading to decide what to do
// depending on the return type
static inline QString fromstrerror_helper(int, const QByteArray &buf)
{
return QString::fromLocal8Bit(buf);
}
static inline QString fromstrerror_helper(const char *str, const QByteArray &)
{
return QString::fromLocal8Bit(str);
}
}
#endif
#ifdef Q_OS_WIN
static QString windowsErrorString(int errorCode)
{
QString ret;
#ifndef Q_OS_WINRT
wchar_t *string = 0;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&string,
0,
NULL);
ret = QString::fromWCharArray(string);
LocalFree((HLOCAL)string);
#else
wchar_t errorString[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&errorString,
sizeof(errorString)/sizeof(wchar_t),
NULL);
ret = QString::fromWCharArray(errorString);
#endif // Q_OS_WINRT
if (ret.isEmpty() && errorCode == ERROR_MOD_NOT_FOUND)
ret = QString::fromLatin1("The specified module could not be found.");
return ret;
}
#endif
static QString standardLibraryErrorString(int errorCode)
{
const char *s = 0;
QString ret;
switch (errorCode) {
case 0:
break;
case EACCES:
s = QT_TRANSLATE_NOOP("QIODevice", "Permission denied");
break;
case EMFILE:
s = QT_TRANSLATE_NOOP("QIODevice", "Too many open files");
break;
case ENOENT:
s = QT_TRANSLATE_NOOP("QIODevice", "No such file or directory");
break;
case ENOSPC:
s = QT_TRANSLATE_NOOP("QIODevice", "No space left on device");
break;
default: {
#ifdef Q_OS_WINCE
ret = windowsErrorString(errorCode);
#else
#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && _POSIX_VERSION >= 200112L && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX)
QByteArray buf(1024, '\0');
ret = fromstrerror_helper(strerror_r(errorCode, buf.data(), buf.size()), buf);
#else
ret = QString::fromLocal8Bit(strerror(errorCode));
#endif
#endif
break; }
}
if (s) {
// ######## this breaks moc build currently
// ret = QCoreApplication::translate("QIODevice", s);
ret = QString::fromLatin1(s);
}
return ret.trimmed();
}
QString QSystemError::toString()
{
switch(errorScope) {
case NativeError:
#if defined (Q_OS_WIN)
return windowsErrorString(errorCode);
#else
//unix: fall through as native and standard library are the same
#endif
case StandardLibraryError:
return standardLibraryErrorString(errorCode);
default:
qWarning("invalid error scope");
//fall through
case NoError:
return QLatin1String("No error");
}
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)

View File

@ -0,0 +1,85 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QSYSTEMERROR_P_H
#define QSYSTEMERROR_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 <QString>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
class QSystemError
{
public:
enum ErrorScope
{
NoError,
StandardLibraryError,
NativeError
};
inline QSystemError(int error, ErrorScope scope);
inline QSystemError();
QString toString();
inline ErrorScope scope();
inline int error();
//data members
int errorCode;
ErrorScope errorScope;
};
QSystemError::QSystemError(int error, QSystemError::ErrorScope scope)
: errorCode(error), errorScope(scope)
{
}
QSystemError::QSystemError()
: errorCode(0), errorScope(NoError)
{
}
QSystemError::ErrorScope QSystemError::scope()
{
return errorScope;
}
int QSystemError::error()
{
return errorCode;
}
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif // QSYSTEMERROR_P_H

View File

@ -0,0 +1,90 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** $QT_BEGIN_LICENSE:GPL$
**
** 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 QSYSTEMLIBRARY_P_H
#define QSYSTEMLIBRARY_P_H
#include <QtGlobal>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#ifdef Q_OS_WIN
# include <QString>
# include <qt_windows.h>
class QSystemLibrary
{
public:
explicit QSystemLibrary(const QString &libraryName)
{
m_libraryName = libraryName;
m_handle = 0;
m_didLoad = false;
}
explicit QSystemLibrary(const wchar_t *libraryName)
{
m_libraryName = QString::fromWCharArray(libraryName);
m_handle = 0;
m_didLoad = false;
}
bool load(bool onlySystemDirectory = true)
{
m_handle = load((const wchar_t *)m_libraryName.utf16(), onlySystemDirectory);
m_didLoad = true;
return (m_handle != 0);
}
bool isLoaded()
{
return (m_handle != 0);
}
QFunctionPointer resolve(const char *symbol)
{
if (!m_didLoad)
load();
if (!m_handle)
return 0;
#ifdef Q_OS_WINCE
return QFunctionPointer(GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16()));
#else
return QFunctionPointer(GetProcAddress(m_handle, symbol));
#endif
}
static QFunctionPointer resolve(const QString &libraryName, const char *symbol)
{
return QSystemLibrary(libraryName).resolve(symbol);
}
static Q_CORE_EXPORT HINSTANCE load(const wchar_t *lpFileName, bool onlySystemDirectory = true);
private:
HINSTANCE m_handle;
QString m_libraryName;
bool m_didLoad;
};
#endif //Q_OS_WIN
#endif //QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
#endif //QSYSTEMLIBRARY_P_H

View File

@ -5,15 +5,67 @@ HEADERS += \
$$PWD/vapplication.h \
$$PWD/undoevent.h \
$$PWD/vsettings.h \
$$PWD/qcommandlineoption.h \
$$PWD/qcommandlineparser.h \
$$PWD/qlockfile.h \
$$PWD/qlockfile_p.h
$$PWD/backport/qcommandlineoption.h \
$$PWD/backport/qcommandlineparser.h \
$$PWD/backport/qlockfile.h \
$$PWD/backport/qlockfile_p.h \
$$PWD/backport/qfilesystementry_p.h \
$$PWD/backport/qfsfileengine_p.h \
$$PWD/backport/qabstractfileengine_p.h \
$$PWD/backport/qresource_p.h \
$$PWD/backport/qresource.h \
$$PWD/backport/qfilesystemmetadata_p.h \
$$PWD/backport/qfilesystemengine_p.h \
$$PWD/backport/qsystemerror_p.h \
$$PWD/backport/qfsfileengine_iterator_p.h \
$$PWD/backport/qfilesystemiterator_p.h \
$$PWD/backport/qfileinfo_p.h \
$$PWD/backport/qmutexpool_p.h \
$$PWD/backport/qsystemlibrary_p.h \
unix:!macx {
HEADERS += \
$$PWD/backport/qcore_unix_p.h
}
unix:macx {
HEADERS += \
$$PWD/backport/qcore_mac_p.h
}
SOURCES += \
$$PWD/vapplication.cpp \
$$PWD/undoevent.cpp \
$$PWD/vsettings.cpp \
$$PWD/qcommandlineoption.cpp \
$$PWD/qcommandlineparser.cpp \
$$PWD/qlockfile.cpp
$$PWD/backport/qcommandlineoption.cpp \
$$PWD/backport/qcommandlineparser.cpp \
$$PWD/backport/qlockfile.cpp \
$$PWD/backport/qfilesystementry.cpp \
$$PWD/backport/qfsfileengine.cpp \
$$PWD/backport/qabstractfileengine.cpp \
$$PWD/backport/qfilesystemengine.cpp \
$$PWD/backport/qsystemerror.cpp \
$$PWD/backport/qfsfileengine_iterator.cpp \
$$PWD/backport/qmutexpool.cpp
unix:!macx {
SOURCES += \
$$PWD/backport/qlockfile_unix.cpp \
$$PWD/backport/qfilesystemiterator_unix.cpp \
$$PWD/backport/qfsfileengine_unix.cpp \
$$PWD/backport/qfilesystemengine_unix.cpp \
$$PWD/backport/qcore_unix.cpp
}
unix:macx {
SOURCES += \
$$PWD/backport/qcore_mac.cpp
}
win32 {
SOURCES += \
$$PWD/backport/qlockfile_win.cpp \
$$PWD/backport/qfilesystemiterator_win.cpp \
$$PWD/backport/qfsfileengine_win.cpp \
$$PWD/backport/qfilesystemengine_win.cpp
}

View File

@ -50,7 +50,7 @@
#include <QThread>
#include <QDateTime>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
# include "qlockfile.h"
# include "backport/qlockfile.h"
#else
# include <QLockFile>
#endif

View File

@ -36,7 +36,7 @@
#include <QMessageBox>
#include <QThread>
#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
# include "../core/qcommandlineparser.h"
# include "../core/backport/qcommandlineparser.h"
#else
# include <QCommandLineParser>
#endif

View File

@ -62,7 +62,7 @@
#include <QDesktopWidget>
#include <QDesktopServices>
#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
# include "core/qlockfile.h"
# include "core/backport/qlockfile.h"
#else
# include <QLockFile>
#endif