From e4de050cc8e819a2751f94ac0429a0d7fe64e64a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 8 Sep 2010 15:15:45 +0100 Subject: Enable symbian IO code in the build This patch contains several changes that needed to be done atomically. The native file path im QFileSystemEntry is changed from 8 bit to 16 bit character set. QFsFileEngine has some new symbian specific code (as the unix code does not compile with the above change), and forwards more calls to the new QFileSystemEngine. Unix implementations of link, rename and remove are moved to the unix version of this class, so less ifdef'ing is needed. Finally, io.pri now selects the _symbian.cpp source files instead of the _unix.cpp equivalents when building for symbian. --- src/corelib/io/io.pri | 15 +- src/corelib/io/qfilesystemengine_unix.cpp | 8 +- src/corelib/io/qfilesystementry.cpp | 7 +- src/corelib/io/qfilesystementry_p.h | 6 +- src/corelib/io/qfsfileengine.cpp | 6 + src/corelib/io/qfsfileengine_p.h | 28 +++ src/corelib/io/qfsfileengine_unix.cpp | 343 +++++++++++++++++------------- 7 files changed, 250 insertions(+), 163 deletions(-) diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 7c3712e..4a20dfa 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -73,12 +73,17 @@ win32 { SOURCES += io/qfilesystemengine_win.cpp SOURCES += io/qfilesystemiterator_win.cpp } else:unix { - SOURCES += io/qfilesystemengine_unix.cpp - SOURCES += io/qfilesystemiterator_unix.cpp - SOURCES += io/qfsfileengine_unix.cpp SOURCES += io/qfsfileengine_iterator_unix.cpp - symbian:SOURCES += io/qprocess_symbian.cpp - else:SOURCES += io/qprocess_unix.cpp + SOURCES += io/qfsfileengine_unix.cpp + symbian { + SOURCES += io/qfilesystemengine_symbian.cpp + SOURCES += io/qprocess_symbian.cpp + SOURCES += io/qfilesystemiterator_symbian.cpp + } else { + SOURCES += io/qfilesystemengine_unix.cpp + SOURCES += io/qprocess_unix.cpp + SOURCES += io/qfilesystemiterator_unix.cpp + } macx-*: { HEADERS += io/qfilesystemwatcher_fsevents_p.h SOURCES += io/qfilesystemengine_mac.cpp diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index f26a8c0..8d77963 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -45,6 +45,8 @@ #include "qfsfileengine.h" #include // for realpath() +#include +#include #include #if defined(Q_OS_SYMBIAN) @@ -489,7 +491,7 @@ bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool remo //static bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target) { - return false; // TODO implement; + return (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0); } //static @@ -501,13 +503,13 @@ bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSyst //static bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target) { - return false; // TODO implement; + return (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0); } //static bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry) { - return false; // TODO implement; + return (unlink(entry.nativeFilePath().constData()) == 0); } //static diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp index c3ada48..f5009b4 100644 --- a/src/corelib/io/qfilesystementry.cpp +++ b/src/corelib/io/qfilesystementry.cpp @@ -121,7 +121,7 @@ QFileSystemEntry::NativePath QFileSystemEntry::nativeFilePath() const void QFileSystemEntry::resolveFilePath() const { if (m_filePath.isEmpty() && !m_nativeFilePath.isEmpty()) { -#ifdef Q_OS_WIN +#ifdef QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16 m_filePath = QDir::fromNativeSeparators(m_nativeFilePath); #else m_filePath = QDir::fromNativeSeparators(QFile::decodeName(m_nativeFilePath)); @@ -137,6 +137,8 @@ void QFileSystemEntry::resolveNativeFilePath() const 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 @@ -199,11 +201,10 @@ bool QFileSystemEntry::isAbsolute() const return (!m_filePath.isEmpty() && (m_filePath[0].unicode() == '/') #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) || (m_filePath.length() >= 2 - && ((m_filePath[0].isLetter() && m_filePath[1] == QLatin1Char(':')) + && ((m_filePath[0].isLetter() && m_filePath[1].unicode() == ':') || (m_filePath.at(0) == QLatin1Char('/') && m_filePath.at(1) == QLatin1Char('/')))) #endif ); - } #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) diff --git a/src/corelib/io/qfilesystementry_p.h b/src/corelib/io/qfilesystementry_p.h index 3786bb3..6b2cedd 100644 --- a/src/corelib/io/qfilesystementry_p.h +++ b/src/corelib/io/qfilesystementry_p.h @@ -56,13 +56,17 @@ #include #include +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +#define QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16 +#endif + QT_BEGIN_NAMESPACE class QFileSystemEntry { public: -#ifndef Q_OS_WIN +#ifndef QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16 typedef QByteArray NativePath; #else typedef QString NativePath; diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 1b0a28c..089f1a1 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -364,6 +364,12 @@ bool QFSFileEnginePrivate::closeFdFh() if (closeFileHandle) { int ret; do { +#ifdef Q_OS_SYMBIAN + if (symbianFile.SubSessionHandle()) { + symbianFile.Close(); + ret = 0; + } else +#endif if (fh) { // Close buffered file. ret = fclose(fh) != 0 ? -1 : 0; diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 6e5f30e..a3733d8 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -60,6 +60,10 @@ #include #include +#ifdef Q_OS_SYMBIAN +#include +#endif + #ifndef QT_NO_FSFILEENGINE QT_BEGIN_NAMESPACE @@ -115,6 +119,30 @@ public: #endif FILE *fh; +#ifdef Q_OS_SYMBIAN +#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + RFile64 symbianFile; + TInt64 symbianFilePos; +#else + RFile symbianFile; + + /** + * The cursor position in the underlying file. This differs + * from devicePos because the latter is updated on calls to + * writeData, even if no data was physically transferred to + * the file, but instead stored in the write buffer. + * + * iFilePos is updated on calls to RFile::Read and + * RFile::Write. It is also updated on calls to seek() but + * RFile::Seek is not called when that happens because + * Symbian supports positioned reads and writes, saving a file + * server call, and because Symbian does not support seeking + * past the end of a file. + */ + TInt symbianFilePos; +#endif +#endif + #ifdef Q_WS_WIN HANDLE fileHandle; HANDLE mapHandle; diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index c7df5ed..048aa1b 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -197,6 +197,90 @@ static inline bool setCloseOnExec(int fd) return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1; } +#ifdef Q_OS_SYMBIAN +/*! + \internal +*/ +bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) +{ + Q_Q(QFSFileEngine); + + fh = 0; + fd = -1; + + QString fn(QFileSystemEngine::absoluteName(fileEntry).nativeFilePath()); + RFs& fs = qt_s60GetRFs(); + + TUint symbianMode = 0; + + if(openMode & QIODevice::ReadOnly) + symbianMode |= EFileRead; + if(openMode & QIODevice::WriteOnly) + symbianMode |= EFileWrite; + if(openMode & QIODevice::Text) + symbianMode |= EFileStreamText; + + // pre Symbian 9.4, file I/O is always unbuffered, and the enum values don't exist + if(QSysInfo::symbianVersion() >= QSysInfo::SV_9_4) { + if (openMode & QFile::Unbuffered) { + if (openMode & QIODevice::WriteOnly) + symbianMode |= 0x00001000; //EFileWriteDirectIO; + if (openMode & QIODevice::ReadOnly) + symbianMode |= 0x00004000; //EFileReadDirectIO; + } else { + if (openMode & QIODevice::WriteOnly) + symbianMode |= 0x00000800; //EFileWriteBuffered; + // use implementation defaults for read buffering + } + } + + // Until Qt supports file sharing, we can't support EFileShareReadersOrWriters safely, + // but Qt does this on other platforms and autotests rely on it. + // The reason is that Unix locks are only advisory - the application needs to test the + // lock after opening the file. Symbian and Windows locks are mandatory - opening a + // locked file will fail. + symbianMode |= EFileShareReadersOrWriters; + + TInt r; + //note QIODevice::Truncate only has meaning for read/write access + //write-only files are always truncated unless append is specified + //reference openModeToOpenFlags in qfsfileengine_unix.cpp + if ((openMode & QIODevice::Truncate) || (!(openMode & QIODevice::ReadOnly) && !(openMode & QIODevice::Append))) { + r = symbianFile.Replace(fs, qt_QString2TPtrC(fn), symbianMode); + } else { + r = symbianFile.Open(fs, qt_QString2TPtrC(fn), symbianMode); + if (r == KErrNotFound && (openMode & QIODevice::WriteOnly)) { + r = symbianFile.Create(fs, qt_QString2TPtrC(fn), symbianMode); + } + } + + if (r == KErrNone) { +#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + TInt64 size; +#else + TInt size; +#endif + r = symbianFile.Size(size); + if (r==KErrNone) { + if (openMode & QIODevice::Append) + symbianFilePos = size; + else + symbianFilePos = 0; + //TODO: port this (QFileSystemMetaData in open?) + //cachedSize = size; + } + } + + if (r != KErrNone) { + setSymbianError(r, QFile::OpenError, QLatin1String("open error")); + symbianFile.Close(); + return false; + } + + closeFileHandle = true; + return true; +} +#else /*! \internal */ @@ -293,6 +377,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) closeFileHandle = true; return true; } +#endif /*! \internal @@ -423,61 +508,64 @@ bool QFSFileEnginePrivate::nativeIsSequential() const bool QFSFileEngine::remove() { Q_D(QFSFileEngine); - bool ret = unlink(d->fileEntry.nativeFilePath().constData()) == 0; - if (!ret) + bool ret = QFileSystemEngine::removeFile(d->fileEntry); + if (!ret) { +#ifdef Q_OS_SYMBIAN + //TODO: error reporting + d->setSymbianError(KErrGeneral, QFile::RemoveError, QLatin1String("remove error")); +#else setError(QFile::RemoveError, qt_error_string(errno)); +#endif + } return ret; } bool QFSFileEngine::copy(const QString &newName) { -#if defined(Q_OS_SYMBIAN) Q_D(QFSFileEngine); - RFs rfs = qt_s60GetRFs(); - CFileMan* fm = NULL; - QString oldNative(QDir::toNativeSeparators(d->fileEntry.filePath())); - TPtrC oldPtr(qt_QString2TPtrC(oldNative)); - QFileInfo fi(newName); - QString absoluteNewName = fi.absoluteFilePath(); - QString newNative(QDir::toNativeSeparators(absoluteNewName)); - TPtrC newPtr(qt_QString2TPtrC(newNative)); - TRAPD (err, - fm = CFileMan::NewL(rfs); - RFile rfile; - err = rfile.Open(rfs, oldPtr, EFileShareReadersOrWriters); - if (err == KErrNone) { - err = fm->Copy(rfile, newPtr); - rfile.Close(); - } - ) // End TRAP - delete fm; - if (err == KErrNone) - return true; - d->setSymbianError(err, QFile::CopyError, QLatin1String("copy error")); - return false; + bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(newName)); + if (!ret) { +#ifdef Q_OS_SYMBIAN + //TODO: error reporting + d->setSymbianError(KErrGeneral, QFile::CopyError, QLatin1String("copy error")); #else - Q_UNUSED(newName); - // ### Add copy code for Unix here - setError(QFile::UnspecifiedError, QLatin1String("Not implemented!")); - return false; + // ### Add copy code for Unix to the filesystem engine + setError(QFile::UnspecifiedError, QLatin1String("Not implemented!")); + //setError(QFile::CopyError, qt_error_string(errno)); #endif + } + return ret; } bool QFSFileEngine::rename(const QString &newName) { Q_D(QFSFileEngine); - bool ret = ::rename(d->fileEntry.nativeFilePath().constData(), QFile::encodeName(newName).constData()) == 0; - if (!ret) + bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName)); + + if (!ret) { +#ifdef Q_OS_SYMBIAN + //TODO: error reporting + d->setSymbianError(KErrGeneral, QFile::RenameError, QLatin1String("rename error")); +#else setError(QFile::RenameError, qt_error_string(errno)); +#endif + } + return ret; } bool QFSFileEngine::link(const QString &newName) { Q_D(QFSFileEngine); - bool ret = ::symlink(d->fileEntry.nativeFilePath().constData(), QFile::encodeName(newName).constData()) == 0; - if (!ret) + bool ret = QFileSystemEngine::createLink(d->fileEntry, QFileSystemEntry(newName)); + if (!ret) { +#ifdef Q_OS_SYMBIAN + //TODO: error reporting + d->setSymbianError(KErrNotSupported, QFile::RenameError, QLatin1String("not supported")); +#else setError(QFile::RenameError, qt_error_string(errno)); +#endif + } return ret; } @@ -722,123 +810,6 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const return ret; } -#if defined(Q_OS_SYMBIAN) -QString QFSFileEngine::fileName(FileName file) const -{ - Q_D(const QFSFileEngine); - const QLatin1Char slashChar('/'); - if(file == BaseName) { - int slash = d->fileEntry.filePath().lastIndexOf(slashChar); - if(slash == -1) { - int colon = d->fileEntry.filePath().lastIndexOf(QLatin1Char(':')); - if(colon != -1) - return d->fileEntry.filePath().mid(colon + 1); - return d->fileEntry.filePath(); - } - return d->fileEntry.filePath().mid(slash + 1); - } else if(file == PathName) { - if(!d->fileEntry.filePath().size()) - return d->fileEntry.filePath(); - - int slash = d->fileEntry.filePath().lastIndexOf(slashChar); - if(slash == -1) { - if(d->fileEntry.filePath().length() >= 2 && d->fileEntry.filePath().at(1) == QLatin1Char(':')) - return d->fileEntry.filePath().left(2); - return QLatin1String("."); - } else { - if(!slash) - return QLatin1String("/"); - if(slash == 2 && d->fileEntry.filePath().length() >= 2 && d->fileEntry.filePath().at(1) == QLatin1Char(':')) - slash++; - return d->fileEntry.filePath().left(slash); - } - } else if(file == AbsoluteName || file == AbsolutePathName) { - QString ret; - if (!isRelativePathSymbian(d->fileEntry.filePath())) { - if (d->fileEntry.filePath().size() > 2 && d->fileEntry.filePath().at(1) == QLatin1Char(':') - && d->fileEntry.filePath().at(2) != slashChar){ - // It's a drive-relative path, so C:a.txt -> C:/currentpath/a.txt, - // or if it's different drive than current, Z:a.txt -> Z:/a.txt - QString currentPath = QDir::currentPath(); - if (0 == currentPath.left(1).compare(d->fileEntry.filePath().left(1), Qt::CaseInsensitive)) - ret = currentPath + slashChar + d->fileEntry.filePath().mid(2); - else - ret = d->fileEntry.filePath().left(2) + slashChar + d->fileEntry.filePath().mid(2); - } else if (d->fileEntry.filePath().startsWith(slashChar)) { - // It's a absolute path to the current drive, so /a.txt -> C:/a.txt - ret = QDir::currentPath().left(2) + d->fileEntry.filePath(); - } else { - ret = d->fileEntry.filePath(); - } - } else { - ret = QDir::currentPath() + slashChar + d->fileEntry.filePath(); - } - - // The path should be absolute at this point. - // From the docs : - // Absolute paths begin with the directory separator "/" - // (optionally preceded by a drive specification under Windows). - if (ret.at(0) != slashChar) { - Q_ASSERT(ret.length() >= 2); - Q_ASSERT(ret.at(0).isLetter()); - Q_ASSERT(ret.at(1) == QLatin1Char(':')); - - // Force uppercase drive letters. - ret[0] = ret.at(0).toUpper(); - } - - // Clean up the path - bool isDir = ret.endsWith(slashChar); - ret = QDir::cleanPath(ret); - if (isDir && !ret.endsWith(slashChar)) - ret += slashChar; - - if (file == AbsolutePathName) { - int slash = ret.lastIndexOf(slashChar); - if (slash < 0) - return ret; - else if (ret.at(0) != slashChar && slash == 2) - return ret.left(3); // include the slash - else - return ret.left(slash > 0 ? slash : 1); - } - return ret; - } else if(file == CanonicalName || file == CanonicalPathName) { - QFileSystemEntry entry(QFileSystemEngine::canonicalName(d->fileEntry)); - if (file == CanonicalPathName) - return entry.path(); - return entry.filePath(); - } else if(file == LinkName) { - if (d->isSymlink()) { - char s[PATH_MAX+1]; - int len = readlink(d->fileEntry.nativeFilePath().constData(), s, PATH_MAX); - if (len > 0) { - s[len] = '\0'; - QString ret = QFile::decodeName(QByteArray(s)); - - if (isRelativePathSymbian(ret)) { - if (!isRelativePathSymbian(d->fileEntry.filePath())) { - ret.prepend(d->fileEntry.filePath().left(d->fileEntry.filePath().lastIndexOf(slashChar)) - + slashChar); - } else { - ret.prepend(QDir::currentPath() + slashChar); - } - } - ret = QDir::cleanPath(ret); - if (ret.size() > 1 && ret.endsWith(slashChar)) - ret.chop(1); - return ret; - } - } - return QString(); - } else if(file == BundleName) { - return QString(); - } - return d->fileEntry.filePath(); -} - -#else - QString QFSFileEngine::fileName(FileName file) const { Q_D(const QFSFileEngine); @@ -868,7 +839,6 @@ QString QFSFileEngine::fileName(FileName file) const } return d->fileEntry.filePath(); } -#endif // Q_OS_SYMBIAN bool QFSFileEngine::isRelativePath() const { @@ -939,6 +909,51 @@ QString QFSFileEngine::owner(FileOwner own) const return QString(); } +#ifdef Q_OS_SYMBIAN +bool QFSFileEngine::setPermissions(uint perms) +{ + Q_D(QFSFileEngine); + //TODO: connect up error reporting properly + if (!QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), 0)) { + setError(QFile::PermissionsError, QString()); + return false; + } + return true; +} + +bool QFSFileEngine::setSize(qint64 size) +{ + Q_D(QFSFileEngine); + bool ret = false; + TInt err = KErrNone; + if (d->symbianFile.SubSessionHandle()) { + TInt err = d->symbianFile.SetSize(size); + ret = (err == KErrNone); + } + 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 { + RFile tmp; + QString symbianFilename(d->fileEntry.nativeFilePath()); + err = tmp.Open(qt_s60GetRFs(), qt_QString2TPtrC(symbianFilename), EFileWrite); + if (err == KErrNone) + { + err = tmp.SetSize(size); + tmp.Close(); + } + ret = (err == KErrNone); + } + if (!ret) { + if (err) + d->setSymbianError(err, QFile::ResizeError, QString()); + else + setError(QFile::ResizeError, qt_error_string(errno)); + } + return ret; +} +#else bool QFSFileEngine::setPermissions(uint perms) { Q_D(QFSFileEngine); @@ -991,6 +1006,7 @@ bool QFSFileEngine::setSize(qint64 size) setError(QFile::ResizeError, qt_error_string(errno)); return ret; } +#endif QDateTime QFSFileEngine::fileTime(FileTime time) const { @@ -1002,6 +1018,30 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const return QDateTime(); } +#ifdef Q_OS_SYMBIAN +uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags) +{ + //Q_Q(QFSFileEngine); + Q_UNUSED(flags) + Q_UNUSED(offset) + Q_UNUSED(size) + return 0; + //TODO: use RFileMap when available in symbian^4 +} + +bool QFSFileEnginePrivate::unmap(uchar *ptr) +{ + //TODO: RFileMap as the value in maps, unmap it here when API is available... + //Q_Q(QFSFileEngine); + //if (!maps.contains(ptr)) { + // q->setError(QFile::PermissionsError, qt_error_string(EACCES)); + // return false; + //} + Q_UNUSED(ptr) + + return false; +} +#else uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags) { Q_Q(QFSFileEngine); @@ -1092,6 +1132,7 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) maps.remove(ptr); return true; } +#endif QT_END_NAMESPACE -- cgit v0.12