1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtCore module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qplatformdefs.h"
43 #include "qabstractfileengine.h"
44 #include "private/qfsfileengine_p.h"
45 #include "private/qcore_unix_p.h"
47 #ifndef QT_NO_FSFILEENGINE
51 #include "qdatetime.h"
52 #include "qvarlengtharray.h"
57 #if defined(Q_OS_SYMBIAN)
58 # include <syslimits.h>
60 # include <pathinfo.h>
61 # include "private/qcore_symbian_p.h"
64 #if !defined(QWS) && defined(Q_OS_MAC)
65 # include <private/qcore_mac_p.h>
71 #if defined(Q_OS_SYMBIAN)
75 Returns true if supplied path is a relative path
77 static bool isRelativePathSymbian(const QString
& fileName
)
79 return !(fileName
.startsWith(QLatin1Char('/'))
80 || (fileName
.length() >= 2
81 && ((fileName
.at(0).isLetter() && fileName
.at(1) == QLatin1Char(':'))
82 || (fileName
.at(0) == QLatin1Char('/') && fileName
.at(1) == QLatin1Char('/')))));
89 Returns the stdlib open string corresponding to a QIODevice::OpenMode.
91 static inline QByteArray
openModeToFopenMode(QIODevice::OpenMode flags
, const QString
&fileName
)
94 if ((flags
& QIODevice::ReadOnly
) && !(flags
& QIODevice::Truncate
)) {
96 if (flags
& QIODevice::WriteOnly
) {
98 if (!fileName
.isEmpty()
99 && QT_STAT(QFile::encodeName(fileName
), &statBuf
) == 0
100 && (statBuf
.st_mode
& S_IFMT
) == S_IFREG
) {
106 } else if (flags
& QIODevice::WriteOnly
) {
108 if (flags
& QIODevice::ReadOnly
)
111 if (flags
& QIODevice::Append
) {
113 if (flags
& QIODevice::ReadOnly
)
117 #if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0207
118 // must be glibc >= 2.7
128 Returns the stdio open flags corresponding to a QIODevice::OpenMode.
130 static inline int openModeToOpenFlags(QIODevice::OpenMode mode
)
132 int oflags
= QT_OPEN_RDONLY
;
133 #ifdef QT_LARGEFILE_SUPPORT
134 oflags
|= QT_OPEN_LARGEFILE
;
137 if ((mode
& QFile::ReadWrite
) == QFile::ReadWrite
) {
138 oflags
= QT_OPEN_RDWR
| QT_OPEN_CREAT
;
139 } else if (mode
& QFile::WriteOnly
) {
140 oflags
= QT_OPEN_WRONLY
| QT_OPEN_CREAT
;
143 if (mode
& QFile::Append
) {
144 oflags
|= QT_OPEN_APPEND
;
145 } else if (mode
& QFile::WriteOnly
) {
146 if ((mode
& QFile::Truncate
) || !(mode
& QFile::ReadOnly
))
147 oflags
|= QT_OPEN_TRUNC
;
156 Sets the file descriptor to close on exec. That is, the file
157 descriptor is not inherited by child processes.
159 static inline bool setCloseOnExec(int fd
)
161 return fd
!= -1 && fcntl(fd
, F_SETFD
, FD_CLOEXEC
) != -1;
167 void QFSFileEnginePrivate::nativeInitFileName()
169 nativeFilePath
= QFile::encodeName(filePath
);
175 bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode
)
179 if (openMode
& QIODevice::Unbuffered
) {
180 int flags
= openModeToOpenFlags(openMode
);
182 // Try to open the file in unbuffered mode.
184 fd
= QT_OPEN(nativeFilePath
.constData(), flags
, 0666);
185 } while (fd
== -1 && errno
== EINTR
);
187 // On failure, return and report the error.
189 q
->setError(errno
== EMFILE
? QFile::ResourceError
: QFile::OpenError
,
190 qt_error_string(errno
));
195 if (QT_FSTAT(fd
, &statBuf
) != -1) {
196 if ((statBuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
197 q
->setError(QFile::OpenError
, QLatin1String("file to open is a directory"));
203 // Seek to the end when in Append mode.
204 if (flags
& QFile::Append
) {
207 ret
= QT_LSEEK(fd
, 0, SEEK_END
);
208 } while (ret
== -1 && errno
== EINTR
);
211 q
->setError(errno
== EMFILE
? QFile::ResourceError
: QFile::OpenError
,
212 qt_error_string(int(errno
)));
219 QByteArray fopenMode
= openModeToFopenMode(openMode
, filePath
);
221 // Try to open the file in buffered mode.
223 fh
= QT_FOPEN(nativeFilePath
.constData(), fopenMode
.constData());
224 } while (!fh
&& errno
== EINTR
);
226 // On failure, return and report the error.
228 q
->setError(errno
== EMFILE
? QFile::ResourceError
: QFile::OpenError
,
229 qt_error_string(int(errno
)));
234 if (QT_FSTAT(fileno(fh
), &statBuf
) != -1) {
235 if ((statBuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
236 q
->setError(QFile::OpenError
, QLatin1String("file to open is a directory"));
242 setCloseOnExec(fileno(fh
)); // ignore failure
244 // Seek to the end when in Append mode.
245 if (openMode
& QIODevice::Append
) {
248 ret
= QT_FSEEK(fh
, 0, SEEK_END
);
249 } while (ret
== -1 && errno
== EINTR
);
252 q
->setError(errno
== EMFILE
? QFile::ResourceError
: QFile::OpenError
,
253 qt_error_string(int(errno
)));
261 closeFileHandle
= true;
268 bool QFSFileEnginePrivate::nativeClose()
277 bool QFSFileEnginePrivate::nativeFlush()
279 return fh
? flushFh() : fd
!= -1;
285 qint64
QFSFileEnginePrivate::nativeRead(char *data
, qint64 len
)
289 if (fh
&& nativeIsSequential()) {
290 size_t readBytes
= 0;
291 int oldFlags
= fcntl(QT_FILENO(fh
), F_GETFL
);
292 for (int i
= 0; i
< 2; ++i
) {
293 // Unix: Make the underlying file descriptor non-blocking
294 if ((oldFlags
& O_NONBLOCK
) == 0)
295 fcntl(QT_FILENO(fh
), F_SETFL
, oldFlags
| O_NONBLOCK
);
297 // Cross platform stdlib read
300 read
= fread(data
+ readBytes
, 1, size_t(len
- readBytes
), fh
);
301 } while (read
== 0 && !feof(fh
) && errno
== EINTR
);
311 // Unix: Restore the blocking state of the underlying socket
312 if ((oldFlags
& O_NONBLOCK
) == 0) {
313 fcntl(QT_FILENO(fh
), F_SETFL
, oldFlags
);
314 if (readBytes
== 0) {
317 readByte
= fgetc(fh
);
318 } while (readByte
== -1 && errno
== EINTR
);
319 if (readByte
!= -1) {
320 *data
= uchar(readByte
);
328 // Unix: Restore the blocking state of the underlying socket
329 if ((oldFlags
& O_NONBLOCK
) == 0) {
330 fcntl(QT_FILENO(fh
), F_SETFL
, oldFlags
);
332 if (readBytes
== 0 && !feof(fh
)) {
333 // if we didn't read anything and we're not at EOF, it must be an error
334 q
->setError(QFile::ReadError
, qt_error_string(int(errno
)));
340 return readFdFh(data
, len
);
346 qint64
QFSFileEnginePrivate::nativeReadLine(char *data
, qint64 maxlen
)
348 return readLineFdFh(data
, maxlen
);
354 qint64
QFSFileEnginePrivate::nativeWrite(const char *data
, qint64 len
)
356 return writeFdFh(data
, len
);
362 qint64
QFSFileEnginePrivate::nativePos() const
370 bool QFSFileEnginePrivate::nativeSeek(qint64 pos
)
372 return seekFdFh(pos
);
378 int QFSFileEnginePrivate::nativeHandle() const
380 return fh
? fileno(fh
) : fd
;
386 bool QFSFileEnginePrivate::nativeIsSequential() const
388 return isSequentialFdFh();
391 bool QFSFileEngine::remove()
394 bool ret
= unlink(d
->nativeFilePath
.constData()) == 0;
396 setError(QFile::RemoveError
, qt_error_string(errno
));
400 bool QFSFileEngine::copy(const QString
&newName
)
402 #if defined(Q_OS_SYMBIAN)
404 RFs rfs
= qt_s60GetRFs();
406 QString
oldNative(QDir::toNativeSeparators(d
->filePath
));
407 TPtrC
oldPtr(qt_QString2TPtrC(oldNative
));
408 QFileInfo
fi(newName
);
409 QString absoluteNewName
= fi
.absoluteFilePath();
410 QString
newNative(QDir::toNativeSeparators(absoluteNewName
));
411 TPtrC
newPtr(qt_QString2TPtrC(newNative
));
413 fm
= CFileMan::NewL(rfs
);
415 err
= rfile
.Open(rfs
, oldPtr
, EFileShareReadersOrWriters
);
416 if (err
== KErrNone
) {
417 err
= fm
->Copy(rfile
, newPtr
);
422 // ### Add error reporting on failure
423 return (err
== KErrNone
);
426 // ### Add copy code for Unix here
427 setError(QFile::UnspecifiedError
, QLatin1String("Not implemented!"));
432 bool QFSFileEngine::rename(const QString
&newName
)
435 bool ret
= ::rename(d
->nativeFilePath
.constData(), QFile::encodeName(newName
).constData()) == 0;
437 setError(QFile::RenameError
, qt_error_string(errno
));
441 bool QFSFileEngine::link(const QString
&newName
)
444 bool ret
= ::symlink(d
->nativeFilePath
.constData(), QFile::encodeName(newName
).constData()) == 0;
446 setError(QFile::RenameError
, qt_error_string(errno
));
450 qint64
QFSFileEnginePrivate::nativeSize() const
455 bool QFSFileEngine::mkdir(const QString
&name
, bool createParentDirectories
) const
457 QString dirName
= name
;
458 if (createParentDirectories
) {
459 dirName
= QDir::cleanPath(dirName
);
460 #if defined(Q_OS_SYMBIAN)
461 dirName
= QDir::toNativeSeparators(dirName
);
463 for(int oldslash
= -1, slash
=0; slash
!= -1; oldslash
= slash
) {
464 slash
= dirName
.indexOf(QDir::separator(), oldslash
+1);
466 if (oldslash
== dirName
.length())
468 slash
= dirName
.length();
471 QByteArray chunk
= QFile::encodeName(dirName
.left(slash
));
473 if (QT_STAT(chunk
, &st
) != -1) {
474 if ((st
.st_mode
& S_IFMT
) != S_IFDIR
)
476 } else if (QT_MKDIR(chunk
, 0777) != 0) {
483 #if defined(Q_OS_DARWIN) // Mac X doesn't support trailing /'s
484 if (dirName
.endsWith(QLatin1Char('/')))
487 return (QT_MKDIR(QFile::encodeName(dirName
), 0777) == 0);
490 bool QFSFileEngine::rmdir(const QString
&name
, bool recurseParentDirectories
) const
492 QString dirName
= name
;
493 if (recurseParentDirectories
) {
494 dirName
= QDir::cleanPath(dirName
);
495 #if defined(Q_OS_SYMBIAN)
496 dirName
= QDir::toNativeSeparators(dirName
);
498 for(int oldslash
= 0, slash
=dirName
.length(); slash
> 0; oldslash
= slash
) {
499 QByteArray chunk
= QFile::encodeName(dirName
.left(slash
));
501 if (QT_STAT(chunk
, &st
) != -1) {
502 if ((st
.st_mode
& S_IFMT
) != S_IFDIR
)
504 if (::rmdir(chunk
) != 0)
505 return oldslash
!= 0;
509 slash
= dirName
.lastIndexOf(QDir::separator(), oldslash
-1);
513 return ::rmdir(QFile::encodeName(dirName
)) == 0;
516 bool QFSFileEngine::caseSensitive() const
518 #if defined(Q_OS_SYMBIAN)
525 bool QFSFileEngine::setCurrentPath(const QString
&path
)
528 r
= QT_CHDIR(QFile::encodeName(path
));
532 QString
QFSFileEngine::currentPath(const QString
&)
536 #if defined(Q_OS_SYMBIAN)
537 char nativeCurrentName
[PATH_MAX
+1];
538 if (::getcwd(nativeCurrentName
, PATH_MAX
))
539 result
= QDir::fromNativeSeparators(QFile::decodeName(QByteArray(nativeCurrentName
)));
540 if (result
.isEmpty()) {
541 # if defined(QT_DEBUG)
542 qWarning("QFSFileEngine::currentPath: getcwd() failed");
546 if (QT_STAT(".", &st
) == 0) {
547 #if defined(__GLIBC__) && !defined(PATH_MAX)
548 char *currentName
= ::get_current_dir_name();
550 result
= QFile::decodeName(QByteArray(currentName
));
553 #elif !defined(Q_OS_SYMBIAN)
554 char currentName
[PATH_MAX
+1];
555 if (::getcwd(currentName
, PATH_MAX
))
556 result
= QFile::decodeName(QByteArray(currentName
));
557 # if defined(QT_DEBUG)
559 qWarning("QFSFileEngine::currentPath: getcwd() failed");
563 #if defined(Q_OS_SYMBIAN)
564 // If current dir returned by Open C doesn't exist,
565 // try to create it (can happen with application private dirs)
566 // Ignore mkdir failures; we want to be consistent with Open C
567 // current path regardless.
568 QT_MKDIR(QFile::encodeName(QLatin1String(nativeCurrentName
)), 0777);
570 # if defined(QT_DEBUG)
571 qWarning("QFSFileEngine::currentPath: stat(\".\") failed");
578 QString
QFSFileEngine::homePath()
580 #if defined(Q_OS_SYMBIAN)
581 QString home
= rootPath();
583 QString home
= QFile::decodeName(qgetenv("HOME"));
590 QString
QFSFileEngine::rootPath()
592 #if defined(Q_OS_SYMBIAN)
594 TFileName symbianPath
= PathInfo::PhoneMemoryRootPath();
595 return QDir::cleanPath(QDir::fromNativeSeparators(qt_TDesC2QString(symbianPath
)));
597 # warning No fallback implementation of QFSFileEngine::rootPath()
601 return QLatin1String("/");
605 QString
QFSFileEngine::tempPath()
607 #if defined(Q_OS_SYMBIAN)
609 TFileName symbianPath
= PathInfo::PhoneMemoryRootPath();
610 QString temp
= QDir::fromNativeSeparators(qt_TDesC2QString(symbianPath
));
611 temp
+= QLatin1String( "temp/");
613 // Just to verify that folder really exist on hardware
614 QT_MKDIR(QFile::encodeName(temp
), 0777);
616 # warning No fallback implementation of QFSFileEngine::tempPath()
620 QString temp
= QFile::decodeName(qgetenv("TMPDIR"));
622 temp
= QLatin1String("/tmp/");
627 QFileInfoList
QFSFileEngine::drives()
630 #if defined(Q_OS_SYMBIAN)
631 TDriveList driveList
;
632 RFs rfs
= qt_s60GetRFs();
633 TInt err
= rfs
.DriveList(driveList
);
634 if (err
== KErrNone
) {
635 char driveName
[] = "A:/";
637 for (char i
= 0; i
< KMaxDrives
; i
++) {
639 driveName
[0] = 'A' + i
;
640 ret
.append(QFileInfo(QLatin1String(driveName
)));
644 qWarning("QFSFileEngine::drives: Getting drives failed");
647 ret
.append(QFileInfo(rootPath()));
652 bool QFSFileEnginePrivate::doStat() const
658 if (fh
&& nativeFilePath
.isEmpty()) {
659 // ### actually covers two cases: d->fh and when the file is not open
660 could_stat
= (QT_FSTAT(QT_FILENO(fh
), &st
) == 0);
661 } else if (fd
== -1) {
662 // ### actually covers two cases: d->fh and when the file is not open
663 could_stat
= (QT_STAT(nativeFilePath
.constData(), &st
) == 0);
665 could_stat
= (QT_FSTAT(fd
, &st
) == 0);
671 bool QFSFileEnginePrivate::isSymlink() const
676 QT_STATBUF st
; // don't clobber our main one
677 is_link
= (QT_LSTAT(nativeFilePath
.constData(), &st
) == 0) ? S_ISLNK(st
.st_mode
) : false;
682 #if defined(Q_OS_SYMBIAN)
683 static bool _q_isSymbianHidden(const QString
&path
, bool isDir
)
685 RFs rfs
= qt_s60GetRFs();
687 QString absPath
= fi
.absoluteFilePath();
688 if (isDir
&& !absPath
.endsWith(QLatin1Char('/')))
689 absPath
.append(QLatin1Char('/'));
690 QString
native(QDir::toNativeSeparators(absPath
));
691 TPtrC
ptr(qt_QString2TPtrC(native
));
693 TInt err
= rfs
.Att(ptr
, attributes
);
694 return (err
== KErrNone
&& (attributes
& KEntryAttHidden
));
698 #if !defined(QWS) && defined(Q_OS_MAC)
699 static bool _q_isMacHidden(const QString
&path
)
705 err
= FSPathMakeRefWithOptions(reinterpret_cast<const UInt8
*>(QFile::encodeName(QDir::cleanPath(path
)).constData()),
706 kFSPathMakeRefDoNotFollowLeafSymlink
, &fsRef
, 0);
710 FSCatalogInfo catInfo
;
711 err
= FSGetCatalogInfo(&fsRef
, kFSCatInfoFinderInfo
, &catInfo
, NULL
, NULL
, NULL
);
715 FileInfo
* const fileInfo
= reinterpret_cast<FileInfo
*>(&catInfo
.finderInfo
);
716 bool result
= (fileInfo
->finderFlags
& kIsInvisible
);
724 QAbstractFileEngine::FileFlags
QFSFileEngine::fileFlags(FileFlags type
) const
726 Q_D(const QFSFileEngine
);
727 // Force a stat, so that we're guaranteed to get up-to-date results
728 if (type
& Refresh
) {
733 QAbstractFileEngine::FileFlags ret
= 0;
734 if (type
& FlagsMask
)
735 ret
|= LocalDiskFlag
;
736 bool exists
= d
->doStat();
737 if (!exists
&& !d
->isSymlink())
740 if (exists
&& (type
& PermsMask
)) {
741 if (d
->st
.st_mode
& S_IRUSR
)
742 ret
|= ReadOwnerPerm
;
743 if (d
->st
.st_mode
& S_IWUSR
)
744 ret
|= WriteOwnerPerm
;
745 if (d
->st
.st_mode
& S_IXUSR
)
747 if (d
->st
.st_mode
& S_IRUSR
)
749 if (d
->st
.st_mode
& S_IWUSR
)
750 ret
|= WriteUserPerm
;
751 if (d
->st
.st_mode
& S_IXUSR
)
753 if (d
->st
.st_mode
& S_IRGRP
)
754 ret
|= ReadGroupPerm
;
755 if (d
->st
.st_mode
& S_IWGRP
)
756 ret
|= WriteGroupPerm
;
757 if (d
->st
.st_mode
& S_IXGRP
)
759 if (d
->st
.st_mode
& S_IROTH
)
760 ret
|= ReadOtherPerm
;
761 if (d
->st
.st_mode
& S_IWOTH
)
762 ret
|= WriteOtherPerm
;
763 if (d
->st
.st_mode
& S_IXOTH
)
766 if (type
& TypesMask
) {
767 #if !defined(QWS) && defined(Q_OS_MAC)
768 bool foundAlias
= false;
771 if (FSPathMakeRef((const UInt8
*)QFile::encodeName(QDir::cleanPath(d
->filePath
)).data(),
772 &fref
, NULL
) == noErr
) {
773 Boolean isAlias
, isFolder
;
774 if (FSIsAliasFile(&fref
, &isAlias
, &isFolder
) == noErr
&& isAlias
) {
783 if ((type
& LinkType
) && d
->isSymlink())
785 if (exists
&& (d
->st
.st_mode
& S_IFMT
) == S_IFREG
)
787 else if (exists
&& (d
->st
.st_mode
& S_IFMT
) == S_IFDIR
)
788 ret
|= DirectoryType
;
789 #if !defined(QWS) && defined(Q_OS_MAC)
790 if ((ret
& DirectoryType
) && (type
& BundleType
)) {
791 QCFType
<CFURLRef
> url
= CFURLCreateWithFileSystemPath(0, QCFString(d
->filePath
),
792 kCFURLPOSIXPathStyle
, true);
793 UInt32 type
, creator
;
794 if (CFBundleGetPackageInfoInDirectory(url
, &type
, &creator
))
800 if (type
& FlagsMask
) {
803 #if defined(Q_OS_SYMBIAN)
804 if (d
->filePath
== QLatin1String("/")
805 || (d
->filePath
.length() == 3 && d
->filePath
.at(0).isLetter()
806 && d
->filePath
.at(1) == QLatin1Char(':') && d
->filePath
.at(2) == QLatin1Char('/'))) {
809 // In Symbian, all symlinks have hidden attribute for some reason;
810 // lets make them visible for better compatibility with other platforms.
811 // If somebody actually wants a hidden link, then they are out of luck.
812 if (!d
->isSymlink() && _q_isSymbianHidden(d
->filePath
, ret
& DirectoryType
))
816 if (d
->filePath
== QLatin1String("/")) {
819 QString baseName
= fileName(BaseName
);
820 if ((baseName
.size() > 1
821 && baseName
.at(0) == QLatin1Char('.') && baseName
.at(1) != QLatin1Char('.'))
822 # if !defined(QWS) && defined(Q_OS_MAC)
823 || _q_isMacHidden(d
->filePath
)
834 #if defined(Q_OS_SYMBIAN)
835 QString
QFSFileEngine::fileName(FileName file
) const
837 Q_D(const QFSFileEngine
);
838 const QLatin1Char
slashChar('/');
839 if(file
== BaseName
) {
840 int slash
= d
->filePath
.lastIndexOf(slashChar
);
842 int colon
= d
->filePath
.lastIndexOf(QLatin1Char(':'));
844 return d
->filePath
.mid(colon
+ 1);
847 return d
->filePath
.mid(slash
+ 1);
848 } else if(file
== PathName
) {
849 if(!d
->filePath
.size())
852 int slash
= d
->filePath
.lastIndexOf(slashChar
);
854 if(d
->filePath
.length() >= 2 && d
->filePath
.at(1) == QLatin1Char(':'))
855 return d
->filePath
.left(2);
856 return QLatin1String(".");
859 return QLatin1String("/");
860 if(slash
== 2 && d
->filePath
.length() >= 2 && d
->filePath
.at(1) == QLatin1Char(':'))
862 return d
->filePath
.left(slash
);
864 } else if(file
== AbsoluteName
|| file
== AbsolutePathName
) {
866 if (!isRelativePathSymbian(d
->filePath
)) {
867 if (d
->filePath
.size() > 2 && d
->filePath
.at(1) == QLatin1Char(':')
868 && d
->filePath
.at(2) != slashChar
){
869 // It's a drive-relative path, so C:a.txt -> C:/currentpath/a.txt,
870 // or if it's different drive than current, Z:a.txt -> Z:/a.txt
871 QString currentPath
= QDir::currentPath();
872 if (0 == currentPath
.left(1).compare(d
->filePath
.left(1), Qt::CaseInsensitive
))
873 ret
= currentPath
+ slashChar
+ d
->filePath
.mid(2);
875 ret
= d
->filePath
.left(2) + slashChar
+ d
->filePath
.mid(2);
876 } else if (d
->filePath
.startsWith(slashChar
)) {
877 // It's a absolute path to the current drive, so /a.txt -> C:/a.txt
878 ret
= QDir::currentPath().left(2) + d
->filePath
;
883 ret
= QDir::currentPath() + slashChar
+ d
->filePath
;
886 // The path should be absolute at this point.
888 // Absolute paths begin with the directory separator "/"
889 // (optionally preceded by a drive specification under Windows).
890 if (ret
.at(0) != slashChar
) {
891 Q_ASSERT(ret
.length() >= 2);
892 Q_ASSERT(ret
.at(0).isLetter());
893 Q_ASSERT(ret
.at(1) == QLatin1Char(':'));
895 // Force uppercase drive letters.
896 ret
[0] = ret
.at(0).toUpper();
900 bool isDir
= ret
.endsWith(slashChar
);
901 ret
= QDir::cleanPath(ret
);
902 if (isDir
&& !ret
.endsWith(slashChar
))
905 if (file
== AbsolutePathName
) {
906 int slash
= ret
.lastIndexOf(slashChar
);
909 else if (ret
.at(0) != slashChar
&& slash
== 2)
910 return ret
.left(3); // include the slash
912 return ret
.left(slash
> 0 ? slash
: 1);
915 } else if(file
== CanonicalName
|| file
== CanonicalPathName
) {
916 if (!(fileFlags(ExistsFlag
) & ExistsFlag
))
919 QString ret
= QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName
));
920 if (file
== CanonicalPathName
&& !ret
.isEmpty()) {
921 int slash
= ret
.lastIndexOf(slashChar
);
923 ret
= QDir::fromNativeSeparators(QDir::currentPath());
925 ret
= QLatin1String("/");
926 ret
= ret
.left(slash
);
929 } else if(file
== LinkName
) {
930 if (d
->isSymlink()) {
932 int len
= readlink(d
->nativeFilePath
.constData(), s
, PATH_MAX
);
935 QString ret
= QFile::decodeName(QByteArray(s
));
937 if (isRelativePathSymbian(ret
)) {
938 if (!isRelativePathSymbian(d
->filePath
)) {
939 ret
.prepend(d
->filePath
.left(d
->filePath
.lastIndexOf(slashChar
))
942 ret
.prepend(QDir::currentPath() + slashChar
);
945 ret
= QDir::cleanPath(ret
);
946 if (ret
.size() > 1 && ret
.endsWith(slashChar
))
952 } else if(file
== BundleName
) {
960 QString
QFSFileEngine::fileName(FileName file
) const
962 Q_D(const QFSFileEngine
);
963 if (file
== BundleName
) {
964 #if !defined(QWS) && defined(Q_OS_MAC)
965 QCFType
<CFURLRef
> url
= CFURLCreateWithFileSystemPath(0, QCFString(d
->filePath
),
966 kCFURLPOSIXPathStyle
, true);
967 if (CFDictionaryRef dict
= CFBundleCopyInfoDictionaryForURL(url
)) {
968 if (CFTypeRef name
= (CFTypeRef
)CFDictionaryGetValue(dict
, kCFBundleNameKey
)) {
969 if (CFGetTypeID(name
) == CFStringGetTypeID())
970 return QCFString::toQString((CFStringRef
)name
);
975 } else if (file
== BaseName
) {
976 int slash
= d
->filePath
.lastIndexOf(QLatin1Char('/'));
978 return d
->filePath
.mid(slash
+ 1);
979 } else if (file
== PathName
) {
980 int slash
= d
->filePath
.lastIndexOf(QLatin1Char('/'));
982 return QLatin1String(".");
984 return QLatin1String("/");
985 return d
->filePath
.left(slash
);
986 } else if (file
== AbsoluteName
|| file
== AbsolutePathName
) {
988 if (d
->filePath
.isEmpty() || !d
->filePath
.startsWith(QLatin1Char('/')))
989 ret
= QDir::currentPath();
990 if (!d
->filePath
.isEmpty() && d
->filePath
!= QLatin1String(".")) {
991 if (!ret
.isEmpty() && !ret
.endsWith(QLatin1Char('/')))
992 ret
+= QLatin1Char('/');
995 if (ret
== QLatin1String("/"))
997 bool isDir
= ret
.endsWith(QLatin1Char('/'));
998 ret
= QDir::cleanPath(ret
);
1000 ret
+= QLatin1Char('/');
1001 if (file
== AbsolutePathName
) {
1002 int slash
= ret
.lastIndexOf(QLatin1Char('/'));
1004 return QDir::currentPath();
1006 return QLatin1String("/");
1007 return ret
.left(slash
);
1010 } else if (file
== CanonicalName
|| file
== CanonicalPathName
) {
1011 if (!(fileFlags(ExistsFlag
) & ExistsFlag
))
1014 QString ret
= QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName
));
1015 if (file
== CanonicalPathName
&& !ret
.isEmpty()) {
1016 int slash
= ret
.lastIndexOf(QLatin1Char('/'));
1018 ret
= QDir::currentPath();
1019 else if (slash
== 0)
1020 ret
= QLatin1String("/");
1021 ret
= ret
.left(slash
);
1024 } else if (file
== LinkName
) {
1025 if (d
->isSymlink()) {
1026 #if defined(__GLIBC__) && !defined(PATH_MAX)
1027 #define PATH_CHUNK_SIZE 256
1030 int size
= PATH_CHUNK_SIZE
;
1033 s
= q_check_ptr((char *) ::realloc(s
, size
));
1034 len
= ::readlink(d
->nativeFilePath
.constData(), s
, size
);
1046 int len
= readlink(d
->nativeFilePath
.constData(), s
, PATH_MAX
);
1050 if (d
->doStat() && S_ISDIR(d
->st
.st_mode
) && s
[0] != '/') {
1051 QDir
parent(d
->filePath
);
1053 ret
= parent
.path();
1054 if (!ret
.isEmpty() && !ret
.endsWith(QLatin1Char('/')))
1055 ret
+= QLatin1Char('/');
1058 ret
+= QFile::decodeName(QByteArray(s
));
1059 #if defined(__GLIBC__) && !defined(PATH_MAX)
1063 if (!ret
.startsWith(QLatin1Char('/'))) {
1064 if (d
->filePath
.startsWith(QLatin1Char('/'))) {
1065 ret
.prepend(d
->filePath
.left(d
->filePath
.lastIndexOf(QLatin1Char('/')))
1066 + QLatin1Char('/'));
1068 ret
.prepend(QDir::currentPath() + QLatin1Char('/'));
1071 ret
= QDir::cleanPath(ret
);
1072 if (ret
.size() > 1 && ret
.endsWith(QLatin1Char('/')))
1077 #if !defined(QWS) && defined(Q_OS_MAC)
1080 if (FSPathMakeRef((const UInt8
*)QFile::encodeName(QDir::cleanPath(d
->filePath
)).data(), &fref
, 0) == noErr
) {
1081 Boolean isAlias
, isFolder
;
1082 if (FSResolveAliasFile(&fref
, true, &isFolder
, &isAlias
) == noErr
&& isAlias
) {
1084 if (FSNewAlias(0, &fref
, &alias
) == noErr
&& alias
) {
1086 if (FSCopyAliasInfo(alias
, 0, 0, &cfstr
, 0, 0) == noErr
)
1087 return QCFString::toQString(cfstr
);
1097 #endif // Q_OS_SYMBIAN
1099 bool QFSFileEngine::isRelativePath() const
1101 Q_D(const QFSFileEngine
);
1102 #if defined(Q_OS_SYMBIAN)
1103 return isRelativePathSymbian(d
->filePath
);
1105 return d
->filePath
.length() ? d
->filePath
[0] != QLatin1Char('/') : true;
1109 uint
QFSFileEngine::ownerId(FileOwner own
) const
1111 Q_D(const QFSFileEngine
);
1112 static const uint nobodyID
= (uint
) -2;
1114 if (own
== OwnerUser
)
1115 return d
->st
.st_uid
;
1117 return d
->st
.st_gid
;
1122 QString
QFSFileEngine::owner(FileOwner own
) const
1124 #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
1125 int size_max
= sysconf(_SC_GETPW_R_SIZE_MAX
);
1128 QVarLengthArray
<char, 1024> buf(size_max
);
1131 if (own
== OwnerUser
) {
1132 struct passwd
*pw
= 0;
1133 #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
1134 struct passwd entry
;
1135 getpwuid_r(ownerId(own
), &entry
, buf
.data(), buf
.size(), &pw
);
1137 pw
= getpwuid(ownerId(own
));
1140 return QFile::decodeName(QByteArray(pw
->pw_name
));
1141 } else if (own
== OwnerGroup
) {
1142 #if !defined(Q_OS_SYMBIAN)
1143 struct group
*gr
= 0;
1144 #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
1145 size_max
= sysconf(_SC_GETGR_R_SIZE_MAX
);
1148 buf
.resize(size_max
);
1150 // Some large systems have more members than the POSIX max size
1151 // Loop over by doubling the buffer size (upper limit 250k)
1152 for (unsigned size
= size_max
; size
< 256000; size
+= size
)
1155 // ERANGE indicates that the buffer was too small
1156 if (!getgrgid_r(ownerId(own
), &entry
, buf
.data(), buf
.size(), &gr
)
1161 gr
= getgrgid(ownerId(own
));
1164 return QFile::decodeName(QByteArray(gr
->gr_name
));
1170 bool QFSFileEngine::setPermissions(uint perms
)
1175 if (perms
& ReadOwnerPerm
)
1177 if (perms
& WriteOwnerPerm
)
1179 if (perms
& ExeOwnerPerm
)
1181 if (perms
& ReadUserPerm
)
1183 if (perms
& WriteUserPerm
)
1185 if (perms
& ExeUserPerm
)
1187 if (perms
& ReadGroupPerm
)
1189 if (perms
& WriteGroupPerm
)
1191 if (perms
& ExeGroupPerm
)
1193 if (perms
& ReadOtherPerm
)
1195 if (perms
& WriteOtherPerm
)
1197 if (perms
& ExeOtherPerm
)
1200 ret
= fchmod(d
->fd
, mode
) == 0;
1202 ret
= ::chmod(d
->nativeFilePath
.constData(), mode
) == 0;
1204 setError(QFile::PermissionsError
, qt_error_string(errno
));
1208 bool QFSFileEngine::setSize(qint64 size
)
1213 ret
= QT_FTRUNCATE(d
->fd
, size
) == 0;
1215 ret
= QT_FTRUNCATE(QT_FILENO(d
->fh
), size
) == 0;
1217 ret
= QT_TRUNCATE(d
->nativeFilePath
.constData(), size
) == 0;
1219 setError(QFile::ResizeError
, qt_error_string(errno
));
1223 QDateTime
QFSFileEngine::fileTime(FileTime time
) const
1225 Q_D(const QFSFileEngine
);
1228 if (time
== CreationTime
)
1229 ret
.setTime_t(d
->st
.st_ctime
? d
->st
.st_ctime
: d
->st
.st_mtime
);
1230 else if (time
== ModificationTime
)
1231 ret
.setTime_t(d
->st
.st_mtime
);
1232 else if (time
== AccessTime
)
1233 ret
.setTime_t(d
->st
.st_atime
);
1238 uchar
*QFSFileEnginePrivate::map(qint64 offset
, qint64 size
, QFile::MemoryMapFlags flags
)
1242 if (openMode
== QIODevice::NotOpen
) {
1243 q
->setError(QFile::PermissionsError
, qt_error_string(int(EACCES
)));
1247 if (offset
< 0 || offset
!= qint64(QT_OFF_T(offset
))
1248 || size
< 0 || size
> (size_t)-1) {
1249 q
->setError(QFile::UnspecifiedError
, qt_error_string(int(EINVAL
)));
1254 if (openMode
& QIODevice::ReadOnly
) access
|= PROT_READ
;
1255 if (openMode
& QIODevice::WriteOnly
) access
|= PROT_WRITE
;
1257 int pageSize
= getpagesize();
1258 int extra
= offset
% pageSize
;
1260 if (size
+ extra
> (size_t)-1) {
1261 q
->setError(QFile::UnspecifiedError
, qt_error_string(int(EINVAL
)));
1265 size_t realSize
= (size_t)size
+ extra
;
1266 QT_OFF_T realOffset
= QT_OFF_T(offset
);
1267 realOffset
&= ~(QT_OFF_T(pageSize
));
1271 TRAPD(err
, mapAddress
= QT_MMAP((void*)0, realSize
,
1272 access
, MAP_SHARED
, nativeHandle(), realOffset
));
1273 if (err
!= KErrNone
) {
1274 qWarning("OpenC bug: leave from mmap %d", err
);
1275 mapAddress
= MAP_FAILED
;
1279 void *mapAddress
= QT_MMAP((void*)0, realSize
,
1280 access
, MAP_SHARED
, nativeHandle(), realOffset
);
1282 if (MAP_FAILED
!= mapAddress
) {
1283 uchar
*address
= extra
+ static_cast<uchar
*>(mapAddress
);
1284 maps
[address
] = QPair
<int,size_t>(extra
, realSize
);
1290 q
->setError(QFile::PermissionsError
, qt_error_string(int(EACCES
)));
1294 q
->setError(QFile::ResourceError
, qt_error_string(int(errno
)));
1297 // size are out of bounds
1299 q
->setError(QFile::UnspecifiedError
, qt_error_string(int(errno
)));
1305 bool QFSFileEnginePrivate::unmap(uchar
*ptr
)
1308 if (!maps
.contains(ptr
)) {
1309 q
->setError(QFile::PermissionsError
, qt_error_string(EACCES
));
1313 uchar
*start
= ptr
- maps
[ptr
].first
;
1314 size_t len
= maps
[ptr
].second
;
1315 if (-1 == munmap(start
, len
)) {
1316 q
->setError(QFile::UnspecifiedError
, qt_error_string(errno
));
1325 #endif // QT_NO_FSFILEENGINE